summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop.yml72
-rw-r--r--CHANGELOG.md42
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock21
-rw-r--r--PROCESS.md7
-rw-r--r--app/assets/images/icons.json2
-rw-r--r--app/assets/images/icons.svg2
-rw-r--r--app/assets/images/illustrations/canceled-job_empty.svg1
-rw-r--r--app/assets/images/illustrations/epics.svg2
-rw-r--r--app/assets/images/illustrations/epics/list.svg1
-rw-r--r--app/assets/images/illustrations/epics/roadmap.svg1
-rw-r--r--app/assets/images/illustrations/issue-dashboard_results-without-filiter.svg1
-rw-r--r--app/assets/images/illustrations/lock_promotion.svg1
-rw-r--r--app/assets/images/illustrations/milestone_removing-page.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/activity.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/contributed-projects.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/groups.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/personal-project.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/personal-projects.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/snippets.svg1
-rw-r--r--app/assets/images/illustrations/prometheus-graphs_empty.svg1
-rw-r--r--app/assets/images/illustrations/web-ide_promotion.svg1
-rw-r--r--app/assets/javascripts/behaviors/quick_submit.js2
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue2
-rw-r--r--app/assets/javascripts/commons/vue.js1
-rw-r--r--app/assets/javascripts/importer_status.js31
-rw-r--r--app/assets/javascripts/notes/components/diff_file_header.vue2
-rw-r--r--app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue64
-rw-r--r--app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js84
-rw-r--r--app/assets/javascripts/pages/milestones/shared/index.js89
-rw-r--r--app/assets/javascripts/pages/milestones/shared/promote_milestone_modal_init.js82
-rw-r--r--app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue79
-rw-r--r--app/assets/javascripts/pages/projects/labels/event_hub.js3
-rw-r--r--app/assets/javascripts/pages/projects/labels/index/index.js90
-rw-r--r--app/assets/javascripts/pipelines/components/nav_controls.vue27
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines.vue21
-rw-r--r--app/assets/javascripts/pipelines/mixins/pipelines.js6
-rw-r--r--app/assets/javascripts/prometheus_metrics/prometheus_metrics.js59
-rw-r--r--app/assets/javascripts/registry/components/collapsible_container.vue1
-rw-r--r--app/assets/javascripts/registry/components/table_registry.vue1
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue (renamed from app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.js)89
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js2
-rw-r--r--app/assets/javascripts/terminal/terminal.js10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue (renamed from app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js)87
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue20
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/dependencies.js1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/clipboard_button.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/memory_graph.vue (renamed from app/assets/javascripts/vue_shared/components/memory_graph.js)38
-rw-r--r--app/assets/stylesheets/framework/common.scss4
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss2
-rw-r--r--app/assets/stylesheets/framework/flash.scss6
-rw-r--r--app/assets/stylesheets/framework/modal.scss9
-rw-r--r--app/assets/stylesheets/pages/settings.scss3
-rw-r--r--app/controllers/concerns/authenticates_with_two_factor.rb1
-rw-r--r--app/controllers/concerns/creates_commit.rb8
-rw-r--r--app/controllers/import/github_controller.rb18
-rw-r--r--app/controllers/projects/application_controller.rb12
-rw-r--r--app/controllers/projects/blob_controller.rb8
-rw-r--r--app/controllers/projects/labels_controller.rb8
-rw-r--r--app/controllers/projects/merge_requests/application_controller.rb1
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/controllers/projects/milestones_controller.rb14
-rw-r--r--app/controllers/projects/services_controller.rb33
-rw-r--r--app/controllers/projects/settings/ci_cd_controller.rb10
-rw-r--r--app/finders/user_recent_events_finder.rb45
-rw-r--r--app/helpers/import_helper.rb36
-rw-r--r--app/helpers/merge_requests_helper.rb13
-rw-r--r--app/helpers/tree_helper.rb21
-rw-r--r--app/mailers/notify.rb2
-rw-r--r--app/models/concerns/deployment_platform.rb3
-rw-r--r--app/models/concerns/issuable.rb4
-rw-r--r--app/models/cycle_analytics/summary.rb0
-rw-r--r--app/models/environment.rb6
-rw-r--r--app/models/event.rb8
-rw-r--r--app/models/member.rb5
-rw-r--r--app/models/members/project_member.rb6
-rw-r--r--app/models/merge_request.rb40
-rw-r--r--app/models/merge_request_diff.rb4
-rw-r--r--app/models/note.rb9
-rw-r--r--app/models/project.rb46
-rw-r--r--app/models/project_team.rb9
-rw-r--r--app/models/repository.rb21
-rw-r--r--app/models/service.rb11
-rw-r--r--app/models/snippet.rb4
-rw-r--r--app/models/user.rb40
-rw-r--r--app/models/user_interacted_project.rb59
-rw-r--r--app/policies/project_policy.rb14
-rw-r--r--app/presenters/merge_request_presenter.rb19
-rw-r--r--app/serializers/merge_request_widget_entity.rb8
-rw-r--r--app/services/ci/create_pipeline_service.rb2
-rw-r--r--app/services/members/destroy_service.rb40
-rw-r--r--app/services/merge_requests/base_service.rb8
-rw-r--r--app/services/merge_requests/build_service.rb1
-rw-r--r--app/services/notes/build_service.rb9
-rw-r--r--app/services/notes/post_process_service.rb2
-rw-r--r--app/services/notification_recipient_service.rb2
-rw-r--r--app/services/projects/create_service.rb2
-rw-r--r--app/services/projects/update_service.rb2
-rw-r--r--app/services/todo_service.rb3
-rw-r--r--app/services/users/destroy_service.rb2
-rw-r--r--app/views/admin/application_settings/_form.html.haml6
-rw-r--r--app/views/admin/hooks/_form.html.haml42
-rw-r--r--app/views/admin/hooks/index.html.haml58
-rw-r--r--app/views/groups/issues.html.haml3
-rw-r--r--app/views/import/_githubish_status.html.haml22
-rw-r--r--app/views/import/github/new.html.haml38
-rw-r--r--app/views/import/github/status.html.haml6
-rw-r--r--app/views/projects/_commit_button.html.haml4
-rw-r--r--app/views/projects/blob/_new_dir.html.haml4
-rw-r--r--app/views/projects/blob/_upload.html.haml4
-rw-r--r--app/views/projects/clusters/_integration_form.html.haml6
-rw-r--r--app/views/projects/commit/_change.html.haml4
-rw-r--r--app/views/projects/cycle_analytics/show.html.haml2
-rw-r--r--app/views/projects/environments/index.html.haml3
-rw-r--r--app/views/projects/issues/index.html.haml3
-rw-r--r--app/views/projects/labels/index.html.haml1
-rw-r--r--app/views/projects/merge_requests/index.html.haml3
-rw-r--r--app/views/projects/milestones/index.html.haml1
-rw-r--r--app/views/projects/milestones/show.html.haml11
-rw-r--r--app/views/projects/new.html.haml2
-rw-r--r--app/views/projects/pipelines/show.html.haml3
-rw-r--r--app/views/projects/registry/repositories/index.html.haml2
-rw-r--r--app/views/projects/services/_form.html.haml3
-rw-r--r--app/views/projects/services/prometheus/_show.html.haml18
-rw-r--r--app/views/projects/settings/repository/show.html.haml3
-rw-r--r--app/views/shared/_label.html.haml12
-rw-r--r--app/views/shared/_new_commit_form.html.haml9
-rw-r--r--app/views/shared/_service_settings.html.haml4
-rw-r--r--app/views/shared/boards/_show.html.haml1
-rw-r--r--app/views/shared/issuable/_form.html.haml2
-rw-r--r--app/views/shared/issuable/form/_contribution.html.haml20
-rw-r--r--app/views/shared/milestones/_milestone.html.haml31
-rw-r--r--app/views/shared/plugins/_index.html.haml23
-rw-r--r--app/views/shared/projects/_edit_information.html.haml6
-rw-r--r--app/workers/emails_on_push_worker.rb2
-rw-r--r--app/workers/post_receive.rb2
-rw-r--r--changelogs/unreleased/39444-make-margin-around-dropdown-dividers-4px.yml5
-rw-r--r--changelogs/unreleased/40525-listing-user-activity-timeouts.yml5
-rw-r--r--changelogs/unreleased/42921-ci-charts-include-current-day.yml5
-rw-r--r--changelogs/unreleased/43261-fix-prometheus-installation.yml5
-rw-r--r--changelogs/unreleased/43460-track-projects-a-user-interacted-with.yml5
-rw-r--r--changelogs/unreleased/43510-merge-requests-and-issues-don-t-show-for-all-subgroups.yml6
-rw-r--r--changelogs/unreleased/43531-500-error-searching-wiki-incompatible-character-encodings-utf-8-and-ascii-8bit.yml5
-rw-r--r--changelogs/unreleased/43532-error-on-admin-applications-prometheus-template.yml5
-rw-r--r--changelogs/unreleased/43780-add-a-paragraph-about-clusters-security-implications.yml5
-rw-r--r--changelogs/unreleased/43802-ensure-foreign-keys-on-clusters-applications.yml5
-rw-r--r--changelogs/unreleased/43949-verify-job-artifacts.yml5
-rw-r--r--changelogs/unreleased/bvl-allow-maintainer-to-push.yml5
-rw-r--r--changelogs/unreleased/ce-jej-github-project-service-for-ci.yml5
-rw-r--r--changelogs/unreleased/ce-jej-integrations-can-hide-trigger-checkboxes.yml6
-rw-r--r--changelogs/unreleased/discussions-api.yml5
-rw-r--r--changelogs/unreleased/dz-plugins-project-integrations.yml5
-rw-r--r--changelogs/unreleased/feature--43691-count-diff-note-calendar-activity.yml2
-rw-r--r--changelogs/unreleased/fix-mattermost-delete-team.yml5
-rw-r--r--changelogs/unreleased/fix-sm-fix_pages_worker.yml5
-rw-r--r--changelogs/unreleased/grpc-unavailable-restart.yml5
-rw-r--r--changelogs/unreleased/issue-edit-shortcut.yml5
-rw-r--r--changelogs/unreleased/jivl-new-modal-project-labels-milestones.yml5
-rw-r--r--changelogs/unreleased/minimal-fix-for-artifacts-service.yml5
-rw-r--r--changelogs/unreleased/mk-fix-error-code-for-repo-does-not-exist.yml5
-rw-r--r--changelogs/unreleased/mr-commit-optimization.yml5
-rw-r--r--changelogs/unreleased/refactor-move-mr-widget-memory-usage-and-graph-components.yml5
-rw-r--r--changelogs/unreleased/refactor-move-sidebar-assignee-vue-component.yml5
-rw-r--r--changelogs/unreleased/remove-projects-finder-from-todos-finder.yml5
-rw-r--r--changelogs/unreleased/replace_redcarpet_with_cmark.yml5
-rw-r--r--changelogs/unreleased/revert-project-visibility-changes.yml5
-rw-r--r--changelogs/unreleased/sh-add-missing-acts-as-taggable-indices.yml5
-rw-r--r--changelogs/unreleased/sh-add-section-name-index.yml5
-rw-r--r--changelogs/unreleased/sh-fix-otp-backup-code-invalidation.yml5
-rw-r--r--changelogs/unreleased/sh-make-prune-optional-in-git-fetch.yml5
-rw-r--r--changelogs/unreleased/sh-remove-double-caching-repo-empty.yml5
-rw-r--r--changelogs/unreleased/unassign-when-leaving.yml5
-rw-r--r--changelogs/unreleased/upgrade-workhorse-4-0-0.yml5
-rw-r--r--changelogs/unreleased/zj-gitaly-encoding-issue.yml5
-rw-r--r--changelogs/unreleased/zj-move-opt-out-ruby-endpoints.yml5
-rw-r--r--config/application.rb6
-rw-r--r--config/initializers/8_metrics.rb1
-rw-r--r--config/routes/git_http.rb2
-rw-r--r--config/routes/group.rb4
-rw-r--r--config/routes/project.rb6
-rw-r--r--config/routes/user.rb4
-rw-r--r--config/webpack.config.js2
-rw-r--r--db/migrate/20180221151752_add_allow_maintainer_to_push_to_merge_requests.rb18
-rw-r--r--db/migrate/20180223120443_create_user_interacted_projects_table.rb18
-rw-r--r--db/migrate/20180227182112_add_group_id_to_boards_ce.rb (renamed from db/migrate/20180227182112_add_group_id_to_boards.rb)2
-rw-r--r--db/migrate/20180302152117_ensure_foreign_keys_on_clusters_applications.rb50
-rw-r--r--db/migrate/20180304204842_clean_commits_count_migration.rb14
-rw-r--r--db/migrate/20180306134842_add_missing_indexes_acts_as_taggable_on_engine.rb21
-rw-r--r--db/migrate/20180308052825_add_section_name_id_index_on_ci_build_trace_sections.rb22
-rw-r--r--db/post_migrate/20180223124427_build_user_interacted_projects_table.rb124
-rw-r--r--db/schema.rb17
-rw-r--r--doc/administration/monitoring/index.md1
-rw-r--r--doc/administration/raketasks/check.md4
-rw-r--r--doc/api/README.md1
-rw-r--r--doc/api/discussions.md411
-rw-r--r--doc/api/merge_requests.md62
-rw-r--r--doc/api/notes.md77
-rw-r--r--doc/ci/runners/README.md3
-rw-r--r--doc/development/i18n/externalization.md2
-rw-r--r--doc/development/new_fe_guide/dependencies.md3
-rw-r--r--doc/development/new_fe_guide/development/accessibility.md3
-rw-r--r--doc/development/new_fe_guide/development/components.md3
-rw-r--r--doc/development/new_fe_guide/development/design_patterns.md3
-rw-r--r--doc/development/new_fe_guide/development/index.md29
-rw-r--r--doc/development/new_fe_guide/development/network_requests.md3
-rw-r--r--doc/development/new_fe_guide/development/performance.md3
-rw-r--r--doc/development/new_fe_guide/development/security.md3
-rw-r--r--doc/development/new_fe_guide/development/testing.md3
-rw-r--r--doc/development/new_fe_guide/index.md28
-rw-r--r--doc/development/new_fe_guide/initiatives.md3
-rw-r--r--doc/development/new_fe_guide/principles.md3
-rw-r--r--doc/development/new_fe_guide/style/html.md3
-rw-r--r--doc/development/new_fe_guide/style/index.md9
-rw-r--r--doc/development/new_fe_guide/style/javascript.md3
-rw-r--r--doc/development/new_fe_guide/style/scss.md3
-rw-r--r--doc/development/new_fe_guide/style/vue.md3
-rw-r--r--doc/development/new_fe_guide/tips.md3
-rw-r--r--doc/install/installation.md4
-rw-r--r--doc/topics/autodevops/index.md12
-rw-r--r--doc/update/10.5-to-10.6.md361
-rw-r--r--doc/user/admin_area/settings/img/update-available.pngbin0 -> 89748 bytes
-rw-r--r--doc/user/admin_area/settings/usage_statistics.md26
-rw-r--r--doc/user/permissions.md3
-rw-r--r--doc/user/project/clusters/index.md42
-rw-r--r--doc/user/project/issue_board.md11
-rw-r--r--doc/user/project/merge_requests/img/allow_maintainer_push.pngbin0 -> 99079 bytes
-rw-r--r--doc/user/project/merge_requests/index.md1
-rw-r--r--doc/user/project/merge_requests/maintainer_access.md13
-rw-r--r--doc/user/project/settings/import_export.md3
-rw-r--r--features/steps/shared/project.rb6
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/discussions.rb195
-rw-r--r--lib/api/entities.rb8
-rw-r--r--lib/api/helpers/internal_helpers.rb7
-rw-r--r--lib/api/helpers/notes_helpers.rb76
-rw-r--r--lib/api/merge_requests.rb1
-rw-r--r--lib/api/notes.rb94
-rw-r--r--lib/banzai/filter/commit_reference_filter.rb3
-rw-r--r--lib/banzai/filter/markdown_engines/common_mark.rb45
-rw-r--r--lib/banzai/filter/markdown_engines/redcarpet.rb32
-rw-r--r--lib/banzai/filter/markdown_filter.rb41
-rw-r--r--lib/banzai/filter/syntax_highlight_filter.rb1
-rw-r--r--lib/banzai/renderer/common_mark/html.rb21
-rw-r--r--lib/banzai/renderer/html.rb13
-rw-r--r--lib/banzai/renderer/redcarpet/html.rb15
-rw-r--r--lib/constraints/group_url_constrainer.rb12
-rw-r--r--lib/constraints/project_url_constrainer.rb20
-rw-r--r--lib/constraints/user_url_constrainer.rb12
-rw-r--r--lib/declarative_policy.rb4
-rw-r--r--lib/declarative_policy/delegate_dsl.rb16
-rw-r--r--lib/declarative_policy/dsl.rb103
-rw-r--r--lib/declarative_policy/policy_dsl.rb44
-rw-r--r--lib/declarative_policy/preferred_scope.rb2
-rw-r--r--lib/declarative_policy/rule_dsl.rb45
-rw-r--r--lib/gitlab/auth/result.rb2
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb2
-rw-r--r--lib/gitlab/checks/change_access.rb7
-rw-r--r--lib/gitlab/ci/charts.rb15
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb2
-rw-r--r--lib/gitlab/contributions_calendar.rb2
-rw-r--r--lib/gitlab/data_builder/build.rb2
-rw-r--r--lib/gitlab/data_builder/pipeline.rb1
-rw-r--r--lib/gitlab/git/commit.rb2
-rw-r--r--lib/gitlab/git/gitlab_projects.rb5
-rw-r--r--lib/gitlab/git/repository.rb60
-rw-r--r--lib/gitlab/gitaly_client/repository_service.rb4
-rw-r--r--lib/gitlab/health_checks/metric.rb2
-rw-r--r--lib/gitlab/health_checks/result.rb2
-rw-r--r--lib/gitlab/import_export.rb2
-rw-r--r--lib/gitlab/legacy_github_import/project_creator.rb9
-rw-r--r--lib/gitlab/middleware/release_env.rb2
-rw-r--r--lib/gitlab/shell.rb10
-rw-r--r--lib/gitlab/slash_commands/presenters/issue_new.rb2
-rw-r--r--lib/gitlab/slash_commands/presenters/issue_show.rb2
-rw-r--r--lib/gitlab/slash_commands/result.rb2
-rw-r--r--lib/gitlab/user_access.rb7
-rw-r--r--lib/gitlab/utils.rb8
-rw-r--r--lib/gitlab/verify/job_artifacts.rb27
-rw-r--r--lib/gitlab/workhorse.rb22
-rw-r--r--lib/haml_lint/inline_javascript.rb2
-rw-r--r--lib/mattermost/session.rb6
-rw-r--r--lib/mattermost/team.rb5
-rw-r--r--lib/rouge/plugins/common_mark.rb20
-rw-r--r--lib/system_check/helpers.rb2
-rw-r--r--lib/tasks/gitlab/artifacts/check.rake8
-rw-r--r--locale/gitlab.pot219
-rw-r--r--package.json2
-rw-r--r--qa/qa/page/project/settings/ci_cd.rb2
-rw-r--r--rubocop/rubocop.rb1
-rw-r--r--spec/controllers/projects/milestones_controller_spec.rb6
-rw-r--r--spec/controllers/projects/services_controller_spec.rb12
-rw-r--r--spec/controllers/projects/settings/ci_cd_controller_spec.rb19
-rw-r--r--spec/factories/ci/job_artifacts.rb6
-rw-r--r--spec/factories/notes.rb8
-rw-r--r--spec/features/admin/admin_hooks_spec.rb10
-rw-r--r--spec/features/merge_request/maintainer_edits_fork_spec.rb44
-rw-r--r--spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb85
-rw-r--r--spec/features/milestone_spec.rb11
-rw-r--r--spec/features/projects/import_export/test_project_export.tar.gzbin343087 -> 343092 bytes
-rw-r--r--spec/features/projects/new_project_spec.rb4
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb8
-rw-r--r--spec/features/projects/services/disable_triggers_spec.rb35
-rw-r--r--spec/features/projects/user_creates_files_spec.rb11
-rw-r--r--spec/features/users/login_spec.rb12
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_basic.json3
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_widget.json1
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/merge_requests.json3
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/notes.json1
-rw-r--r--spec/helpers/tree_helper_spec.rb9
-rw-r--r--spec/javascripts/environments/environments_app_spec.js13
-rw-r--r--spec/javascripts/importer_status_spec.js15
-rw-r--r--spec/javascripts/pages/labels/components/promote_label_modal_spec.js88
-rw-r--r--spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js83
-rw-r--r--spec/javascripts/pipelines/nav_controls_spec.js37
-rw-r--r--spec/javascripts/pipelines/pipelines_spec.js14
-rw-r--r--spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js2
-rw-r--r--spec/javascripts/sidebar/sidebar_assignees_spec.js2
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js40
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js18
-rw-r--r--spec/javascripts/vue_mr_widget/mr_widget_options_spec.js1
-rw-r--r--spec/javascripts/vue_shared/components/clipboard_button_spec.js5
-rw-r--r--spec/javascripts/vue_shared/components/memory_graph_spec.js26
-rw-r--r--spec/lib/constraints/group_url_constrainer_spec.rb2
-rw-r--r--spec/lib/constraints/project_url_constrainer_spec.rb2
-rw-r--r--spec/lib/constraints/user_url_constrainer_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/change_access_spec.rb3
-rw-r--r--spec/lib/gitlab/ci/charts_spec.rb45
-rw-r--r--spec/lib/gitlab/contributions_calendar_spec.rb7
-rw-r--r--spec/lib/gitlab/data_builder/pipeline_spec.rb1
-rw-r--r--spec/lib/gitlab/git/gitlab_projects_spec.rb20
-rw-r--r--spec/lib/gitlab/gitaly_client/repository_service_spec.rb14
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml1
-rw-r--r--spec/lib/gitlab/shell_spec.rb32
-rw-r--r--spec/lib/gitlab/user_access_spec.rb35
-rw-r--r--spec/lib/gitlab/utils_spec.rb16
-rw-r--r--spec/lib/gitlab/verify/job_artifacts_spec.rb35
-rw-r--r--spec/lib/mattermost/team_spec.rb104
-rw-r--r--spec/models/environment_spec.rb6
-rw-r--r--spec/models/event_spec.rb16
-rw-r--r--spec/models/members/project_member_spec.rb23
-rw-r--r--spec/models/merge_request_spec.rb78
-rw-r--r--spec/models/project_spec.rb101
-rw-r--r--spec/models/repository_spec.rb8
-rw-r--r--spec/models/user_interacted_project_spec.rb60
-rw-r--r--spec/models/user_spec.rb1
-rw-r--r--spec/policies/project_policy_spec.rb37
-rw-r--r--spec/requests/api/discussions_spec.rb33
-rw-r--r--spec/requests/api/internal_spec.rb28
-rw-r--r--spec/requests/api/merge_requests_spec.rb28
-rw-r--r--spec/requests/api/notes_spec.rb590
-rw-r--r--spec/routing/routing_spec.rb4
-rw-r--r--spec/serializers/merge_request_widget_entity_spec.rb6
-rw-r--r--spec/services/members/destroy_service_spec.rb96
-rw-r--r--spec/services/merge_requests/update_service_spec.rb37
-rw-r--r--spec/services/projects/update_service_spec.rb9
-rw-r--r--spec/support/matchers/match_ids.rb24
-rw-r--r--spec/support/shared_examples/requests/api/discussions.rb169
-rw-r--r--spec/support/shared_examples/requests/api/notes.rb206
-rw-r--r--spec/tasks/gitlab/artifacts/check_rake_spec.rb34
-rw-r--r--spec/views/projects/tree/show.html.haml_spec.rb1
-rw-r--r--spec/workers/post_receive_spec.rb12
-rw-r--r--vendor/gitignore/Dart.gitignore2
-rw-r--r--vendor/gitignore/Qt.gitignore8
-rw-r--r--vendor/gitignore/R.gitignore3
-rw-r--r--vendor/gitignore/TeX.gitignore8
-rw-r--r--vendor/gitignore/VisualStudio.gitignore3
-rw-r--r--vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml19
-rw-r--r--vendor/licenses.csv514
-rw-r--r--vendor/project_templates/express.tar.gzbin5608 -> 5614 bytes
-rw-r--r--vendor/project_templates/rails.tar.gzbin25004 -> 25007 bytes
-rw-r--r--vendor/project_templates/spring.tar.gzbin50938 -> 50945 bytes
-rw-r--r--yarn.lock6
380 files changed, 6130 insertions, 2023 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index 293f61fb725..14840ddd262 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -31,6 +31,78 @@ Style/MutableConstant:
- 'ee/db/post_migrate/**/*'
- 'ee/db/geo/migrate/**/*'
+Naming/FileName:
+ ExpectMatchingDefinition: true
+ Exclude:
+ - 'spec/**/*'
+ - 'features/**/*'
+ - 'ee/spec/**/*'
+ - 'qa/spec/**/*'
+ - 'qa/qa/specs/**/*'
+ - 'qa/bin/*'
+ - 'config/**/*'
+ - 'lib/generators/**/*'
+ - 'ee/lib/generators/**/*'
+ IgnoreExecutableScripts: true
+ AllowedAcronyms:
+ - EE
+ - JSON
+ - LDAP
+ - IO
+ - HMAC
+ - QA
+ - ENV
+ - STL
+ - PDF
+ - SVG
+ - CTE
+ - DN
+ - RSA
+ - CI
+ - CD
+ - OAuth
+ # default ones:
+ - CLI
+ - DSL
+ - ACL
+ - API
+ - ASCII
+ - CPU
+ - CSS
+ - DNS
+ - EOF
+ - GUID
+ - HTML
+ - HTTP
+ - HTTPS
+ - ID
+ - IP
+ - JSON
+ - LHS
+ - QPS
+ - RAM
+ - RHS
+ - RPC
+ - SLA
+ - SMTP
+ - SQL
+ - SSH
+ - TCP
+ - TLS
+ - TTL
+ - UDP
+ - UI
+ - UID
+ - UUID
+ - URI
+ - URL
+ - UTF8
+ - VM
+ - XML
+ - XMPP
+ - XSRF
+ - XSS
+
# Gitlab ###################################################################
Gitlab/ModuleWithInstanceVariables:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c8d399b2b98..630aef6751f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,34 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 10.5.4 (2018-03-08)
+
+### Fixed (11 changes)
+
+- Encode branch name as binary before creating a RPC request to copy attributes. !17291
+- Restart Unicorn and Sidekiq when GRPC throws 14:Endpoint read failed. !17293
+- Ensure group issues and merge requests pages show results from subgroups when there are no results from the current group. !17312
+- Prevent trace artifact migration to incur data loss. !17313
+- Return a 404 instead of 403 if the repository does not exist on disk. !17341
+- Allow Prometheus application to be installed from Cluster applications. !17372
+- Fixes Prometheus admin configuration page. !17377
+- Fix code and wiki search results pages when non-ASCII text is displayed. !17413
+- Fix pages flaky failure by reloading stale object. !17522
+- Fixed issue edit shortcut not opening edit form.
+- Revert Project.public_or_visible_to_user changes and only apply to snippets.
+
+### Performance (1 change)
+
+- Don't use ProjectsFinder in TodosFinder.
+
+
+## 10.5.3 (2018-03-01)
+
+### Security (1 change)
+
+- Ensure that OTP backup codes are always invalidated.
+
+
## 10.5.2 (2018-02-25)
### Fixed (7 changes)
@@ -219,6 +247,13 @@ entry.
- Adds empty state illustration for pending job.
+## 10.4.5 (2018-03-01)
+
+### Security (1 change)
+
+- Ensure that OTP backup codes are always invalidated.
+
+
## 10.4.4 (2018-02-16)
### Security (1 change)
@@ -443,6 +478,13 @@ entry.
- Use a background migration for issues.closed_at.
+## 10.3.8 (2018-03-01)
+
+### Security (1 change)
+
+- Ensure that OTP backup codes are always invalidated.
+
+
## 10.3.7 (2018-02-05)
### Security (4 changes)
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index a918a2aa18d..faef31a4357 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-0.6.0
+0.7.0
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 090ea9dad19..1aa5e414fd3 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-6.0.3
+6.0.4
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index 19811903a7f..fcdb2e109f6 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-3.8.0
+4.0.0
diff --git a/Gemfile b/Gemfile
index 35f9b081fdf..2793463fd81 100644
--- a/Gemfile
+++ b/Gemfile
@@ -126,6 +126,7 @@ gem 'html-pipeline', '~> 1.11.0'
gem 'deckar01-task_list', '2.0.0'
gem 'gitlab-markup', '~> 1.6.2'
gem 'redcarpet', '~> 3.4'
+gem 'commonmarker', '~> 0.17'
gem 'RedCloth', '~> 4.3.2'
gem 'rdoc', '~> 4.2'
gem 'org-ruby', '~> 0.9.12'
@@ -412,9 +413,7 @@ end
# Gitaly GRPC client
gem 'gitaly-proto', '~> 0.88.0', require: 'gitaly'
-# Explicitly lock grpc as we know 1.9 is bad
-# 1.10 is still being tested. See gitlab-org/gitaly#1059
-gem 'grpc', '~> 1.8.3'
+gem 'grpc', '~> 1.10.0'
# Locked until https://github.com/google/protobuf/issues/4210 is closed
gem 'google-protobuf', '= 3.5.1'
diff --git a/Gemfile.lock b/Gemfile.lock
index 010d4f7b56a..fa99ec3febe 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -131,6 +131,8 @@ GEM
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
colorize (0.7.7)
+ commonmarker (0.17.8)
+ ruby-enum (~> 0.5)
concord (0.1.5)
adamantium (~> 0.2.0)
equalizer (~> 0.0.9)
@@ -343,9 +345,9 @@ GEM
google-protobuf (3.5.1)
googleapis-common-protos-types (1.0.1)
google-protobuf (~> 3.0)
- googleauth (0.5.3)
+ googleauth (0.6.2)
faraday (~> 0.12)
- jwt (~> 1.4)
+ jwt (>= 1.4, < 3.0)
logging (~> 2.0)
memoist (~> 0.12)
multi_json (~> 1.11)
@@ -369,7 +371,7 @@ GEM
rake
grape_logging (1.7.0)
grape
- grpc (1.8.3)
+ grpc (1.10.0)
google-protobuf (~> 3.1)
googleapis-common-protos-types (~> 1.0.0)
googleauth (>= 0.5.1, < 0.7)
@@ -503,7 +505,7 @@ GEM
mini_portile2 (2.3.0)
minitest (5.7.0)
mousetrap-rails (1.4.6)
- multi_json (1.12.2)
+ multi_json (1.13.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
mustermann (1.0.0)
@@ -646,7 +648,7 @@ GEM
pry (~> 0.10)
pry-rails (0.3.5)
pry (>= 0.9.10)
- public_suffix (3.0.0)
+ public_suffix (3.0.2)
pyu-ruby-sasl (0.0.3.3)
rack (1.6.8)
rack-accept (0.4.5)
@@ -797,6 +799,8 @@ GEM
rubocop (>= 0.51)
rubocop-rspec (1.22.1)
rubocop (>= 0.52.1)
+ ruby-enum (0.7.2)
+ i18n
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-prof (0.16.2)
@@ -858,10 +862,10 @@ GEM
sidekiq (>= 4.2.1)
sidekiq-limit_fetch (3.4.0)
sidekiq (>= 4)
- signet (0.7.3)
+ signet (0.8.1)
addressable (~> 2.3)
faraday (~> 0.9)
- jwt (~> 1.5)
+ jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simple_po_parser (1.1.2)
simplecov (0.14.1)
@@ -1019,6 +1023,7 @@ DEPENDENCIES
charlock_holmes (~> 0.7.5)
chronic (~> 0.10.2)
chronic_duration (~> 0.10.6)
+ commonmarker (~> 0.17)
concurrent-ruby (~> 1.0.5)
connection_pool (~> 2.0)
creole (~> 0.5.0)
@@ -1073,7 +1078,7 @@ DEPENDENCIES
grape-entity (~> 0.6.0)
grape-route-helpers (~> 2.1.0)
grape_logging (~> 1.7)
- grpc (~> 1.8.3)
+ grpc (~> 1.10.0)
haml_lint (~> 0.26.0)
hamlit (~> 2.6.1)
hashie-forbidden_attributes
diff --git a/PROCESS.md b/PROCESS.md
index c24210341e0..f206506f7c5 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -53,7 +53,7 @@ Below we describe the contributing process to GitLab for two reasons:
Several people from the [GitLab team][team] are helping community members to get
their contributions accepted by meeting our [Definition of done][done].
-What you can expect from them is described at https://about.gitlab.com/jobs/merge-request-coach/.
+What you can expect from them is described at https://about.gitlab.com/roles/merge-request-coach/.
## Assigning issues
@@ -71,7 +71,7 @@ star, smile, etc.). Some good tips about code reviews can be found in our
## Feature freeze on the 7th for the release on the 22nd
-After 7th at 23:59 (Pacific Standard Time Zone) of each month, RC1 of the upcoming release (to be shipped on the 22nd) is created and deployed to GitLab.com and the stable branch for this release is frozen, which means master is no longer merged into it.
+After 7th at 23:59 (Pacific Time Zone) of each month, RC1 of the upcoming release (to be shipped on the 22nd) is created and deployed to GitLab.com and the stable branch for this release is frozen, which means master is no longer merged into it.
Merge requests may still be merged into master during this period,
but they will go into the _next_ release, unless they are manually cherry-picked into the stable branch.
@@ -202,6 +202,9 @@ you can ask for an exception to be made.
Go to [Release tasks issue tracker](https://gitlab.com/gitlab-org/release/tasks/issues/new) and create an issue
using the `Exception-request` issue template.
+**Do not** set the relevant `Pick into X.Y` label (see above) before request an
+exception; this should be done after the exception is approved.
+
You can find who is who on the [team page](https://about.gitlab.com/team/).
Whether an exception is made is determined by weighing the benefit and urgency of the change
diff --git a/app/assets/images/icons.json b/app/assets/images/icons.json
index 19843d24e22..d6f6e50398b 100644
--- a/app/assets/images/icons.json
+++ b/app/assets/images/icons.json
@@ -1 +1 @@
-{"iconCount":191,"spriteSize":86607,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","soft-unwrap","soft-wrap","spam","spinner","staged","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_notfound","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","unstaged","user","users","volume-up","warning","work"]} \ No newline at end of file
+{"iconCount":198,"spriteSize":89379,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","blame","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","compress","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","error","expand","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","go-back","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor-lines","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","soft-unwrap","soft-wrap","spam","spinner","staged","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_notfound","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","time-out","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","unstaged","user","users","volume-up","warning","work"]} \ No newline at end of file
diff --git a/app/assets/images/icons.svg b/app/assets/images/icons.svg
index 6aec54d0543..70205220e87 100644
--- a/app/assets/images/icons.svg
+++ b/app/assets/images/icons.svg
@@ -1 +1 @@
-<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol viewBox="0 0 16 16" id="abuse" xmlns="http://www.w3.org/2000/svg"><path d="M11.408.328l4.029 3.222A1.5 1.5 0 0 1 16 4.72v6.555a1.5 1.5 0 0 1-.563 1.171l-4.026 3.224a1.5 1.5 0 0 1-.937.329H5.529a1.5 1.5 0 0 1-.937-.328L.563 12.45A1.5 1.5 0 0 1 0 11.28V4.724a1.5 1.5 0 0 1 .563-1.171L4.589.329A1.5 1.5 0 0 1 5.526 0h4.945c.34 0 .67.116.937.328zM10.296 2H5.702L2 4.964v6.074L5.704 14h4.594L14 11.036V4.962L10.296 2zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="account" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.195 9.965l-.568-.875a.25.25 0 0 1 .015-.294l.405-.5a.25.25 0 0 1 .283-.075l.938.36c.257-.183.543-.325.851-.42l.322-.988A.25.25 0 0 1 11.679 7h.642a.25.25 0 0 1 .238.173l.322.988c.308.095.594.237.851.42l.938-.36a.25.25 0 0 1 .283.076l.405.5a.25.25 0 0 1 .015.293l-.568.875c.113.297.18.616.193.95l.898.54a.25.25 0 0 1 .115.27l-.144.626a.25.25 0 0 1-.222.193l-1.115.098a3.015 3.015 0 0 1-.512.608l.165 1.18a.25.25 0 0 1-.138.259l-.577.281a.25.25 0 0 1-.29-.05l-.874-.905a3.035 3.035 0 0 1-.608 0l-.875.904a.25.25 0 0 1-.289.051l-.577-.281a.25.25 0 0 1-.138-.26l.165-1.18a3.015 3.015 0 0 1-.512-.607l-1.115-.098a.25.25 0 0 1-.222-.193l-.144-.626a.25.25 0 0 1 .115-.27l.898-.54c.013-.334.08-.653.193-.95zM6.789 8.023A12.845 12.845 0 0 0 6 8c-5.036 0-6 2.74-6 4.48C0 14.22.076 15 6 15c.553 0 1.055-.006 1.51-.02A5.977 5.977 0 0 1 6 11c0-1.083.287-2.1.79-2.977zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM12 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="admin" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.162 2.5a3.5 3.5 0 0 1-3.163 5.479L6.08 14.766a1.5 1.5 0 0 1-2.598-1.5L7.4 6.479A3.5 3.5 0 0 1 10.564 1L8.9 3.88l2.599 1.5 1.663-2.88zm-8.63 11.949a.5.5 0 1 0 .5-.866.5.5 0 0 0-.5.866z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.414 7.95l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 1 0 1.414-1.415L10.414 7.95zm-7 0l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 0 0 1.414-1.415L3.414 7.95z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.536 7.95L1.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 1 1-1.414-1.415L5.536 7.95zm7 0L8.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 0 1-1.414-1.415l4.243-4.242z"/></symbol><symbol viewBox="0 0 16 16" id="angle-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 10.243l-4.95-4.95a1 1 0 0 0-1.414 1.414l5.657 5.657a.997.997 0 0 0 1.414 0l5.657-5.657a1 1 0 0 0-1.414-1.414L8 10.243z"/></symbol><symbol viewBox="0 0 16 16" id="angle-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.757 8l4.95-4.95a1 1 0 1 0-1.414-1.414L3.636 7.293a.997.997 0 0 0 0 1.414l5.657 5.657a1 1 0 0 0 1.414-1.414L5.757 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.243 8l-4.95-4.95a1 1 0 0 1 1.414-1.414l5.657 5.657a.997.997 0 0 1 0 1.414l-5.657 5.657a1 1 0 0 1-1.414-1.414L10.243 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 6.757l-4.95 4.95a1 1 0 1 1-1.414-1.414l5.657-5.657a.997.997 0 0 1 1.414 0l5.657 5.657a1 1 0 0 1-1.414 1.414L8 6.757z"/></symbol><symbol viewBox="0 0 16 16" id="appearance" xmlns="http://www.w3.org/2000/svg"><path d="M11.161 12.456l.232.121c.1.053.175.094.249.137.53.318.844.75.857 1.402.012 1.397-1.116 1.756-3.12 1.858a23.85 23.85 0 0 1-1.38.026A8 8 0 0 1 0 8a8 8 0 0 1 8-8c4.417 0 7.998 3.582 7.998 7.977.06 2.621-1.312 3.586-4.48 3.648-.602.008-1.068.043-1.4.104.228.192.598.47 1.043.727zm-3.287-.943c-.019-1.495 1.228-1.856 3.611-1.888C13.67 9.582 14.028 9.33 13.998 8A6 6 0 1 0 8 14c.603 0 .91-.004 1.277-.023a9.7 9.7 0 0 0 .478-.035c-1.172-.738-1.868-1.47-1.88-2.43zM6 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-2-3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM4 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="applications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 1v2h2V1H7zm0 5h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm0 1v2h2V7h-2zM1 12h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm0 1v2h2v-2H1zm6-1h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm6 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="approval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.536 10.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 1 1 9.12 9.243l1.415 1.414zM7.632 8.109A2 2 0 0 0 7 11.364l2.121 2.121a1.996 1.996 0 0 0 2.807.021C11.686 14.554 10.627 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.6 0 1.142.038 1.632.109zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="arrow-down" xmlns="http://www.w3.org/2000/svg"><path d="M10.472 7.282a.862.862 0 0 1 1.26-.006c.357.364.357.958 0 1.285L8.627 11.73A.886.886 0 0 1 8 12a.849.849 0 0 1-.627-.27L4.275 8.561a.904.904 0 0 1-.013-1.285.861.861 0 0 1 1.26-.007l2.486 2.527z"/></symbol><symbol viewBox="0 0 16 16" id="arrow-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 6H2a2 2 0 1 0 0 4h7v2.586a1 1 0 0 0 1.707.707l4.586-4.586a1 1 0 0 0 0-1.414l-4.586-4.586A1 1 0 0 0 9 3.414V6z"/></symbol><symbol viewBox="0 0 16 16" id="assignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 5V4a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V7h-1a1 1 0 0 1 0-2h1zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="bold" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4 12.5v-9A1.5 1.5 0 0 1 5.5 2h2.104c2.182 0 3.879.681 3.879 2.982 0 1.067-.517 2.227-1.374 2.595v.073C11.176 7.963 12 8.865 12 10.466 12 12.914 10.19 14 7.911 14H5.5A1.5 1.5 0 0 1 4 12.5zm2.376-5.696H7.49c1.164 0 1.665-.552 1.665-1.417 0-.94-.534-1.289-1.649-1.289h-1.13v2.706zm0 5.098h1.341c1.293 0 1.956-.515 1.956-1.62 0-1.049-.647-1.472-1.956-1.472H6.376v3.092z"/></symbol><symbol viewBox="0 0 16 16" id="book" xmlns="http://www.w3.org/2000/svg"><path d="M7 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2v4.191a.5.5 0 0 1-.724.447l-1.052-.526a.5.5 0 0 0-.448 0l-1.052.526A.5.5 0 0 1 7 6.191V2zM5 0h6a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="bookmark" xmlns="http://www.w3.org/2000/svg"><path d="M6.746 10.505a2 2 0 0 1 2.508 0L11 11.911V3H5v8.91l1.746-1.405zM5 1h6a2 2 0 0 1 2 2v10.999a1 1 0 0 1-1.627.779L8 12.064l-3.373 2.714A1 1 0 0 1 3 13.998V3a2 2 0 0 1 2-2z"/></symbol><symbol viewBox="0 0 16 16" id="branch" xmlns="http://www.w3.org/2000/svg"><path d="M6 11.978v.29a2 2 0 1 1-2 0V3.732a2 2 0 1 1 2 0v3.849c.592-.491 1.31-.854 2.15-1.081 1.308-.353 1.875-.882 1.893-1.743a2 2 0 1 1 2.002-.051C12.053 6.54 10.857 7.84 8.67 8.43 7.056 8.867 6.195 9.98 6 11.978zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm6 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="bullhorn" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.143 10H7V4H3a3 3 0 1 0 0 6h.143l.734 5.141a1 1 0 0 0 .99.859h1.556a.5.5 0 0 0 .495-.57L6.143 10zM8 4c1.034.02 2.039-.274 3.014-.883.727-.455 1.836-1.334 3.328-2.637A1 1 0 0 1 16 1.233v10.764a1 1 0 0 1-1.595.803c-1.658-1.227-2.788-1.992-3.392-2.294-.781-.39-1.785-.559-3.013-.506V4z"/></symbol><symbol viewBox="0 0 16 16" id="calendar" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 2h2a2 2 0 0 1 2 2H0a2 2 0 0 1 2-2h2V1a1 1 0 1 1 2 0v1h4V1a1 1 0 1 1 2 0v1zM0 4h16v9a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4zm2 2.5V13a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6.5a.5.5 0 0 0-.5-.5h-11a.5.5 0 0 0-.5.5zM5 8h2a1 1 0 1 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="cancel" xmlns="http://www.w3.org/2000/svg"><path d="M3.11 4.523a6 6 0 0 0 8.367 8.367L3.109 4.524zM4.522 3.11l8.368 8.368A6 6 0 0 0 4.524 3.11zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 16 16" id="chart" xmlns="http://www.w3.org/2000/svg"><path d="M15 14a1 1 0 0 1 0 2H2a2 2 0 0 1-2-2V1a1 1 0 1 1 2 0v13h13zM3.142 8.735l2.502-2.561a.5.5 0 0 1 .714-.003L8 7.833l3.592-4.553a.5.5 0 0 1 .796.015l2.516 3.454a.5.5 0 0 1 .096.295V12.5a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5V9.085a.5.5 0 0 1 .142-.35z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.078 8.2l3.535-3.536a2 2 0 0 1 2.828 2.828l-4.949 4.95c-.39.39-.902.586-1.414.586a1.994 1.994 0 0 1-1.414-.586l-4.95-4.95a2 2 0 1 1 2.828-2.828l3.536 3.535z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.977 7.998l3.535-3.535a2 2 0 1 0-2.828-2.828l-4.95 4.949c-.39.39-.586.902-.586 1.414 0 .512.196 1.024.586 1.414l4.95 4.95a2 2 0 1 0 2.828-2.828L7.977 7.998z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.22 7.998L4.683 4.463a2 2 0 0 1 2.828-2.828l4.95 4.949c.39.39.586.902.586 1.414a1.99 1.99 0 0 1-.586 1.414l-4.95 4.95a2 2 0 0 1-2.828-2.828l3.535-3.536z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.778 8.957l3.535 3.535a2 2 0 1 0 2.828-2.828l-4.949-4.95a1.994 1.994 0 0 0-1.414-.586c-.512 0-1.024.196-1.414.586l-4.95 4.95a2 2 0 1 0 2.828 2.828l3.536-3.535z"/></symbol><symbol viewBox="0 0 16 16" id="clock" xmlns="http://www.w3.org/2000/svg"><path d="M9 7h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V5a1 1 0 1 1 2 0v2zm-1 9A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.414 8l4.95-4.95a1 1 0 0 0-1.414-1.414L8 6.586l-4.95-4.95A1 1 0 0 0 1.636 3.05L6.586 8l-4.95 4.95a1 1 0 1 0 1.414 1.414L8 9.414l4.95 4.95a1 1 0 1 0 1.414-1.414L9.414 8z"/></symbol><symbol viewBox="0 0 16 16" id="code" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M15.871 8.243a.997.997 0 0 0-.293-.707L12.75 4.707a1 1 0 0 0-1.414 1.414l2.12 2.122-2.12 2.121a1 1 0 0 0 1.414 1.414l2.828-2.828a.997.997 0 0 0 .293-.707zm-13.243 0L4.75 6.12a1 1 0 1 0-1.414-1.414L.507 7.536a.997.997 0 0 0 0 1.414l2.829 2.828a1 1 0 1 0 1.414-1.414L2.628 8.243zm6.407-4.107a1 1 0 0 1 .707 1.225L8.19 11.157a1 1 0 1 1-1.931-.518L7.81 4.843a1 1 0 0 1 1.224-.707z"/></symbol><symbol viewBox="0 0 9 13" id="collapse"><path d="M.084.25C.01.18-.015.12.008.071.031.024.093 0 .194 0h8.521c.1 0 .162.024.185.072.023.048-.002.107-.075.177l-4.11 3.935a.372.372 0 0 1-.11.072h-.301a.508.508 0 0 1-.11-.072L.084.249zM.377 6.88a.364.364 0 0 1-.26-.105.334.334 0 0 1-.11-.25v-.709c0-.096.036-.179.11-.249a.364.364 0 0 1 .26-.105h8.15c.101 0 .188.035.261.105.074.07.11.153.11.25v.709c0 .096-.036.179-.11.249a.364.364 0 0 1-.26.105H.377zM.084 12.132c-.074.07-.099.129-.076.177.023.048.085.072.186.072h8.521c.1 0 .162-.024.185-.072.023-.048-.002-.107-.075-.177l-4.11-3.935a.372.372 0 0 0-.11-.072h-.301a.508.508 0 0 0-.11.072l-4.11 3.935z"/></symbol><symbol viewBox="0 0 16 16" id="comment" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comment-dots" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586zM5 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="comment-next" xmlns="http://www.w3.org/2000/svg"><path d="M8 5V4a.5.5 0 0 1 .8-.4l2.667 2a.5.5 0 0 1 0 .8L8.8 8.4A.5.5 0 0 1 8 8V7H6a1 1 0 1 1 0-2h2zM1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comments" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.75 10L0 13V3a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H3.75zM13 5h1a2 2 0 0 1 2 2v8l-2.667-2H8a2 2 0 0 1-2-2h4a3 3 0 0 0 3-3V5z"/></symbol><symbol viewBox="0 0 16 16" id="commit" xmlns="http://www.w3.org/2000/svg"><path d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm3.876-1.008a4.002 4.002 0 0 1-7.752 0A1.01 1.01 0 0 1 4 9H1a1 1 0 1 1 0-2h3c.042 0 .083.003.124.008a4.002 4.002 0 0 1 7.752 0A1.01 1.01 0 0 1 12 7h3a1 1 0 0 1 0 2h-3a1.01 1.01 0 0 1-.124-.008z"/></symbol><symbol viewBox="0 0 16 16" id="credit-card" xmlns="http://www.w3.org/2000/svg"><path d="M14 5a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1h12zm0 3H2v3a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V8zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm6.5 8h3a.5.5 0 1 1 0 1h-3a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="cut" xmlns="http://www.w3.org/2000/svg"><rect width="16" height="2" y="7" fill-rule="evenodd" rx="1"/></symbol><symbol viewBox="0 0 16 16" id="dashboard" xmlns="http://www.w3.org/2000/svg"><path d="M7.709 10.021l.696-2.6a.5.5 0 0 1 .966.26l-.657 2.45A2 2 0 0 1 10 12H6a2 2 0 0 1 1.709-1.979zM0 8.9a8 8 0 0 1 15.998 0H16v3.6a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5V8.9zM14 9A6 6 0 1 0 2 9v3.5a.5.5 0 0 0 .5.5h11a.5.5 0 0 0 .5-.5V9zM3.5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm9 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-7-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm5 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1z"/></symbol><symbol viewBox="0 0 16 16" id="disk" xmlns="http://www.w3.org/2000/svg"><path d="M16 11.764V3a3 3 0 0 0-3-3H3a3 3 0 0 0-3 3v8.764A2.989 2.989 0 0 1 2 11V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v8c.768 0 1.47.289 2 .764zM2 12h12a2 2 0 1 1 0 4H2a2 2 0 1 1 0-4zm10 1a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="doc_code" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zm1.036 7.607a.498.498 0 0 1-.147.354l-1.414 1.414a.5.5 0 0 1-.707-.707l1.06-1.06-1.06-1.061a.5.5 0 0 1 .707-.707l1.414 1.414a.498.498 0 0 1 .147.353zm-4.822 0l1.06 1.061a.5.5 0 0 1-.706.707l-1.414-1.414a.498.498 0 0 1 0-.707l1.414-1.414a.5.5 0 1 1 .707.707l-1.06 1.06zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="doc_image" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM7.333 9.667l1.313-1.313a.5.5 0 0 1 .708 0L12 11H4l2.188-1.75a.5.5 0 0 1 .624 0l.521.417zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 8a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM4 11h8v.7a.3.3 0 0 1-.3.3H4.3a.3.3 0 0 1-.3-.3V11z"/></symbol><symbol viewBox="0 0 16 16" id="doc_text" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 11h5a.5.5 0 1 1 0 1h-5a.5.5 0 1 1 0-1zm0-2h5a.5.5 0 1 1 0 1h-5a.5.5 0 0 1 0-1zm0-2h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1z"/></symbol><symbol viewBox="0 0 105 26" id="double-headed-arrow" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.018 11.089L15.138.614c1.23-.911 3.086-.795 4.147.26.461.46.715 1.045.715 1.651v20.95C20 24.869 18.684 26 17.06 26a3.238 3.238 0 0 1-1.921-.614L1.019 14.911C-.212 14-.347 12.405.714 11.35c.094-.094.195-.18.303-.261zm102.964 0c.108.08.21.167.303.26 1.061 1.056.925 2.65-.303 3.562l-14.12 10.475A3.238 3.238 0 0 1 87.94 26C86.316 26 85 24.87 85 23.475V2.525c0-.606.254-1.192.715-1.65 1.061-1.056 2.917-1.172 4.146-.26l14.12 10.474zM35 17a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="download" xmlns="http://www.w3.org/2000/svg"><path d="M9 12h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0l-2-2.667A.5.5 0 0 1 6 12h1V8a1 1 0 1 1 2 0v4zM4 9a1 1 0 1 1 0 2 4 4 0 0 1-1.971-7.481 4 4 0 0 1 6.633-2.505 3.999 3.999 0 0 1 3.82 2.014A4 4 0 0 1 12 11a1 1 0 0 1 0-2 2 2 0 1 0 0-4h-1a2 2 0 0 0-3.112-1.662A2 2 0 1 0 4.268 5H4a2 2 0 1 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M14 10h-3a1 1 0 0 1-1-1V6H8.527A.527.527 0 0 0 8 6.527V13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-3zm-4-7H8.527c-.18 0-.355.013-.527.04V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2v2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3zM8.527 4h2.323a.5.5 0 0 1 .35.143l4.65 4.551a.5.5 0 0 1 .15.357V13a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V6.527A2.527 2.527 0 0 1 8.527 4z"/></symbol><symbol viewBox="0 0 16 16" id="earth" xmlns="http://www.w3.org/2000/svg"><path d="M8.7 2.04l-.082.177c.283.223.422.413.417.571-.008.237-.311.057-.444.274-.133.218.038.542-.112.637-.15.096-.398-.386-.479-.46-.054-.049-.166-.257-.336-.625l-.216-.225a.844.844 0 0 0-.418-.035c-.177.038-.075.1-.035.132.04.032.32.037.452.2.132.164.03.224-.05.298-.054.05-.157.062-.31.035H5.952l-.402.398.03.325.229.455.324-.463c.008-.206.058-.342.15-.41.14-.1.342-.15.534-.085.191.066-.057.218.011.271.068.053.204-.098.313-.02.11.08.07.155.104.322.036.167.254.114.398.328.144.215.19.29.147.483-.043.195-.168.26-.305.232-.138-.028-.107-.246-.275-.348-.168-.102-.266-.114-.386-.054-.12.06-.016.129.023.235.04.106.274.321.224.43-.05.107-.108.116-.42 0-.21-.077-.414-.007-.615.212l-.76.722c-.153.715-.3 1.13-.44 1.243-.211.17-.177-.483-.483-.656-.306-.174-.494-.047-.8-.07-.307-.023-.42.65-.38.873a.434.434 0 0 0 .221.321c.236-.141.39-.184.465-.128.11.084-.144.267-.074.425.07.158.314.069.386.283.073.213.084.48-.05.706-.135.227-.275.178-.4.053-.127-.126-.033-.375-.255-.704-.223-.329-.381-.337-.63-.787-.158-.287-.35-.743-.575-1.366a6 6 0 0 0 3.21 7.198l.001-.075c0-.577-.004-.944-.012-1.102-.011-.236-.95-.945-1.104-1.2-.154-.256-.34-.595-.355-.746-.016-.151.185-.232.344-.325.16-.093-.11-.367.028-.626.137-.258.395-.438.496-.356.101.081.058.228.267.333.209.104.077-.213.456-.178.38.035.143.201.252.216.11.016.113-.127.299-.143.186-.015.282.445.471.622.19.178.452.008.611.043.159.034.267.09.402.255.136.166-.03.352.073.557.103.205 1.07.22 1.433.255.364.034.371.011.371.324s-.166.314-.453.507c-.286.193-.166.462-.38.762-.212.3-.316.062-.622.14-.306.077-.413.382-.452.568-.039.186-.386.094-.877.232-.29.082-.429.144-.569.204a6.002 6.002 0 0 0 7.682-4.3c-.094-.384-.18-.63-.258-.74-.213-.297-.36.21-.924.49-.564.278-.57-.288-.81-.49-.16-.133-.212-.44-.158-.92-.005-.478.02-.828.077-1.049.057-.221.126-.543.207-.965.351-.373.606-.572.764-.595.237-.034.336.374.658.3a.315.315 0 0 0 .035-.01 5.993 5.993 0 0 0-.475-.824l-.309-.043a.646.646 0 0 0-.332-.117c-.205-.02-.025.128-.089.24-.064.112-.235.724-.437.685-.201-.039-.204-.374-.17-.668.036-.294-.077-.35-.2-.412-.124-.062-.325-.213-.556-.295-.232-.082-.123-.175-.093-.274.03-.1.208-.015.193-.058-.014-.044-.313-.135-.266-.167.03-.02.2-.02.506.003l.216-.012.293-.163a.58.58 0 0 0-.376-.22c-.233-.036-.513-.034-.73-.142-.205-.103-.458-.36-.643-.638A5.965 5.965 0 0 0 8.7 2.04zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 1600 1600" id="ellipsis_v" xmlns="http://www.w3.org/2000/svg"><path d="M1088 1248v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h192q40 0 68 28t28 68zm0-512v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68V736q0-40 28-68t68-28h192q40 0 68 28t28 68zm0-512v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68V224q0-40 28-68t68-28h192q40 0 68 28t28 68z"/></symbol><symbol viewBox="0 0 18 18" id="emoji_slightly_smiling_face" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369.721.721 0 0 1 .568.047.715.715 0 0 1 .37.445 2.91 2.91 0 0 0 1.084 1.518A2.93 2.93 0 0 0 9 12.75a2.93 2.93 0 0 0 1.775-.58 2.913 2.913 0 0 0 1.084-1.518.711.711 0 0 1 .375-.445.737.737 0 0 1 .575-.047c.195.063.34.186.433.37.094.183.11.372.047.568zM7.5 6c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 6 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 6 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 12 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 12 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 18 18" id="emoji_smile" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568zM14 6.37c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm-6.5 0c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm9 2.63a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 18 18" id="emoji_smiley" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568h.001zM7.5 6c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 6 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 6 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 12 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 12 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6c.92.397 1.91.6 2.912.598a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39c.397-.92.6-1.91.598-2.912zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z"/></symbol><symbol viewBox="0 0 16 16" id="epic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.985 8.044l-.757 2.272a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l.318-.637A2 2 0 0 0 1.618 9h11.661a2 2 0 0 0 1.706-.956zm0 3l-.757 2.272a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l.318-.637a2 2 0 0 0 .576.084h11.661a2 2 0 0 0 1.706-.956zM3.618 2h10.995a1 1 0 0 1 .948 1.316l-1.333 4a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l2-4A1 1 0 0 1 3.618 2zm-.382 4h9.322l.667-2H4.236l-1 2z"/></symbol><symbol viewBox="0 0 16 16" id="external-link" xmlns="http://www.w3.org/2000/svg"><path d="M13.121 4.177l-4.95 4.95a1 1 0 1 1-1.414-1.414l4.95-4.95-1.386-1.386a.5.5 0 0 1 .299-.85l4.709-.524a.5.5 0 0 1 .552.552l-.523 4.71a.5.5 0 0 1-.851.297l-1.386-1.385zM12 8.884a1 1 0 0 1 2 0v4a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3v-8a3 3 0 0 1 3-3h4a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-4z"/></symbol><symbol viewBox="0 0 16 16" id="eye" xmlns="http://www.w3.org/2000/svg"><path d="M8 14C4.816 14 2.253 12.284.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2s5.747 1.716 7.607 5.019a2 2 0 0 1 0 1.962C13.747 12.284 11.184 14 8 14zm0-2c2.41 0 4.338-1.29 5.864-4C12.338 5.29 10.411 4 8 4 5.59 4 3.662 5.29 2.136 8 3.662 10.71 5.589 12 8 12zm0-1a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm1-3a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="eye-slash" xmlns="http://www.w3.org/2000/svg"><path d="M13.618 2.62L1.62 14.619a1 1 0 0 1-.985-1.668l1.525-1.526C1.516 10.742.926 9.927.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2c1.074 0 2.076.195 3.006.58l.944-.944a1 1 0 0 1 1.668.985zM8.068 11a3 3 0 0 0 2.931-2.932l-2.931 2.931zm-3.02-2.462a3 3 0 0 1 3.49-3.49l.884-.884A6.044 6.044 0 0 0 8 4C5.59 4 3.662 5.29 2.136 8c.445.79.924 1.46 1.439 2.011l1.473-1.473zm.421 5.06l1.658-1.658c.283.04.575.06.873.06 2.41 0 4.338-1.29 5.864-4a11.023 11.023 0 0 0-1.133-1.664l1.418-1.418a12.799 12.799 0 0 1 1.458 2.1 2 2 0 0 1 0 1.963C13.747 12.284 11.184 14 8 14a7.883 7.883 0 0 1-2.53-.402z"/></symbol><symbol viewBox="0 0 16 16" id="file-addition" xmlns="http://www.w3.org/2000/svg"><path d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3z"/></symbol><symbol viewBox="0 0 16 16" id="file-deletion" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm2 6h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="file-modified" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm5 4a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"/></symbol><symbol viewBox="0 0 16 16" id="filter" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 6v9l-3.724-1.862A.5.5 0 0 1 6 12.691V6L1.854 1.854A.5.5 0 0 1 2.207 1h11.586a.5.5 0 0 1 .353.854L10 6z"/></symbol><symbol viewBox="0 0 16 16" id="folder" xmlns="http://www.w3.org/2000/svg"><path d="M13 3a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.81a3 3 0 0 1 2.827 1.995L13 3z"/></symbol><symbol viewBox="0 0 16 16" id="folder-o" xmlns="http://www.w3.org/2000/svg"><path d="M13 5l-4.365-.005a2 2 0 0 1-1.882-1.33A1 1 0 0 0 5.81 3H2v9a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1zm0-2a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.81a3 3 0 0 1 2.827 1.995L13 3z"/></symbol><symbol viewBox="0 0 16 16" id="folder-open" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.59 5.464a2.998 2.998 0 0 1 1.096 3.845l-1.666 3.436A4 4 0 0 1 10.46 15H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.558a2 2 0 0 1 1.898 1.368l.21.632h4.973a2 2 0 0 1 2 2 2 2 0 0 1-.027.329l-.023.135zM5.285 7a1 1 0 0 0-.9.564l-1.939 4a1 1 0 0 0 .9 1.436h7.074a2 2 0 0 0 1.8-1.128l1.665-3.436a1 1 0 0 0-.9-1.436h-7.7z"/></symbol><symbol viewBox="0 0 16 16" id="fork" xmlns="http://www.w3.org/2000/svg"><path d="M9 12.268a2 2 0 1 1-2 0V8.874A4.002 4.002 0 0 1 4 5V3.732a2 2 0 1 1 2 0V5a2 2 0 1 0 4 0V3.732a2 2 0 1 1 2 0V5a4.002 4.002 0 0 1-3 3.874v3.394zM11 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm3 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="geo-nodes" xmlns="http://www.w3.org/2000/svg"><path d="M9.7 13.1l-.2.2c-.7.8-2 .9-2.8.1-.1 0-.1-.1-.1-.1l-.2-.2c-2 .2-3.4.7-3.4 1.4 0 .8 2.2 1.5 5 1.5s5-.7 5-1.5c0-.7-1.4-1.2-3.3-1.4M7.3 12.7c.4.4 1 .3 1.4-.1C11.6 9.5 13 7 13 5.3 13 2.4 10.8 0 8 0S3 2.4 3 5.3C3 7 4.4 9.5 7.3 12.7M8 2c1.6 0 3 1.4 3 3.3 0 1-1 2.8-3 5.2-2-2.4-3-4.2-3-5.2C5 3.4 6.4 2 8 2"/><circle cx="8" cy="5" r="1"/></symbol><symbol viewBox="0 0 16 16" id="git-merge" xmlns="http://www.w3.org/2000/svg"><path d="M11 12.268V5a1 1 0 0 0-1-1v1a.5.5 0 0 1-.8.4l-2.667-2a.5.5 0 0 1 0-.8L9.2.6a.5.5 0 0 1 .8.4v1a3 3 0 0 1 3 3v7.268a2 2 0 1 1-2 0zm-6 0a2 2 0 1 1-2 0V4.732a2 2 0 1 1 2 0v7.536zM4 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm8 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="group" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.048 11.997C-.377 11.975.013 11.782.013 10.56.013 9.235.653 8 4 8c.444 0 .84.022 1.194.062.164.435.426.82.76 1.132-1.786.389-2.721 1.353-2.906 2.803zm2.94-7.222a2.993 2.993 0 0 0-.976 1.95 2 2 0 1 1 .975-1.95zm6.964 7.222c-.185-1.45-1.12-2.414-2.906-2.803.334-.311.596-.697.76-1.132C11.16 8.022 11.556 8 12 8c3.346 0 3.987 1.235 3.987 2.56 0 1.222.39 1.415-3.035 1.437zm-1.964-5.272a2.993 2.993 0 0 0-.976-1.95 2 2 0 1 1 .976 1.95zM8 9a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 5c-2.177 0-3.987-.115-3.987-1.44S4.653 10 8 10c3.346 0 3.987 1.235 3.987 2.56S10.177 14 8 14z"/></symbol><symbol viewBox="0 0 16 16" id="history" xmlns="http://www.w3.org/2000/svg"><path d="M2.868 3.24a7 7 0 1 1-.043 9.475 1 1 0 0 1 1.478-1.348 5 5 0 1 0 .124-6.865l.796.645a.5.5 0 0 1-.193.873l-3.232.814a.5.5 0 0 1-.622-.504L1.3 3a.5.5 0 0 1 .814-.37l.754.61zM9 8h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V6a1 1 0 1 1 2 0v2z"/></symbol><symbol viewBox="0 0 16 16" id="home" xmlns="http://www.w3.org/2000/svg"><path d="M9 13h3v-3H4v3h3v-1a1 1 0 0 1 2 0v1zm5-3v3.659c0 .729-.657 1.341-1.5 1.341h-9c-.843 0-1.5-.612-1.5-1.341V10h-.88C.502 10 0 9.486 0 8.853c0-.307.12-.601.333-.816l6.405-6.463a1.56 1.56 0 0 1 2.374-.052L15.66 8.03c.444.441.455 1.167.024 1.622a1.108 1.108 0 0 1-.804.348H14zM7.95 3.273l-4.595 4.64h9.264l-4.67-4.64z"/></symbol><symbol viewBox="0 0 16 16" id="hook" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1h4zm0 1H6v1a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V4zM7 8a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h2a3 3 0 0 1 3 3v2a3 3 0 0 1-3 3v4a2 2 0 1 0 4 0h-.44a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H15a4 4 0 0 1-7 2.646A4 4 0 0 1 1 12H.56a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H3a2 2 0 1 0 4 0V8z"/></symbol><symbol viewBox="0 0 16 16" id="hourglass" xmlns="http://www.w3.org/2000/svg"><path d="M10.331 4.889A2.988 2.988 0 0 0 11 3V2H5v1c0 .362.064.709.182 1.03l5.15.859zM3 14v-1c0-1.78.93-3.342 2.33-4.228.447-.327.67-.582.67-.764 0-.19-.242-.46-.725-.815A4.996 4.996 0 0 1 3 3V2H2a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2h-1v1a4.997 4.997 0 0 1-2.39 4.266c-.407.3-.61.545-.61.734 0 .19.203.434.61.734A4.997 4.997 0 0 1 13 13v1h1a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2h1zm8 0v-1a3 3 0 0 0-6 0v1h6z"/></symbol><symbol viewBox="0 0 38 38" id="image-comment-dark" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="19" cy="19" r="18" fill="#1F78D1"/><path fill="#FFF" fill-rule="nonzero" d="M19 38C8.507 38 0 29.493 0 19S8.507 0 19 0s19 8.507 19 19-8.507 19-19 19zm0-2c9.389 0 17-7.611 17-17S28.389 2 19 2 2 9.611 2 19s7.611 17 17 17zm-6.293-8.293c-.63.63-1.707.184-1.707-.707V15a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3h-7.586l-3.707 3.707zM13 24.586l2.293-2.293A1 1 0 0 1 16 22h8a1 1 0 0 0 1-1v-6a1 1 0 0 0-1-1H14a1 1 0 0 0-1 1v9.586z"/></g></symbol><symbol viewBox="0 0 38 38" id="image-comment-light" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="19" cy="19" r="18" fill="#FFF"/><path fill="#1F78D1" fill-rule="nonzero" d="M19 38C8.507 38 0 29.493 0 19S8.507 0 19 0s19 8.507 19 19-8.507 19-19 19zm0-2c9.389 0 17-7.611 17-17S28.389 2 19 2 2 9.611 2 19s7.611 17 17 17zm-6.293-8.293c-.63.63-1.707.184-1.707-.707V15a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3h-7.586l-3.707 3.707zM13 24.586l2.293-2.293A1 1 0 0 1 16 22h8a1 1 0 0 0 1-1v-6a1 1 0 0 0-1-1H14a1 1 0 0 0-1 1v9.586z"/></g></symbol><symbol viewBox="0 0 16 16" id="import" xmlns="http://www.w3.org/2000/svg"><path d="M9 8h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0L5.6 8.8A.5.5 0 0 1 6 8h1V1a1 1 0 1 1 2 0v7zM0 8a1 1 0 1 1 2 0 6 6 0 1 0 12 0 1 1 0 0 1 2 0A8 8 0 1 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-block" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.803 8a5.97 5.97 0 0 0-.462 1H4.5a.5.5 0 0 1 0-1h1.303zM4.5 5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1 0-1zm7.5.083a6.04 6.04 0 0 0-2 0V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h2.083a5.96 5.96 0 0 0 .72 2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h6a3 3 0 0 1 3 3v2.083zm1.121 3.796zM11 16a5 5 0 1 1 0-10 5 5 0 0 1 0 10zm-1.293-2.292a3 3 0 0 0 4.001-4.001l-4.001 4zm-1.415-1.415l4.001-4a3 3 0 0 0-4.001 4.001z"/></symbol><symbol viewBox="0 0 16 16" id="issue-child" xmlns="http://www.w3.org/2000/svg"><path d="M11 8H5v1h1a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h2V7a.997.997 0 0 1 1-1h3V4H4.5a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9v2h3a.997.997 0 0 1 1 1v2h2a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h1V8zm-9 3v2h3v-2H2zm9 0v2h3v-2h-3z"/></symbol><symbol viewBox="0 0 16 16" id="issue-close" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M10.874 2H12a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-2c-.918 0-1.74-.413-2.29-1.063a3.987 3.987 0 0 0 1.988-.984A1 1 0 0 0 10 14h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-1V3c0-.345-.044-.68-.126-1zM4 0h3a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-external" xmlns="http://www.w3.org/2000/svg"><path d="M11 4a5.99 5.99 0 0 0-2 .341V3a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h2.528a6.003 6.003 0 0 0 2.705 1.736A2.99 2.99 0 0 1 8 16H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3v1zM8.212 8.97l-.568-.876A.25.25 0 0 1 7.66 7.8l.404-.5a.25.25 0 0 1 .284-.076l.938.36c.256-.182.543-.325.85-.42l.323-.988a.25.25 0 0 1 .237-.173h.643a.25.25 0 0 1 .238.173l.321.989c.308.094.595.237.852.418l.937-.359a.25.25 0 0 1 .284.076l.404.5a.25.25 0 0 1 .016.293l-.568.875c.113.297.18.616.192.95l.9.54a.25.25 0 0 1 .114.27l-.145.627a.25.25 0 0 1-.221.192l-1.115.098a3.015 3.015 0 0 1-.512.608l.165 1.18a.25.25 0 0 1-.138.259l-.577.282a.25.25 0 0 1-.29-.051l-.874-.905a3.035 3.035 0 0 1-.608 0l-.875.905a.25.25 0 0 1-.29.05l-.577-.281a.25.25 0 0 1-.138-.26L9 12.254a3.015 3.015 0 0 1-.512-.607l-1.114-.098a.25.25 0 0 1-.222-.192l-.145-.627a.25.25 0 0 1 .115-.27l.899-.54c.012-.334.08-.653.192-.95zm2.806 2.034a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="issue-new" xmlns="http://www.w3.org/2000/svg"><path d="M10 2V1a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V4H9a1 1 0 1 1 0-2h1zm0 6a1 1 0 0 1 2 0v5a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h1a1 1 0 1 1 0 2H5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm0-2a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open-m" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-parent" xmlns="http://www.w3.org/2000/svg"><path d="M11 11H5v1h1.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H3v-2a.997.997 0 0 1 1-1h3V7H5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H9v2h3a.997.997 0 0 1 1 1v2h2.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H11v-1zM6 3v2h4V3H6z"/></symbol><symbol viewBox="0 0 16 16" id="issues" xmlns="http://www.w3.org/2000/svg"><path d="M10.458 15.012l.311.055a3 3 0 0 0 3.476-2.433l1.389-7.879A3 3 0 0 0 13.2 1.28L11.23.933a3.002 3.002 0 0 0-.824-.031c.364.59.58 1.28.593 2.02l1.854.328a1 1 0 0 1 .811 1.158l-1.389 7.879a1 1 0 0 1-1.158.81l-.118-.02a3.98 3.98 0 0 1-.541 1.935zM3 0h4a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="italic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.5 12l2-8H6a1 1 0 1 1 0-2h6a1 1 0 0 1 0 2h-1.5l-2 8H10a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2h1.5z"/></symbol><symbol viewBox="0 0 16 16" id="key" xmlns="http://www.w3.org/2000/svg"><path d="M7.575 6.689a4.002 4.002 0 0 1 6.274-4.86 4 4 0 0 1-4.86 6.274l-2.21 2.21.706.708a1 1 0 1 1-1.414 1.414l-.707-.707-.707.707.707.707a1 1 0 1 1-1.414 1.414l-.707-.707a1 1 0 0 1-1.414-1.414l5.746-5.746zm2.032-.618a2 2 0 1 0 2.828-2.828A2 2 0 0 0 9.607 6.07z"/></symbol><symbol viewBox="0 0 16 16" id="key-2" xmlns="http://www.w3.org/2000/svg"><path d="M5.172 14.157l-.344.344-2.485.133a.462.462 0 0 1-.497-.503l.14-2.24a.599.599 0 0 1 .177-.382l5.155-5.155a4 4 0 1 1 2.828 2.828l-1.439 1.44-1.06-.354-.708.707.354 1.06-.707.708-1.06-.354-.708.707.354 1.06zm6.01-8.839a1 1 0 1 0 1.414-1.414 1 1 0 0 0-1.414 1.414z"/></symbol><symbol viewBox="0 0 16 16" id="label" xmlns="http://www.w3.org/2000/svg"><path d="M11.782 14.718a3 3 0 0 1-4.242 0L1.652 8.829a2 2 0 0 1-.565-1.702l.54-3.703a2 2 0 0 1 1.69-1.69l3.703-.54a2 2 0 0 1 1.703.564l5.888 5.888a3 3 0 0 1 0 4.243l-2.829 2.829zm1.415-5.657L7.309 3.173l-3.703.54-.54 3.702 5.888 5.888a1 1 0 0 0 1.414 0l2.829-2.828a1 1 0 0 0 0-1.414zM5.732 5.525A1 1 0 1 1 7.146 6.94a1 1 0 0 1-1.414-1.414z"/></symbol><symbol viewBox="0 0 16 16" id="labels" xmlns="http://www.w3.org/2000/svg"><path d="M9.424 2.254l2.08-.905a1 1 0 0 1 1.206.326l3.013 4.12a1 1 0 0 1 .16.849l-1.947 7.264a3 3 0 0 1-3.675 2.122l-.5-.135a3.999 3.999 0 0 0 1.082-1.782 1 1 0 0 0 1.16-.722l1.823-6.802-2.258-3.087-.687.299a2 2 0 0 0-.628-.88l-.829-.667zM.377 3.7L4.4.498a1 1 0 0 1 1.25.003L9.627 3.7a1 1 0 0 1 .373.78V13a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4.482A1 1 0 0 1 .377 3.7zM2 13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V4.958L5.02 2.561 2 4.964V13zm3-6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="leave" xmlns="http://www.w3.org/2000/svg"><path d="M11 7V5.883a.5.5 0 0 1 .757-.429l3.528 2.117a.5.5 0 0 1 0 .858l-3.528 2.117a.5.5 0 0 1-.757-.43V9H7a1 1 0 1 1 0-2h4zm-2 6.256a1 1 0 0 1 2 0A2.744 2.744 0 0 1 8.256 16H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h5.19A2.81 2.81 0 0 1 11 2.81a1 1 0 0 1-2 0A.81.81 0 0 0 8.19 2H3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h5.256c.41 0 .744-.333.744-.744z"/></symbol><symbol viewBox="0 0 16 16" id="level-up" xmlns="http://www.w3.org/2000/svg"><path fill="#2E2E2E" fill-rule="evenodd" d="M7 6h3.489a.5.5 0 0 0 .373-.832L6.374.117a.5.5 0 0 0-.748 0l-4.488 5.05A.5.5 0 0 0 1.51 6H5v7a3 3 0 0 0 3 3h6a1 1 0 0 0 0-2H8a1 1 0 0 1-1-1V6z"/></symbol><symbol viewBox="0 0 16 16" id="license" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12.56 8.9l2.66 4.606a.3.3 0 0 1-.243.45l-1.678.094a.1.1 0 0 0-.078.044l-.953 1.432a.3.3 0 0 1-.51-.016L9.097 10.9a5.994 5.994 0 0 0 3.464-2zm-5.23 2.063L4.707 15.51a.3.3 0 0 1-.51.016l-.953-1.432a.1.1 0 0 0-.078-.044l-1.678-.094a.3.3 0 0 1-.243-.45l2.48-4.297a5.983 5.983 0 0 0 3.607 1.754zM8 10A5 5 0 1 1 8 0a5 5 0 0 1 0 10zm0-2a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-1a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="link" xmlns="http://www.w3.org/2000/svg"><path d="M6.986 3.35l2.12-2.122a4 4 0 0 1 5.657 5.657l-2.828 2.829a4 4 0 0 1-5.657 0 1 1 0 0 1 1.414-1.415 2 2 0 0 0 2.829 0l2.828-2.828a2 2 0 1 0-2.828-2.828l-1.001 1a5.018 5.018 0 0 0-2.534-.294zm2.12 9.192l-2.12 2.121a4 4 0 1 1-5.658-5.656l2.829-2.829a4 4 0 0 1 5.657 0 1 1 0 1 1-1.415 1.414 2 2 0 0 0-2.828 0l-2.828 2.829a2 2 0 1 0 2.828 2.828l1.001-1.001a5.018 5.018 0 0 0 2.534.294z"/></symbol><symbol viewBox="0 0 16 16" id="list-bulleted" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-7h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm0 5h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm-4 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-2h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="list-numbered" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 2h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2zM1.156 5v-.828h.816V2.204h-.72v-.636c.432-.084.708-.192.996-.372h.756v2.976h.684V5H1.156zm-.18 5v-.588c.9-.828 1.596-1.464 1.596-1.98 0-.342-.192-.504-.468-.504-.252 0-.444.18-.624.36l-.552-.552c.396-.42.756-.612 1.32-.612.768 0 1.308.492 1.308 1.248 0 .612-.576 1.284-1.092 1.812.192-.024.468-.048.636-.048h.636V10H.976zm1.26 5.072c-.618 0-1.068-.204-1.356-.54l.468-.648c.234.216.51.36.78.36.336 0 .552-.12.552-.36 0-.288-.15-.456-.948-.456v-.72c.636 0 .828-.168.828-.432 0-.228-.138-.348-.396-.348-.252 0-.432.108-.672.312l-.516-.624c.372-.312.768-.492 1.236-.492.84 0 1.38.384 1.38 1.074 0 .366-.204.642-.612.822v.024c.432.132.732.432.732.912 0 .72-.684 1.116-1.476 1.116z"/></symbol><symbol viewBox="0 0 16 16" id="location" xmlns="http://www.w3.org/2000/svg"><path d="M8.755 15.144a1 1 0 0 1-1.51 0C3.748 11.114 2 8.065 2 6a6 6 0 1 1 12 0c0 2.065-1.748 5.113-5.245 9.144zM12 6a4 4 0 1 0-8 0c0 1.314 1.312 3.71 4 6.944C10.688 9.71 12 7.314 12 6zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="location-dot" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.314 13.087C4.382 13.295 3 13.85 3 14.5c0 .828 2.239 1.5 5 1.5s5-.672 5-1.5c0-.65-1.382-1.205-3.314-1.413l-.202.225a2 2 0 0 1-2.968 0l-.202-.225zm2.428-.445a1 1 0 0 1-1.484 0C4.419 9.5 3 7.037 3 5.252 3 2.353 5.239 0 8 0s5 2.352 5 5.253c0 1.784-1.42 4.247-4.258 7.389zM11 5.252C11 3.436 9.634 2 8 2S5 3.435 5 5.253c0 1.027.974 2.824 3 5.203 2.026-2.38 3-4.176 3-5.203zM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="lock" xmlns="http://www.w3.org/2000/svg"><path d="M10 5V4h2v1a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V8a3 3 0 0 1 3-3V4h2v1h4zM4 7a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1H4zm0-3a4 4 0 1 1 8 0h-2a2 2 0 1 0-4 0H4z"/></symbol><symbol viewBox="0 0 16 16" id="lock-open" xmlns="http://www.w3.org/2000/svg"><path d="M4.044 4a4 4 0 0 1 6.99-2.658 1 1 0 1 1-1.495 1.33A2 2 0 0 0 6.044 4a.998.998 0 0 1-.07.367v.701H12a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3v-5a3 3 0 0 1 2.974-3V4h.07zM4 7.07a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="log" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4zm1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-5h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm0 3h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm-3 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-2h3a1 1 0 0 1 0 2H8a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="mail" xmlns="http://www.w3.org/2000/svg"><path d="M14 5.6L9.338 9.796a2 2 0 0 1-2.676 0L2 5.6V11a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5.6zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm.212 2L8 8.31 12.788 4H3.212z"/></symbol><symbol viewBox="0 0 16 16" id="menu" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.143 2h13.714C15.488 2 16 2.448 16 3s-.512 1-1.143 1H1.143C.512 4 0 3.552 0 3s.512-1 1.143-1zm0 5h13.714C15.488 7 16 7.448 16 8s-.512 1-1.143 1H1.143C.512 9 0 8.552 0 8s.512-1 1.143-1zm0 5h13.714c.631 0 1.143.448 1.143 1s-.512 1-1.143 1H1.143C.512 14 0 13.552 0 13s.512-1 1.143-1z"/></symbol><symbol viewBox="0 0 16 16" id="merge-request-close" xmlns="http://www.w3.org/2000/svg"><path d="M9.414 8l1.414 1.414a1 1 0 1 1-1.414 1.414L8 9.414l-1.414 1.414a1 1 0 1 1-1.414-1.414L6.586 8 5.172 6.586a1 1 0 1 1 1.414-1.414L8 6.586l1.414-1.414a1 1 0 1 1 1.414 1.414L9.414 8zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="messages" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.588 8.942l1.173 5.862A1 1 0 0 1 8.78 16H7.22a1 1 0 0 1-.98-1.196l1.172-5.862a3.014 3.014 0 0 0 1.176 0zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4zM4.464 2.464L5.88 3.88a3 3 0 0 0 0 4.242L4.464 9.536a5 5 0 0 1 0-7.072zm7.072 7.072L10.12 8.12a3 3 0 0 0 0-4.242l1.415-1.415a5 5 0 0 1 0 7.072zM2.343.343l1.414 1.414a6 6 0 0 0 0 8.486l-1.414 1.414a8 8 0 0 1 0-11.314zm11.314 11.314l-1.414-1.414a6 6 0 0 0 0-8.486L13.657.343a8 8 0 0 1 0 11.314z"/></symbol><symbol viewBox="0 0 16 16" id="mobile-issue-close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.657 10.728L2.12 7.192A1 1 0 1 0 .707 8.607l4.243 4.242a.997.997 0 0 0 1.414 0l8.485-8.485a1 1 0 1 0-1.414-1.414l-7.778 7.778z"/></symbol><symbol viewBox="0 0 16 16" id="monitor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 13v1h3a1 1 0 0 1 0 2H3a1 1 0 0 1 0-2h3v-1H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3h-3zM3 2a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm5.723 6.416l-2.66-1.773-1.71 1.71a.5.5 0 1 1-.707-.707l2-2a.5.5 0 0 1 .631-.062l2.66 1.773 2.71-2.71a.5.5 0 0 1 .707.707l-3 3a.5.5 0 0 1-.631.062z"/></symbol><symbol viewBox="0 0 16 16" id="more" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 4a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="notifications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 14H2.435a2 2 0 0 1-1.761-2.947c.962-1.788 1.521-3.065 1.68-3.832.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024c3.755.528 4.375 4.27 4.761 6.043.188.86.742 2.188 1.661 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0zm5.805-6.468c-.325-1.492-.37-1.674-.61-2.288C10.6 3.716 9.742 3 8.07 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.208 1.012-.827 2.424-1.877 4.375H13.64c-.993-1.937-1.6-3.396-1.835-4.468z"/></symbol><symbol viewBox="0 0 16 16" id="notifications-off" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.26 5.089c.243.757.382 1.478.5 2.017.187.86.74 2.188 1.66 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0H4.35l2-2h7.29c-.993-1.937-1.6-3.396-1.835-4.468-.07-.326-.129-.59-.178-.81l1.634-1.633zM10.943 1.75l-1.48 1.48C9.07 3.076 8.612 3 8.069 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.065.317-.17.673-.317 1.073L.45 12.242a1.99 1.99 0 0 1 .224-1.19c.962-1.787 1.521-3.064 1.68-3.831.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024 4.867 4.867 0 0 1 1.944.688zm2.932-.105a1 1 0 0 1 0 1.415L2.561 14.374a1 1 0 1 1-1.415-1.414L12.46 1.646a1 1 0 0 1 1.414 0z"/></symbol><symbol viewBox="0 0 16 16" id="overview" xmlns="http://www.w3.org/2000/svg"><path d="M2 0h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2h-3zM2 9h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3h-3z"/></symbol><symbol viewBox="0 0 16 16" id="pencil" xmlns="http://www.w3.org/2000/svg"><path d="M13.02 1.293l1.414 1.414a1 1 0 0 1 0 1.414L4.119 14.436a1 1 0 0 1-.704.293l-2.407.008L1 12.316a1 1 0 0 1 .293-.71L11.605 1.292a1 1 0 0 1 1.414 0zm-1.416 1.415l-.707.707L12.31 4.83l.707-.707-1.414-1.415zM3.411 13.73l1.123-1.122H3.12v-1.415L2 12.312l.005 1.422 1.406-.005z"/></symbol><symbol viewBox="0 0 16 16" id="pencil-square" xmlns="http://www.w3.org/2000/svg"><path d="M12 9a1 1 0 0 1 2 0v4a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h4a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V9zm.778-7.179l1.414 1.415-6.476 6.476a1 1 0 0 1-.498.27l-1.51.325.323-1.512a1 1 0 0 1 .27-.497l6.477-6.477zM15.607.407a1 1 0 0 1 0 1.414l-.708.707-1.414-1.414.707-.707a1 1 0 0 1 1.415 0z"/></symbol><symbol viewBox="0 0 16 16" id="pipeline" xmlns="http://www.w3.org/2000/svg"><path d="M8.969 7.25a2 2 0 1 1-1.938 0A1.002 1.002 0 0 1 7 7V5.083a.2.2 0 0 1 .06-.142l.877-.87a.1.1 0 0 1 .141 0l.864.87A.2.2 0 0 1 9 5.083V7c0 .086-.01.17-.031.25zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm4.5-4a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zM8 10a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="play" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.765 15.835c-.545.321-1.258.159-1.593-.363A1.075 1.075 0 0 1 1 14.89V1.11C1 .496 1.518 0 2.158 0c.214 0 .424.057.607.165l11.684 6.89c.544.321.714 1.005.38 1.526a1.135 1.135 0 0 1-.38.364l-11.684 6.89z"/></symbol><symbol viewBox="0 0 16 16" id="plus" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7H2a1 1 0 1 0 0 2h5v5a1 1 0 0 0 2 0V9h5a1 1 0 0 0 0-2H9V2a1 1 0 1 0-2 0v5z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 7V4a1 1 0 1 0-2 0v3H4a1 1 0 1 0 0 2h3v3a1 1 0 0 0 2 0V9h3a1 1 0 0 0 0-2H9zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square-o" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="podcast" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.588 8.942l1.173 5.862a1 1 0 0 1-.785 1.177A1 1 0 0 1 8.78 16H7.22a1 1 0 0 1-1-1 1 1 0 0 1 .02-.196l1.172-5.862a3.014 3.014 0 0 0 1.176 0zM8 7.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM4.464 2.464A1 1 0 0 1 5.88 3.88a3 3 0 0 0 0 4.242 1 1 0 0 1-1.415 1.415 5 5 0 0 1 0-7.072zm7.072 7.072A1 1 0 0 1 10.12 8.12a3 3 0 0 0 0-4.242 1 1 0 0 1 1.415-1.415 5 5 0 0 1 0 7.072zM2.343.343a1 1 0 1 1 1.414 1.414 6 6 0 0 0 0 8.486 1 1 0 1 1-1.414 1.414 8 8 0 0 1 0-11.314zm11.314 11.314a1 1 0 1 1-1.414-1.414 6 6 0 0 0 0-8.486A1 1 0 0 1 13.657.343a8 8 0 0 1 0 11.314z"/></symbol><symbol viewBox="0 0 16 16" id="preferences" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5 12h10a1 1 0 0 1 0 2H5a1 1 0 0 1-2 0v-2a1 1 0 0 1 2 0zm-3 0H1a1 1 0 0 0 0 2h1v-2zm11-5h2a1 1 0 0 1 0 2h-2a1 1 0 0 1-2 0V7a1 1 0 0 1 2 0zm-3 0H1a1 1 0 1 0 0 2h9V7zM6 2h9a1 1 0 0 1 0 2H6a1 1 0 1 1-2 0V2a1 1 0 1 1 2 0zM3 2H1a1 1 0 1 0 0 2h2V2z"/></symbol><symbol viewBox="0 0 16 16" id="profile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-4.274-3.404C4.412 9.709 5.694 9 8 9c2.313 0 3.595.7 4.28 1.586A4.997 4.997 0 0 1 8 13a4.997 4.997 0 0 1-4.274-2.404zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="project" xmlns="http://www.w3.org/2000/svg"><path d="M8.462 2.177l-.038.044a.505.505 0 0 0 .038-.044zm-.787 0a.5.5 0 0 0 .038.043l-.038-.043zM3.706 7h8.725L8.069 2.585 3.706 7zM7 13.369V12a1 1 0 0 1 2 0v1.369h3V9H4v4.369h3zM14 9v4.836c0 .833-.657 1.533-1.5 1.533h-9c-.843 0-1.5-.7-1.5-1.533V9h-.448a1.1 1.1 0 0 1-.783-1.873L6.934.887a1.5 1.5 0 0 1 2.269 0l6.165 6.24A1.1 1.1 0 0 1 14.585 9H14z"/></symbol><symbol viewBox="0 0 16 16" id="push-rules" xmlns="http://www.w3.org/2000/svg"><path d="M6.268 9a2 2 0 0 1 3.464 0H11a1 1 0 0 1 0 2H9.732a2 2 0 0 1-3.464 0H5a1 1 0 0 1 0-2h1.268zM7 2H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1h-1v3.515a.3.3 0 0 1-.434.268l-1.432-.716a.3.3 0 0 0-.268 0l-1.432.716A.3.3 0 0 1 7 5.515V2zM4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm4 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="question" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm-1.46-5.602h2.233a3.97 3.97 0 0 1 .051-.558c.029-.17.073-.326.133-.469.06-.143.14-.28.242-.41.102-.13.228-.263.38-.399.26-.24.504-.467.733-.683a5.03 5.03 0 0 0 .598-.668c.17-.23.302-.477.399-.742a2.66 2.66 0 0 0 .144-.907c0-.505-.083-.95-.25-1.335a2.55 2.55 0 0 0-.723-.97 3.2 3.2 0 0 0-1.152-.589 5.441 5.441 0 0 0-1.531-.2c-.516 0-.998.063-1.445.188a3.19 3.19 0 0 0-1.168.59c-.331.268-.594.61-.79 1.027-.195.417-.295.917-.3 1.5h2.64c.006-.224.04-.416.102-.578.062-.161.142-.293.238-.394a.921.921 0 0 1 .332-.227 1.04 1.04 0 0 1 .39-.074c.34 0 .593.095.763.285.169.19.254.488.254.895 0 .328-.106.63-.317.906-.21.276-.499.565-.863.867-.214.182-.39.374-.531.574-.141.2-.253.42-.336.657a3.656 3.656 0 0 0-.176.777 7.89 7.89 0 0 0-.05.937zm-.321 2.375c0 .188.035.362.105.524.07.161.17.3.301.418.13.117.284.21.46.277.178.068.376.102.595.102.218 0 .416-.034.593-.102.178-.068.331-.16.461-.277a1.2 1.2 0 0 0 .301-.418c.07-.162.106-.336.106-.524a1.3 1.3 0 0 0-.106-.523 1.2 1.2 0 0 0-.3-.418 1.461 1.461 0 0 0-.462-.277 1.651 1.651 0 0 0-.593-.102c-.22 0-.417.034-.594.102a1.46 1.46 0 0 0-.461.277 1.2 1.2 0 0 0-.3.418 1.284 1.284 0 0 0-.106.523z"/></symbol><symbol viewBox="0 0 16 16" id="question-o" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-.778-4.151c0-.301.014-.575.044-.82a3.2 3.2 0 0 1 .154-.68c.073-.208.17-.4.294-.575.123-.176.278-.343.465-.503a4.81 4.81 0 0 0 .755-.758c.185-.242.277-.506.277-.793 0-.356-.074-.617-.222-.783-.148-.166-.37-.25-.667-.25a.92.92 0 0 0-.342.065.806.806 0 0 0-.29.199 1.04 1.04 0 0 0-.209.345 1.5 1.5 0 0 0-.088.506H5.082c.005-.51.092-.948.263-1.313.171-.364.401-.664.69-.899.29-.234.63-.406 1.023-.516a4.66 4.66 0 0 1 1.264-.164c.497 0 .944.058 1.34.174.397.117.733.289 1.008.517.276.227.487.51.633.847.146.337.218.727.218 1.17 0 .295-.042.56-.126.792a2.52 2.52 0 0 1-.349.65 4.4 4.4 0 0 1-.523.584c-.2.19-.414.389-.642.598a2.73 2.73 0 0 0-.332.349c-.089.114-.16.233-.212.359a1.868 1.868 0 0 0-.116.41 3.39 3.39 0 0 0-.044.489H7.222zm-.28 2.078c0-.164.03-.317.092-.458a1.05 1.05 0 0 1 .263-.366c.114-.103.248-.183.403-.243a1.45 1.45 0 0 1 .52-.089c.191 0 .364.03.52.09.154.059.289.14.403.242.114.103.201.224.263.366.061.141.092.294.092.458 0 .164-.03.316-.092.458a1.05 1.05 0 0 1-.263.365 1.278 1.278 0 0 1-.404.243 1.43 1.43 0 0 1-.52.089c-.19 0-.364-.03-.519-.089-.155-.06-.29-.14-.403-.243a1.05 1.05 0 0 1-.263-.365 1.135 1.135 0 0 1-.093-.458z"/></symbol><symbol viewBox="0 0 16 16" id="quote" xmlns="http://www.w3.org/2000/svg"><path d="M15 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9h-2a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1zM7 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9H3a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="redo" xmlns="http://www.w3.org/2000/svg"><path d="M4.625 4.423A4.897 4.897 0 0 1 8.079 3c2.73 0 4.944 2.239 4.944 5s-2.214 5-4.944 5c-1.41 0-2.723-.6-3.655-1.633a.98.98 0 0 0-1.397-.066 1.008 1.008 0 0 0-.064 1.413A6.87 6.87 0 0 0 8.079 15C11.9 15 15 11.866 15 8s-3.099-7-6.921-7A6.866 6.866 0 0 0 3.08 3.158L1.833 2.137a.49.49 0 0 0-.695.074.504.504 0 0 0-.11.311L1 7.26a.497.497 0 0 0 .6.492l4.576-1.013a.5.5 0 0 0 .206-.877L4.625 4.423z"/></symbol><symbol viewBox="0 0 16 16" id="remove" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2v10a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V3zm3-2a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1H5zM4 3v10a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3H4zm2.5 2a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm3 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 16 16" id="repeat" xmlns="http://www.w3.org/2000/svg"><path d="M11.375 4.423A4.897 4.897 0 0 0 7.921 3c-2.73 0-4.944 2.239-4.944 5s2.214 5 4.944 5c1.41 0 2.723-.6 3.655-1.633a.98.98 0 0 1 1.397-.066c.403.373.432 1.005.064 1.413A6.87 6.87 0 0 1 7.921 15C4.1 15 1 11.866 1 8s3.099-7 6.921-7c1.915 0 3.706.792 4.999 2.158l1.247-1.021a.49.49 0 0 1 .695.074c.07.088.11.198.11.311L15 7.26a.497.497 0 0 1-.6.492L9.824 6.739a.5.5 0 0 1-.206-.877l1.757-1.439z"/></symbol><symbol viewBox="0 0 16 16" id="retry" xmlns="http://www.w3.org/2000/svg"><path d="M4.114 6.958a4 4 0 0 0 5.283 4.775 1 1 0 1 1 .712 1.87A6 6 0 0 1 2.182 6.44l-.741-.2a.5.5 0 0 1-.12-.915l2.195-1.268a.5.5 0 0 1 .683.183l1.268 2.196a.5.5 0 0 1-.563.733l-.79-.212zm7.777 2.084a4 4 0 0 0-5.284-4.775 1 1 0 0 1-.712-1.87 6 6 0 0 1 7.927 7.162l.742.2a.5.5 0 0 1 .12.915l-2.196 1.268a.5.5 0 0 1-.683-.183l-1.267-2.196a.5.5 0 0 1 .562-.733l.79.212z"/></symbol><symbol viewBox="0 0 16 16" id="scale" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.99 9a.792.792 0 0 0-.078-.231L13 7l-.912 1.769a.791.791 0 0 0-.077.231h1.978zm-10 0a.792.792 0 0 0-.078-.231L3 7l-.912 1.769A.791.791 0 0 0 2.011 9h1.978zM2 0h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm3 14h6a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zM8 4a1 1 0 0 1 1 1v9H7V5a1 1 0 0 1 1-1zm-4.53-.714l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 3 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158L2.53 3.286a.53.53 0 0 1 .94 0zm10 0l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 13 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158l2.266-4.735a.53.53 0 0 1 .94 0z"/></symbol><symbol viewBox="0 0 16 16" id="screen-full" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14 14v-2a1 1 0 0 1 2 0v3a.997.997 0 0 1-1 1h-3a1 1 0 0 1 0-2h2zM2 14v-2a1 1 0 0 0-2 0v3a1 1 0 0 0 1 1h3a1 1 0 0 0 0-2H2zM15.707.293A.997.997 0 0 1 16 1v3a1 1 0 0 1-2 0V2h-2a1 1 0 0 1 0-2h3c.276 0 .526.112.707.293zM2 2v2a1 1 0 1 1-2 0V1a.997.997 0 0 1 1-1h3a1 1 0 1 1 0 2H2zm4 4h4a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="screen-normal" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 3V1a1 1 0 1 1 2 0v3a.997.997 0 0 1-1 1H1a1 1 0 1 1 0-2h2zm10 0h2a1 1 0 0 1 0 2h-3a.997.997 0 0 1-1-1V1a1 1 0 0 1 2 0v2zM3 13H1a1 1 0 0 1 0-2h3a.997.997 0 0 1 1 1v3a1 1 0 0 1-2 0v-2zm10 0v2a1 1 0 0 1-2 0v-3a.997.997 0 0 1 1-1h3a1 1 0 0 1 0 2h-2zM6.5 7h3a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 12 16" id="scroll_down" xmlns="http://www.w3.org/2000/svg"><path class="fbfirst-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.043a.51.51 0 0 0 .321-.105c.09-.07.136-.154.136-.25v-.71c0-.095-.045-.178-.136-.249a.508.508 0 0 0-.32-.105"/><path class="fbsecond-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="fbthird-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-.136.09h-.37a.626.626 0 0 1-.136-.09"/></symbol><symbol viewBox="0 0 12 16" id="scroll_up" xmlns="http://www.w3.org/2000/svg"><path d="M1.048 1.845a.508.508 0 0 1-.32-.105c-.091-.07-.136-.154-.136-.25V.78c0-.095.045-.178.135-.249a.508.508 0 0 1 .321-.105h10.043a.51.51 0 0 1 .321.105c.09.07.136.154.136.25v.71c0 .095-.045.178-.136.249a.508.508 0 0 1-.32.105M.687 7.973c-.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 3.09A.458.458 0 0 0 6.257 3h-.37a.626.626 0 0 0-.136.09M.687 14.973c-.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 10.09a.458.458 0 0 0-.136-.09h-.37a.626.626 0 0 0-.136.09"/></symbol><symbol viewBox="0 0 16 16" id="search" xmlns="http://www.w3.org/2000/svg"><path d="M8.853 8.854a3.5 3.5 0 1 0-4.95-4.95 3.5 3.5 0 0 0 4.95 4.95zm.207 2.328a5.5 5.5 0 1 1 2.121-2.121l3.329 3.328a1.5 1.5 0 0 1-2.121 2.121L9.06 11.182z"/></symbol><symbol viewBox="0 0 16 16" id="settings" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.415 5.803L1.317 4.084A.5.5 0 0 1 1.35 3.5l.805-.994a.5.5 0 0 1 .564-.153l1.878.704a5.975 5.975 0 0 1 1.65-.797L6.885.342A.5.5 0 0 1 7.36 0h1.28a.5.5 0 0 1 .474.342l.639 1.918a5.97 5.97 0 0 1 1.65.797l1.877-.704a.5.5 0 0 1 .565.153l.805.994a.5.5 0 0 1 .032.584l-1.097 1.719c.217.551.354 1.143.399 1.76l1.731 1.058a.5.5 0 0 1 .227.54l-.288 1.246a.5.5 0 0 1-.44.385l-2.008.19a6.026 6.026 0 0 1-1.142 1.431l.265 1.995a.5.5 0 0 1-.277.516l-1.15.56a.5.5 0 0 1-.576-.1l-1.424-1.452a6.047 6.047 0 0 1-1.804 0l-1.425 1.453a.5.5 0 0 1-.576.1l-1.15-.561a.5.5 0 0 1-.276-.516l.265-1.995a6.026 6.026 0 0 1-1.143-1.43l-2.008-.191a.5.5 0 0 1-.44-.385L.058 9.16a.5.5 0 0 1 .226-.539l1.732-1.058a5.968 5.968 0 0 1 .399-1.76zM8 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="shield" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8c1.657 0 3 1.373 3 3.067v7.346c0 1.065-.54 2.053-1.426 2.611l-4 2.52a2.944 2.944 0 0 1-3.148 0l-4-2.52A3.083 3.083 0 0 1 1 10.414V3.066C1 1.373 2.343 0 4 0zm0 2.045c-.552 0-1 .457-1 1.022v7.346c0 .355.18.685.475.87l4 2.52a.981.981 0 0 0 1.05 0l4-2.52c.295-.185.475-.515.475-.87V3.067c0-.565-.448-1.022-1-1.022H4zm0 1.533c0-.282.224-.511.5-.511h4V12.1a.52.52 0 0 1-.069.258.494.494 0 0 1-.684.183l-3.5-2.098a.513.513 0 0 1-.247-.44V3.577z"/></symbol><symbol viewBox="0 0 16 16" id="slight-frown" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-2.163-3.275a2.499 2.499 0 0 1 4.343.03.5.5 0 0 1-.871.49 1.5 1.5 0 0 0-2.607-.018.5.5 0 1 1-.865-.502zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="slight-smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-5.163 2.254a.5.5 0 1 1 .865-.502 1.499 1.499 0 0 0 2.607-.018.5.5 0 1 1 .871.49 2.499 2.499 0 0 1-4.343.03z"/></symbol><symbol viewBox="0 0 16 16" id="smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM6.18 6.27a.5.5 0 0 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zm6 0a.5.5 0 1 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zM5 9a3 3 0 0 0 6 0H5z"/></symbol><symbol viewBox="0 0 16 16" id="smiley" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM5 9h6a3 3 0 0 1-6 0z"/></symbol><symbol viewBox="0 0 16 16" id="snippet" xmlns="http://www.w3.org/2000/svg"><path d="M10.67 9.31a3.001 3.001 0 0 1 2.062 5.546 3 3 0 0 1-3.771-4.559 1.007 1.007 0 0 1-.095-.137l-4.5-7.794a1 1 0 0 1 1.732-1l4.5 7.794c.028.05.052.1.071.15zm-3.283.35l-.289.5c-.028.05-.06.095-.095.137a3.001 3.001 0 0 1-3.77 4.56A3 3 0 0 1 5.294 9.31c.02-.051.043-.102.071-.15l.866-1.5 1.155 2zm2.31-4l-1.156-2 1.325-2.294a1 1 0 0 1 1.732 1L9.696 5.66zm-5.465 7.464a1 1 0 1 0 1-1.732 1 1 0 0 0-1 1.732zm7.5 0a1 1 0 1 0-1-1.732 1 1 0 0 0 1 1.732z"/></symbol><symbol viewBox="0 0 16 16" id="soft-unwrap" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.5 11v-.598a.5.5 0 0 1 .765-.424l2.557 1.598a.5.5 0 0 1 0 .848l-2.557 1.598a.5.5 0 0 1-.765-.424V13H2a1 1 0 0 1 0-2h4.5zM2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm10 4h2a1 1 0 0 1 0 2h-2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="soft-wrap" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.5 13v.598a.5.5 0 0 1-.765.424l-2.557-1.598a.5.5 0 0 1 0-.848l2.557-1.598a.5.5 0 0 1 .765.424V11H12a1 1 0 0 0 0-2H2a1 1 0 1 1 0-2h10a3 3 0 0 1 0 6h-1.5zM2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 8h3a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="spam" xmlns="http://www.w3.org/2000/svg"><path d="M8.75.433l5.428 3.134a1.5 1.5 0 0 1 .75 1.299v6.268a1.5 1.5 0 0 1-.75 1.299L8.75 15.567a1.5 1.5 0 0 1-1.5 0l-5.428-3.134a1.5 1.5 0 0 1-.75-1.299V4.866a1.5 1.5 0 0 1 .75-1.299L7.25.433a1.5 1.5 0 0 1 1.5 0zM3.072 5.155v5.69L8 13.691l4.928-2.846v-5.69L8 2.309 3.072 5.155zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 14 14" id="spinner" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="7" cy="7" r="6" stroke="#000" stroke-opacity=".1" stroke-width="2"/><path fill="#000" fill-opacity=".1" fill-rule="nonzero" d="M7 0a7 7 0 0 1 7 7h-2a5 5 0 0 0-5-5V0z"/></g></symbol><symbol viewBox="0 0 16 16" id="staged" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3h4a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm9 6a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM2 7h4a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="star" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.609 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 16 16" id="star-o" xmlns="http://www.w3.org/2000/svg"><path d="M10.975 10.99a3 3 0 0 1 .655-2.083l1.54-1.916-2.219-.576a3 3 0 0 1-1.825-1.37L8 3.15 6.874 5.044a3 3 0 0 1-1.825 1.371l-2.218.576 1.54 1.916a3 3 0 0 1 .654 2.083l-.165 2.4 1.965-.836a3 3 0 0 1 2.348 0l1.965.836-.164-2.399zM7.61 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 14 14" id="status_canceled" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M5.2 3.8l4.9 4.9c.2.2.2.5 0 .7l-.7.7c-.2.2-.5.2-.7 0L3.8 5.2c-.2-.2-.2-.5 0-.7l.7-.7c.2-.2.5-.2.7 0"/></g></symbol><symbol viewBox="0 0 22 22" id="status_canceled_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M8.171 5.971l7.7 7.7a.76.76 0 0 1 0 1.1l-1.1 1.1a.76.76 0 0 1-1.1 0l-7.7-7.7a.76.76 0 0 1 0-1.1l1.1-1.1a.76.76 0 0 1 1.1 0"/></symbol><symbol viewBox="0 0 16 16" id="status_closed" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.83a1 1 0 0 1 1.414 1.416l-3.535 3.535a1 1 0 0 1-1.415.001l-2.12-2.12a1 1 0 1 1 1.413-1.415zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 14 14" id="status_created" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><circle cx="7" cy="7" r="3.25"/></g></symbol><symbol viewBox="0 0 22 22" id="status_created_borderless" xmlns="http://www.w3.org/2000/svg"><circle cx="11" cy="11" r="5.107"/></symbol><symbol viewBox="0 0 14 14" id="status_failed" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 5.969L5.599 4.568a.29.29 0 0 0-.413.004l-.614.614a.294.294 0 0 0-.004.413L5.968 7l-1.4 1.401a.29.29 0 0 0 .004.413l.614.614c.113.114.3.117.413.004L7 8.032l1.401 1.4a.29.29 0 0 0 .413-.004l.614-.614a.294.294 0 0 0 .004-.413L8.032 7l1.4-1.401a.29.29 0 0 0-.004-.413l-.614-.614a.294.294 0 0 0-.413-.004L7 5.968z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_failed_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 9.38L8.798 7.178a.455.455 0 0 0-.65.006l-.964.965a.462.462 0 0 0-.006.65L9.38 11l-2.202 2.202a.455.455 0 0 0 .006.65l.965.964a.462.462 0 0 0 .65.006L11 12.62l2.202 2.202a.455.455 0 0 0 .65-.006l.964-.965a.462.462 0 0 0 .006-.65L12.62 11l2.202-2.202a.455.455 0 0 0-.006-.65l-.965-.964a.462.462 0 0 0-.65-.006L11 9.38z"/></symbol><symbol viewBox="0 0 14 14" id="status_manual" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M10.5 7.63V6.37l-.787-.13c-.044-.175-.132-.349-.263-.61l.481-.652-.918-.913-.657.478a2.346 2.346 0 0 0-.612-.26L7.656 3.5H6.388l-.132.783c-.219.043-.394.13-.612.26l-.657-.478-.918.913.437.652c-.131.218-.175.392-.262.61l-.744.086v1.261l.787.13c.044.218.132.392.263.61l-.438.651.92.913.655-.434c.175.086.394.173.613.26l.131.783h1.313l.131-.783c.219-.043.394-.13.613-.26l.656.478.918-.913-.48-.652c.13-.218.218-.435.262-.61l.656-.13zM7 8.283a1.285 1.285 0 0 1-1.313-1.305c0-.739.57-1.304 1.313-1.304.744 0 1.313.565 1.313 1.304 0 .74-.57 1.305-1.313 1.305z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_manual_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M16.5 11.99v-1.98l-1.238-.206c-.068-.273-.206-.546-.412-.956l.756-1.025-1.444-1.435-1.03.752a3.686 3.686 0 0 0-.963-.41L12.03 5.5h-1.994l-.206 1.23c-.343.068-.618.205-.962.41l-1.031-.752-1.444 1.435.687 1.025c-.206.341-.275.615-.412.956L5.5 9.941v1.981l1.237.205c.07.342.207.615.413.957l-.688 1.025 1.444 1.434 1.032-.683c.274.137.618.274.962.41l.206 1.23h2.063l.206-1.23c.344-.068.619-.205.963-.41l1.03.752 1.444-1.435-.756-1.025c.207-.341.344-.683.413-.956l1.031-.205zM11 13.017c-1.169 0-2.063-.889-2.063-2.05 0-1.162.894-2.05 2.063-2.05s2.063.888 2.063 2.05c0 1.161-.894 2.05-2.063 2.05z"/></symbol><symbol viewBox="0 0 14 14" id="status_notfound" xmlns="http://www.w3.org/2000/svg"><path d="M7 14A7 7 0 1 1 7 0a7 7 0 0 1 0 14z"/><path d="M7 13A6 6 0 1 0 7 1a6 6 0 0 0 0 12z" fill="#FFF"/><path d="M8.16 7.184c.519-.37.904-.857 1.07-1.477.384-1.427-.619-2.897-2.246-2.897-.732 0-1.327.26-1.766.692a2.163 2.163 0 0 0-.509.743.75.75 0 0 0 1.4.54.78.78 0 0 1 .16-.213c.168-.165.39-.262.715-.262.597 0 .936.496.798 1.007-.067.249-.235.462-.492.644-.231.165-.47.264-.601.3a.75.75 0 0 0-.556.724v1.421a.75.75 0 0 0 1.5 0v-.909a3.74 3.74 0 0 0 .526-.313z"/><ellipse cx="6.889" cy="10.634" rx="1" ry="1"/></symbol><symbol viewBox="0 0 22 22" id="status_notfound_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M12.822 11.29c.816-.581 1.421-1.348 1.683-2.322.603-2.243-.973-4.553-3.53-4.553-1.15 0-2.085.41-2.775 1.089-.42.413-.672.835-.8 1.167a1.179 1.179 0 0 0 2.2.847c.016-.043.1-.184.252-.334.264-.259.613-.412 1.123-.412.938 0 1.47.78 1.254 1.584-.105.39-.37.726-.773 1.012a3.25 3.25 0 0 1-.945.47 1.179 1.179 0 0 0-.874 1.138v2.234a1.179 1.179 0 1 0 2.358 0v-1.43a5.9 5.9 0 0 0 .827-.492z"/><ellipse cx="10.825" cy="16.711" rx="1.275" ry="1.322"/></symbol><symbol viewBox="0 0 14 14" id="status_open" xmlns="http://www.w3.org/2000/svg"><path d="M0 7c0-3.866 3.142-7 7-7 3.866 0 7 3.142 7 7 0 3.866-3.142 7-7 7-3.866 0-7-3.142-7-7z"/><path d="M1 7c0 3.309 2.69 6 6 6 3.309 0 6-2.69 6-6 0-3.309-2.69-6-6-6-3.309 0-6 2.69-6 6z" fill="#FFF"/><path d="M7 9.219a2.218 2.218 0 1 0 0-4.436A2.218 2.218 0 0 0 7 9.22zm0 1.12a3.338 3.338 0 1 1 0-6.676 3.338 3.338 0 0 1 0 6.676z"/></symbol><symbol viewBox="0 0 14 14" id="status_pending" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M4.7 5.3c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H5c-.2 0-.3-.1-.3-.3V5.3m3 0c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H8c-.2 0-.3-.1-.3-.3V5.3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_pending_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M7.386 8.329c0-.315.157-.472.471-.472h1.414c.315 0 .472.157.472.472v5.342c0 .315-.157.472-.472.472H7.857c-.314 0-.471-.157-.471-.472V8.33m4.714 0c0-.315.157-.472.471-.472h1.415c.314 0 .471.157.471.472v5.342c0 .315-.157.472-.471.472H12.57c-.314 0-.471-.157-.471-.472V8.33"/></symbol><symbol viewBox="0 0 14 14" id="status_running" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 3c2.2 0 4 1.8 4 4s-1.8 4-4 4c-1.3 0-2.5-.7-3.3-1.7L7 7V3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_running_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 4.714c3.457 0 6.286 2.829 6.286 6.286 0 3.457-2.829 6.286-6.286 6.286-2.043 0-3.929-1.1-5.186-2.672L11 11V4.714"/></symbol><symbol viewBox="0 0 14 14" id="status_skipped" xmlns="http://www.w3.org/2000/svg"><path d="M7 14A7 7 0 1 1 7 0a7 7 0 0 1 0 14z"/><path d="M7 13A6 6 0 1 0 7 1a6 6 0 0 0 0 12z" fill="#FFF"/><path d="M6.415 7.04L4.579 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L5.341 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L6.415 7.04zm2.54 0L7.119 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L7.881 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L8.955 7.04z"/></symbol><symbol viewBox="0 0 22 22" id="status_skipped_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M14.072 11.063l-2.82 2.82a.46.46 0 0 0-.001.652l.495.495a.457.457 0 0 0 .653-.001l3.7-3.7a.46.46 0 0 0 .001-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.479-3.479a.464.464 0 0 0-.654.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/><path d="M10.08 11.063l-2.819 2.82a.46.46 0 0 0-.002.652l.496.495a.457.457 0 0 0 .652-.001l3.7-3.7a.46.46 0 0 0 .002-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.48-3.479a.464.464 0 0 0-.653.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/></symbol><symbol viewBox="0 0 14 14" id="status_success" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6.278 7.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_success_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.866 12.095l-1.95-1.95a.462.462 0 0 0-.647.01l-.964.964a.46.46 0 0 0-.01.646l3.013 3.014a.787.787 0 0 0 1.106.008l.425-.425 4.854-4.853a.462.462 0 0 0 .002-.659l-.964-.964a.468.468 0 0 0-.658.002l-4.207 4.207z"/></symbol><symbol viewBox="0 0 14 14" id="status_success_solid" xmlns="http://www.w3.org/2000/svg"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7zm6.278.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 14 14" id="status_warning" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6 3.5c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v4c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-4m0 6c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v1c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-1"/></g></symbol><symbol viewBox="0 0 22 22" id="status_warning_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.429 5.5c0-.471.314-.786.785-.786h1.572c.471 0 .785.315.785.786v6.286c0 .471-.314.785-.785.785h-1.572c-.471 0-.785-.314-.785-.785V5.5m0 9.429c0-.472.314-.786.785-.786h1.572c.471 0 .785.314.785.786V16.5c0 .471-.314.786-.785.786h-1.572c-.471 0-.785-.315-.785-.786v-1.571"/></symbol><symbol viewBox="0 0 16 16" id="stop" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 0h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2z"/></symbol><symbol viewBox="0 0 16 16" id="task-done" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="template" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm.8 2h2.4a.8.8 0 0 1 .8.8v1.4a.8.8 0 0 1-.8.8H3.8a.8.8 0 0 1-.8-.8V4.8a.8.8 0 0 1 .8-.8zm4.7 0h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm0 2h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm-5 3h9a.5.5 0 1 1 0 1h-9a.5.5 0 0 1 0-1zm0 2h9a.5.5 0 1 1 0 1h-9a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="terminal" xmlns="http://www.w3.org/2000/svg"><path d="M7 8a.997.997 0 0 1-.293.707l-1.414 1.414a1 1 0 1 1-1.414-1.414L4.586 8l-.707-.707a1 1 0 1 1 1.414-1.414l1.414 1.414A.997.997 0 0 1 7 8zM4 0h8a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H4zm5 7h2a1 1 0 0 1 0 2H9a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 11h5.282a2 2 0 0 0 1.963-2.38l-.563-2.905a3 3 0 0 0-.243-.732l-1.103-2.286A3 3 0 0 0 10.964 1H7a3 3 0 0 0-3 3v6.3a2 2 0 0 0 .436 1.247l3.11 3.9a.632.632 0 0 0 .941.053l.137-.137a1 1 0 0 0 .28-.87L8.329 11zM1 10h2V3H1a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 5h5.282a2 2 0 0 1 1.963 2.38l-.563 2.905a3 3 0 0 1-.243.732l-1.103 2.286A3 3 0 0 1 10.964 15H7a3 3 0 0 1-3-3V5.7a2 2 0 0 1 .436-1.247l3.11-3.9A.632.632 0 0 1 8.487.5l.137.137a1 1 0 0 1 .28.87L8.329 5zM1 6h2v7H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="thumbtack" xmlns="http://www.w3.org/2000/svg"><path d="M7.125 9h-2.19a.5.5 0 0 1-.417-.777L6 6V2L5.362.724A.5.5 0 0 1 5.809 0h4.382a.5.5 0 0 1 .447.724L10 2v4l1.482 2.223a.5.5 0 0 1-.416.777H8.875L8 16l-.875-7z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 16 16" id="timer" xmlns="http://www.w3.org/2000/svg"><path d="M12.022 3.27l.77-.77a1 1 0 0 1 1.415 1.414l-.728.729a7 7 0 1 1-1.456-1.372zM8 14A5 5 0 1 0 8 4a5 5 0 0 0 0 10zm0-9a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zM6 0h4a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-add" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 4V2a1 1 0 0 1 2 0v2h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0V6H8a1 1 0 1 1 0-2h2zm2 7a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-done" xmlns="http://www.w3.org/2000/svg"><path d="M8.243 7.485l4.95-4.95a1 1 0 1 1 1.414 1.415L8.95 9.607a.997.997 0 0 1-1.414 0L4.707 6.778a1 1 0 0 1 1.414-1.414l2.122 2.121zM12 11a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="token" xmlns="http://www.w3.org/2000/svg"><path d="M3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H3zm1 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="unapproval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11.95 8.536l1.06-1.061a1 1 0 0 1 1.415 1.414l-1.061 1.06 1.06 1.061a1 1 0 0 1-1.414 1.415l-1.06-1.061-1.06 1.06a1 1 0 1 1-1.415-1.414l1.06-1.06-1.06-1.06a1 1 0 0 1 1.414-1.415l1.06 1.06zm-3.768-.33c.006.503.201 1.006.586 1.39l.353.354-.353.353a2 2 0 1 0 2.828 2.829l.354-.354.047.048C11.964 14.363 11.527 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.834 0 1.557.074 2.182.205zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="unassignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11 5h4a1 1 0 0 1 0 2h-4a1 1 0 0 1 0-2zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="unlink" xmlns="http://www.w3.org/2000/svg"><path d="M11.295 8.845l-.659-1.664a1.78 1.78 0 0 0 .04-.04l1.415-1.414c.586-.586.654-1.468.152-1.97s-1.384-.434-1.97.152L8.859 5.323a1.781 1.781 0 0 0-.04.04l-1.664-.658c.141-.208.305-.408.491-.594l1.415-1.414c1.366-1.367 3.424-1.525 4.596-.354 1.171 1.172 1.013 3.23-.354 4.596L11.89 8.354c-.186.186-.386.35-.594.491zm-2.45 2.45a4.075 4.075 0 0 1-.491.594l-1.415 1.414c-1.366 1.367-3.424 1.525-4.596.354-1.171-1.172-1.013-3.23.354-4.596L4.11 7.646c.186-.186.386-.35.594-.491l.659 1.664a1.781 1.781 0 0 0-.04.04l-1.415 1.414c-.586.586-.654 1.468-.152 1.97s1.384.434 1.97-.152l1.414-1.414a1.78 1.78 0 0 0 .04-.04l1.664.658zm3.812-2.088h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-.05a.5.5 0 0 1 .5-.5zm-.384 2.116l1.415 1.414a.5.5 0 0 1 0 .708l-.037.036a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 0-.707l.036-.037a.5.5 0 0 1 .707 0zm-2.823 1.09a.5.5 0 0 1 .5-.5h.052a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9.95a.5.5 0 0 1-.5-.5v-2zm-2.748-9.16a.5.5 0 0 1-.5.5h-.05a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h.05a.5.5 0 0 1 .5.5v2zm-2.116.383a.5.5 0 0 1 0 .707l-.036.036a.5.5 0 0 1-.707 0L2.428 2.965a.5.5 0 0 1 0-.707l.037-.036a.5.5 0 0 1 .707 0l1.414 1.414zm-1.09 2.823h-2a.5.5 0 0 1-.5-.5v-.051a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5z"/></symbol><symbol viewBox="0 0 16 16" id="unstaged" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="user" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 8c-6.888 0-6.976-.78-6.976-2.52S2.144 8 8 8s6.976 2.692 6.976 4.48c0 1.788-.088 2.52-6.976 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="users" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.521 8.01C15.103 8.19 16 10.755 16 12.48c0 1.533-.056 2.29-3.808 2.475.609-.54.808-1.331.808-2.475 0-1.911-.804-3.503-2.479-4.47zm-1.67-1.228A3.987 3.987 0 0 0 9.976 4a3.987 3.987 0 0 0-1.125-2.782 3 3 0 1 1 0 5.563zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="volume-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 5h1v6H1a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1zm2 0l4.445-2.964A1 1 0 0 1 9 2.87v10.26a1 1 0 0 1-1.555.833L3 11V5zm10.283 7.89a.5.5 0 0 1-.66-.752A5.485 5.485 0 0 0 14.5 8c0-1.601-.687-3.09-1.865-4.128a.5.5 0 0 1 .661-.75A6.484 6.484 0 0 1 15.5 8a6.485 6.485 0 0 1-2.217 4.89zm-2.002-2.236a.5.5 0 1 1-.652-.758c.55-.472.871-1.157.871-1.896 0-.732-.315-1.411-.856-1.883a.5.5 0 0 1 .658-.753A3.492 3.492 0 0 1 12.5 8c0 1.033-.45 1.994-1.219 2.654z"/></symbol><symbol viewBox="0 0 16 16" id="warning" xmlns="http://www.w3.org/2000/svg"><path d="M15.572 10.506c.867 1.42.375 3.247-1.098 4.082a3.184 3.184 0 0 1-1.57.412h-9.81C1.387 15 0 13.665 0 12.018a2.9 2.9 0 0 1 .427-1.512L5.332 2.47C6.2 1.05 8.096.577 9.57 1.412c.453.257.831.622 1.098 1.059l4.905 8.035zM8.89 3.479a1.014 1.014 0 0 0-.366-.353 1.053 1.053 0 0 0-1.412.353l-4.905 8.035a.967.967 0 0 0-.143.504c0 .549.462.994 1.032.994h9.81c.184 0 .364-.048.523-.137a.974.974 0 0 0 .366-1.361L8.889 3.479zM8 5a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zm0 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="work" xmlns="http://www.w3.org/2000/svg"><path d="M12 3h1a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h1V2a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v1zM6 2v1h4V2H6zM3 5a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H3zm1.5 1a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm7 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol></svg> \ No newline at end of file
+<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol viewBox="0 0 16 16" id="abuse" xmlns="http://www.w3.org/2000/svg"><path d="M11.408.328l4.029 3.222A1.5 1.5 0 0 1 16 4.72v6.555a1.5 1.5 0 0 1-.563 1.171l-4.026 3.224a1.5 1.5 0 0 1-.937.329H5.529a1.5 1.5 0 0 1-.937-.328L.563 12.45A1.5 1.5 0 0 1 0 11.28V4.724a1.5 1.5 0 0 1 .563-1.171L4.589.329A1.5 1.5 0 0 1 5.526 0h4.945c.34 0 .67.116.937.328zM10.296 2H5.702L2 4.964v6.074L5.704 14h4.594L14 11.036V4.962L10.296 2zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="account" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.195 9.965l-.568-.875a.25.25 0 0 1 .015-.294l.405-.5a.25.25 0 0 1 .283-.075l.938.36c.257-.183.543-.325.851-.42l.322-.988A.25.25 0 0 1 11.679 7h.642a.25.25 0 0 1 .238.173l.322.988c.308.095.594.237.851.42l.938-.36a.25.25 0 0 1 .283.076l.405.5a.25.25 0 0 1 .015.293l-.568.875c.113.297.18.616.193.95l.898.54a.25.25 0 0 1 .115.27l-.144.626a.25.25 0 0 1-.222.193l-1.115.098a3.015 3.015 0 0 1-.512.608l.165 1.18a.25.25 0 0 1-.138.259l-.577.281a.25.25 0 0 1-.29-.05l-.874-.905a3.035 3.035 0 0 1-.608 0l-.875.904a.25.25 0 0 1-.289.051l-.577-.281a.25.25 0 0 1-.138-.26l.165-1.18a3.015 3.015 0 0 1-.512-.607l-1.115-.098a.25.25 0 0 1-.222-.193l-.144-.626a.25.25 0 0 1 .115-.27l.898-.54c.013-.334.08-.653.193-.95zM6.789 8.023A12.845 12.845 0 0 0 6 8c-5.036 0-6 2.74-6 4.48C0 14.22.076 15 6 15c.553 0 1.055-.006 1.51-.02A5.977 5.977 0 0 1 6 11c0-1.083.287-2.1.79-2.977zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM12 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="admin" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.162 2.5a3.5 3.5 0 0 1-3.163 5.479L6.08 14.766a1.5 1.5 0 0 1-2.598-1.5L7.4 6.479A3.5 3.5 0 0 1 10.564 1L8.9 3.88l2.599 1.5 1.663-2.88zm-8.63 11.949a.5.5 0 1 0 .5-.866.5.5 0 0 0-.5.866z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.414 7.95l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 1 0 1.414-1.415L10.414 7.95zm-7 0l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 0 0 1.414-1.415L3.414 7.95z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.536 7.95L1.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 1 1-1.414-1.415L5.536 7.95zm7 0L8.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 0 1-1.414-1.415l4.243-4.242z"/></symbol><symbol viewBox="0 0 16 16" id="angle-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 10.243l-4.95-4.95a1 1 0 0 0-1.414 1.414l5.657 5.657a.997.997 0 0 0 1.414 0l5.657-5.657a1 1 0 0 0-1.414-1.414L8 10.243z"/></symbol><symbol viewBox="0 0 16 16" id="angle-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.757 8l4.95-4.95a1 1 0 1 0-1.414-1.414L3.636 7.293a.997.997 0 0 0 0 1.414l5.657 5.657a1 1 0 0 0 1.414-1.414L5.757 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.243 8l-4.95-4.95a1 1 0 0 1 1.414-1.414l5.657 5.657a.997.997 0 0 1 0 1.414l-5.657 5.657a1 1 0 0 1-1.414-1.414L10.243 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 6.757l-4.95 4.95a1 1 0 1 1-1.414-1.414l5.657-5.657a.997.997 0 0 1 1.414 0l5.657 5.657a1 1 0 0 1-1.414 1.414L8 6.757z"/></symbol><symbol viewBox="0 0 16 16" id="appearance" xmlns="http://www.w3.org/2000/svg"><path d="M11.161 12.456l.232.121c.1.053.175.094.249.137.53.318.844.75.857 1.402.012 1.397-1.116 1.756-3.12 1.858a23.85 23.85 0 0 1-1.38.026A8 8 0 0 1 0 8a8 8 0 0 1 8-8c4.417 0 7.998 3.582 7.998 7.977.06 2.621-1.312 3.586-4.48 3.648-.602.008-1.068.043-1.4.104.228.192.598.47 1.043.727zm-3.287-.943c-.019-1.495 1.228-1.856 3.611-1.888C13.67 9.582 14.028 9.33 13.998 8A6 6 0 1 0 8 14c.603 0 .91-.004 1.277-.023a9.7 9.7 0 0 0 .478-.035c-1.172-.738-1.868-1.47-1.88-2.43zM6 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-2-3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM4 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="applications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 1v2h2V1H7zm0 5h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm0 1v2h2V7h-2zM1 12h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm0 1v2h2v-2H1zm6-1h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm6 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="approval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.536 10.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 1 1 9.12 9.243l1.415 1.414zM7.632 8.109A2 2 0 0 0 7 11.364l2.121 2.121a1.996 1.996 0 0 0 2.807.021C11.686 14.554 10.627 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.6 0 1.142.038 1.632.109zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="arrow-down" xmlns="http://www.w3.org/2000/svg"><path d="M10.472 7.282a.862.862 0 0 1 1.26-.006c.357.364.357.958 0 1.285L8.627 11.73A.886.886 0 0 1 8 12a.849.849 0 0 1-.627-.27L4.275 8.561a.904.904 0 0 1-.013-1.285.861.861 0 0 1 1.26-.007l2.486 2.527z"/></symbol><symbol viewBox="0 0 16 16" id="arrow-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 6H2a2 2 0 1 0 0 4h7v2.586a1 1 0 0 0 1.707.707l4.586-4.586a1 1 0 0 0 0-1.414l-4.586-4.586A1 1 0 0 0 9 3.414V6z"/></symbol><symbol viewBox="0 0 16 16" id="assignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 5V4a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V7h-1a1 1 0 0 1 0-2h1zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="blame" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 4h3a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm9 3h3a1 1 0 0 1 0 2h-3a1 1 0 0 1 0-2zm-9 3h3a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2zm9 0h3a1 1 0 0 1 0 2h-3a1 1 0 0 1 0-2zm0-6h3a1 1 0 0 1 0 2h-3a1 1 0 0 1 0-2zM2 7h3a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm6-6a1 1 0 0 1 1 1v12a1 1 0 0 1-2 0V2a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="bold" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4 12.5v-9A1.5 1.5 0 0 1 5.5 2h2.104c2.182 0 3.879.681 3.879 2.982 0 1.067-.517 2.227-1.374 2.595v.073C11.176 7.963 12 8.865 12 10.466 12 12.914 10.19 14 7.911 14H5.5A1.5 1.5 0 0 1 4 12.5zm2.376-5.696H7.49c1.164 0 1.665-.552 1.665-1.417 0-.94-.534-1.289-1.649-1.289h-1.13v2.706zm0 5.098h1.341c1.293 0 1.956-.515 1.956-1.62 0-1.049-.647-1.472-1.956-1.472H6.376v3.092z"/></symbol><symbol viewBox="0 0 16 16" id="book" xmlns="http://www.w3.org/2000/svg"><path d="M7 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2v4.191a.5.5 0 0 1-.724.447l-1.052-.526a.5.5 0 0 0-.448 0l-1.052.526A.5.5 0 0 1 7 6.191V2zM5 0h6a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="bookmark" xmlns="http://www.w3.org/2000/svg"><path d="M6.746 10.505a2 2 0 0 1 2.508 0L11 11.911V3H5v8.91l1.746-1.405zM5 1h6a2 2 0 0 1 2 2v10.999a1 1 0 0 1-1.627.779L8 12.064l-3.373 2.714A1 1 0 0 1 3 13.998V3a2 2 0 0 1 2-2z"/></symbol><symbol viewBox="0 0 16 16" id="branch" xmlns="http://www.w3.org/2000/svg"><path d="M6 11.978v.29a2 2 0 1 1-2 0V3.732a2 2 0 1 1 2 0v3.849c.592-.491 1.31-.854 2.15-1.081 1.308-.353 1.875-.882 1.893-1.743a2 2 0 1 1 2.002-.051C12.053 6.54 10.857 7.84 8.67 8.43 7.056 8.867 6.195 9.98 6 11.978zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm6 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="bullhorn" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.143 10H7V4H3a3 3 0 1 0 0 6h.143l.734 5.141a1 1 0 0 0 .99.859h1.556a.5.5 0 0 0 .495-.57L6.143 10zM8 4c1.034.02 2.039-.274 3.014-.883.727-.455 1.836-1.334 3.328-2.637A1 1 0 0 1 16 1.233v10.764a1 1 0 0 1-1.595.803c-1.658-1.227-2.788-1.992-3.392-2.294-.781-.39-1.785-.559-3.013-.506V4z"/></symbol><symbol viewBox="0 0 16 16" id="calendar" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 2h2a2 2 0 0 1 2 2H0a2 2 0 0 1 2-2h2V1a1 1 0 1 1 2 0v1h4V1a1 1 0 1 1 2 0v1zM0 4h16v9a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4zm2 2.5V13a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6.5a.5.5 0 0 0-.5-.5h-11a.5.5 0 0 0-.5.5zM5 8h2a1 1 0 1 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="cancel" xmlns="http://www.w3.org/2000/svg"><path d="M3.11 4.523a6 6 0 0 0 8.367 8.367L3.109 4.524zM4.522 3.11l8.368 8.368A6 6 0 0 0 4.524 3.11zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 16 16" id="chart" xmlns="http://www.w3.org/2000/svg"><path d="M15 14a1 1 0 0 1 0 2H2a2 2 0 0 1-2-2V1a1 1 0 1 1 2 0v13h13zM3.142 8.735l2.502-2.561a.5.5 0 0 1 .714-.003L8 7.833l3.592-4.553a.5.5 0 0 1 .796.015l2.516 3.454a.5.5 0 0 1 .096.295V12.5a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5V9.085a.5.5 0 0 1 .142-.35z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.078 8.2l3.535-3.536a2 2 0 0 1 2.828 2.828l-4.949 4.95c-.39.39-.902.586-1.414.586a1.994 1.994 0 0 1-1.414-.586l-4.95-4.95a2 2 0 1 1 2.828-2.828l3.536 3.535z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.977 7.998l3.535-3.535a2 2 0 1 0-2.828-2.828l-4.95 4.949c-.39.39-.586.902-.586 1.414 0 .512.196 1.024.586 1.414l4.95 4.95a2 2 0 1 0 2.828-2.828L7.977 7.998z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.22 7.998L4.683 4.463a2 2 0 0 1 2.828-2.828l4.95 4.949c.39.39.586.902.586 1.414a1.99 1.99 0 0 1-.586 1.414l-4.95 4.95a2 2 0 0 1-2.828-2.828l3.535-3.536z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.778 8.957l3.535 3.535a2 2 0 1 0 2.828-2.828l-4.949-4.95a1.994 1.994 0 0 0-1.414-.586c-.512 0-1.024.196-1.414.586l-4.95 4.95a2 2 0 1 0 2.828 2.828l3.536-3.535z"/></symbol><symbol viewBox="0 0 16 16" id="clock" xmlns="http://www.w3.org/2000/svg"><path d="M9 7h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V5a1 1 0 1 1 2 0v2zm-1 9A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.414 8l4.95-4.95a1 1 0 0 0-1.414-1.414L8 6.586l-4.95-4.95A1 1 0 0 0 1.636 3.05L6.586 8l-4.95 4.95a1 1 0 1 0 1.414 1.414L8 9.414l4.95 4.95a1 1 0 1 0 1.414-1.414L9.414 8z"/></symbol><symbol viewBox="0 0 16 16" id="code" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M15.871 8.243a.997.997 0 0 0-.293-.707L12.75 4.707a1 1 0 0 0-1.414 1.414l2.12 2.122-2.12 2.121a1 1 0 0 0 1.414 1.414l2.828-2.828a.997.997 0 0 0 .293-.707zm-13.243 0L4.75 6.12a1 1 0 1 0-1.414-1.414L.507 7.536a.997.997 0 0 0 0 1.414l2.829 2.828a1 1 0 1 0 1.414-1.414L2.628 8.243zm6.407-4.107a1 1 0 0 1 .707 1.225L8.19 11.157a1 1 0 1 1-1.931-.518L7.81 4.843a1 1 0 0 1 1.224-.707z"/></symbol><symbol viewBox="0 0 9 13" id="collapse"><path d="M.084.25C.01.18-.015.12.008.071.031.024.093 0 .194 0h8.521c.1 0 .162.024.185.072.023.048-.002.107-.075.177l-4.11 3.935a.372.372 0 0 1-.11.072h-.301a.508.508 0 0 1-.11-.072L.084.249zM.377 6.88a.364.364 0 0 1-.26-.105.334.334 0 0 1-.11-.25v-.709c0-.096.036-.179.11-.249a.364.364 0 0 1 .26-.105h8.15c.101 0 .188.035.261.105.074.07.11.153.11.25v.709c0 .096-.036.179-.11.249a.364.364 0 0 1-.26.105H.377zM.084 12.132c-.074.07-.099.129-.076.177.023.048.085.072.186.072h8.521c.1 0 .162-.024.185-.072.023-.048-.002-.107-.075-.177l-4.11-3.935a.372.372 0 0 0-.11-.072h-.301a.508.508 0 0 0-.11.072l-4.11 3.935z"/></symbol><symbol viewBox="0 0 16 16" id="comment" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comment-dots" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586zM5 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="comment-next" xmlns="http://www.w3.org/2000/svg"><path d="M8 5V4a.5.5 0 0 1 .8-.4l2.667 2a.5.5 0 0 1 0 .8L8.8 8.4A.5.5 0 0 1 8 8V7H6a1 1 0 1 1 0-2h2zM1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comments" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.75 10L0 13V3a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H3.75zM13 5h1a2 2 0 0 1 2 2v8l-2.667-2H8a2 2 0 0 1-2-2h4a3 3 0 0 0 3-3V5z"/></symbol><symbol viewBox="0 0 16 16" id="commit" xmlns="http://www.w3.org/2000/svg"><path d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm3.876-1.008a4.002 4.002 0 0 1-7.752 0A1.01 1.01 0 0 1 4 9H1a1 1 0 1 1 0-2h3c.042 0 .083.003.124.008a4.002 4.002 0 0 1 7.752 0A1.01 1.01 0 0 1 12 7h3a1 1 0 0 1 0 2h-3a1.01 1.01 0 0 1-.124-.008z"/></symbol><symbol viewBox="0 0 16 16" id="compress" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.587 12.707l-1.414 1.415a1 1 0 0 1-1.414-1.415l1.414-1.414-1.386-1.386a.5.5 0 0 1 .299-.85l4.708-.523a.5.5 0 0 1 .553.552l-.524 4.709a.5.5 0 0 1-.85.298l-1.386-1.386zm6.859-9.687l1.414-1.414a1 1 0 0 1 1.414 1.414L12.86 4.434l1.386 1.386a.5.5 0 0 1-.299.85l-4.708.524a.5.5 0 0 1-.553-.552l.524-4.71a.5.5 0 0 1 .85-.297l1.386 1.385z"/></symbol><symbol viewBox="0 0 16 16" id="credit-card" xmlns="http://www.w3.org/2000/svg"><path d="M14 5a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1h12zm0 3H2v3a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V8zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm6.5 8h3a.5.5 0 1 1 0 1h-3a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="cut" xmlns="http://www.w3.org/2000/svg"><rect width="16" height="2" y="7" fill-rule="evenodd" rx="1"/></symbol><symbol viewBox="0 0 16 16" id="dashboard" xmlns="http://www.w3.org/2000/svg"><path d="M7.709 10.021l.696-2.6a.5.5 0 0 1 .966.26l-.657 2.45A2 2 0 0 1 10 12H6a2 2 0 0 1 1.709-1.979zM0 8.9a8 8 0 0 1 15.998 0H16v3.6a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5V8.9zM14 9A6 6 0 1 0 2 9v3.5a.5.5 0 0 0 .5.5h11a.5.5 0 0 0 .5-.5V9zM3.5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm9 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-7-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm5 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1z"/></symbol><symbol viewBox="0 0 16 16" id="disk" xmlns="http://www.w3.org/2000/svg"><path d="M16 11.764V3a3 3 0 0 0-3-3H3a3 3 0 0 0-3 3v8.764A2.989 2.989 0 0 1 2 11V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v8c.768 0 1.47.289 2 .764zM2 12h12a2 2 0 1 1 0 4H2a2 2 0 1 1 0-4zm10 1a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="doc_code" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zm1.036 7.607a.498.498 0 0 1-.147.354l-1.414 1.414a.5.5 0 0 1-.707-.707l1.06-1.06-1.06-1.061a.5.5 0 0 1 .707-.707l1.414 1.414a.498.498 0 0 1 .147.353zm-4.822 0l1.06 1.061a.5.5 0 0 1-.706.707l-1.414-1.414a.498.498 0 0 1 0-.707l1.414-1.414a.5.5 0 1 1 .707.707l-1.06 1.06zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="doc_image" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM7.333 9.667l1.313-1.313a.5.5 0 0 1 .708 0L12 11H4l2.188-1.75a.5.5 0 0 1 .624 0l.521.417zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 8a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM4 11h8v.7a.3.3 0 0 1-.3.3H4.3a.3.3 0 0 1-.3-.3V11z"/></symbol><symbol viewBox="0 0 16 16" id="doc_text" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 11h5a.5.5 0 1 1 0 1h-5a.5.5 0 1 1 0-1zm0-2h5a.5.5 0 1 1 0 1h-5a.5.5 0 0 1 0-1zm0-2h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1z"/></symbol><symbol viewBox="0 0 105 26" id="double-headed-arrow" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.018 11.089L15.138.614c1.23-.911 3.086-.795 4.147.26.461.46.715 1.045.715 1.651v20.95C20 24.869 18.684 26 17.06 26a3.238 3.238 0 0 1-1.921-.614L1.019 14.911C-.212 14-.347 12.405.714 11.35c.094-.094.195-.18.303-.261zm102.964 0c.108.08.21.167.303.26 1.061 1.056.925 2.65-.303 3.562l-14.12 10.475A3.238 3.238 0 0 1 87.94 26C86.316 26 85 24.87 85 23.475V2.525c0-.606.254-1.192.715-1.65 1.061-1.056 2.917-1.172 4.146-.26l14.12 10.474zM35 17a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="download" xmlns="http://www.w3.org/2000/svg"><path d="M9 12h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0l-2-2.667A.5.5 0 0 1 6 12h1V8a1 1 0 1 1 2 0v4zM4 9a1 1 0 1 1 0 2 4 4 0 0 1-1.971-7.481 4 4 0 0 1 6.633-2.505 3.999 3.999 0 0 1 3.82 2.014A4 4 0 0 1 12 11a1 1 0 0 1 0-2 2 2 0 1 0 0-4h-1a2 2 0 0 0-3.112-1.662A2 2 0 1 0 4.268 5H4a2 2 0 1 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M14 10h-3a1 1 0 0 1-1-1V6H8.527A.527.527 0 0 0 8 6.527V13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-3zm-4-7H8.527c-.18 0-.355.013-.527.04V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2v2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3zM8.527 4h2.323a.5.5 0 0 1 .35.143l4.65 4.551a.5.5 0 0 1 .15.357V13a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V6.527A2.527 2.527 0 0 1 8.527 4z"/></symbol><symbol viewBox="0 0 16 16" id="earth" xmlns="http://www.w3.org/2000/svg"><path d="M8.7 2.04l-.082.177c.283.223.422.413.417.571-.008.237-.311.057-.444.274-.133.218.038.542-.112.637-.15.096-.398-.386-.479-.46-.054-.049-.166-.257-.336-.625l-.216-.225a.844.844 0 0 0-.418-.035c-.177.038-.075.1-.035.132.04.032.32.037.452.2.132.164.03.224-.05.298-.054.05-.157.062-.31.035H5.952l-.402.398.03.325.229.455.324-.463c.008-.206.058-.342.15-.41.14-.1.342-.15.534-.085.191.066-.057.218.011.271.068.053.204-.098.313-.02.11.08.07.155.104.322.036.167.254.114.398.328.144.215.19.29.147.483-.043.195-.168.26-.305.232-.138-.028-.107-.246-.275-.348-.168-.102-.266-.114-.386-.054-.12.06-.016.129.023.235.04.106.274.321.224.43-.05.107-.108.116-.42 0-.21-.077-.414-.007-.615.212l-.76.722c-.153.715-.3 1.13-.44 1.243-.211.17-.177-.483-.483-.656-.306-.174-.494-.047-.8-.07-.307-.023-.42.65-.38.873a.434.434 0 0 0 .221.321c.236-.141.39-.184.465-.128.11.084-.144.267-.074.425.07.158.314.069.386.283.073.213.084.48-.05.706-.135.227-.275.178-.4.053-.127-.126-.033-.375-.255-.704-.223-.329-.381-.337-.63-.787-.158-.287-.35-.743-.575-1.366a6 6 0 0 0 3.21 7.198l.001-.075c0-.577-.004-.944-.012-1.102-.011-.236-.95-.945-1.104-1.2-.154-.256-.34-.595-.355-.746-.016-.151.185-.232.344-.325.16-.093-.11-.367.028-.626.137-.258.395-.438.496-.356.101.081.058.228.267.333.209.104.077-.213.456-.178.38.035.143.201.252.216.11.016.113-.127.299-.143.186-.015.282.445.471.622.19.178.452.008.611.043.159.034.267.09.402.255.136.166-.03.352.073.557.103.205 1.07.22 1.433.255.364.034.371.011.371.324s-.166.314-.453.507c-.286.193-.166.462-.38.762-.212.3-.316.062-.622.14-.306.077-.413.382-.452.568-.039.186-.386.094-.877.232-.29.082-.429.144-.569.204a6.002 6.002 0 0 0 7.682-4.3c-.094-.384-.18-.63-.258-.74-.213-.297-.36.21-.924.49-.564.278-.57-.288-.81-.49-.16-.133-.212-.44-.158-.92-.005-.478.02-.828.077-1.049.057-.221.126-.543.207-.965.351-.373.606-.572.764-.595.237-.034.336.374.658.3a.315.315 0 0 0 .035-.01 5.993 5.993 0 0 0-.475-.824l-.309-.043a.646.646 0 0 0-.332-.117c-.205-.02-.025.128-.089.24-.064.112-.235.724-.437.685-.201-.039-.204-.374-.17-.668.036-.294-.077-.35-.2-.412-.124-.062-.325-.213-.556-.295-.232-.082-.123-.175-.093-.274.03-.1.208-.015.193-.058-.014-.044-.313-.135-.266-.167.03-.02.2-.02.506.003l.216-.012.293-.163a.58.58 0 0 0-.376-.22c-.233-.036-.513-.034-.73-.142-.205-.103-.458-.36-.643-.638A5.965 5.965 0 0 0 8.7 2.04zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 1600 1600" id="ellipsis_v" xmlns="http://www.w3.org/2000/svg"><path d="M1088 1248v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h192q40 0 68 28t28 68zm0-512v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68V736q0-40 28-68t68-28h192q40 0 68 28t28 68zm0-512v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68V224q0-40 28-68t68-28h192q40 0 68 28t28 68z"/></symbol><symbol viewBox="0 0 18 18" id="emoji_slightly_smiling_face" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369.721.721 0 0 1 .568.047.715.715 0 0 1 .37.445 2.91 2.91 0 0 0 1.084 1.518A2.93 2.93 0 0 0 9 12.75a2.93 2.93 0 0 0 1.775-.58 2.913 2.913 0 0 0 1.084-1.518.711.711 0 0 1 .375-.445.737.737 0 0 1 .575-.047c.195.063.34.186.433.37.094.183.11.372.047.568zM7.5 6c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 6 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 6 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 12 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 12 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 18 18" id="emoji_smile" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568zM14 6.37c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm-6.5 0c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm9 2.63a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 18 18" id="emoji_smiley" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568h.001zM7.5 6c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 6 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 6 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 12 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 12 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6c.92.397 1.91.6 2.912.598a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39c.397-.92.6-1.91.598-2.912zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z"/></symbol><symbol viewBox="0 0 16 16" id="epic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.985 8.044l-.757 2.272a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l.318-.637A2 2 0 0 0 1.618 9h11.661a2 2 0 0 0 1.706-.956zm0 3l-.757 2.272a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l.318-.637a2 2 0 0 0 .576.084h11.661a2 2 0 0 0 1.706-.956zM3.618 2h10.995a1 1 0 0 1 .948 1.316l-1.333 4a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l2-4A1 1 0 0 1 3.618 2zm-.382 4h9.322l.667-2H4.236l-1 2z"/></symbol><symbol viewBox="0 0 16 16" id="error" xmlns="http://www.w3.org/2000/svg"><title>error</title><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0-2A5 5 0 1 0 8 3a5 5 0 0 0 0 10zm0-9a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="expand" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.435 10.092l1.414-1.414a1 1 0 1 1 1.414 1.414L5.85 11.507l1.386 1.385a.5.5 0 0 1-.299.85l-4.709.524a.5.5 0 0 1-.552-.552L2.2 9.005a.5.5 0 0 1 .85-.298l1.386 1.385zm7.283-4.455l-1.414 1.415A1 1 0 1 1 8.89 5.637l1.414-1.414-1.386-1.386a.5.5 0 0 1 .299-.85l4.708-.523a.5.5 0 0 1 .553.552l-.524 4.709a.5.5 0 0 1-.85.298l-1.386-1.386z"/></symbol><symbol viewBox="0 0 16 16" id="external-link" xmlns="http://www.w3.org/2000/svg"><path d="M13.121 4.177l-4.95 4.95a1 1 0 1 1-1.414-1.414l4.95-4.95-1.386-1.386a.5.5 0 0 1 .299-.85l4.709-.524a.5.5 0 0 1 .552.552l-.523 4.71a.5.5 0 0 1-.851.297l-1.386-1.385zM12 8.884a1 1 0 0 1 2 0v4a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3v-8a3 3 0 0 1 3-3h4a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-4z"/></symbol><symbol viewBox="0 0 16 16" id="eye" xmlns="http://www.w3.org/2000/svg"><path d="M8 14C4.816 14 2.253 12.284.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2s5.747 1.716 7.607 5.019a2 2 0 0 1 0 1.962C13.747 12.284 11.184 14 8 14zm0-2c2.41 0 4.338-1.29 5.864-4C12.338 5.29 10.411 4 8 4 5.59 4 3.662 5.29 2.136 8 3.662 10.71 5.589 12 8 12zm0-1a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm1-3a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="eye-slash" xmlns="http://www.w3.org/2000/svg"><path d="M13.618 2.62L1.62 14.619a1 1 0 0 1-.985-1.668l1.525-1.526C1.516 10.742.926 9.927.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2c1.074 0 2.076.195 3.006.58l.944-.944a1 1 0 0 1 1.668.985zM8.068 11a3 3 0 0 0 2.931-2.932l-2.931 2.931zm-3.02-2.462a3 3 0 0 1 3.49-3.49l.884-.884A6.044 6.044 0 0 0 8 4C5.59 4 3.662 5.29 2.136 8c.445.79.924 1.46 1.439 2.011l1.473-1.473zm.421 5.06l1.658-1.658c.283.04.575.06.873.06 2.41 0 4.338-1.29 5.864-4a11.023 11.023 0 0 0-1.133-1.664l1.418-1.418a12.799 12.799 0 0 1 1.458 2.1 2 2 0 0 1 0 1.963C13.747 12.284 11.184 14 8 14a7.883 7.883 0 0 1-2.53-.402z"/></symbol><symbol viewBox="0 0 16 16" id="file-addition" xmlns="http://www.w3.org/2000/svg"><path d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3z"/></symbol><symbol viewBox="0 0 16 16" id="file-deletion" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm2 6h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="file-modified" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm5 4a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"/></symbol><symbol viewBox="0 0 16 16" id="filter" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 6v9l-3.724-1.862A.5.5 0 0 1 6 12.691V6L1.854 1.854A.5.5 0 0 1 2.207 1h11.586a.5.5 0 0 1 .353.854L10 6z"/></symbol><symbol viewBox="0 0 16 16" id="folder" xmlns="http://www.w3.org/2000/svg"><path d="M13 3a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.81a3 3 0 0 1 2.827 1.995L13 3z"/></symbol><symbol viewBox="0 0 16 16" id="folder-o" xmlns="http://www.w3.org/2000/svg"><path d="M13 5l-4.365-.005a2 2 0 0 1-1.882-1.33A1 1 0 0 0 5.81 3H2v9a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1zm0-2a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.81a3 3 0 0 1 2.827 1.995L13 3z"/></symbol><symbol viewBox="0 0 16 16" id="folder-open" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.59 5.464a2.998 2.998 0 0 1 1.096 3.845l-1.666 3.436A4 4 0 0 1 10.46 15H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.558a2 2 0 0 1 1.898 1.368l.21.632h4.973a2 2 0 0 1 2 2 2 2 0 0 1-.027.329l-.023.135zM5.285 7a1 1 0 0 0-.9.564l-1.939 4a1 1 0 0 0 .9 1.436h7.074a2 2 0 0 0 1.8-1.128l1.665-3.436a1 1 0 0 0-.9-1.436h-7.7z"/></symbol><symbol viewBox="0 0 16 16" id="fork" xmlns="http://www.w3.org/2000/svg"><path d="M9 12.268a2 2 0 1 1-2 0V8.874A4.002 4.002 0 0 1 4 5V3.732a2 2 0 1 1 2 0V5a2 2 0 1 0 4 0V3.732a2 2 0 1 1 2 0V5a4.002 4.002 0 0 1-3 3.874v3.394zM11 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm3 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="geo-nodes" xmlns="http://www.w3.org/2000/svg"><path d="M9.7 13.1l-.2.2c-.7.8-2 .9-2.8.1-.1 0-.1-.1-.1-.1l-.2-.2c-2 .2-3.4.7-3.4 1.4 0 .8 2.2 1.5 5 1.5s5-.7 5-1.5c0-.7-1.4-1.2-3.3-1.4M7.3 12.7c.4.4 1 .3 1.4-.1C11.6 9.5 13 7 13 5.3 13 2.4 10.8 0 8 0S3 2.4 3 5.3C3 7 4.4 9.5 7.3 12.7M8 2c1.6 0 3 1.4 3 3.3 0 1-1 2.8-3 5.2-2-2.4-3-4.2-3-5.2C5 3.4 6.4 2 8 2"/><circle cx="8" cy="5" r="1"/></symbol><symbol viewBox="0 0 16 16" id="git-merge" xmlns="http://www.w3.org/2000/svg"><path d="M11 12.268V5a1 1 0 0 0-1-1v1a.5.5 0 0 1-.8.4l-2.667-2a.5.5 0 0 1 0-.8L9.2.6a.5.5 0 0 1 .8.4v1a3 3 0 0 1 3 3v7.268a2 2 0 1 1-2 0zm-6 0a2 2 0 1 1-2 0V4.732a2 2 0 1 1 2 0v7.536zM4 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm8 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="go-back" xmlns="http://www.w3.org/2000/svg"><path d="M4.9 7V6a.5.5 0 0 0-.8-.4l-2.667 2a.5.5 0 0 0 0 .8l2.667 2a.5.5 0 0 0 .8-.4V9h4a1 1 0 1 0 0-2h-4zM7 12a1 1 0 0 0-2 0 3 3 0 0 0 3 3h3a4 4 0 0 0 4-4V5a4 4 0 0 0-4-4H8a3 3 0 0 0-3 3 1 1 0 1 0 2 0 1 1 0 0 1 1-1h3a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H8a1 1 0 0 1-1-1z"/></symbol><symbol viewBox="0 0 16 16" id="group" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.048 11.997C-.377 11.975.013 11.782.013 10.56.013 9.235.653 8 4 8c.444 0 .84.022 1.194.062.164.435.426.82.76 1.132-1.786.389-2.721 1.353-2.906 2.803zm2.94-7.222a2.993 2.993 0 0 0-.976 1.95 2 2 0 1 1 .975-1.95zm6.964 7.222c-.185-1.45-1.12-2.414-2.906-2.803.334-.311.596-.697.76-1.132C11.16 8.022 11.556 8 12 8c3.346 0 3.987 1.235 3.987 2.56 0 1.222.39 1.415-3.035 1.437zm-1.964-5.272a2.993 2.993 0 0 0-.976-1.95 2 2 0 1 1 .976 1.95zM8 9a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 5c-2.177 0-3.987-.115-3.987-1.44S4.653 10 8 10c3.346 0 3.987 1.235 3.987 2.56S10.177 14 8 14z"/></symbol><symbol viewBox="0 0 16 16" id="history" xmlns="http://www.w3.org/2000/svg"><path d="M2.868 3.24a7 7 0 1 1-.043 9.475 1 1 0 0 1 1.478-1.348 5 5 0 1 0 .124-6.865l.796.645a.5.5 0 0 1-.193.873l-3.232.814a.5.5 0 0 1-.622-.504L1.3 3a.5.5 0 0 1 .814-.37l.754.61zM9 8h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V6a1 1 0 1 1 2 0v2z"/></symbol><symbol viewBox="0 0 16 16" id="home" xmlns="http://www.w3.org/2000/svg"><path d="M9 13h3v-3H4v3h3v-1a1 1 0 0 1 2 0v1zm5-3v3.659c0 .729-.657 1.341-1.5 1.341h-9c-.843 0-1.5-.612-1.5-1.341V10h-.88C.502 10 0 9.486 0 8.853c0-.307.12-.601.333-.816l6.405-6.463a1.56 1.56 0 0 1 2.374-.052L15.66 8.03c.444.441.455 1.167.024 1.622a1.108 1.108 0 0 1-.804.348H14zM7.95 3.273l-4.595 4.64h9.264l-4.67-4.64z"/></symbol><symbol viewBox="0 0 16 16" id="hook" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1h4zm0 1H6v1a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V4zM7 8a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h2a3 3 0 0 1 3 3v2a3 3 0 0 1-3 3v4a2 2 0 1 0 4 0h-.44a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H15a4 4 0 0 1-7 2.646A4 4 0 0 1 1 12H.56a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H3a2 2 0 1 0 4 0V8z"/></symbol><symbol viewBox="0 0 16 16" id="hourglass" xmlns="http://www.w3.org/2000/svg"><path d="M10.331 4.889A2.988 2.988 0 0 0 11 3V2H5v1c0 .362.064.709.182 1.03l5.15.859zM3 14v-1c0-1.78.93-3.342 2.33-4.228.447-.327.67-.582.67-.764 0-.19-.242-.46-.725-.815A4.996 4.996 0 0 1 3 3V2H2a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2h-1v1a4.997 4.997 0 0 1-2.39 4.266c-.407.3-.61.545-.61.734 0 .19.203.434.61.734A4.997 4.997 0 0 1 13 13v1h1a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2h1zm8 0v-1a3 3 0 0 0-6 0v1h6z"/></symbol><symbol viewBox="0 0 38 38" id="image-comment-dark" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="19" cy="19" r="18" fill="#1F78D1"/><path fill="#FFF" fill-rule="nonzero" d="M19 38C8.507 38 0 29.493 0 19S8.507 0 19 0s19 8.507 19 19-8.507 19-19 19zm0-2c9.389 0 17-7.611 17-17S28.389 2 19 2 2 9.611 2 19s7.611 17 17 17zm-6.293-8.293c-.63.63-1.707.184-1.707-.707V15a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3h-7.586l-3.707 3.707zM13 24.586l2.293-2.293A1 1 0 0 1 16 22h8a1 1 0 0 0 1-1v-6a1 1 0 0 0-1-1H14a1 1 0 0 0-1 1v9.586z"/></g></symbol><symbol viewBox="0 0 38 38" id="image-comment-light" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="19" cy="19" r="18" fill="#FFF"/><path fill="#1F78D1" fill-rule="nonzero" d="M19 38C8.507 38 0 29.493 0 19S8.507 0 19 0s19 8.507 19 19-8.507 19-19 19zm0-2c9.389 0 17-7.611 17-17S28.389 2 19 2 2 9.611 2 19s7.611 17 17 17zm-6.293-8.293c-.63.63-1.707.184-1.707-.707V15a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3h-7.586l-3.707 3.707zM13 24.586l2.293-2.293A1 1 0 0 1 16 22h8a1 1 0 0 0 1-1v-6a1 1 0 0 0-1-1H14a1 1 0 0 0-1 1v9.586z"/></g></symbol><symbol viewBox="0 0 16 16" id="import" xmlns="http://www.w3.org/2000/svg"><path d="M9 8h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0L5.6 8.8A.5.5 0 0 1 6 8h1V1a1 1 0 1 1 2 0v7zM0 8a1 1 0 1 1 2 0 6 6 0 1 0 12 0 1 1 0 0 1 2 0A8 8 0 1 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-block" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.803 8a5.97 5.97 0 0 0-.462 1H4.5a.5.5 0 0 1 0-1h1.303zM4.5 5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1 0-1zm7.5.083a6.04 6.04 0 0 0-2 0V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h2.083a5.96 5.96 0 0 0 .72 2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h6a3 3 0 0 1 3 3v2.083zm1.121 3.796zM11 16a5 5 0 1 1 0-10 5 5 0 0 1 0 10zm-1.293-2.292a3 3 0 0 0 4.001-4.001l-4.001 4zm-1.415-1.415l4.001-4a3 3 0 0 0-4.001 4.001z"/></symbol><symbol viewBox="0 0 16 16" id="issue-child" xmlns="http://www.w3.org/2000/svg"><path d="M11 8H5v1h1a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h2V7a.997.997 0 0 1 1-1h3V4H4.5a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9v2h3a.997.997 0 0 1 1 1v2h2a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h1V8zm-9 3v2h3v-2H2zm9 0v2h3v-2h-3z"/></symbol><symbol viewBox="0 0 16 16" id="issue-close" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M10.874 2H12a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-2c-.918 0-1.74-.413-2.29-1.063a3.987 3.987 0 0 0 1.988-.984A1 1 0 0 0 10 14h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-1V3c0-.345-.044-.68-.126-1zM4 0h3a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-external" xmlns="http://www.w3.org/2000/svg"><path d="M11 4a5.99 5.99 0 0 0-2 .341V3a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h2.528a6.003 6.003 0 0 0 2.705 1.736A2.99 2.99 0 0 1 8 16H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3v1zM8.212 8.97l-.568-.876A.25.25 0 0 1 7.66 7.8l.404-.5a.25.25 0 0 1 .284-.076l.938.36c.256-.182.543-.325.85-.42l.323-.988a.25.25 0 0 1 .237-.173h.643a.25.25 0 0 1 .238.173l.321.989c.308.094.595.237.852.418l.937-.359a.25.25 0 0 1 .284.076l.404.5a.25.25 0 0 1 .016.293l-.568.875c.113.297.18.616.192.95l.9.54a.25.25 0 0 1 .114.27l-.145.627a.25.25 0 0 1-.221.192l-1.115.098a3.015 3.015 0 0 1-.512.608l.165 1.18a.25.25 0 0 1-.138.259l-.577.282a.25.25 0 0 1-.29-.051l-.874-.905a3.035 3.035 0 0 1-.608 0l-.875.905a.25.25 0 0 1-.29.05l-.577-.281a.25.25 0 0 1-.138-.26L9 12.254a3.015 3.015 0 0 1-.512-.607l-1.114-.098a.25.25 0 0 1-.222-.192l-.145-.627a.25.25 0 0 1 .115-.27l.899-.54c.012-.334.08-.653.192-.95zm2.806 2.034a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="issue-new" xmlns="http://www.w3.org/2000/svg"><path d="M10 2V1a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V4H9a1 1 0 1 1 0-2h1zm0 6a1 1 0 0 1 2 0v5a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h1a1 1 0 1 1 0 2H5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm0-2a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open-m" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-parent" xmlns="http://www.w3.org/2000/svg"><path d="M11 11H5v1h1.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H3v-2a.997.997 0 0 1 1-1h3V7H5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H9v2h3a.997.997 0 0 1 1 1v2h2.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H11v-1zM6 3v2h4V3H6z"/></symbol><symbol viewBox="0 0 16 16" id="issues" xmlns="http://www.w3.org/2000/svg"><path d="M10.458 15.012l.311.055a3 3 0 0 0 3.476-2.433l1.389-7.879A3 3 0 0 0 13.2 1.28L11.23.933a3.002 3.002 0 0 0-.824-.031c.364.59.58 1.28.593 2.02l1.854.328a1 1 0 0 1 .811 1.158l-1.389 7.879a1 1 0 0 1-1.158.81l-.118-.02a3.98 3.98 0 0 1-.541 1.935zM3 0h4a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="italic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.5 12l2-8H6a1 1 0 1 1 0-2h6a1 1 0 0 1 0 2h-1.5l-2 8H10a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2h1.5z"/></symbol><symbol viewBox="0 0 16 16" id="key" xmlns="http://www.w3.org/2000/svg"><path d="M7.575 6.689a4.002 4.002 0 0 1 6.274-4.86 4 4 0 0 1-4.86 6.274l-2.21 2.21.706.708a1 1 0 1 1-1.414 1.414l-.707-.707-.707.707.707.707a1 1 0 1 1-1.414 1.414l-.707-.707a1 1 0 0 1-1.414-1.414l5.746-5.746zm2.032-.618a2 2 0 1 0 2.828-2.828A2 2 0 0 0 9.607 6.07z"/></symbol><symbol viewBox="0 0 16 16" id="key-2" xmlns="http://www.w3.org/2000/svg"><path d="M5.172 14.157l-.344.344-2.485.133a.462.462 0 0 1-.497-.503l.14-2.24a.599.599 0 0 1 .177-.382l5.155-5.155a4 4 0 1 1 2.828 2.828l-1.439 1.44-1.06-.354-.708.707.354 1.06-.707.708-1.06-.354-.708.707.354 1.06zm6.01-8.839a1 1 0 1 0 1.414-1.414 1 1 0 0 0-1.414 1.414z"/></symbol><symbol viewBox="0 0 16 16" id="label" xmlns="http://www.w3.org/2000/svg"><path d="M11.782 14.718a3 3 0 0 1-4.242 0L1.652 8.829a2 2 0 0 1-.565-1.702l.54-3.703a2 2 0 0 1 1.69-1.69l3.703-.54a2 2 0 0 1 1.703.564l5.888 5.888a3 3 0 0 1 0 4.243l-2.829 2.829zm1.415-5.657L7.309 3.173l-3.703.54-.54 3.702 5.888 5.888a1 1 0 0 0 1.414 0l2.829-2.828a1 1 0 0 0 0-1.414zM5.732 5.525A1 1 0 1 1 7.146 6.94a1 1 0 0 1-1.414-1.414z"/></symbol><symbol viewBox="0 0 16 16" id="labels" xmlns="http://www.w3.org/2000/svg"><path d="M9.424 2.254l2.08-.905a1 1 0 0 1 1.206.326l3.013 4.12a1 1 0 0 1 .16.849l-1.947 7.264a3 3 0 0 1-3.675 2.122l-.5-.135a3.999 3.999 0 0 0 1.082-1.782 1 1 0 0 0 1.16-.722l1.823-6.802-2.258-3.087-.687.299a2 2 0 0 0-.628-.88l-.829-.667zM.377 3.7L4.4.498a1 1 0 0 1 1.25.003L9.627 3.7a1 1 0 0 1 .373.78V13a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4.482A1 1 0 0 1 .377 3.7zM2 13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V4.958L5.02 2.561 2 4.964V13zm3-6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="leave" xmlns="http://www.w3.org/2000/svg"><path d="M11 7V5.883a.5.5 0 0 1 .757-.429l3.528 2.117a.5.5 0 0 1 0 .858l-3.528 2.117a.5.5 0 0 1-.757-.43V9H7a1 1 0 1 1 0-2h4zm-2 6.256a1 1 0 0 1 2 0A2.744 2.744 0 0 1 8.256 16H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h5.19A2.81 2.81 0 0 1 11 2.81a1 1 0 0 1-2 0A.81.81 0 0 0 8.19 2H3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h5.256c.41 0 .744-.333.744-.744z"/></symbol><symbol viewBox="0 0 16 16" id="level-up" xmlns="http://www.w3.org/2000/svg"><path fill="#2E2E2E" fill-rule="evenodd" d="M7 6h3.489a.5.5 0 0 0 .373-.832L6.374.117a.5.5 0 0 0-.748 0l-4.488 5.05A.5.5 0 0 0 1.51 6H5v7a3 3 0 0 0 3 3h6a1 1 0 0 0 0-2H8a1 1 0 0 1-1-1V6z"/></symbol><symbol viewBox="0 0 16 16" id="license" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12.56 8.9l2.66 4.606a.3.3 0 0 1-.243.45l-1.678.094a.1.1 0 0 0-.078.044l-.953 1.432a.3.3 0 0 1-.51-.016L9.097 10.9a5.994 5.994 0 0 0 3.464-2zm-5.23 2.063L4.707 15.51a.3.3 0 0 1-.51.016l-.953-1.432a.1.1 0 0 0-.078-.044l-1.678-.094a.3.3 0 0 1-.243-.45l2.48-4.297a5.983 5.983 0 0 0 3.607 1.754zM8 10A5 5 0 1 1 8 0a5 5 0 0 1 0 10zm0-2a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-1a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="link" xmlns="http://www.w3.org/2000/svg"><path d="M6.986 3.35l2.12-2.122a4 4 0 0 1 5.657 5.657l-2.828 2.829a4 4 0 0 1-5.657 0 1 1 0 0 1 1.414-1.415 2 2 0 0 0 2.829 0l2.828-2.828a2 2 0 1 0-2.828-2.828l-1.001 1a5.018 5.018 0 0 0-2.534-.294zm2.12 9.192l-2.12 2.121a4 4 0 1 1-5.658-5.656l2.829-2.829a4 4 0 0 1 5.657 0 1 1 0 1 1-1.415 1.414 2 2 0 0 0-2.828 0l-2.828 2.829a2 2 0 1 0 2.828 2.828l1.001-1.001a5.018 5.018 0 0 0 2.534.294z"/></symbol><symbol viewBox="0 0 16 16" id="list-bulleted" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-7h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm0 5h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm-4 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-2h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="list-numbered" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 2h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2zM1.156 5v-.828h.816V2.204h-.72v-.636c.432-.084.708-.192.996-.372h.756v2.976h.684V5H1.156zm-.18 5v-.588c.9-.828 1.596-1.464 1.596-1.98 0-.342-.192-.504-.468-.504-.252 0-.444.18-.624.36l-.552-.552c.396-.42.756-.612 1.32-.612.768 0 1.308.492 1.308 1.248 0 .612-.576 1.284-1.092 1.812.192-.024.468-.048.636-.048h.636V10H.976zm1.26 5.072c-.618 0-1.068-.204-1.356-.54l.468-.648c.234.216.51.36.78.36.336 0 .552-.12.552-.36 0-.288-.15-.456-.948-.456v-.72c.636 0 .828-.168.828-.432 0-.228-.138-.348-.396-.348-.252 0-.432.108-.672.312l-.516-.624c.372-.312.768-.492 1.236-.492.84 0 1.38.384 1.38 1.074 0 .366-.204.642-.612.822v.024c.432.132.732.432.732.912 0 .72-.684 1.116-1.476 1.116z"/></symbol><symbol viewBox="0 0 16 16" id="location" xmlns="http://www.w3.org/2000/svg"><path d="M8.755 15.144a1 1 0 0 1-1.51 0C3.748 11.114 2 8.065 2 6a6 6 0 1 1 12 0c0 2.065-1.748 5.113-5.245 9.144zM12 6a4 4 0 1 0-8 0c0 1.314 1.312 3.71 4 6.944C10.688 9.71 12 7.314 12 6zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="location-dot" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.314 13.087C4.382 13.295 3 13.85 3 14.5c0 .828 2.239 1.5 5 1.5s5-.672 5-1.5c0-.65-1.382-1.205-3.314-1.413l-.202.225a2 2 0 0 1-2.968 0l-.202-.225zm2.428-.445a1 1 0 0 1-1.484 0C4.419 9.5 3 7.037 3 5.252 3 2.353 5.239 0 8 0s5 2.352 5 5.253c0 1.784-1.42 4.247-4.258 7.389zM11 5.252C11 3.436 9.634 2 8 2S5 3.435 5 5.253c0 1.027.974 2.824 3 5.203 2.026-2.38 3-4.176 3-5.203zM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="lock" xmlns="http://www.w3.org/2000/svg"><path d="M10 5V4h2v1a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V8a3 3 0 0 1 3-3V4h2v1h4zM4 7a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1H4zm0-3a4 4 0 1 1 8 0h-2a2 2 0 1 0-4 0H4z"/></symbol><symbol viewBox="0 0 16 16" id="lock-open" xmlns="http://www.w3.org/2000/svg"><path d="M4.044 4a4 4 0 0 1 6.99-2.658 1 1 0 1 1-1.495 1.33A2 2 0 0 0 6.044 4a.998.998 0 0 1-.07.367v.701H12a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3v-5a3 3 0 0 1 2.974-3V4h.07zM4 7.07a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="log" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4zm1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-5h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm0 3h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm-3 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-2h3a1 1 0 0 1 0 2H8a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="mail" xmlns="http://www.w3.org/2000/svg"><path d="M14 5.6L9.338 9.796a2 2 0 0 1-2.676 0L2 5.6V11a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5.6zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm.212 2L8 8.31 12.788 4H3.212z"/></symbol><symbol viewBox="0 0 16 16" id="menu" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.143 2h13.714C15.488 2 16 2.448 16 3s-.512 1-1.143 1H1.143C.512 4 0 3.552 0 3s.512-1 1.143-1zm0 5h13.714C15.488 7 16 7.448 16 8s-.512 1-1.143 1H1.143C.512 9 0 8.552 0 8s.512-1 1.143-1zm0 5h13.714c.631 0 1.143.448 1.143 1s-.512 1-1.143 1H1.143C.512 14 0 13.552 0 13s.512-1 1.143-1z"/></symbol><symbol viewBox="0 0 16 16" id="merge-request-close" xmlns="http://www.w3.org/2000/svg"><path d="M9.414 8l1.414 1.414a1 1 0 1 1-1.414 1.414L8 9.414l-1.414 1.414a1 1 0 1 1-1.414-1.414L6.586 8 5.172 6.586a1 1 0 1 1 1.414-1.414L8 6.586l1.414-1.414a1 1 0 1 1 1.414 1.414L9.414 8zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="messages" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.588 8.942l1.173 5.862A1 1 0 0 1 8.78 16H7.22a1 1 0 0 1-.98-1.196l1.172-5.862a3.014 3.014 0 0 0 1.176 0zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4zM4.464 2.464L5.88 3.88a3 3 0 0 0 0 4.242L4.464 9.536a5 5 0 0 1 0-7.072zm7.072 7.072L10.12 8.12a3 3 0 0 0 0-4.242l1.415-1.415a5 5 0 0 1 0 7.072zM2.343.343l1.414 1.414a6 6 0 0 0 0 8.486l-1.414 1.414a8 8 0 0 1 0-11.314zm11.314 11.314l-1.414-1.414a6 6 0 0 0 0-8.486L13.657.343a8 8 0 0 1 0 11.314z"/></symbol><symbol viewBox="0 0 16 16" id="mobile-issue-close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.657 10.728L2.12 7.192A1 1 0 1 0 .707 8.607l4.243 4.242a.997.997 0 0 0 1.414 0l8.485-8.485a1 1 0 1 0-1.414-1.414l-7.778 7.778z"/></symbol><symbol viewBox="0 0 16 16" id="monitor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 13v1h3a1 1 0 0 1 0 2H3a1 1 0 0 1 0-2h3v-1H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3h-3zM3 2a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm5.723 6.416l-2.66-1.773-1.71 1.71a.5.5 0 1 1-.707-.707l2-2a.5.5 0 0 1 .631-.062l2.66 1.773 2.71-2.71a.5.5 0 0 1 .707.707l-3 3a.5.5 0 0 1-.631.062z"/></symbol><symbol viewBox="0 0 16 16" id="monitor-lines" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 12v1h3a1 1 0 0 1 0 2H3a1 1 0 0 1 0-2h3v-1H4a3 3 0 0 1-3-3V4a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3h-2zM4 3a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H4zm1.5 2h5a.5.5 0 1 1 0 1h-5a.5.5 0 0 1 0-1zm0 2h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="more" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 4a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="notifications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 14H2.435a2 2 0 0 1-1.761-2.947c.962-1.788 1.521-3.065 1.68-3.832.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024c3.755.528 4.375 4.27 4.761 6.043.188.86.742 2.188 1.661 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0zm5.805-6.468c-.325-1.492-.37-1.674-.61-2.288C10.6 3.716 9.742 3 8.07 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.208 1.012-.827 2.424-1.877 4.375H13.64c-.993-1.937-1.6-3.396-1.835-4.468z"/></symbol><symbol viewBox="0 0 16 16" id="notifications-off" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.26 5.089c.243.757.382 1.478.5 2.017.187.86.74 2.188 1.66 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0H4.35l2-2h7.29c-.993-1.937-1.6-3.396-1.835-4.468-.07-.326-.129-.59-.178-.81l1.634-1.633zM10.943 1.75l-1.48 1.48C9.07 3.076 8.612 3 8.069 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.065.317-.17.673-.317 1.073L.45 12.242a1.99 1.99 0 0 1 .224-1.19c.962-1.787 1.521-3.064 1.68-3.831.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024 4.867 4.867 0 0 1 1.944.688zm2.932-.105a1 1 0 0 1 0 1.415L2.561 14.374a1 1 0 1 1-1.415-1.414L12.46 1.646a1 1 0 0 1 1.414 0z"/></symbol><symbol viewBox="0 0 16 16" id="overview" xmlns="http://www.w3.org/2000/svg"><path d="M2 0h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2h-3zM2 9h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3h-3z"/></symbol><symbol viewBox="0 0 16 16" id="pencil" xmlns="http://www.w3.org/2000/svg"><path d="M13.02 1.293l1.414 1.414a1 1 0 0 1 0 1.414L4.119 14.436a1 1 0 0 1-.704.293l-2.407.008L1 12.316a1 1 0 0 1 .293-.71L11.605 1.292a1 1 0 0 1 1.414 0zm-1.416 1.415l-.707.707L12.31 4.83l.707-.707-1.414-1.415zM3.411 13.73l1.123-1.122H3.12v-1.415L2 12.312l.005 1.422 1.406-.005z"/></symbol><symbol viewBox="0 0 16 16" id="pencil-square" xmlns="http://www.w3.org/2000/svg"><path d="M12 9a1 1 0 0 1 2 0v4a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h4a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V9zm.778-7.179l1.414 1.415-6.476 6.476a1 1 0 0 1-.498.27l-1.51.325.323-1.512a1 1 0 0 1 .27-.497l6.477-6.477zM15.607.407a1 1 0 0 1 0 1.414l-.708.707-1.414-1.414.707-.707a1 1 0 0 1 1.415 0z"/></symbol><symbol viewBox="0 0 16 16" id="pipeline" xmlns="http://www.w3.org/2000/svg"><path d="M8.969 7.25a2 2 0 1 1-1.938 0A1.002 1.002 0 0 1 7 7V5.083a.2.2 0 0 1 .06-.142l.877-.87a.1.1 0 0 1 .141 0l.864.87A.2.2 0 0 1 9 5.083V7c0 .086-.01.17-.031.25zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm4.5-4a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zM8 10a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="play" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.765 15.835c-.545.321-1.258.159-1.593-.363A1.075 1.075 0 0 1 1 14.89V1.11C1 .496 1.518 0 2.158 0c.214 0 .424.057.607.165l11.684 6.89c.544.321.714 1.005.38 1.526a1.135 1.135 0 0 1-.38.364l-11.684 6.89z"/></symbol><symbol viewBox="0 0 16 16" id="plus" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7H2a1 1 0 1 0 0 2h5v5a1 1 0 0 0 2 0V9h5a1 1 0 0 0 0-2H9V2a1 1 0 1 0-2 0v5z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 7V4a1 1 0 1 0-2 0v3H4a1 1 0 1 0 0 2h3v3a1 1 0 0 0 2 0V9h3a1 1 0 0 0 0-2H9zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square-o" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="podcast" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.588 8.942l1.173 5.862a1 1 0 0 1-.785 1.177A1 1 0 0 1 8.78 16H7.22a1 1 0 0 1-1-1 1 1 0 0 1 .02-.196l1.172-5.862a3.014 3.014 0 0 0 1.176 0zM8 7.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM4.464 2.464A1 1 0 0 1 5.88 3.88a3 3 0 0 0 0 4.242 1 1 0 0 1-1.415 1.415 5 5 0 0 1 0-7.072zm7.072 7.072A1 1 0 0 1 10.12 8.12a3 3 0 0 0 0-4.242 1 1 0 0 1 1.415-1.415 5 5 0 0 1 0 7.072zM2.343.343a1 1 0 1 1 1.414 1.414 6 6 0 0 0 0 8.486 1 1 0 1 1-1.414 1.414 8 8 0 0 1 0-11.314zm11.314 11.314a1 1 0 1 1-1.414-1.414 6 6 0 0 0 0-8.486A1 1 0 0 1 13.657.343a8 8 0 0 1 0 11.314z"/></symbol><symbol viewBox="0 0 16 16" id="preferences" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5 12h10a1 1 0 0 1 0 2H5a1 1 0 0 1-2 0v-2a1 1 0 0 1 2 0zm-3 0H1a1 1 0 0 0 0 2h1v-2zm11-5h2a1 1 0 0 1 0 2h-2a1 1 0 0 1-2 0V7a1 1 0 0 1 2 0zm-3 0H1a1 1 0 1 0 0 2h9V7zM6 2h9a1 1 0 0 1 0 2H6a1 1 0 1 1-2 0V2a1 1 0 1 1 2 0zM3 2H1a1 1 0 1 0 0 2h2V2z"/></symbol><symbol viewBox="0 0 16 16" id="profile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-4.274-3.404C4.412 9.709 5.694 9 8 9c2.313 0 3.595.7 4.28 1.586A4.997 4.997 0 0 1 8 13a4.997 4.997 0 0 1-4.274-2.404zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="project" xmlns="http://www.w3.org/2000/svg"><path d="M8.462 2.177l-.038.044a.505.505 0 0 0 .038-.044zm-.787 0a.5.5 0 0 0 .038.043l-.038-.043zM3.706 7h8.725L8.069 2.585 3.706 7zM7 13.369V12a1 1 0 0 1 2 0v1.369h3V9H4v4.369h3zM14 9v4.836c0 .833-.657 1.533-1.5 1.533h-9c-.843 0-1.5-.7-1.5-1.533V9h-.448a1.1 1.1 0 0 1-.783-1.873L6.934.887a1.5 1.5 0 0 1 2.269 0l6.165 6.24A1.1 1.1 0 0 1 14.585 9H14z"/></symbol><symbol viewBox="0 0 16 16" id="push-rules" xmlns="http://www.w3.org/2000/svg"><path d="M6.268 9a2 2 0 0 1 3.464 0H11a1 1 0 0 1 0 2H9.732a2 2 0 0 1-3.464 0H5a1 1 0 0 1 0-2h1.268zM7 2H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1h-1v3.515a.3.3 0 0 1-.434.268l-1.432-.716a.3.3 0 0 0-.268 0l-1.432.716A.3.3 0 0 1 7 5.515V2zM4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm4 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="question" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm-1.46-5.602h2.233a3.97 3.97 0 0 1 .051-.558c.029-.17.073-.326.133-.469.06-.143.14-.28.242-.41.102-.13.228-.263.38-.399.26-.24.504-.467.733-.683a5.03 5.03 0 0 0 .598-.668c.17-.23.302-.477.399-.742a2.66 2.66 0 0 0 .144-.907c0-.505-.083-.95-.25-1.335a2.55 2.55 0 0 0-.723-.97 3.2 3.2 0 0 0-1.152-.589 5.441 5.441 0 0 0-1.531-.2c-.516 0-.998.063-1.445.188a3.19 3.19 0 0 0-1.168.59c-.331.268-.594.61-.79 1.027-.195.417-.295.917-.3 1.5h2.64c.006-.224.04-.416.102-.578.062-.161.142-.293.238-.394a.921.921 0 0 1 .332-.227 1.04 1.04 0 0 1 .39-.074c.34 0 .593.095.763.285.169.19.254.488.254.895 0 .328-.106.63-.317.906-.21.276-.499.565-.863.867-.214.182-.39.374-.531.574-.141.2-.253.42-.336.657a3.656 3.656 0 0 0-.176.777 7.89 7.89 0 0 0-.05.937zm-.321 2.375c0 .188.035.362.105.524.07.161.17.3.301.418.13.117.284.21.46.277.178.068.376.102.595.102.218 0 .416-.034.593-.102.178-.068.331-.16.461-.277a1.2 1.2 0 0 0 .301-.418c.07-.162.106-.336.106-.524a1.3 1.3 0 0 0-.106-.523 1.2 1.2 0 0 0-.3-.418 1.461 1.461 0 0 0-.462-.277 1.651 1.651 0 0 0-.593-.102c-.22 0-.417.034-.594.102a1.46 1.46 0 0 0-.461.277 1.2 1.2 0 0 0-.3.418 1.284 1.284 0 0 0-.106.523z"/></symbol><symbol viewBox="0 0 16 16" id="question-o" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-.778-4.151c0-.301.014-.575.044-.82a3.2 3.2 0 0 1 .154-.68c.073-.208.17-.4.294-.575.123-.176.278-.343.465-.503a4.81 4.81 0 0 0 .755-.758c.185-.242.277-.506.277-.793 0-.356-.074-.617-.222-.783-.148-.166-.37-.25-.667-.25a.92.92 0 0 0-.342.065.806.806 0 0 0-.29.199 1.04 1.04 0 0 0-.209.345 1.5 1.5 0 0 0-.088.506H5.082c.005-.51.092-.948.263-1.313.171-.364.401-.664.69-.899.29-.234.63-.406 1.023-.516a4.66 4.66 0 0 1 1.264-.164c.497 0 .944.058 1.34.174.397.117.733.289 1.008.517.276.227.487.51.633.847.146.337.218.727.218 1.17 0 .295-.042.56-.126.792a2.52 2.52 0 0 1-.349.65 4.4 4.4 0 0 1-.523.584c-.2.19-.414.389-.642.598a2.73 2.73 0 0 0-.332.349c-.089.114-.16.233-.212.359a1.868 1.868 0 0 0-.116.41 3.39 3.39 0 0 0-.044.489H7.222zm-.28 2.078c0-.164.03-.317.092-.458a1.05 1.05 0 0 1 .263-.366c.114-.103.248-.183.403-.243a1.45 1.45 0 0 1 .52-.089c.191 0 .364.03.52.09.154.059.289.14.403.242.114.103.201.224.263.366.061.141.092.294.092.458 0 .164-.03.316-.092.458a1.05 1.05 0 0 1-.263.365 1.278 1.278 0 0 1-.404.243 1.43 1.43 0 0 1-.52.089c-.19 0-.364-.03-.519-.089-.155-.06-.29-.14-.403-.243a1.05 1.05 0 0 1-.263-.365 1.135 1.135 0 0 1-.093-.458z"/></symbol><symbol viewBox="0 0 16 16" id="quote" xmlns="http://www.w3.org/2000/svg"><path d="M15 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9h-2a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1zM7 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9H3a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="redo" xmlns="http://www.w3.org/2000/svg"><path d="M4.625 4.423A4.897 4.897 0 0 1 8.079 3c2.73 0 4.944 2.239 4.944 5s-2.214 5-4.944 5c-1.41 0-2.723-.6-3.655-1.633a.98.98 0 0 0-1.397-.066 1.008 1.008 0 0 0-.064 1.413A6.87 6.87 0 0 0 8.079 15C11.9 15 15 11.866 15 8s-3.099-7-6.921-7A6.866 6.866 0 0 0 3.08 3.158L1.833 2.137a.49.49 0 0 0-.695.074.504.504 0 0 0-.11.311L1 7.26a.497.497 0 0 0 .6.492l4.576-1.013a.5.5 0 0 0 .206-.877L4.625 4.423z"/></symbol><symbol viewBox="0 0 16 16" id="remove" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2v10a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V3zm3-2a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1H5zM4 3v10a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3H4zm2.5 2a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm3 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 16 16" id="repeat" xmlns="http://www.w3.org/2000/svg"><path d="M11.375 4.423A4.897 4.897 0 0 0 7.921 3c-2.73 0-4.944 2.239-4.944 5s2.214 5 4.944 5c1.41 0 2.723-.6 3.655-1.633a.98.98 0 0 1 1.397-.066c.403.373.432 1.005.064 1.413A6.87 6.87 0 0 1 7.921 15C4.1 15 1 11.866 1 8s3.099-7 6.921-7c1.915 0 3.706.792 4.999 2.158l1.247-1.021a.49.49 0 0 1 .695.074c.07.088.11.198.11.311L15 7.26a.497.497 0 0 1-.6.492L9.824 6.739a.5.5 0 0 1-.206-.877l1.757-1.439z"/></symbol><symbol viewBox="0 0 16 16" id="retry" xmlns="http://www.w3.org/2000/svg"><path d="M4.114 6.958a4 4 0 0 0 5.283 4.775 1 1 0 1 1 .712 1.87A6 6 0 0 1 2.182 6.44l-.741-.2a.5.5 0 0 1-.12-.915l2.195-1.268a.5.5 0 0 1 .683.183l1.268 2.196a.5.5 0 0 1-.563.733l-.79-.212zm7.777 2.084a4 4 0 0 0-5.284-4.775 1 1 0 0 1-.712-1.87 6 6 0 0 1 7.927 7.162l.742.2a.5.5 0 0 1 .12.915l-2.196 1.268a.5.5 0 0 1-.683-.183l-1.267-2.196a.5.5 0 0 1 .562-.733l.79.212z"/></symbol><symbol viewBox="0 0 16 16" id="scale" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.99 9a.792.792 0 0 0-.078-.231L13 7l-.912 1.769a.791.791 0 0 0-.077.231h1.978zm-10 0a.792.792 0 0 0-.078-.231L3 7l-.912 1.769A.791.791 0 0 0 2.011 9h1.978zM2 0h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm3 14h6a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zM8 4a1 1 0 0 1 1 1v9H7V5a1 1 0 0 1 1-1zm-4.53-.714l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 3 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158L2.53 3.286a.53.53 0 0 1 .94 0zm10 0l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 13 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158l2.266-4.735a.53.53 0 0 1 .94 0z"/></symbol><symbol viewBox="0 0 16 16" id="screen-full" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14 14v-2a1 1 0 0 1 2 0v3a.997.997 0 0 1-1 1h-3a1 1 0 0 1 0-2h2zM2 14v-2a1 1 0 0 0-2 0v3a1 1 0 0 0 1 1h3a1 1 0 0 0 0-2H2zM15.707.293A.997.997 0 0 1 16 1v3a1 1 0 0 1-2 0V2h-2a1 1 0 0 1 0-2h3c.276 0 .526.112.707.293zM2 2v2a1 1 0 1 1-2 0V1a.997.997 0 0 1 1-1h3a1 1 0 1 1 0 2H2zm4 4h4a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="screen-normal" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 3V1a1 1 0 1 1 2 0v3a.997.997 0 0 1-1 1H1a1 1 0 1 1 0-2h2zm10 0h2a1 1 0 0 1 0 2h-3a.997.997 0 0 1-1-1V1a1 1 0 0 1 2 0v2zM3 13H1a1 1 0 0 1 0-2h3a.997.997 0 0 1 1 1v3a1 1 0 0 1-2 0v-2zm10 0v2a1 1 0 0 1-2 0v-3a.997.997 0 0 1 1-1h3a1 1 0 0 1 0 2h-2zM6.5 7h3a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 12 16" id="scroll_down" xmlns="http://www.w3.org/2000/svg"><path class="fhfirst-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.043a.51.51 0 0 0 .321-.105c.09-.07.136-.154.136-.25v-.71c0-.095-.045-.178-.136-.249a.508.508 0 0 0-.32-.105"/><path class="fhsecond-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="fhthird-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-.136.09h-.37a.626.626 0 0 1-.136-.09"/></symbol><symbol viewBox="0 0 12 16" id="scroll_up" xmlns="http://www.w3.org/2000/svg"><path d="M1.048 1.845a.508.508 0 0 1-.32-.105c-.091-.07-.136-.154-.136-.25V.78c0-.095.045-.178.135-.249a.508.508 0 0 1 .321-.105h10.043a.51.51 0 0 1 .321.105c.09.07.136.154.136.25v.71c0 .095-.045.178-.136.249a.508.508 0 0 1-.32.105M.687 7.973c-.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 3.09A.458.458 0 0 0 6.257 3h-.37a.626.626 0 0 0-.136.09M.687 14.973c-.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 10.09a.458.458 0 0 0-.136-.09h-.37a.626.626 0 0 0-.136.09"/></symbol><symbol viewBox="0 0 16 16" id="search" xmlns="http://www.w3.org/2000/svg"><path d="M8.853 8.854a3.5 3.5 0 1 0-4.95-4.95 3.5 3.5 0 0 0 4.95 4.95zm.207 2.328a5.5 5.5 0 1 1 2.121-2.121l3.329 3.328a1.5 1.5 0 0 1-2.121 2.121L9.06 11.182z"/></symbol><symbol viewBox="0 0 16 16" id="settings" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.415 5.803L1.317 4.084A.5.5 0 0 1 1.35 3.5l.805-.994a.5.5 0 0 1 .564-.153l1.878.704a5.975 5.975 0 0 1 1.65-.797L6.885.342A.5.5 0 0 1 7.36 0h1.28a.5.5 0 0 1 .474.342l.639 1.918a5.97 5.97 0 0 1 1.65.797l1.877-.704a.5.5 0 0 1 .565.153l.805.994a.5.5 0 0 1 .032.584l-1.097 1.719c.217.551.354 1.143.399 1.76l1.731 1.058a.5.5 0 0 1 .227.54l-.288 1.246a.5.5 0 0 1-.44.385l-2.008.19a6.026 6.026 0 0 1-1.142 1.431l.265 1.995a.5.5 0 0 1-.277.516l-1.15.56a.5.5 0 0 1-.576-.1l-1.424-1.452a6.047 6.047 0 0 1-1.804 0l-1.425 1.453a.5.5 0 0 1-.576.1l-1.15-.561a.5.5 0 0 1-.276-.516l.265-1.995a6.026 6.026 0 0 1-1.143-1.43l-2.008-.191a.5.5 0 0 1-.44-.385L.058 9.16a.5.5 0 0 1 .226-.539l1.732-1.058a5.968 5.968 0 0 1 .399-1.76zM8 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="shield" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8c1.657 0 3 1.373 3 3.067v7.346c0 1.065-.54 2.053-1.426 2.611l-4 2.52a2.944 2.944 0 0 1-3.148 0l-4-2.52A3.083 3.083 0 0 1 1 10.414V3.066C1 1.373 2.343 0 4 0zm0 2.045c-.552 0-1 .457-1 1.022v7.346c0 .355.18.685.475.87l4 2.52a.981.981 0 0 0 1.05 0l4-2.52c.295-.185.475-.515.475-.87V3.067c0-.565-.448-1.022-1-1.022H4zm0 1.533c0-.282.224-.511.5-.511h4V12.1a.52.52 0 0 1-.069.258.494.494 0 0 1-.684.183l-3.5-2.098a.513.513 0 0 1-.247-.44V3.577z"/></symbol><symbol viewBox="0 0 16 16" id="slight-frown" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-2.163-3.275a2.499 2.499 0 0 1 4.343.03.5.5 0 0 1-.871.49 1.5 1.5 0 0 0-2.607-.018.5.5 0 1 1-.865-.502zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="slight-smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-5.163 2.254a.5.5 0 1 1 .865-.502 1.499 1.499 0 0 0 2.607-.018.5.5 0 1 1 .871.49 2.499 2.499 0 0 1-4.343.03z"/></symbol><symbol viewBox="0 0 16 16" id="smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM6.18 6.27a.5.5 0 0 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zm6 0a.5.5 0 1 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zM5 9a3 3 0 0 0 6 0H5z"/></symbol><symbol viewBox="0 0 16 16" id="smiley" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM5 9h6a3 3 0 0 1-6 0z"/></symbol><symbol viewBox="0 0 16 16" id="snippet" xmlns="http://www.w3.org/2000/svg"><path d="M10.67 9.31a3.001 3.001 0 0 1 2.062 5.546 3 3 0 0 1-3.771-4.559 1.007 1.007 0 0 1-.095-.137l-4.5-7.794a1 1 0 0 1 1.732-1l4.5 7.794c.028.05.052.1.071.15zm-3.283.35l-.289.5c-.028.05-.06.095-.095.137a3.001 3.001 0 0 1-3.77 4.56A3 3 0 0 1 5.294 9.31c.02-.051.043-.102.071-.15l.866-1.5 1.155 2zm2.31-4l-1.156-2 1.325-2.294a1 1 0 0 1 1.732 1L9.696 5.66zm-5.465 7.464a1 1 0 1 0 1-1.732 1 1 0 0 0-1 1.732zm7.5 0a1 1 0 1 0-1-1.732 1 1 0 0 0 1 1.732z"/></symbol><symbol viewBox="0 0 16 16" id="soft-unwrap" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.5 11v-.598a.5.5 0 0 1 .765-.424l2.557 1.598a.5.5 0 0 1 0 .848l-2.557 1.598a.5.5 0 0 1-.765-.424V13H2a1 1 0 0 1 0-2h4.5zM2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm10 4h2a1 1 0 0 1 0 2h-2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="soft-wrap" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.5 13v.598a.5.5 0 0 1-.765.424l-2.557-1.598a.5.5 0 0 1 0-.848l2.557-1.598a.5.5 0 0 1 .765.424V11H12a1 1 0 0 0 0-2H2a1 1 0 1 1 0-2h10a3 3 0 0 1 0 6h-1.5zM2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 8h3a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="spam" xmlns="http://www.w3.org/2000/svg"><path d="M8.75.433l5.428 3.134a1.5 1.5 0 0 1 .75 1.299v6.268a1.5 1.5 0 0 1-.75 1.299L8.75 15.567a1.5 1.5 0 0 1-1.5 0l-5.428-3.134a1.5 1.5 0 0 1-.75-1.299V4.866a1.5 1.5 0 0 1 .75-1.299L7.25.433a1.5 1.5 0 0 1 1.5 0zM3.072 5.155v5.69L8 13.691l4.928-2.846v-5.69L8 2.309 3.072 5.155zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 14 14" id="spinner" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="7" cy="7" r="6" stroke="#000" stroke-opacity=".1" stroke-width="2"/><path fill="#000" fill-opacity=".1" fill-rule="nonzero" d="M7 0a7 7 0 0 1 7 7h-2a5 5 0 0 0-5-5V0z"/></g></symbol><symbol viewBox="0 0 16 16" id="staged" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3h4a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm9 6a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM2 7h4a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="star" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.609 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 16 16" id="star-o" xmlns="http://www.w3.org/2000/svg"><path d="M10.975 10.99a3 3 0 0 1 .655-2.083l1.54-1.916-2.219-.576a3 3 0 0 1-1.825-1.37L8 3.15 6.874 5.044a3 3 0 0 1-1.825 1.371l-2.218.576 1.54 1.916a3 3 0 0 1 .654 2.083l-.165 2.4 1.965-.836a3 3 0 0 1 2.348 0l1.965.836-.164-2.399zM7.61 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 14 14" id="status_canceled" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M5.2 3.8l4.9 4.9c.2.2.2.5 0 .7l-.7.7c-.2.2-.5.2-.7 0L3.8 5.2c-.2-.2-.2-.5 0-.7l.7-.7c.2-.2.5-.2.7 0"/></g></symbol><symbol viewBox="0 0 22 22" id="status_canceled_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M8.171 5.971l7.7 7.7a.76.76 0 0 1 0 1.1l-1.1 1.1a.76.76 0 0 1-1.1 0l-7.7-7.7a.76.76 0 0 1 0-1.1l1.1-1.1a.76.76 0 0 1 1.1 0"/></symbol><symbol viewBox="0 0 16 16" id="status_closed" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.83a1 1 0 0 1 1.414 1.416l-3.535 3.535a1 1 0 0 1-1.415.001l-2.12-2.12a1 1 0 1 1 1.413-1.415zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 14 14" id="status_created" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><circle cx="7" cy="7" r="3.25"/></g></symbol><symbol viewBox="0 0 22 22" id="status_created_borderless" xmlns="http://www.w3.org/2000/svg"><circle cx="11" cy="11" r="5.107"/></symbol><symbol viewBox="0 0 14 14" id="status_failed" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 5.969L5.599 4.568a.29.29 0 0 0-.413.004l-.614.614a.294.294 0 0 0-.004.413L5.968 7l-1.4 1.401a.29.29 0 0 0 .004.413l.614.614c.113.114.3.117.413.004L7 8.032l1.401 1.4a.29.29 0 0 0 .413-.004l.614-.614a.294.294 0 0 0 .004-.413L8.032 7l1.4-1.401a.29.29 0 0 0-.004-.413l-.614-.614a.294.294 0 0 0-.413-.004L7 5.968z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_failed_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 9.38L8.798 7.178a.455.455 0 0 0-.65.006l-.964.965a.462.462 0 0 0-.006.65L9.38 11l-2.202 2.202a.455.455 0 0 0 .006.65l.965.964a.462.462 0 0 0 .65.006L11 12.62l2.202 2.202a.455.455 0 0 0 .65-.006l.964-.965a.462.462 0 0 0 .006-.65L12.62 11l2.202-2.202a.455.455 0 0 0-.006-.65l-.965-.964a.462.462 0 0 0-.65-.006L11 9.38z"/></symbol><symbol viewBox="0 0 14 14" id="status_manual" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M10.5 7.63V6.37l-.787-.13c-.044-.175-.132-.349-.263-.61l.481-.652-.918-.913-.657.478a2.346 2.346 0 0 0-.612-.26L7.656 3.5H6.388l-.132.783c-.219.043-.394.13-.612.26l-.657-.478-.918.913.437.652c-.131.218-.175.392-.262.61l-.744.086v1.261l.787.13c.044.218.132.392.263.61l-.438.651.92.913.655-.434c.175.086.394.173.613.26l.131.783h1.313l.131-.783c.219-.043.394-.13.613-.26l.656.478.918-.913-.48-.652c.13-.218.218-.435.262-.61l.656-.13zM7 8.283a1.285 1.285 0 0 1-1.313-1.305c0-.739.57-1.304 1.313-1.304.744 0 1.313.565 1.313 1.304 0 .74-.57 1.305-1.313 1.305z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_manual_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M16.5 11.99v-1.98l-1.238-.206c-.068-.273-.206-.546-.412-.956l.756-1.025-1.444-1.435-1.03.752a3.686 3.686 0 0 0-.963-.41L12.03 5.5h-1.994l-.206 1.23c-.343.068-.618.205-.962.41l-1.031-.752-1.444 1.435.687 1.025c-.206.341-.275.615-.412.956L5.5 9.941v1.981l1.237.205c.07.342.207.615.413.957l-.688 1.025 1.444 1.434 1.032-.683c.274.137.618.274.962.41l.206 1.23h2.063l.206-1.23c.344-.068.619-.205.963-.41l1.03.752 1.444-1.435-.756-1.025c.207-.341.344-.683.413-.956l1.031-.205zM11 13.017c-1.169 0-2.063-.889-2.063-2.05 0-1.162.894-2.05 2.063-2.05s2.063.888 2.063 2.05c0 1.161-.894 2.05-2.063 2.05z"/></symbol><symbol viewBox="0 0 14 14" id="status_notfound" xmlns="http://www.w3.org/2000/svg"><path d="M7 14A7 7 0 1 1 7 0a7 7 0 0 1 0 14z"/><path d="M7 13A6 6 0 1 0 7 1a6 6 0 0 0 0 12z" fill="#FFF"/><path d="M8.16 7.184c.519-.37.904-.857 1.07-1.477.384-1.427-.619-2.897-2.246-2.897-.732 0-1.327.26-1.766.692a2.163 2.163 0 0 0-.509.743.75.75 0 0 0 1.4.54.78.78 0 0 1 .16-.213c.168-.165.39-.262.715-.262.597 0 .936.496.798 1.007-.067.249-.235.462-.492.644-.231.165-.47.264-.601.3a.75.75 0 0 0-.556.724v1.421a.75.75 0 0 0 1.5 0v-.909a3.74 3.74 0 0 0 .526-.313z"/><ellipse cx="6.889" cy="10.634" rx="1" ry="1"/></symbol><symbol viewBox="0 0 22 22" id="status_notfound_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M12.822 11.29c.816-.581 1.421-1.348 1.683-2.322.603-2.243-.973-4.553-3.53-4.553-1.15 0-2.085.41-2.775 1.089-.42.413-.672.835-.8 1.167a1.179 1.179 0 0 0 2.2.847c.016-.043.1-.184.252-.334.264-.259.613-.412 1.123-.412.938 0 1.47.78 1.254 1.584-.105.39-.37.726-.773 1.012a3.25 3.25 0 0 1-.945.47 1.179 1.179 0 0 0-.874 1.138v2.234a1.179 1.179 0 1 0 2.358 0v-1.43a5.9 5.9 0 0 0 .827-.492z"/><ellipse cx="10.825" cy="16.711" rx="1.275" ry="1.322"/></symbol><symbol viewBox="0 0 14 14" id="status_open" xmlns="http://www.w3.org/2000/svg"><path d="M0 7c0-3.866 3.142-7 7-7 3.866 0 7 3.142 7 7 0 3.866-3.142 7-7 7-3.866 0-7-3.142-7-7z"/><path d="M1 7c0 3.309 2.69 6 6 6 3.309 0 6-2.69 6-6 0-3.309-2.69-6-6-6-3.309 0-6 2.69-6 6z" fill="#FFF"/><path d="M7 9.219a2.218 2.218 0 1 0 0-4.436A2.218 2.218 0 0 0 7 9.22zm0 1.12a3.338 3.338 0 1 1 0-6.676 3.338 3.338 0 0 1 0 6.676z"/></symbol><symbol viewBox="0 0 14 14" id="status_pending" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M4.7 5.3c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H5c-.2 0-.3-.1-.3-.3V5.3m3 0c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H8c-.2 0-.3-.1-.3-.3V5.3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_pending_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M7.386 8.329c0-.315.157-.472.471-.472h1.414c.315 0 .472.157.472.472v5.342c0 .315-.157.472-.472.472H7.857c-.314 0-.471-.157-.471-.472V8.33m4.714 0c0-.315.157-.472.471-.472h1.415c.314 0 .471.157.471.472v5.342c0 .315-.157.472-.471.472H12.57c-.314 0-.471-.157-.471-.472V8.33"/></symbol><symbol viewBox="0 0 14 14" id="status_running" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 3c2.2 0 4 1.8 4 4s-1.8 4-4 4c-1.3 0-2.5-.7-3.3-1.7L7 7V3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_running_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 4.714c3.457 0 6.286 2.829 6.286 6.286 0 3.457-2.829 6.286-6.286 6.286-2.043 0-3.929-1.1-5.186-2.672L11 11V4.714"/></symbol><symbol viewBox="0 0 14 14" id="status_skipped" xmlns="http://www.w3.org/2000/svg"><path d="M7 14A7 7 0 1 1 7 0a7 7 0 0 1 0 14z"/><path d="M7 13A6 6 0 1 0 7 1a6 6 0 0 0 0 12z" fill="#FFF"/><path d="M6.415 7.04L4.579 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L5.341 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L6.415 7.04zm2.54 0L7.119 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L7.881 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L8.955 7.04z"/></symbol><symbol viewBox="0 0 22 22" id="status_skipped_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M14.072 11.063l-2.82 2.82a.46.46 0 0 0-.001.652l.495.495a.457.457 0 0 0 .653-.001l3.7-3.7a.46.46 0 0 0 .001-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.479-3.479a.464.464 0 0 0-.654.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/><path d="M10.08 11.063l-2.819 2.82a.46.46 0 0 0-.002.652l.496.495a.457.457 0 0 0 .652-.001l3.7-3.7a.46.46 0 0 0 .002-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.48-3.479a.464.464 0 0 0-.653.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/></symbol><symbol viewBox="0 0 14 14" id="status_success" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6.278 7.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_success_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.866 12.095l-1.95-1.95a.462.462 0 0 0-.647.01l-.964.964a.46.46 0 0 0-.01.646l3.013 3.014a.787.787 0 0 0 1.106.008l.425-.425 4.854-4.853a.462.462 0 0 0 .002-.659l-.964-.964a.468.468 0 0 0-.658.002l-4.207 4.207z"/></symbol><symbol viewBox="0 0 14 14" id="status_success_solid" xmlns="http://www.w3.org/2000/svg"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7zm6.278.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 14 14" id="status_warning" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6 3.5c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v4c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-4m0 6c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v1c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-1"/></g></symbol><symbol viewBox="0 0 22 22" id="status_warning_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.429 5.5c0-.471.314-.786.785-.786h1.572c.471 0 .785.315.785.786v6.286c0 .471-.314.785-.785.785h-1.572c-.471 0-.785-.314-.785-.785V5.5m0 9.429c0-.472.314-.786.785-.786h1.572c.471 0 .785.314.785.786V16.5c0 .471-.314.786-.785.786h-1.572c-.471 0-.785-.315-.785-.786v-1.571"/></symbol><symbol viewBox="0 0 16 16" id="stop" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 0h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2z"/></symbol><symbol viewBox="0 0 16 16" id="task-done" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="template" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm.8 2h2.4a.8.8 0 0 1 .8.8v1.4a.8.8 0 0 1-.8.8H3.8a.8.8 0 0 1-.8-.8V4.8a.8.8 0 0 1 .8-.8zm4.7 0h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm0 2h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm-5 3h9a.5.5 0 1 1 0 1h-9a.5.5 0 0 1 0-1zm0 2h9a.5.5 0 1 1 0 1h-9a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="terminal" xmlns="http://www.w3.org/2000/svg"><path d="M7 8a.997.997 0 0 1-.293.707l-1.414 1.414a1 1 0 1 1-1.414-1.414L4.586 8l-.707-.707a1 1 0 1 1 1.414-1.414l1.414 1.414A.997.997 0 0 1 7 8zM4 0h8a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H4zm5 7h2a1 1 0 0 1 0 2H9a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 11h5.282a2 2 0 0 0 1.963-2.38l-.563-2.905a3 3 0 0 0-.243-.732l-1.103-2.286A3 3 0 0 0 10.964 1H7a3 3 0 0 0-3 3v6.3a2 2 0 0 0 .436 1.247l3.11 3.9a.632.632 0 0 0 .941.053l.137-.137a1 1 0 0 0 .28-.87L8.329 11zM1 10h2V3H1a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 5h5.282a2 2 0 0 1 1.963 2.38l-.563 2.905a3 3 0 0 1-.243.732l-1.103 2.286A3 3 0 0 1 10.964 15H7a3 3 0 0 1-3-3V5.7a2 2 0 0 1 .436-1.247l3.11-3.9A.632.632 0 0 1 8.487.5l.137.137a1 1 0 0 1 .28.87L8.329 5zM1 6h2v7H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="thumbtack" xmlns="http://www.w3.org/2000/svg"><path d="M7.125 9h-2.19a.5.5 0 0 1-.417-.777L6 6V2L5.362.724A.5.5 0 0 1 5.809 0h4.382a.5.5 0 0 1 .447.724L10 2v4l1.482 2.223a.5.5 0 0 1-.416.777H8.875L8 16l-.875-7z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 16 16" id="time-out" xmlns="http://www.w3.org/2000/svg"><path d="M12 13.36l-1.36 1.358a.961.961 0 1 1-1.358-1.359L10.64 12l-1.36-1.36a.961.961 0 0 1 1.36-1.358L12 10.64l1.36-1.36a.961.961 0 1 1 1.358 1.36L13.36 12l1.36 1.36a.961.961 0 1 1-1.36 1.358L12 13.36zM8 9H5a1 1 0 1 1 0-2h2V5a1 1 0 1 1 2 0v3a1 1 0 0 1-1 1zm0 6a7 7 0 1 1 7-7 4.976 4.976 0 0 0-2.084-.916A5.002 5.002 0 0 0 3 8a5.002 5.002 0 0 0 4.084 4.916c.143.772.462 1.48.916 2.084z"/></symbol><symbol viewBox="0 0 16 16" id="timer" xmlns="http://www.w3.org/2000/svg"><path d="M12.022 3.27l.77-.77a1 1 0 0 1 1.415 1.414l-.728.729a7 7 0 1 1-1.456-1.372zM8 14A5 5 0 1 0 8 4a5 5 0 0 0 0 10zm0-9a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zM6 0h4a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-add" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 4V2a1 1 0 0 1 2 0v2h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0V6H8a1 1 0 1 1 0-2h2zm2 7a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-done" xmlns="http://www.w3.org/2000/svg"><path d="M8.243 7.485l4.95-4.95a1 1 0 1 1 1.414 1.415L8.95 9.607a.997.997 0 0 1-1.414 0L4.707 6.778a1 1 0 0 1 1.414-1.414l2.122 2.121zM12 11a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="token" xmlns="http://www.w3.org/2000/svg"><path d="M3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H3zm1 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="unapproval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11.95 8.536l1.06-1.061a1 1 0 0 1 1.415 1.414l-1.061 1.06 1.06 1.061a1 1 0 0 1-1.414 1.415l-1.06-1.061-1.06 1.06a1 1 0 1 1-1.415-1.414l1.06-1.06-1.06-1.06a1 1 0 0 1 1.414-1.415l1.06 1.06zm-3.768-.33c.006.503.201 1.006.586 1.39l.353.354-.353.353a2 2 0 1 0 2.828 2.829l.354-.354.047.048C11.964 14.363 11.527 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.834 0 1.557.074 2.182.205zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="unassignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11 5h4a1 1 0 0 1 0 2h-4a1 1 0 0 1 0-2zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="unlink" xmlns="http://www.w3.org/2000/svg"><path d="M11.295 8.845l-.659-1.664a1.78 1.78 0 0 0 .04-.04l1.415-1.414c.586-.586.654-1.468.152-1.97s-1.384-.434-1.97.152L8.859 5.323a1.781 1.781 0 0 0-.04.04l-1.664-.658c.141-.208.305-.408.491-.594l1.415-1.414c1.366-1.367 3.424-1.525 4.596-.354 1.171 1.172 1.013 3.23-.354 4.596L11.89 8.354c-.186.186-.386.35-.594.491zm-2.45 2.45a4.075 4.075 0 0 1-.491.594l-1.415 1.414c-1.366 1.367-3.424 1.525-4.596.354-1.171-1.172-1.013-3.23.354-4.596L4.11 7.646c.186-.186.386-.35.594-.491l.659 1.664a1.781 1.781 0 0 0-.04.04l-1.415 1.414c-.586.586-.654 1.468-.152 1.97s1.384.434 1.97-.152l1.414-1.414a1.78 1.78 0 0 0 .04-.04l1.664.658zm3.812-2.088h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-.05a.5.5 0 0 1 .5-.5zm-.384 2.116l1.415 1.414a.5.5 0 0 1 0 .708l-.037.036a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 0-.707l.036-.037a.5.5 0 0 1 .707 0zm-2.823 1.09a.5.5 0 0 1 .5-.5h.052a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9.95a.5.5 0 0 1-.5-.5v-2zm-2.748-9.16a.5.5 0 0 1-.5.5h-.05a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h.05a.5.5 0 0 1 .5.5v2zm-2.116.383a.5.5 0 0 1 0 .707l-.036.036a.5.5 0 0 1-.707 0L2.428 2.965a.5.5 0 0 1 0-.707l.037-.036a.5.5 0 0 1 .707 0l1.414 1.414zm-1.09 2.823h-2a.5.5 0 0 1-.5-.5v-.051a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5z"/></symbol><symbol viewBox="0 0 16 16" id="unstaged" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="user" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 8c-6.888 0-6.976-.78-6.976-2.52S2.144 8 8 8s6.976 2.692 6.976 4.48c0 1.788-.088 2.52-6.976 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="users" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.521 8.01C15.103 8.19 16 10.755 16 12.48c0 1.533-.056 2.29-3.808 2.475.609-.54.808-1.331.808-2.475 0-1.911-.804-3.503-2.479-4.47zm-1.67-1.228A3.987 3.987 0 0 0 9.976 4a3.987 3.987 0 0 0-1.125-2.782 3 3 0 1 1 0 5.563zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="volume-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 5h1v6H1a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1zm2 0l4.445-2.964A1 1 0 0 1 9 2.87v10.26a1 1 0 0 1-1.555.833L3 11V5zm10.283 7.89a.5.5 0 0 1-.66-.752A5.485 5.485 0 0 0 14.5 8c0-1.601-.687-3.09-1.865-4.128a.5.5 0 0 1 .661-.75A6.484 6.484 0 0 1 15.5 8a6.485 6.485 0 0 1-2.217 4.89zm-2.002-2.236a.5.5 0 1 1-.652-.758c.55-.472.871-1.157.871-1.896 0-.732-.315-1.411-.856-1.883a.5.5 0 0 1 .658-.753A3.492 3.492 0 0 1 12.5 8c0 1.033-.45 1.994-1.219 2.654z"/></symbol><symbol viewBox="0 0 16 16" id="warning" xmlns="http://www.w3.org/2000/svg"><path d="M15.572 10.506c.867 1.42.375 3.247-1.098 4.082a3.184 3.184 0 0 1-1.57.412h-9.81C1.387 15 0 13.665 0 12.018a2.9 2.9 0 0 1 .427-1.512L5.332 2.47C6.2 1.05 8.096.577 9.57 1.412c.453.257.831.622 1.098 1.059l4.905 8.035zM8.89 3.479a1.014 1.014 0 0 0-.366-.353 1.053 1.053 0 0 0-1.412.353l-4.905 8.035a.967.967 0 0 0-.143.504c0 .549.462.994 1.032.994h9.81c.184 0 .364-.048.523-.137a.974.974 0 0 0 .366-1.361L8.889 3.479zM8 5a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zm0 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="work" xmlns="http://www.w3.org/2000/svg"><path d="M12 3h1a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h1V2a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v1zM6 2v1h4V2H6zM3 5a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H3zm1.5 1a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm7 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/canceled-job_empty.svg b/app/assets/images/illustrations/canceled-job_empty.svg
new file mode 100644
index 00000000000..e4a7c244f56
--- /dev/null
+++ b/app/assets/images/illustrations/canceled-job_empty.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="430" height="172" viewBox="0 0 430 172"><g fill="none" fill-rule="evenodd"><path fill="#EEE" fill-rule="nonzero" d="M187 121a2 2 0 1 1 0-4c2.542 0 5.042-.305 7.463-.904a2 2 0 1 1 .96 3.884A35.075 35.075 0 0 1 187 121zm18.21-5.105a2 2 0 1 1-2.083-3.414 31.143 31.143 0 0 0 5.896-4.664 2 2 0 1 1 2.842 2.815 35.143 35.143 0 0 1-6.654 5.263zm12.895-13.835a2 2 0 0 1-3.552-1.838 30.77 30.77 0 0 0 2.612-7.042 2 2 0 1 1 3.892.922 34.77 34.77 0 0 1-2.952 7.958zm3.816-18.433a2 2 0 1 1-3.991.268 30.873 30.873 0 0 0-1.407-7.38 2 2 0 0 1 3.808-1.223 34.873 34.873 0 0 1 1.59 8.335zm-6.346-17.842a2 2 0 0 1-3.264 2.312 31.188 31.188 0 0 0-5.054-5.564 2 2 0 0 1 2.615-3.027 35.188 35.188 0 0 1 5.703 6.279zm-14.68-11.918a2 2 0 0 1-1.59 3.67 30.758 30.758 0 0 0-7.206-2.12 2 2 0 1 1 .653-3.946 34.758 34.758 0 0 1 8.143 2.396zm-18.632-2.549a2 2 0 0 1 .537 3.964c-2.505.339-4.94.98-7.266 1.907a2 2 0 1 1-1.48-3.716 34.774 34.774 0 0 1 8.209-2.155zm-17.356 7.535a2 2 0 0 1 2.527 3.1 31.196 31.196 0 0 0-5.213 5.416 2 2 0 0 1-3.196-2.406 35.196 35.196 0 0 1 5.882-6.11zm-10.918 15.49a2 2 0 0 1 3.772 1.331 30.82 30.82 0 0 0-1.619 7.337 2 2 0 1 1-3.982-.38 34.82 34.82 0 0 1 1.829-8.289zm-1.27 18.744a2 2 0 1 1 3.917-.806 30.757 30.757 0 0 0 2.4 7.118 2 2 0 1 1-3.605 1.73 34.757 34.757 0 0 1-2.713-8.042zm8.675 16.774a2 2 0 0 1 2.926-2.728 31.167 31.167 0 0 0 5.751 4.841 2 2 0 1 1-2.187 3.349 35.167 35.167 0 0 1-6.49-5.462zm16.245 9.873a2 2 0 1 1 1.067-3.855 30.979 30.979 0 0 0 7.434 1.11 2 2 0 1 1-.11 3.998 34.979 34.979 0 0 1-8.391-1.253z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M187 104c-9.941 0-18-8.059-18-18s8.059-18 18-18 18 8.059 18 18-8.059 18-18 18zm0-4c7.732 0 14-6.268 14-14s-6.268-14-14-14-14 6.268-14 14 6.268 14 14 14z"/><path fill="#6B4FBB" d="M189 84h5a2 2 0 1 1 0 4h-7a2 2 0 0 1-2-2v-8a2 2 0 1 1 4 0v6z"/><g transform="translate(261 16)"><path fill="#F9F9F9" d="M115.575 132.895C114.333 137.006 110.516 140 106 140H10c-5.523 0-10-4.477-10-10V15a10 10 0 0 1 5.884-9.116A9.964 9.964 0 0 0 5 10v114c0 5.523 4.477 10 10 10h96a9.957 9.957 0 0 0 4.575-1.105z"/><rect width="116" height="134" x="5" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M15 2a8 8 0 0 0-8 8v114a8 8 0 0 0 8 8h96a8 8 0 0 0 8-8V10a8 8 0 0 0-8-8H15zm0-4h96c6.627 0 12 5.373 12 12v114c0 6.627-5.373 12-12 12H15c-6.627 0-12-5.373-12-12V10C3 3.373 8.373-2 15-2z"/><g transform="translate(23 23)"><rect width="16" height="4" fill="#E1DBF1" rx="2"/><rect width="16" height="4" x="32" y="12" fill="#E1DBF1" rx="2"/><rect width="16" height="4" x="44" fill="#EEE" rx="2"/><rect width="16" height="4" x="12" y="24" fill="#E1DBF1" rx="2"/><rect width="16" height="4" x="64" y="36" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="20" fill="#FEE1D3" rx="2"/><rect width="8" height="4" x="32" y="36" fill="#FC6D26" rx="2"/><rect width="8" height="4" x="52" y="12" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="64" fill="#FEF0E8" rx="2"/><rect width="12" height="4" x="16" y="48" fill="#E1DBF1" rx="2"/><rect width="8" height="4" x="44" y="36" fill="#FC6D26" rx="2"/><rect width="4" height="4" x="56" y="36" fill="#E1DBF1" rx="2"/><rect width="4" height="4" x="64" y="60" fill="#E1DBF1" rx="2"/><rect width="4" height="4" x="72" y="60" fill="#FC6D26" rx="2"/><rect width="8" height="4" x="32" fill="#FC6D26" rx="2"/><rect width="28" height="4" y="36" fill="#EEE" rx="2"/><rect width="28" height="4" x="44" y="48" fill="#EEE" rx="2"/><rect width="28" height="4" x="32" y="60" fill="#EFEDF8" rx="2"/><rect width="28" height="4" y="12" fill="#6B4FBB" rx="2"/><rect width="28" height="4" x="32" y="24" fill="#C3B8E3" rx="2"/><rect width="8" height="4" y="24" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="32" y="48" fill="#6B4FBB" rx="2"/><rect width="12" height="4" y="48" fill="#FC6D26" rx="2"/><rect width="12" height="4" y="60" fill="#FEF0E8" rx="2"/><rect width="12" height="4" x="16" y="60" fill="#FEF0E8" rx="2"/></g><g transform="translate(23 95)"><rect width="16" height="4" fill="#EFEDF8" rx="2"/><rect width="16" height="4" x="18" y="12" fill="#FC6D26" rx="2"/><rect width="16" height="4" x="44" fill="#6B4FBB" rx="2"/><rect width="8" height="4" x="20" fill="#FEE1D3" rx="2"/><rect width="8" height="4" x="38" y="12" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="64" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="32" fill="#FC6D26" rx="2"/><rect width="14" height="4" y="12" fill="#EEE" rx="2"/></g></g><path fill="#FFF" d="M80 117c17.12 0 31-13.88 31-31 0-17.12-13.88-31-31-31-17.12 0-31 13.88-31 31 0 17.12 13.88 31 31 31z"/><path fill="#EEE" fill-rule="nonzero" d="M80 121c-19.33 0-35-15.67-35-35s15.67-35 35-35 35 15.67 35 35-15.67 35-35 35zm0-4c17.12 0 31-13.88 31-31 0-17.12-13.88-31-31-31-17.12 0-31 13.88-31 31 0 17.12 13.88 31 31 31z"/><g transform="translate(61 67)"><path fill="#CCC" fill-rule="nonzero" d="M19 38C8.507 38 0 29.493 0 19S8.507 0 19 0s19 8.507 19 19-8.507 19-19 19zm0-4c8.284 0 15-6.716 15-15 0-8.284-6.716-15-15-15-8.284 0-15 6.716-15 15 0 8.284 6.716 15 15 15z"/><rect width="18" height="4" x="10" y="17" fill="#2E2E2E" rx="2" transform="rotate(45 19 19)"/></g><path fill="#E5E5E5" fill-rule="nonzero" d="M122 88c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.994 1.994 0 0 1 122 88zm14 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.994 1.994 0 0 1 136 88zm93 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.994 1.994 0 0 1 229 88zm14 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.994 1.994 0 0 1 243 88z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/epics.svg b/app/assets/images/illustrations/epics.svg
index 1a37e6bba5f..be6c3fb76a5 100644
--- a/app/assets/images/illustrations/epics.svg
+++ b/app/assets/images/illustrations/epics.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="430" height="300" viewBox="0 0 430 300"><g fill="none" fill-rule="evenodd"><g transform="translate(75 53)"><rect width="284" height="208" y="5" fill="#F9F9F9" rx="10"/><rect width="284" height="208" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M10 4a6 6 0 0 0-6 6v188a6 6 0 0 0 6 6h264a6 6 0 0 0 6-6V10a6 6 0 0 0-6-6H10zm0-4h264c5.523 0 10 4.477 10 10v188c0 5.523-4.477 10-10 10H10c-5.523 0-10-4.477-10-10V10C0 4.477 4.477 0 10 0z"/><path fill="#EEE" fill-rule="nonzero" d="M25.168 153.995c3.837-.215 7.173.028 10.119.691a3 3 0 1 0 1.318-5.853c-3.509-.79-7.4-1.074-11.773-.828a3 3 0 1 0 .336 5.99zm19.043 4.66c2.401 1.704 4.388 3.61 7.569 7.083a3 3 0 0 0 4.424-4.054c-3.448-3.763-5.686-5.911-8.522-7.923a3 3 0 1 0-3.471 4.894zm15.575 15.173c3.181 2.675 6.52 4.665 10.397 6.039a3 3 0 0 0 2.004-5.655c-3.162-1.121-5.884-2.743-8.54-4.976a3 3 0 1 0-3.861 4.592zm22.133 8.148c1.02.037 2.067.045 3.143.023a72.664 72.664 0 0 0 8.346-.638 3 3 0 1 0-.812-5.945c-2.442.334-4.996.53-7.658.585a48.55 48.55 0 0 1-2.796-.021 3 3 0 0 0-.223 5.996zm22.778-3.286c3.9-1.37 7.427-3.15 10.54-5.305a3 3 0 0 0-3.415-4.933c-2.665 1.845-5.712 3.382-9.114 4.578a3 3 0 0 0 1.989 5.66zm19.156-13.62a33.752 33.752 0 0 0 5.276-10.817 3 3 0 1 0-5.773-1.633 27.753 27.753 0 0 1-4.341 8.9 3 3 0 1 0 4.838 3.55zm6.577-22.657c-.187-3.817-.926-7.71-2.204-11.596a3 3 0 0 0-5.7 1.874c1.113 3.384 1.75 6.745 1.91 10.016a3 3 0 1 0 5.994-.294zm-7.097-22.26c-1.897-3.2-4.152-6.325-6.748-9.344a3 3 0 0 0-4.55 3.913c2.372 2.756 4.421 5.597 6.136 8.49a3 3 0 0 0 5.162-3.06zm-11.546-17.793c-.938-3.025-1.402-6.42-1.365-9.976a3 3 0 0 0-6-.063c-.043 4.163.506 8.177 1.634 11.816a3 3 0 1 0 5.731-1.777zm.053-20.107c.905-3.341 2.22-6.538 3.904-9.448a3 3 0 0 0-5.194-3.004c-1.948 3.368-3.463 7.048-4.501 10.884a3 3 0 1 0 5.791 1.568zm10.134-17.305c2.475-2.28 5.265-4.09 8.335-5.374a3 3 0 1 0-2.314-5.536c-3.725 1.558-7.105 3.75-10.086 6.497a3 3 0 1 0 4.065 4.413zm18.177-7.586c3.202-.18 6.599.092 10.18.843a3 3 0 0 0 1.23-5.872c-4.086-.857-8.009-1.172-11.747-.962a3 3 0 1 0 .337 5.99zm20.047 3.95c3.068 1.268 6.232 2.842 9.487 4.728a3 3 0 0 0 3.009-5.191c-3.48-2.017-6.883-3.71-10.204-5.083a3 3 0 1 0-2.292 5.545zm19.578 9.955c3.711 1.586 7.376 2.77 10.997 3.565a3 3 0 0 0 1.286-5.86c-3.248-.713-6.555-1.782-9.925-3.222a3 3 0 1 0-2.358 5.517zm22.591 4.789c3.94-.04 7.808-.553 11.61-1.513a3 3 0 1 0-1.468-5.817 43.358 43.358 0 0 1-10.203 1.33 3 3 0 0 0 .061 6zm22.52-5.558c3.335-1.637 6.607-3.613 9.845-5.916a3 3 0 1 0-3.477-4.89c-2.984 2.122-5.98 3.931-9.011 5.42a3 3 0 1 0 2.643 5.386zm18.678-13.054a3 3 0 0 1-4.02-4.454 130.547 130.547 0 0 0 5.31-5.088 3 3 0 1 1 4.265 4.22 136.507 136.507 0 0 1-5.555 5.322zm-48.722 25.641a3 3 0 1 1 4.314-4.17c3.056 3.16 5.075 6.744 6.172 10.754a3 3 0 0 1-5.787 1.584c-.834-3.047-2.35-5.739-4.699-8.168zm5.347 18.049a3 3 0 1 1 5.978.52c-.282 3.232-.805 6.273-1.832 11.206a3 3 0 0 1-5.874-1.222c.981-4.717 1.473-7.572 1.728-10.504zm-3.777 21.555a3 3 0 0 1 5.953.747c-.5 3.988-.397 7.09.399 9.67a3 3 0 1 1-5.733 1.769c-1.087-3.52-1.217-7.426-.62-12.186zm7.393 22.444a3 3 0 0 1 4.461-4.013c2.703 3.005 5.224 5.296 7.594 6.947a3 3 0 0 1-3.429 4.924c-2.775-1.932-5.632-4.53-8.626-7.858zm20.352 12.28a3 3 0 1 1 .334-5.99c2.77.154 5.453-.554 9.224-2.254a3 3 0 0 1 2.466 5.47c-4.57 2.06-8.103 2.993-12.024 2.775zm21.784-7.058a3 3 0 0 1-1.815-5.719c4.227-1.342 8.24-1.61 12.496-.572a3 3 0 0 1-1.421 5.83c-3.116-.76-6.025-.566-9.26.46zM106.53 56.038a3 3 0 1 1-3.45 4.909c-1.074-.755-6.723-6.044-8.083-7.204a68.019 68.019 0 0 0-.332-.281 3 3 0 1 1 3.865-4.59l.362.306c1.643 1.402 6.971 6.391 7.638 6.86zM88.536 42.422a3 3 0 0 1-2.285 5.548c-3.14-1.293-5.78-1.34-8.105-.05a3 3 0 0 1-2.91-5.247c4.087-2.266 8.597-2.187 13.3-.25zM66.698 48.73a3 3 0 0 1 2.029 5.647c-4.432 1.592-8.786.835-13.166-1.88a3 3 0 1 1 3.16-5.1c2.93 1.816 5.425 2.25 7.977 1.333zm-15.636-8.038a3 3 0 0 1-4.352 4.13c-.911-.96-1.85-1.98-3.061-3.32-.295-.325-2.437-2.703-3.07-3.4-.47-.518-.9-.988-1.313-1.436a3 3 0 0 1 4.41-4.068c.425.46.866.942 1.346 1.47.642.709 2.79 3.092 3.076 3.41a180.865 180.865 0 0 0 2.964 3.214z"/><path fill="#E1DBF1" d="M254.66 72.196l2-3.464a2 2 0 1 0-3.464-2l-2 3.464-3.464-2a2 2 0 0 0-2 3.464l3.464 2-2 3.464a2 2 0 0 0 3.464 2l2-3.464 3.464 2a2 2 0 1 0 2-3.464l-3.464-2zm-151.904 78.732l2.829-2.828a2 2 0 0 0-2.829-2.829l-2.828 2.829-2.828-2.829a2 2 0 0 0-2.829 2.829l2.829 2.828-2.829 2.829a2 2 0 1 0 2.829 2.828l2.828-2.828 2.828 2.828a2 2 0 1 0 2.829-2.828l-2.829-2.829z"/><path fill="#6B4FBB" d="M210.66 173.66l3.464-2a2 2 0 1 0-2-3.464l-3.464 2-2-3.464a2 2 0 0 0-3.464 2l2 3.464-3.464 2a2 2 0 1 0 2 3.464l3.464-2 2 3.464a2 2 0 1 0 3.464-2l-2-3.464z"/><path fill="#FDC4A8" fill-rule="nonzero" d="M27 181a8 8 0 1 1 0-16 8 8 0 0 1 0 16zm0-4a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"/><path fill="#C3B8E3" fill-rule="nonzero" d="M138 85a7 7 0 1 1 0-14 7 7 0 0 1 0 14zm0-4a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M200 57a7 7 0 1 1 0-14 7 7 0 0 1 0 14zm0-4a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/><path fill="#FC6D26" fill-rule="nonzero" d="M222.647 121.647v5h5v-5h-5zm0-4h5a4 4 0 0 1 4 4v5a4 4 0 0 1-4 4h-5a4 4 0 0 1-4-4v-5a4 4 0 0 1 4-4z"/><path fill="#FEE1D3" fill-rule="nonzero" d="M103.647 28.647v5h5v-5h-5zm0-4h5a4 4 0 0 1 4 4v5a4 4 0 0 1-4 4h-5a4 4 0 0 1-4-4v-5a4 4 0 0 1 4-4z"/><path fill="#FC6D26" fill-rule="nonzero" d="M85 103.488L81.841 108h6.318L85 103.488zm6.436 2.218A4 4 0 0 1 88.159 112H81.84a4 4 0 0 1-3.277-6.294l3.16-4.512a4 4 0 0 1 6.553 0l3.159 4.512z"/></g><path fill="#F9F9F9" d="M334.376 99.43A48.805 48.805 0 0 0 366 111c27.062 0 49-21.938 49-49s-21.938-49-49-49-49 21.938-49 49c0 9.454 2.677 18.283 7.315 25.77l-3.05 11.306a2.5 2.5 0 0 0 3.064 3.065l10.047-2.71z"/><path fill="#FFF" d="M339.376 94.43A48.805 48.805 0 0 0 371 106c27.062 0 49-21.938 49-49S398.062 8 371 8s-49 21.938-49 49c0 9.454 2.677 18.283 7.315 25.77l-3.05 11.306a2.5 2.5 0 0 0 3.064 3.065l10.047-2.71z"/><path fill="#EEE" fill-rule="nonzero" d="M329.85 99.072a4.5 4.5 0 0 1-5.516-5.517l2.827-10.48C322.501 75.258 320 66.31 320 57c0-28.167 22.833-51 51-51s51 22.833 51 51-22.833 51-51 51c-11.859 0-23.096-4.064-32.102-11.37l-9.048 2.442zm10.817-6.169C349.091 100.027 359.737 104 371 104c25.957 0 47-21.043 47-47s-21.043-47-47-47-47 21.043-47 47c0 8.859 2.453 17.351 7.016 24.716l.456.737-3.277 12.144c.072.527.347.685.613.613l11.059-2.984.8.677z"/><g transform="translate(354 34)"><path fill="#E1DBF1" fill-rule="nonzero" d="M13 4a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-8zm0-4h8a5 5 0 0 1 5 5v1a5 5 0 0 1-5 5h-8a5 5 0 0 1-5-5V5a5 5 0 0 1 5-5z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M5 11a1 1 0 0 0 0 2h24a1 1 0 0 0 0-2H5zm0-4h24a5 5 0 0 1 0 10H5A5 5 0 0 1 5 7z"/><rect width="12" height="4" x="11" y="31" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="19" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="37" fill="#E1DBF1" rx="2"/><rect width="12" height="4" x="11" y="43" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="25" fill="#E1DBF1" rx="2"/></g><path fill="#F9F9F9" d="M344.238 225.072A38.83 38.83 0 0 1 368 217c21.54 0 39 17.46 39 39s-17.46 39-39 39-39-17.46-39-39a38.84 38.84 0 0 1 4.001-17.227l-3.737-13.85a2.5 2.5 0 0 1 3.065-3.064l11.91 3.213z"/><path fill="#FFF" d="M348.238 221.072A38.83 38.83 0 0 1 372 213c21.54 0 39 17.46 39 39s-17.46 39-39 39-39-17.46-39-39a38.84 38.84 0 0 1 4.001-17.227l-3.737-13.85a2.5 2.5 0 0 1 3.065-3.064l11.91 3.213z"/><path fill="#EEE" fill-rule="nonzero" d="M336.85 215.928a4.5 4.5 0 0 0-5.516 5.517l3.543 13.13A40.848 40.848 0 0 0 331 252c0 22.644 18.356 41 41 41s41-18.356 41-41-18.356-41-41-41a40.82 40.82 0 0 0-24.182 7.887l-10.968-2.96zm12.608 6.73A36.824 36.824 0 0 1 372 215c20.435 0 37 16.565 37 37s-16.565 37-37 37-37-16.565-37-37c0-5.747 1.31-11.304 3.795-16.343l.334-.677-3.934-14.577a.5.5 0 0 1 .613-.613l12.865 3.471.785-.604z"/><path fill="#FEE1D3" fill-rule="nonzero" d="M356.097 255.962a7 7 0 0 0 8.81 10.88l1.093-.885v1.454a7 7 0 1 0 14 0v-1.454l1.092.885a7 7 0 1 0 8.81-10.88l-1.185-.96 1.455-.337a7 7 0 1 0-3.15-13.64l-1.4.323.623-1.278a7 7 0 0 0-12.583-6.137l-.662 1.356-.662-1.356a7 7 0 0 0-12.583 6.137l.623 1.278-1.4-.324a7 7 0 1 0-3.15 13.641l1.455.336-1.186.96zm5.464-.913a11.914 11.914 0 0 1-.444-1.95l-.19-1.362-4.2-.97a3 3 0 0 1 1.35-5.845l4.178.964.768-1.145c.373-.557.793-1.082 1.254-1.57l.95-1.006-1.877-3.849a3 3 0 0 1 5.393-2.63l1.892 3.879 1.363-.113a12.188 12.188 0 0 1 2.004 0l1.363.113 1.892-3.879a3 3 0 0 1 5.393 2.63l-1.877 3.849.95 1.006c.461.488.88 1.013 1.254 1.57l.768 1.145 4.178-.964a3 3 0 1 1 1.35 5.846l-4.2.97-.19 1.36a11.914 11.914 0 0 1-.444 1.95l-.413 1.302 3.36 2.72a3 3 0 1 1-3.776 4.663l-3.32-2.688-1.196.706a11.94 11.94 0 0 1-1.808.873l-1.286.492v4.295a3 3 0 1 1-6 0v-4.295l-1.286-.492a11.94 11.94 0 0 1-1.808-.873l-1.196-.706-3.32 2.688a3 3 0 1 1-3.776-4.663l3.36-2.72-.413-1.301z"/><path fill="#FC6D26" fill-rule="nonzero" d="M373 245.411a6 6 0 1 0 0 12 6 6 0 0 0 0-12zm0 4a2 2 0 1 1 0 4 2 2 0 0 1 0-4z"/><g><path fill="#F9F9F9" d="M94.624 162.43A48.805 48.805 0 0 1 63 174c-27.062 0-49-21.938-49-49s21.938-49 49-49 49 21.938 49 49c0 9.454-2.677 18.283-7.315 25.77l3.05 11.306a2.5 2.5 0 0 1-3.064 3.065l-10.047-2.71z"/><path fill="#FFF" stroke="#EEE" stroke-width="4" d="M89.624 157.43A48.805 48.805 0 0 1 58 169c-27.062 0-49-21.938-49-49s21.938-49 49-49 49 21.938 49 49c0 9.454-2.677 18.283-7.315 25.77l3.05 11.306a2.5 2.5 0 0 1-3.064 3.065l-10.047-2.71z"/><path fill="#EEE" fill-rule="nonzero" d="M99.15 162.072a4.5 4.5 0 0 0 5.516-5.517l-2.827-10.48C106.499 138.258 109 129.31 109 120c0-28.167-22.833-51-51-51S7 91.833 7 120s22.833 51 51 51c11.859 0 23.096-4.064 32.102-11.37l9.048 2.442zm-10.817-6.169C79.909 163.027 69.263 167 58 167c-25.957 0-47-21.043-47-47s21.043-47 47-47 47 21.043 47 47c0 8.859-2.453 17.351-7.016 24.716l-.456.737 3.277 12.144c-.072.527-.347.685-.613.613l-11.059-2.984-.8.677z"/><g fill-rule="nonzero"><path fill="#FEE1D3" d="M55.47 94.47l-16.148 6.688a4 4 0 0 0-2.164 2.164l-6.689 16.147a4 4 0 0 0 0 3.062l6.689 16.147a4 4 0 0 0 2.164 2.164l16.147 6.689a4 4 0 0 0 3.062 0l16.147-6.689a4 4 0 0 0 2.164-2.164l6.689-16.147a4 4 0 0 0 0-3.062l-6.689-16.147a4 4 0 0 0-2.164-2.164L58.53 94.469a4 4 0 0 0-3.062 0zM57 98.164l16.147 6.688L79.835 121l-6.688 16.147L57 143.835l-16.147-6.688L34.165 121l6.688-16.147L57 98.165zM57 107a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm12 4a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm4 12a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-4 11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-12 6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-12-6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-4-11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm4-11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm12 20c6.075 0 11-4.925 11-11s-4.925-11-11-11-11 4.925-11 11 4.925 11 11 11zm0-4a7 7 0 1 1 0-14 7 7 0 0 1 0 14z"/><path fill="#FC6D26" d="M57 126.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zm0-3a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5z"/></g></g></g></svg> \ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="430" height="300" viewBox="0 0 430 300"><defs><rect id="a" width="280" height="180" x="77" y="60" rx="10"/><rect id="c" width="100" height="48" rx="10"/><filter id="b" width="105%" height="120.8%" x="-2.5%" y="-5.2%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="e" width="84" height="76" rx="10"/><filter id="d" width="106%" height="113.2%" x="-3%" y="-3.3%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="g" width="52" height="76" rx="10"/><filter id="f" width="109.6%" height="113.2%" x="-4.8%" y="-3.3%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="i" width="36" height="132" rx="10"/><filter id="h" width="113.9%" height="107.6%" x="-6.9%" y="-1.9%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="k" width="52" height="48" rx="10"/><filter id="j" width="109.6%" height="120.8%" x="-4.8%" y="-5.2%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h430v300H0z"/><use fill="#FFF" xlink:href="#a"/><rect width="276" height="176" x="79" y="62" stroke="#EEE" stroke-width="4" rx="10"/><rect width="8" height="20" x="244" y="141" fill="#EEE" rx="4"/><rect width="8" height="20" x="311" y="103" fill="#EEE" rx="4"/><rect width="8" height="20" x="272" y="166" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="257" y="203" fill="#EEE" rx="4"/><rect width="8" height="20" x="169" y="77" fill="#EEE" rx="4"/><rect width="8" height="20" x="191" y="104" fill="#FFF" rx="4"/><rect width="8" height="20" x="140" y="157" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="154" y="119" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="163" y="205" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="294" y="186" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="327" y="73" fill="#FEE1D3" rx="4"/><g transform="translate(197 79)"><use fill="#000" filter="url(#b)" xlink:href="#c"/><use fill="#FFF" xlink:href="#c"/><rect width="96" height="44" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="62" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="78" y="14" fill="#FDC4A8" rx="4"/><rect width="8" height="20" x="46" y="14" fill="#FC6D26" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#EEE" rx="4"/></g><g transform="translate(57 30)"><use fill="#000" filter="url(#d)" xlink:href="#e"/><use fill="#FFF" xlink:href="#e"/><rect width="80" height="72" x="2" y="2" stroke="#E1DBF1" stroke-width="4" rx="10"/><rect width="8" height="20" x="62" y="42" fill="#6B4FBB" rx="4"/><rect width="8" height="20" x="46" y="42" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="30" y="42" fill="#C3B8E3" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="62" y="14" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="46" y="14" fill="#C3B8E3" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#EEE" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#C3B8E3" rx="4"/></g><g transform="translate(317 133)"><use fill="#000" filter="url(#f)" xlink:href="#g"/><use fill="#FFF" xlink:href="#g"/><rect width="48" height="72" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="14" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#FC6D26" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#EEE" rx="4"/><rect width="8" height="20" x="30" y="42" fill="#FDC4A8" rx="4"/></g><g transform="translate(89 133)"><use fill="#000" filter="url(#h)" xlink:href="#i"/><use fill="#FFF" xlink:href="#i"/><rect width="32" height="128" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="14" y="14" fill="#FDC4A8" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#EEE" rx="4"/><rect width="8" height="20" x="14" y="70" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="98" fill="#FC6D26" rx="4"/></g><g transform="translate(181 161)"><use fill="#000" filter="url(#j)" xlink:href="#k"/><use fill="#FFF" xlink:href="#k"/><rect width="48" height="44" x="2" y="2" stroke="#E1DBF1" stroke-width="4" rx="10"/><rect width="8" height="20" x="30" y="14" fill="#6B4FBB" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#C3B8E3" rx="4"/></g></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/epics/list.svg b/app/assets/images/illustrations/epics/list.svg
new file mode 100644
index 00000000000..be6c3fb76a5
--- /dev/null
+++ b/app/assets/images/illustrations/epics/list.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="430" height="300" viewBox="0 0 430 300"><defs><rect id="a" width="280" height="180" x="77" y="60" rx="10"/><rect id="c" width="100" height="48" rx="10"/><filter id="b" width="105%" height="120.8%" x="-2.5%" y="-5.2%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="e" width="84" height="76" rx="10"/><filter id="d" width="106%" height="113.2%" x="-3%" y="-3.3%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="g" width="52" height="76" rx="10"/><filter id="f" width="109.6%" height="113.2%" x="-4.8%" y="-3.3%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="i" width="36" height="132" rx="10"/><filter id="h" width="113.9%" height="107.6%" x="-6.9%" y="-1.9%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="k" width="52" height="48" rx="10"/><filter id="j" width="109.6%" height="120.8%" x="-4.8%" y="-5.2%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h430v300H0z"/><use fill="#FFF" xlink:href="#a"/><rect width="276" height="176" x="79" y="62" stroke="#EEE" stroke-width="4" rx="10"/><rect width="8" height="20" x="244" y="141" fill="#EEE" rx="4"/><rect width="8" height="20" x="311" y="103" fill="#EEE" rx="4"/><rect width="8" height="20" x="272" y="166" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="257" y="203" fill="#EEE" rx="4"/><rect width="8" height="20" x="169" y="77" fill="#EEE" rx="4"/><rect width="8" height="20" x="191" y="104" fill="#FFF" rx="4"/><rect width="8" height="20" x="140" y="157" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="154" y="119" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="163" y="205" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="294" y="186" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="327" y="73" fill="#FEE1D3" rx="4"/><g transform="translate(197 79)"><use fill="#000" filter="url(#b)" xlink:href="#c"/><use fill="#FFF" xlink:href="#c"/><rect width="96" height="44" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="62" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="78" y="14" fill="#FDC4A8" rx="4"/><rect width="8" height="20" x="46" y="14" fill="#FC6D26" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#EEE" rx="4"/></g><g transform="translate(57 30)"><use fill="#000" filter="url(#d)" xlink:href="#e"/><use fill="#FFF" xlink:href="#e"/><rect width="80" height="72" x="2" y="2" stroke="#E1DBF1" stroke-width="4" rx="10"/><rect width="8" height="20" x="62" y="42" fill="#6B4FBB" rx="4"/><rect width="8" height="20" x="46" y="42" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="30" y="42" fill="#C3B8E3" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="62" y="14" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="46" y="14" fill="#C3B8E3" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#EEE" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#C3B8E3" rx="4"/></g><g transform="translate(317 133)"><use fill="#000" filter="url(#f)" xlink:href="#g"/><use fill="#FFF" xlink:href="#g"/><rect width="48" height="72" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="14" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#FC6D26" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#EEE" rx="4"/><rect width="8" height="20" x="30" y="42" fill="#FDC4A8" rx="4"/></g><g transform="translate(89 133)"><use fill="#000" filter="url(#h)" xlink:href="#i"/><use fill="#FFF" xlink:href="#i"/><rect width="32" height="128" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="14" y="14" fill="#FDC4A8" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#EEE" rx="4"/><rect width="8" height="20" x="14" y="70" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="98" fill="#FC6D26" rx="4"/></g><g transform="translate(181 161)"><use fill="#000" filter="url(#j)" xlink:href="#k"/><use fill="#FFF" xlink:href="#k"/><rect width="48" height="44" x="2" y="2" stroke="#E1DBF1" stroke-width="4" rx="10"/><rect width="8" height="20" x="30" y="14" fill="#6B4FBB" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#C3B8E3" rx="4"/></g></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/epics/roadmap.svg b/app/assets/images/illustrations/epics/roadmap.svg
new file mode 100644
index 00000000000..a14f14b91c9
--- /dev/null
+++ b/app/assets/images/illustrations/epics/roadmap.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="415" height="289" viewBox="0 0 415 289"><g fill="none" fill-rule="evenodd"><path d="M-9-5h430v300H-9z"/><g transform="translate(68 47)"><rect width="284" height="208" y="5" fill="#F9F9F9" fill-rule="nonzero" rx="10"/><rect width="284" height="208" fill="#FFF" fill-rule="nonzero" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M10 4a6 6 0 0 0-6 6v188a6 6 0 0 0 6 6h264a6 6 0 0 0 6-6V10a6 6 0 0 0-6-6H10zm0-4h264c5.523 0 10 4.477 10 10v188c0 5.523-4.477 10-10 10H10c-5.523 0-10-4.477-10-10V10C0 4.477 4.477 0 10 0z"/><path fill="#E1DBF1" d="M25.168 153.995c3.837-.215 7.173.028 10.119.691a3 3 0 1 0 1.318-5.853c-3.509-.79-7.4-1.074-11.773-.828a3 3 0 1 0 .336 5.99z"/><path fill="#C3B8E3" d="M44.211 158.655c2.401 1.704 4.388 3.61 7.569 7.083a3 3 0 1 0 4.424-4.054c-3.448-3.763-5.686-5.911-8.522-7.923a3 3 0 1 0-3.471 4.894z"/><path fill="#E1DBF1" d="M59.786 173.828c3.181 2.675 6.52 4.665 10.397 6.039a3 3 0 0 0 2.004-5.655c-3.162-1.121-5.884-2.743-8.54-4.976a3 3 0 1 0-3.861 4.592zm22.133 8.148c1.02.037 2.067.045 3.143.023a72.664 72.664 0 0 0 8.346-.638 3 3 0 0 0-.812-5.945c-2.442.334-4.996.53-7.658.585a48.55 48.55 0 0 1-2.796-.021 3 3 0 1 0-.223 5.996z"/><path fill="#C3B8E3" d="M104.697 178.69c3.9-1.37 7.427-3.15 10.54-5.305a3 3 0 0 0-3.415-4.933c-2.665 1.845-5.712 3.382-9.114 4.578a3 3 0 0 0 1.989 5.66z"/><path fill="#E1DBF1" d="M123.853 165.07a33.752 33.752 0 0 0 5.276-10.817 3 3 0 1 0-5.773-1.633 27.753 27.753 0 0 1-4.341 8.9 3 3 0 0 0 4.838 3.55zm6.577-22.657c-.187-3.817-.926-7.71-2.204-11.596a3 3 0 1 0-5.7 1.874c1.113 3.384 1.75 6.745 1.91 10.016a3 3 0 1 0 5.994-.294z"/><path fill="#C3B8E3" d="M123.333 120.153c-1.897-3.2-4.152-6.325-6.748-9.344a3 3 0 0 0-4.55 3.913c2.372 2.756 4.421 5.597 6.136 8.49a3 3 0 1 0 5.162-3.06v.001z"/><path fill="#E1DBF1" d="M111.787 102.36c-.938-3.025-1.402-6.42-1.365-9.976a3 3 0 1 0-6-.063c-.043 4.163.506 8.177 1.634 11.816a3 3 0 1 0 5.731-1.777z"/><path fill="#C3B8E3" d="M111.84 82.253c.905-3.341 2.22-6.538 3.904-9.448a3 3 0 0 0-5.194-3.004c-1.948 3.368-3.463 7.048-4.501 10.884a3 3 0 1 0 5.791 1.568z"/><path fill="#E1DBF1" d="M121.974 64.948c2.475-2.28 5.265-4.09 8.335-5.374a3 3 0 1 0-2.314-5.536c-3.725 1.558-7.105 3.75-10.086 6.497a3 3 0 1 0 4.065 4.413zm18.177-7.586c3.202-.18 6.599.092 10.18.843a3 3 0 0 0 1.23-5.872c-4.086-.857-8.009-1.172-11.747-.962a3 3 0 1 0 .337 5.99v.001z"/><path fill="#C3B8E3" d="M160.198 61.312c3.068 1.268 6.232 2.842 9.487 4.728a3 3 0 1 0 3.009-5.191c-3.48-2.017-6.883-3.71-10.204-5.083a3 3 0 0 0-2.292 5.545v.001z"/><path fill="#E1DBF1" d="M179.776 71.267c3.711 1.586 7.376 2.77 10.997 3.565a3 3 0 0 0 1.286-5.86c-3.248-.713-6.555-1.782-9.925-3.222a3 3 0 1 0-2.358 5.517zm22.591 4.789c3.94-.04 7.808-.553 11.61-1.513a3 3 0 1 0-1.468-5.817 43.358 43.358 0 0 1-10.203 1.33 3 3 0 0 0 .061 6z"/><path fill="#C3B8E3" d="M224.887 70.498c3.335-1.637 6.607-3.613 9.845-5.916a3 3 0 0 0-3.477-4.89c-2.984 2.122-5.98 3.931-9.011 5.42a3 3 0 1 0 2.643 5.386z"/><path fill="#E1DBF1" d="M243.565 57.444a3 3 0 0 1-4.02-4.454 130.547 130.547 0 0 0 5.31-5.088 3 3 0 1 1 4.265 4.22 136.506 136.506 0 0 1-5.555 5.322z"/><path fill="#FDC4A8" d="M194.843 83.085a3 3 0 1 1 4.314-4.17c3.056 3.16 5.075 6.744 6.172 10.754a3 3 0 0 1-5.787 1.584c-.834-3.047-2.35-5.739-4.699-8.168z"/><path fill="#FEE1D3" d="M200.19 101.134a3 3 0 1 1 5.978.52c-.282 3.232-.805 6.273-1.832 11.206a3 3 0 0 1-5.874-1.222c.981-4.717 1.473-7.572 1.728-10.504z"/><path fill="#FDC4A8" d="M196.413 122.689a3 3 0 0 1 5.953.747c-.5 3.988-.397 7.09.399 9.67a3 3 0 1 1-5.733 1.769c-1.087-3.52-1.217-7.426-.62-12.186h.001z"/><path fill="#FEE1D3" d="M203.806 145.133a3 3 0 0 1 4.461-4.013c2.703 3.005 5.224 5.296 7.594 6.947a3 3 0 0 1-3.429 4.924c-2.775-1.932-5.632-4.53-8.626-7.858zm20.352 12.28a3 3 0 1 1 .334-5.99c2.77.154 5.453-.554 9.224-2.254a3 3 0 0 1 2.466 5.47c-4.57 2.06-8.103 2.993-12.024 2.775v-.001z"/><path fill="#FDC4A8" d="M245.942 150.355a3 3 0 0 1-1.815-5.719c4.227-1.342 8.24-1.61 12.496-.572a3 3 0 0 1-1.421 5.83c-3.116-.76-6.025-.566-9.26.46v.001zM106.53 56.038a3 3 0 0 1-3.45 4.909c-1.074-.755-6.723-6.044-8.083-7.204l-.332-.281a3 3 0 1 1 3.865-4.59l.362.306c1.643 1.402 6.971 6.391 7.638 6.86z"/><path fill="#FEE1D3" d="M88.536 42.422a3 3 0 0 1-2.285 5.548c-3.14-1.293-5.78-1.34-8.105-.05a3 3 0 0 1-2.91-5.247c4.087-2.266 8.597-2.187 13.3-.25v-.001z"/><path fill="#FDC4A8" d="M66.698 48.73a3 3 0 0 1 2.029 5.647c-4.432 1.592-8.786.835-13.166-1.88a3 3 0 1 1 3.16-5.1c2.93 1.816 5.425 2.25 7.977 1.333z"/><path fill="#FEE1D3" d="M51.062 40.692a3 3 0 0 1-4.352 4.13c-.911-.96-1.85-1.98-3.061-3.32-.295-.325-2.437-2.703-3.07-3.4-.47-.518-.9-.988-1.313-1.436a3 3 0 0 1 4.41-4.068c.425.46.866.942 1.346 1.47.642.709 2.79 3.092 3.076 3.41a180.865 180.865 0 0 0 2.964 3.214z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M254.66 72.196l2-3.464a2 2 0 1 0-3.464-2l-2 3.464-3.464-2a2 2 0 0 0-2 3.464l3.464 2-2 3.464a2 2 0 0 0 3.464 2l2-3.464 3.464 2a2 2 0 1 0 2-3.464l-3.464-2zm-151.904 78.732l2.829-2.828a2 2 0 1 0-2.829-2.829l-2.828 2.829-2.828-2.829a2 2 0 1 0-2.829 2.829l2.829 2.828-2.829 2.829a2 2 0 0 0 2.829 2.828l2.828-2.828 2.828 2.828a2 2 0 1 0 2.829-2.828l-2.829-2.829z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M210.66 173.66l3.464-2a2 2 0 1 0-2-3.464l-3.464 2-2-3.464a2 2 0 0 0-3.464 2l2 3.464-3.464 2a2 2 0 1 0 2 3.464l3.464-2 2 3.464a2 2 0 1 0 3.464-2l-2-3.464z"/><path fill="#FDC4A8" fill-rule="nonzero" d="M27 181a8 8 0 1 1 0-16 8 8 0 0 1 0 16zm0-4a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"/><path fill="#C3B8E3" fill-rule="nonzero" d="M138 85a7 7 0 1 1 0-14 7 7 0 0 1 0 14zm0-4a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M200 57a7 7 0 1 1 0-14 7 7 0 0 1 0 14zm0-4a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/><path fill="#FC6D26" fill-rule="nonzero" d="M222.647 121.647v5h5v-5h-5zm0-4h5a4 4 0 0 1 4 4v5a4 4 0 0 1-4 4h-5a4 4 0 0 1-4-4v-5a4 4 0 0 1 4-4z"/><path fill="#FEE1D3" fill-rule="nonzero" d="M103.647 28.647v5h5v-5h-5zm0-4h5a4 4 0 0 1 4 4v5a4 4 0 0 1-4 4h-5a4 4 0 0 1-4-4v-5a4 4 0 0 1 4-4z"/><path fill="#FC6D26" fill-rule="nonzero" d="M85 103.488L81.841 108h6.318L85 103.488zm6.436 2.218A4 4 0 0 1 88.159 112H81.84a4 4 0 0 1-3.277-6.294l3.16-4.512a4 4 0 0 1 6.553 0l3.159 4.512h.001z"/></g><path fill="#F9F9F9" fill-rule="nonzero" d="M327.376 93.43A48.805 48.805 0 0 0 359 105c27.062 0 49-21.938 49-49S386.062 7 359 7s-49 21.938-49 49c0 9.454 2.677 18.283 7.315 25.77l-3.05 11.306a2.5 2.5 0 0 0 3.064 3.065l10.047-2.71v-.001z"/><path fill="#FFF" fill-rule="nonzero" d="M332.376 88.43A48.805 48.805 0 0 0 364 100c27.062 0 49-21.938 49-49S391.062 2 364 2s-49 21.938-49 49c0 9.454 2.677 18.283 7.315 25.77l-3.05 11.306a2.5 2.5 0 0 0 3.064 3.065l10.047-2.71v-.001z"/><path fill="#EEE" fill-rule="nonzero" d="M322.85 93.072a4.5 4.5 0 0 1-5.516-5.517l2.827-10.48C315.501 69.258 313 60.31 313 51c0-28.167 22.833-51 51-51s51 22.833 51 51-22.833 51-51 51c-11.859 0-23.096-4.064-32.102-11.37l-9.048 2.442zm10.817-6.169C342.091 94.027 352.737 98 364 98c25.957 0 47-21.043 47-47S389.957 4 364 4s-47 21.043-47 47c0 8.859 2.453 17.351 7.016 24.716l.456.737-3.277 12.144c.072.527.347.685.613.613l11.059-2.984.8.677z"/><g fill-rule="nonzero" transform="translate(347 28)"><path fill="#E1DBF1" d="M13 4a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-8zm0-4h8a5 5 0 0 1 5 5v1a5 5 0 0 1-5 5h-8a5 5 0 0 1-5-5V5a5 5 0 0 1 5-5z"/><path fill="#6B4FBB" d="M5 11a1 1 0 0 0 0 2h24a1 1 0 0 0 0-2H5zm0-4h24a5 5 0 0 1 0 10H5A5 5 0 0 1 5 7z"/><rect width="12" height="4" x="11" y="31" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="19" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="37" fill="#E1DBF1" rx="2"/><rect width="12" height="4" x="11" y="43" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="25" fill="#E1DBF1" rx="2"/></g><g fill-rule="nonzero"><path fill="#F9F9F9" d="M337.238 219.072A38.83 38.83 0 0 1 361 211c21.54 0 39 17.46 39 39s-17.46 39-39 39-39-17.46-39-39a38.84 38.84 0 0 1 4.001-17.227l-3.737-13.85a2.5 2.5 0 0 1 3.065-3.064l11.91 3.213h-.001z"/><path fill="#FFF" d="M341.238 215.072A38.83 38.83 0 0 1 365 207c21.54 0 39 17.46 39 39s-17.46 39-39 39-39-17.46-39-39a38.84 38.84 0 0 1 4.001-17.227l-3.737-13.85a2.5 2.5 0 0 1 3.065-3.064l11.91 3.213h-.001z"/><path fill="#EEE" d="M329.85 209.928a4.5 4.5 0 0 0-5.516 5.517l3.543 13.13A40.848 40.848 0 0 0 324 246c0 22.644 18.356 41 41 41s41-18.356 41-41-18.356-41-41-41a40.82 40.82 0 0 0-24.182 7.887l-10.968-2.96v.001zm12.608 6.73A36.824 36.824 0 0 1 365 209c20.435 0 37 16.565 37 37s-16.565 37-37 37-37-16.565-37-37c0-5.747 1.31-11.304 3.795-16.343l.334-.677-3.934-14.577a.5.5 0 0 1 .613-.613l12.865 3.471.785-.604v.001z"/><path fill="#FEE1D3" d="M348.097 250.962a7 7 0 0 0 8.81 10.88l1.093-.885v1.454a7 7 0 0 0 14 0v-1.454l1.092.885a7 7 0 1 0 8.81-10.88l-1.185-.96 1.455-.337a7 7 0 1 0-3.15-13.64l-1.4.323.623-1.278a7 7 0 0 0-12.583-6.137l-.662 1.356-.662-1.356a7 7 0 0 0-12.583 6.137l.623 1.278-1.4-.324a7 7 0 1 0-3.15 13.641l1.455.336-1.186.96v.001zm5.464-.913a11.914 11.914 0 0 1-.444-1.95l-.19-1.362-4.2-.97a3 3 0 0 1 1.35-5.845l4.178.964.768-1.145c.373-.557.793-1.082 1.254-1.57l.95-1.006-1.877-3.849a3 3 0 0 1 5.393-2.63l1.892 3.879 1.363-.113a12.188 12.188 0 0 1 2.004 0l1.363.113 1.892-3.879a3 3 0 0 1 5.393 2.63l-1.877 3.849.95 1.006c.461.488.88 1.013 1.254 1.57l.768 1.145 4.178-.964a3 3 0 1 1 1.35 5.846l-4.2.97-.19 1.36a11.914 11.914 0 0 1-.444 1.95l-.413 1.302 3.36 2.72a3 3 0 1 1-3.776 4.663l-3.32-2.688-1.196.706a11.94 11.94 0 0 1-1.808.873l-1.286.492v4.295a3 3 0 0 1-6 0v-4.295l-1.286-.492a11.94 11.94 0 0 1-1.808-.873l-1.196-.706-3.32 2.688a3 3 0 0 1-3.776-4.663l3.36-2.72-.413-1.301z"/><path fill="#FC6D26" d="M365 240.411a6 6 0 1 0 0 12 6 6 0 0 0 0-12zm0 4a2 2 0 1 1 0 4 2 2 0 0 1 0-4z"/></g><g fill-rule="nonzero"><path fill="#F9F9F9" d="M87.624 156.43A48.805 48.805 0 0 1 56 168c-27.062 0-49-21.938-49-49s21.938-49 49-49 49 21.938 49 49c0 9.454-2.677 18.283-7.315 25.77l3.05 11.306a2.5 2.5 0 0 1-3.064 3.065l-10.047-2.71v-.001z"/><path fill="#FFF" stroke="#EEE" stroke-width="4" d="M82.624 151.43A48.805 48.805 0 0 1 51 163c-27.062 0-49-21.938-49-49s21.938-49 49-49 49 21.938 49 49c0 9.454-2.677 18.283-7.315 25.77l3.05 11.306a2.5 2.5 0 0 1-3.064 3.065l-10.047-2.71v-.001z"/><path fill="#EEE" d="M92.15 156.072a4.5 4.5 0 0 0 5.516-5.517l-2.827-10.48C99.499 132.258 102 123.31 102 114c0-28.167-22.833-51-51-51S0 85.833 0 114s22.833 51 51 51c11.859 0 23.096-4.064 32.102-11.37l9.048 2.442zm-10.817-6.169C72.909 157.027 62.263 161 51 161c-25.957 0-47-21.043-47-47s21.043-47 47-47 47 21.043 47 47c0 8.859-2.453 17.351-7.016 24.716l-.456.737 3.277 12.144c-.072.527-.347.685-.613.613l-11.059-2.984-.8.677z"/><path fill="#FEE1D3" d="M48.47 88.47l-16.148 6.688a4 4 0 0 0-2.164 2.164l-6.689 16.147a4 4 0 0 0 0 3.062l6.689 16.147a4 4 0 0 0 2.164 2.164l16.147 6.689a4 4 0 0 0 3.062 0l16.147-6.689a4 4 0 0 0 2.164-2.164l6.689-16.147a4 4 0 0 0 0-3.062l-6.689-16.147a4 4 0 0 0-2.164-2.164L51.53 88.469a4 4 0 0 0-3.062 0l.002.001zM50 92.164l16.147 6.688L72.835 115l-6.688 16.147L50 137.835l-16.147-6.688L27.165 115l6.688-16.147L50 92.165v-.001zM50 101a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm12 4a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm4 12a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-4 11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-12 6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-12-6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-4-11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm4-11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm12 20c6.075 0 11-4.925 11-11s-4.925-11-11-11-11 4.925-11 11 4.925 11 11 11zm0-4a7 7 0 1 1 0-14 7 7 0 0 1 0 14z"/><path fill="#FC6D26" d="M50 120.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zm0-3a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5z"/></g></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/issue-dashboard_results-without-filiter.svg b/app/assets/images/illustrations/issue-dashboard_results-without-filiter.svg
new file mode 100644
index 00000000000..cd9070425b0
--- /dev/null
+++ b/app/assets/images/illustrations/issue-dashboard_results-without-filiter.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="104" height="104" viewBox="0 0 104 104"><g fill="none" fill-rule="evenodd"><path fill="#EEE" fill-rule="nonzero" d="M9.565 27.5a2 2 0 0 1 3.464 2C6.226 41.283 5.18 55.239 9.843 67.745a2 2 0 0 1-3.748 1.397C1.02 55.53 2.159 40.328 9.565 27.5zM27.5 94.435a2 2 0 0 1 2-3.464c9.19 5.306 19.725 7.137 29.97 5.406a2 2 0 1 1 .667 3.944A48.798 48.798 0 0 1 27.5 94.435zM94.435 76.5a2 2 0 0 1-3.464-2 44.808 44.808 0 0 0 5.261-30.78 2 2 0 0 1 3.932-.738A48.807 48.807 0 0 1 94.435 76.5zM76.5 9.565a2 2 0 0 1-2 3.464C62.824 6.288 49.012 5.198 36.585 9.72a2 2 0 0 1-1.368-3.758C48.744 1.039 63.789 2.226 76.5 9.565z"/><path fill="#EEE" fill-rule="nonzero" d="M62.612 12.397a2 2 0 0 1-1.036 3.864C51.55 13.574 41.08 15.214 32.44 20.593a2 2 0 0 1-2.114-3.396c9.571-5.958 21.18-7.776 32.287-4.8zM12.397 41.388a2 2 0 0 1 3.864 1.036 36.854 36.854 0 0 0 2.986 26.787 2 2 0 1 1-3.54 1.862 40.854 40.854 0 0 1-3.31-29.685zm28.991 50.215a2 2 0 0 1 1.036-3.864c10.098 2.706 20.644 1.022 29.316-4.445a2 2 0 1 1 2.134 3.384c-9.606 6.056-21.299 7.922-32.486 4.925zm50.215-28.991a2 2 0 0 1-3.864-1.036 36.86 36.86 0 0 0-3.208-27.204 2 2 0 1 1 3.517-1.906 40.859 40.859 0 0 1 3.555 30.146z"/><path fill="#EEE" d="M22.717 56.065c2.039 14.585 14.563 25.81 29.71 25.81 16.569 0 30-13.431 30-30v-.077c.191 1.369.29 2.768.29 4.19 0 16.568-13.431 30-30 30-16.543 0-29.958-13.39-30-29.923z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M52.427 83.875c-17.673 0-32-14.327-32-32 0-17.673 14.327-32 32-32 17.673 0 32 14.327 32 32 0 17.673-14.327 32-32 32zm0-4c15.464 0 28-12.536 28-28s-12.536-28-28-28-28 12.536-28 28 12.536 28 28 28zm6.877-16.24a2 2 0 1 1-2.882 2.773 4.979 4.979 0 0 0-3.603-1.533 4.977 4.977 0 0 0-3.539 1.468 2 2 0 1 1-2.83-2.826 8.976 8.976 0 0 1 6.369-2.642 8.98 8.98 0 0 1 6.485 2.76z"/><path fill="#6B4FBB" d="M41.755 49.774l2.122 2.122a2 2 0 1 1-2.829 2.828l-2.121-2.121-2.121 2.121a2 2 0 0 1-2.829-2.828l2.122-2.122-2.122-2.12a2 2 0 1 1 2.829-2.83l2.121 2.122 2.121-2.121a2 2 0 0 1 2.829 2.828l-2.122 2.121zm27 0l2.122 2.122a2 2 0 1 1-2.829 2.828l-2.121-2.121-2.121 2.121a2 2 0 0 1-2.829-2.828l2.122-2.122-2.122-2.12a2 2 0 1 1 2.829-2.83l2.121 2.122 2.121-2.121a2 2 0 0 1 2.829 2.828l-2.122 2.121z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/lock_promotion.svg b/app/assets/images/illustrations/lock_promotion.svg
new file mode 100644
index 00000000000..6f1f9b2b030
--- /dev/null
+++ b/app/assets/images/illustrations/lock_promotion.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><circle cx="39" cy="45" r="37" fill="#F9F9F9"/><circle cx="39" cy="39" r="37" fill="#FFF"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M30 35a4 4 0 0 0-4 4v10a4 4 0 0 0 4 4h18a4 4 0 0 0 4-4V39a4 4 0 0 0-4-4H30zm0-4h18a8 8 0 0 1 8 8v10a8 8 0 0 1-8 8H30a8 8 0 0 1-8-8V39a8 8 0 0 1 8-8z"/><path fill="#6B4FBB" d="M33 29v2h-4v-2c0-5.523 4.477-10 10-10a9.996 9.996 0 0 1 10 10v2h-4v-2a5.997 5.997 0 0 0-6-6 6 6 0 0 0-6 6zm5 13.732a2 2 0 1 1 2 0V44a1 1 0 0 1-2 0v-1.268z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/milestone_removing-page.svg b/app/assets/images/illustrations/milestone_removing-page.svg
new file mode 100644
index 00000000000..a8cd54da0d3
--- /dev/null
+++ b/app/assets/images/illustrations/milestone_removing-page.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M2.12 42C3.647 61.032 19.575 76 39 76c19.425 0 35.353-14.968 36.88-34 .08.99.12 1.99.12 3 0 20.435-16.565 37-37 37S2 65.435 2 45c0-1.01.04-2.01.12-3z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#FDE1D4" fill-rule="nonzero" d="M25.934 25.205a3 3 0 1 1 4.127 4.356A12.952 12.952 0 0 0 26 39c0 7.18 5.82 13 13 13s13-5.82 13-13c0-3.621-1.484-6.999-4.063-9.44a3 3 0 1 1 4.126-4.357A18.951 18.951 0 0 1 58 39c0 10.493-8.507 19-19 19s-19-8.507-19-19a18.951 18.951 0 0 1 5.934-13.795z"/><rect width="6" height="18" x="36" y="17" fill="#FA6D34" rx="3"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/activity.svg b/app/assets/images/illustrations/profile-page/activity.svg
new file mode 100644
index 00000000000..a0304479737
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/activity.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M10 71.092a3 3 0 0 0 3.413-1.047L22.308 58H66a6 6 0 0 0 6-6V19.528A5.985 5.985 0 0 1 74 24v33a6 6 0 0 1-6 6H24.308l-8.895 12.045A3 3 0 0 1 10 73.263v-2.17z"/><path fill="#EEE" fill-rule="nonzero" d="M20.699 56.812A2 2 0 0 1 22.308 56H66a4 4 0 0 0 4-4V19a4 4 0 0 0-4-4H14a4 4 0 0 0-4 4v49.263a1 1 0 0 0 1.804.594L20.7 56.812zM23.317 60l-8.295 11.233A5 5 0 0 1 6 68.263V19a8 8 0 0 1 8-8h52a8 8 0 0 1 8 8v33a8 8 0 0 1-8 8H23.317z"/><rect width="26" height="4" x="27" y="26" fill="#6B4FBB" rx="2"/><rect width="26" height="4" x="27" y="34" fill="#C3B8E3" rx="2"/><rect width="26" height="4" x="27" y="42" fill="#E1DBF1" rx="2"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/contributed-projects.svg b/app/assets/images/illustrations/profile-page/contributed-projects.svg
new file mode 100644
index 00000000000..023a7e3b956
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/contributed-projects.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M31.526 21.774c.152.38.266.78.339 1.198l.005.028h-.13l-.214-1.226zM69 30.682c.632.95 1 2.091 1 3.318v6.08c2.86 5.48 2.867 12.028 0 17.41v3.267l7.255 7.255a3 3 0 0 1 0 4.243l-1.414 1.414a3 3 0 0 1-4.243 0l-4.519-4.518c-.9.539-1.953.849-3.079.849H12a6 6 0 0 1-6-6v-1.682A5.994 5.994 0 0 0 11 65h52a6 6 0 0 0 6-6V30.682z"/><path fill="#EEE" fill-rule="nonzero" d="M31.74 25a2 2 0 0 1-1.971-1.657l-.875-5.028A4 4 0 0 0 24.954 15H11a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4h52a4 4 0 0 0 4-4V29a4 4 0 0 0-4-4H31.74zm1.681-4H63a8 8 0 0 1 8 8v30a8 8 0 0 1-8 8H11a8 8 0 0 1-8-8V19a8 8 0 0 1 8-8h13.953a8 8 0 0 1 7.882 6.63l.586 3.37z"/><path fill="#E1DBF1" d="M60.991 56.82l1.414-1.414a3 3 0 0 1 4.243 0l9.9 9.9a3 3 0 0 1 0 4.242l-1.415 1.414a3 3 0 0 1-4.242 0l-9.9-9.9a3 3 0 0 1 0-4.242z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M66.294 59.295c-7.224 7.225-18.938 7.225-26.163 0-7.224-7.225-7.224-18.938 0-26.163 7.225-7.225 18.939-7.225 26.163 0 7.225 7.225 7.225 18.938 0 26.163zm-4.95-4.95c4.492-4.49 4.492-11.772 0-16.263-4.49-4.491-11.772-4.491-16.263 0-4.49 4.49-4.49 11.772 0 16.263 4.491 4.491 11.773 4.491 16.264 0z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/groups.svg b/app/assets/images/illustrations/profile-page/groups.svg
new file mode 100644
index 00000000000..97aca4d69ee
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/groups.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M5 23v-2 2zm70 40v4a6 6 0 0 1-6 6H11a6 6 0 0 1-6-6v-4a6 6 0 0 0 6 6h58a6 6 0 0 0 6-6z"/><path stroke="#EEE" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M32.087 23H69a6 6 0 0 1 6 6v34a6 6 0 0 1-6 6H11a6 6 0 0 1-6-6V17a6 6 0 0 1 6-6h13.953a6 6 0 0 1 5.912 4.972L32.087 23z"/><path fill="#6B4FBB" d="M38 44v-7a2 2 0 1 1 4 0v7h7a2 2 0 1 1 0 4h-7v7a2 2 0 1 1-4 0v-7h-7a2 2 0 1 1 0-4h7z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/personal-project.svg b/app/assets/images/illustrations/profile-page/personal-project.svg
new file mode 100644
index 00000000000..3e8df10ed38
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/personal-project.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M67 66v5a6 6 0 0 1-6 6H19a6 6 0 0 1-6-6v-5a6 6 0 0 0 6 6h42a6 6 0 0 0 6-6z"/><path fill="#EEE" fill-rule="nonzero" d="M44 6v4H19a4 4 0 0 0-4 4v52a4 4 0 0 0 4 4h42a4 4 0 0 0 4-4V14a4.002 4.002 0 0 0-3-3.874V6.062c3.946.492 7 3.858 7 7.938v52a8 8 0 0 1-8 8H19a8 8 0 0 1-8-8V14a8 8 0 0 1 8-8h25z"/><path fill="#E1DBF1" d="M55.142 41.9l-5.657-5.657a2 2 0 1 1 2.829-2.829l7.07 7.071a2 2 0 0 1 0 2.829l-7.07 7.07a2 2 0 1 1-2.829-2.828l5.657-5.657zm-29.485 0l5.657 5.656a2 2 0 1 1-2.829 2.829l-7.07-7.071a2 2 0 0 1 0-2.829l7.07-7.07a2 2 0 1 1 2.829 2.828l-5.657 5.656z"/><path fill="#6B4FBB" d="M35 44a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm6 0a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm6 0a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/><path fill="#EFEDF8" d="M47 2h12a3 3 0 0 1 3 3v19.91a1.5 1.5 0 0 1-2.308 1.265l-5.81-3.714a1.5 1.5 0 0 0-1.605-.006l-5.98 3.753A1.5 1.5 0 0 1 44 24.937V5a3 3 0 0 1 3-3z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M48 20.416l2.15-1.35a5.5 5.5 0 0 1 5.886.025L58 20.346V6H48v14.416zM47 2h12a3 3 0 0 1 3 3v19.91a1.5 1.5 0 0 1-2.308 1.265l-5.81-3.714a1.5 1.5 0 0 0-1.605-.006l-5.98 3.753A1.5 1.5 0 0 1 44 24.937V5a3 3 0 0 1 3-3z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/personal-projects.svg b/app/assets/images/illustrations/profile-page/personal-projects.svg
new file mode 100644
index 00000000000..023a7e3b956
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/personal-projects.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M31.526 21.774c.152.38.266.78.339 1.198l.005.028h-.13l-.214-1.226zM69 30.682c.632.95 1 2.091 1 3.318v6.08c2.86 5.48 2.867 12.028 0 17.41v3.267l7.255 7.255a3 3 0 0 1 0 4.243l-1.414 1.414a3 3 0 0 1-4.243 0l-4.519-4.518c-.9.539-1.953.849-3.079.849H12a6 6 0 0 1-6-6v-1.682A5.994 5.994 0 0 0 11 65h52a6 6 0 0 0 6-6V30.682z"/><path fill="#EEE" fill-rule="nonzero" d="M31.74 25a2 2 0 0 1-1.971-1.657l-.875-5.028A4 4 0 0 0 24.954 15H11a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4h52a4 4 0 0 0 4-4V29a4 4 0 0 0-4-4H31.74zm1.681-4H63a8 8 0 0 1 8 8v30a8 8 0 0 1-8 8H11a8 8 0 0 1-8-8V19a8 8 0 0 1 8-8h13.953a8 8 0 0 1 7.882 6.63l.586 3.37z"/><path fill="#E1DBF1" d="M60.991 56.82l1.414-1.414a3 3 0 0 1 4.243 0l9.9 9.9a3 3 0 0 1 0 4.242l-1.415 1.414a3 3 0 0 1-4.242 0l-9.9-9.9a3 3 0 0 1 0-4.242z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M66.294 59.295c-7.224 7.225-18.938 7.225-26.163 0-7.224-7.225-7.224-18.938 0-26.163 7.225-7.225 18.939-7.225 26.163 0 7.225 7.225 7.225 18.938 0 26.163zm-4.95-4.95c4.492-4.49 4.492-11.772 0-16.263-4.49-4.491-11.772-4.491-16.263 0-4.49 4.49-4.49 11.772 0 16.263 4.491 4.491 11.773 4.491 16.264 0z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/snippets.svg b/app/assets/images/illustrations/profile-page/snippets.svg
new file mode 100644
index 00000000000..ef0275cede3
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/snippets.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#EEE" fill-rule="nonzero" d="M23 12a2 2 0 1 1 0-4h3a2 2 0 1 1 0 4h-3zm11 0a2 2 0 1 1 0-4h3a2 2 0 1 1 0 4h-3zm11 0a2 2 0 1 1 0-4h3a2 2 0 1 1 0 4h-3zm11 0a2 2 0 1 1 0-4h3a2 2 0 1 1 0 4h-3zm11 0a2 2 0 1 1 0-4c1.576 0 3.061.613 4.172 1.688a2 2 0 1 1-2.782 2.874A1.986 1.986 0 0 0 67 12zm2 6.877a2 2 0 1 1 4 0v3a2 2 0 1 1-4 0v-3zm0 11a2 2 0 1 1 4 0v3a2 2 0 1 1-4 0v-3zm0 11a2 2 0 1 1 4 0v3a2 2 0 1 1-4 0v-3zm0 11a2 2 0 1 1 4 0v3a2 2 0 1 1-4 0v-3zm-1.348 8.015a2 2 0 0 1 1.303 3.782 6.042 6.042 0 0 1-1.877.325L65.247 64a2 2 0 1 1-.002-4h1.794a1.99 1.99 0 0 0 .613-.108zM57.246 60a2 2 0 1 1 0 4h-3a2 2 0 1 1 0-4h3zm-11 0a2 2 0 1 1 0 4h-3a2 2 0 1 1 0-4h3zM21 32.369a2 2 0 1 1-4 0v-3a2 2 0 1 1 4 0v3zm0-11a2 2 0 1 1-4 0v-3a2 2 0 1 1 4 0v3z"/><g transform="rotate(30 -8.776 48.352)"><path fill="#E1DBF1" fill-rule="nonzero" d="M31.021 27.176l-1.732-3 4.365-7.561c2.01-3.48 2.455-6.572 1.81-9.285a9.09 9.09 0 0 0-.962-2.446c-.231-.4-.419-.655-.508-.756L25.85 18.222l-1.735-3.006 7.38-12.782c1.164-2.016 3.6-2.128 4.842-.18.205.25.472.628.761 1.129.542.937.99 2.024 1.283 3.252.823 3.457.264 7.335-2.13 11.48l-5.231 9.06zm-6.905 11.96L20.55 45.31l-10.357-5.98 7.018-12.155 1.733 3.002-4.653 8.055 5.161 2.98 2.932-5.077 1.732 3z"/><path fill="#6B4FBB" d="M8.282 54.601a8.96 8.96 0 1 1 8.96-15.519 8.96 8.96 0 0 1-8.96 15.52zm2.24-3.88a4.48 4.48 0 1 0 4.48-7.759 4.48 4.48 0 0 0-4.48 7.76z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M33.94 38.233L14.239 4.128c-.09.1-.277.357-.508.756a9.09 9.09 0 0 0-.962 2.446c-.646 2.713-.2 5.805 1.81 9.285l14.201 24.598 5.162-2.98zM11.134 3.383c.289-.501.555-.879.761-1.13 1.241-1.947 3.678-1.835 4.843.181l21.302 36.897-10.358 5.98L11.98 18.115c-2.393-4.145-2.952-8.023-2.13-11.48a12.075 12.075 0 0 1 1.284-3.252z"/><circle cx="24.39" cy="27.383" r="2.24" fill="#6B4FBB" transform="scale(-1 1) rotate(30 0 -63.642)"/><path fill="#6B4FBB" d="M39.95 54.602a8.96 8.96 0 1 1-8.96-15.52 8.96 8.96 0 0 1 8.96 15.52zm-2.24-3.88a4.48 4.48 0 1 0-4.48-7.76 4.48 4.48 0 0 0 4.48 7.76z"/></g></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/prometheus-graphs_empty.svg b/app/assets/images/illustrations/prometheus-graphs_empty.svg
new file mode 100644
index 00000000000..0ef198f59cd
--- /dev/null
+++ b/app/assets/images/illustrations/prometheus-graphs_empty.svg
@@ -0,0 +1 @@
+<svg width="430" height="267" viewBox="0 0 430 267" xmlns="http://www.w3.org/2000/svg"><title>prometheus-graphs_empty</title><g fill="none" fill-rule="evenodd"><path d="M187 43a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm15.769 2.457a2 2 0 0 1 2.883-2.772A11.964 11.964 0 0 1 335 51v.39a2 2 0 0 1-4 0V51a7.965 7.965 0 0 0-2.231-5.543zm2.225 159.857a2 2 0 0 1 3.997.154 11.973 11.973 0 0 1-4.02 8.503 2 2 0 0 1-2.658-2.99 7.974 7.974 0 0 0 2.681-5.667zM320.218 213a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zM89 155.827a2 2 0 1 1-4 0v-8a2 2 0 0 1 4 0v8zm0-18a2 2 0 1 1-4 0v-8a2 2 0 0 1 4 0v8z" fill="#EEE" fill-rule="nonzero"/><path d="M175.116 125.116A10.002 10.002 0 0 1 166 131H54c-5.523 0-10-4.477-10-10V31a10 10 0 0 1 5.884-9.116A9.964 9.964 0 0 0 49 26v90c0 5.523 4.477 10 10 10h112c1.467 0 2.86-.316 4.116-.884z" fill="#F9F9F9"/><path d="M59 20a6 6 0 0 0-6 6v90a6 6 0 0 0 6 6h112a6 6 0 0 0 6-6V26a6 6 0 0 0-6-6H59zm0-4h112c5.523 0 10 4.477 10 10v90c0 5.523-4.477 10-10 10H59c-5.523 0-10-4.477-10-10V26c0-5.523 4.477-10 10-10z" fill="#EEE" fill-rule="nonzero"/><path d="M73 58h4a3 3 0 0 1 3 3v45H70V61a3 3 0 0 1 3-3z" fill="#EFEDF8"/><path d="M93 70h4a3 3 0 0 1 3 3v33H90V73a3 3 0 0 1 3-3z" fill="#E1DBF1"/><path d="M153 70h4a3 3 0 0 1 3 3v33h-10V73a3 3 0 0 1 3-3z" fill="#C3B8E3"/><path d="M133 89h4a3 3 0 0 1 3 3v14h-10V92a3 3 0 0 1 3-3z" fill="#EFEDF8"/><path d="M113 46h4a3 3 0 0 1 3 3v57h-10V49a3 3 0 0 1 3-3z" fill="#6B4FBB"/><path d="M385.4 191.418A10.004 10.004 0 0 1 376 198H221c-5.523 0-10-4.477-10-10V74a9.992 9.992 0 0 1 4.6-8.418A9.981 9.981 0 0 0 215 69v114c0 5.523 4.477 10 10 10h155c1.99 0 3.843-.58 5.4-1.582z" fill="#F9F9F9" opacity=".99"/><path d="M225 63a6 6 0 0 0-6 6v114a6 6 0 0 0 6 6h155a6 6 0 0 0 6-6V69a6 6 0 0 0-6-6H225zm0-4h155c5.523 0 10 4.477 10 10v114c0 5.523-4.477 10-10 10H225c-5.523 0-10-4.477-10-10V69c0-5.523 4.477-10 10-10z" fill="#EEE" fill-rule="nonzero"/><g transform="translate(238 92)"><path d="M44.584 31.917L28.808 49.434a2 2 0 0 1-2.695.255L3.791 32.749a2 2 0 0 1 2.418-3.186l20.858 15.828 15.966-17.73a2 2 0 0 1 2.912-.064l16.09 16.344L77.35.058c.641-1.838 3.263-1.77 3.808.098l19.827 67.92 22.3-37.106a2 2 0 0 1 3.43 2.06l-24.656 41.024c-.898 1.494-3.145 1.204-3.634-.47L79.07 7.273l-14.315 41.02a2 2 0 0 1-3.314.745L44.584 31.917z" fill="#FEF0E8" fill-rule="nonzero"/><circle fill="#FEE1D3" cx="100" cy="71" r="4"/><circle fill="#FDC4A8" cx="44" cy="30" r="4"/><circle stroke="#FC6D26" stroke-width="4" fill="#FFF" cx="5" cy="32" r="5"/><circle stroke="#FC6D26" stroke-width="4" fill="#FFF" cx="125" cy="32" r="5"/></g><path d="M80.41 166.41C72.69 175.07 68 186.486 68 199c0 27.062 21.938 49 49 49 12.513 0 23.93-4.69 32.59-12.41C140.618 245.66 127.55 252 113 252c-27.062 0-49-21.938-49-49 0-14.549 6.34-27.617 16.41-36.59z" fill="#F9F9F9"/><path d="M117 244c24.853 0 45-20.147 45-45s-20.147-45-45-45-45 20.147-45 45 20.147 45 45 45zm0 4c-27.062 0-49-21.938-49-49s21.938-49 49-49 49 21.938 49 49-21.938 49-49 49z" fill="#EEE" fill-rule="nonzero"/><path d="M117 223c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24zm0-12c6.627 0 12-5.373 12-12s-5.373-12-12-12-12 5.373-12 12 5.373 12 12 12z" fill="#FEF0E8"/><path d="M117 175c13.255 0 24 10.745 24 24 0 .674-.028 1.34-.082 2h-12.084c.11-.65.166-1.319.166-2 0-6.627-5.373-12-12-12v-12z" fill="#FDC4A8"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/web-ide_promotion.svg b/app/assets/images/illustrations/web-ide_promotion.svg
new file mode 100644
index 00000000000..ef61348057d
--- /dev/null
+++ b/app/assets/images/illustrations/web-ide_promotion.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="114" height="88" viewBox="0 0 114 88"><g fill="none" fill-rule="evenodd"><rect width="110" height="80" x="2" y="8" fill="#F9F9F9" rx="10"/><path fill="#FFF" d="M12 2h90c5.523 0 10 4.477 10 10v60c0 5.523-4.477 10-10 10H12C6.477 82 2 77.523 2 72V12C2 6.477 6.477 2 12 2z"/><path fill="#EEE" fill-rule="nonzero" d="M33 4v4.255A6.968 6.968 0 0 1 37 7h19a6.98 6.98 0 0 1 4.899 2H75a7 7 0 0 1 7 7v2h28v-6a8 8 0 0 0-8-8H33zm-3 0H12a8 8 0 0 0-8 8v60a8 8 0 0 0 8 8h18V4zm48 14v-2a3 3 0 0 0-3-3H62.93c.046.327.07.66.07 1v4h15zM12 0h90c6.627 0 12 5.373 12 12v60c0 6.627-5.373 12-12 12H12C5.373 84 0 78.627 0 72V12C0 5.373 5.373 0 12 0zm98 22H61a2 2 0 0 1-2-2v-6a3 3 0 0 0-3-3H37a3 3 0 0 0-3 3v66h68a8 8 0 0 0 8-8V22z"/><path fill="#EFEDF8" d="M52 36h40a2 2 0 1 1 0 4H52a2 2 0 1 1 0-4z"/><path fill="#E1DBF2" d="M52 46h30a2 2 0 1 1 0 4H52a2 2 0 1 1 0-4z"/><path fill="#EFEDF8" d="M52 56h40a2 2 0 1 1 0 4H52a2 2 0 1 1 0-4z"/><path fill="#E1DBF2" d="M52 66h30a2 2 0 1 1 0 4H52a2 2 0 1 1 0-4zM10 16h14a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4zm0 10h10a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4z"/><path fill="#EFEDF8" d="M10 36h14a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4z"/><path fill="#6B4FBB" d="M10 46h10a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4z"/><path fill="#E1DBF2" d="M10 56h14a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4z"/><path fill="#EFEDF8" d="M10 66h10a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/javascripts/behaviors/quick_submit.js b/app/assets/javascripts/behaviors/quick_submit.js
index 312edc0cd69..51bd5b8ebe5 100644
--- a/app/assets/javascripts/behaviors/quick_submit.js
+++ b/app/assets/javascripts/behaviors/quick_submit.js
@@ -72,5 +72,5 @@ $(document).on('keyup.quick_submit', '.js-quick-submit input[type=submit], .js-q
title,
trigger: 'manual',
});
- $this.tooltip('show').one('blur', () => $this.tooltip('hide'));
+ $this.tooltip('show').one('blur click', () => $this.tooltip('hide'));
});
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index 27136c7289f..f8dcdf3f60a 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -186,7 +186,7 @@
<clipboard-button
:text="ingressExternalIp"
:title="s__('ClusterIntegration|Copy Ingress IP Address to clipboard')"
- css-class="btn btn-default js-clipboard-btn"
+ class="js-clipboard-btn"
/>
</span>
</div>
diff --git a/app/assets/javascripts/commons/vue.js b/app/assets/javascripts/commons/vue.js
index 8b62d78c043..798623b94fb 100644
--- a/app/assets/javascripts/commons/vue.js
+++ b/app/assets/javascripts/commons/vue.js
@@ -1,4 +1,5 @@
import Vue from 'vue';
+import '../vue_shared/vue_resource_interceptor';
if (process.env.NODE_ENV !== 'production') {
Vue.config.productionTip = false;
diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js
index 35094f8e73b..523bd2adb93 100644
--- a/app/assets/javascripts/importer_status.js
+++ b/app/assets/javascripts/importer_status.js
@@ -1,11 +1,14 @@
-import { __ } from './locale';
+import _ from 'underscore';
+import { __, sprintf } from './locale';
import axios from './lib/utils/axios_utils';
import flash from './flash';
+import { convertPermissionToBoolean } from './lib/utils/common_utils';
class ImporterStatus {
- constructor(jobsUrl, importUrl) {
+ constructor({ jobsUrl, importUrl, ciCdOnly }) {
this.jobsUrl = jobsUrl;
this.importUrl = importUrl;
+ this.ciCdOnly = ciCdOnly;
this.initStatusPage();
this.setAutoUpdate();
}
@@ -45,6 +48,7 @@ class ImporterStatus {
repo_id: id,
target_namespace: targetNamespace,
new_name: newName,
+ ci_cd_only: this.ciCdOnly,
})
.then(({ data }) => {
const job = $(`tr#repo_${id}`);
@@ -54,7 +58,13 @@ class ImporterStatus {
$('table.import-jobs tbody').prepend(job);
job.addClass('active');
- job.find('.import-actions').html('<i class="fa fa-spinner fa-spin" aria-label="importing"></i> started');
+ 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(() => flash(__('An error occurred while importing project')));
}
@@ -71,13 +81,16 @@ class ImporterStatus {
switch (job.import_status) {
case 'finished':
jobItem.removeClass('active').addClass('success');
- statusField.html('<span><i class="fa fa-check"></i> done</span>');
+ statusField.html(`<span><i class="fa fa-check"></i> ${__('Done')}</span>`);
break;
case 'scheduled':
- statusField.html(`${spinner} scheduled`);
+ statusField.html(`${spinner} ${__('Scheduled')}`);
break;
case 'started':
- statusField.html(`${spinner} started`);
+ statusField.html(`${spinner} ${__('Started')}`);
+ break;
+ case 'failed':
+ statusField.html(__('Failed'));
break;
default:
statusField.html(job.import_status);
@@ -98,7 +111,11 @@ function initImporterStatus() {
if (importerStatus) {
const data = importerStatus.dataset;
- return new ImporterStatus(data.jobsImportPath, data.importPath);
+ return new ImporterStatus({
+ jobsUrl: data.jobsImportPath,
+ importUrl: data.importPath,
+ ciCdOnly: convertPermissionToBoolean(data.ciCdOnly),
+ });
}
}
diff --git a/app/assets/javascripts/notes/components/diff_file_header.vue b/app/assets/javascripts/notes/components/diff_file_header.vue
index fe5baa3537f..3bcde17f07c 100644
--- a/app/assets/javascripts/notes/components/diff_file_header.vue
+++ b/app/assets/javascripts/notes/components/diff_file_header.vue
@@ -35,6 +35,7 @@
<clipboard-button
title="Copy file path to clipboard"
:text="diffFile.submoduleLink"
+ css-class="btn-default btn-transparent btn-clipboard"
/>
</span>
</div>
@@ -79,6 +80,7 @@
<clipboard-button
title="Copy file path to clipboard"
:text="diffFile.filePath"
+ css-class="btn-default btn-transparent btn-clipboard"
/>
<small
diff --git a/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue b/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue
new file mode 100644
index 00000000000..22248418c41
--- /dev/null
+++ b/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue
@@ -0,0 +1,64 @@
+<script>
+ 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,
+ },
+ props: {
+ milestoneTitle: {
+ type: String,
+ required: true,
+ },
+ url: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ title() {
+ return sprintf(s__('Milestones|Promote %{milestoneTitle} to group milestone?'), { milestoneTitle: this.milestoneTitle });
+ },
+ text() {
+ return s__(`Milestones|Promoting this milestone will make it available for all projects inside the group.
+ Existing project milestones with the same title will be merged.
+ This action cannot be reversed.`);
+ },
+ },
+ methods: {
+ onSubmit() {
+ eventHub.$emit('promoteMilestoneModal.requestStarted', this.url);
+ return axios.post(this.url, { params: { format: 'json' } })
+ .then((response) => {
+ eventHub.$emit('promoteMilestoneModal.requestFinished', { milestoneUrl: this.url, successful: true });
+ visitUrl(response.data.url);
+ })
+ .catch((error) => {
+ eventHub.$emit('promoteMilestoneModal.requestFinished', { milestoneUrl: this.url, successful: false });
+ createFlash(error);
+ });
+ },
+ },
+ };
+</script>
+<template>
+ <gl-modal
+ id="promote-milestone-modal"
+ footer-primary-button-variant="warning"
+ :footer-primary-button-text="s__('Milestones|Promote Milestone')"
+ @submit="onSubmit"
+ >
+ <template
+ slot="title"
+ >
+ {{ title }}
+ </template>
+ {{ text }}
+ </gl-modal>
+</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
new file mode 100644
index 00000000000..d51b5c221e3
--- /dev/null
+++ b/app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js
@@ -0,0 +1,84 @@
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
+import deleteMilestoneModal from './components/delete_milestone_modal.vue';
+import eventHub from './event_hub';
+
+export default () => {
+ Vue.use(Translate);
+
+ const onRequestFinished = ({ milestoneUrl, successful }) => {
+ const button = document.querySelector(`.js-delete-milestone-button[data-milestone-url="${milestoneUrl}"]`);
+
+ if (!successful) {
+ button.removeAttribute('disabled');
+ }
+
+ button.querySelector('.js-loading-icon').classList.add('hidden');
+ };
+
+ 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 button = event.currentTarget;
+ const modalProps = {
+ milestoneId: parseInt(button.dataset.milestoneId, 10),
+ milestoneTitle: button.dataset.milestoneTitle,
+ milestoneUrl: button.dataset.milestoneUrl,
+ issueCount: parseInt(button.dataset.milestoneIssueCount, 10),
+ mergeRequestCount: parseInt(button.dataset.milestoneMergeRequestCount, 10),
+ };
+ eventHub.$once('deleteMilestoneModal.requestStarted', onRequestStarted);
+ eventHub.$emit('deleteMilestoneModal.props', modalProps);
+ };
+
+ const deleteMilestoneButtons = document.querySelectorAll('.js-delete-milestone-button');
+ deleteMilestoneButtons.forEach((button) => {
+ button.addEventListener('click', onDeleteButtonClick);
+ });
+
+ eventHub.$once('deleteMilestoneModal.mounted', () => {
+ deleteMilestoneButtons.forEach((button) => {
+ button.removeAttribute('disabled');
+ });
+ });
+
+ return new Vue({
+ el: '#delete-milestone-modal',
+ components: {
+ deleteMilestoneModal,
+ },
+ data() {
+ return {
+ modalProps: {
+ milestoneId: -1,
+ milestoneTitle: '',
+ milestoneUrl: '',
+ issueCount: -1,
+ mergeRequestCount: -1,
+ },
+ };
+ },
+ mounted() {
+ eventHub.$on('deleteMilestoneModal.props', this.setModalProps);
+ eventHub.$emit('deleteMilestoneModal.mounted');
+ },
+ beforeDestroy() {
+ eventHub.$off('deleteMilestoneModal.props', this.setModalProps);
+ },
+ methods: {
+ setModalProps(modalProps) {
+ this.modalProps = modalProps;
+ },
+ },
+ render(createElement) {
+ return createElement(deleteMilestoneModal, {
+ props: this.modalProps,
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/pages/milestones/shared/index.js b/app/assets/javascripts/pages/milestones/shared/index.js
index 327e2cf569c..dabfe32848b 100644
--- a/app/assets/javascripts/pages/milestones/shared/index.js
+++ b/app/assets/javascripts/pages/milestones/shared/index.js
@@ -1,88 +1,7 @@
-import Vue from 'vue';
-
-import Translate from '~/vue_shared/translate';
-
-import deleteMilestoneModal from './components/delete_milestone_modal.vue';
-import eventHub from './event_hub';
+import initDeleteMilestoneModal from './delete_milestone_modal_init';
+import initPromoteMilestoneModal from './promote_milestone_modal_init';
export default () => {
- Vue.use(Translate);
-
- const onRequestFinished = ({ milestoneUrl, successful }) => {
- const button = document.querySelector(`.js-delete-milestone-button[data-milestone-url="${milestoneUrl}"]`);
-
- if (!successful) {
- button.removeAttribute('disabled');
- }
-
- button.querySelector('.js-loading-icon').classList.add('hidden');
- };
-
- 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 button = event.currentTarget;
- const modalProps = {
- milestoneId: parseInt(button.dataset.milestoneId, 10),
- milestoneTitle: button.dataset.milestoneTitle,
- milestoneUrl: button.dataset.milestoneUrl,
- issueCount: parseInt(button.dataset.milestoneIssueCount, 10),
- mergeRequestCount: parseInt(button.dataset.milestoneMergeRequestCount, 10),
- };
- eventHub.$once('deleteMilestoneModal.requestStarted', onRequestStarted);
- eventHub.$emit('deleteMilestoneModal.props', modalProps);
- };
-
- const deleteMilestoneButtons = document.querySelectorAll('.js-delete-milestone-button');
- for (let i = 0; i < deleteMilestoneButtons.length; i += 1) {
- const button = deleteMilestoneButtons[i];
- button.addEventListener('click', onDeleteButtonClick);
- }
-
- eventHub.$once('deleteMilestoneModal.mounted', () => {
- for (let i = 0; i < deleteMilestoneButtons.length; i += 1) {
- const button = deleteMilestoneButtons[i];
- button.removeAttribute('disabled');
- }
- });
-
- return new Vue({
- el: '#delete-milestone-modal',
- components: {
- deleteMilestoneModal,
- },
- data() {
- return {
- modalProps: {
- milestoneId: -1,
- milestoneTitle: '',
- milestoneUrl: '',
- issueCount: -1,
- mergeRequestCount: -1,
- },
- };
- },
- mounted() {
- eventHub.$on('deleteMilestoneModal.props', this.setModalProps);
- eventHub.$emit('deleteMilestoneModal.mounted');
- },
- beforeDestroy() {
- eventHub.$off('deleteMilestoneModal.props', this.setModalProps);
- },
- methods: {
- setModalProps(modalProps) {
- this.modalProps = modalProps;
- },
- },
- render(createElement) {
- return createElement(deleteMilestoneModal, {
- props: this.modalProps,
- });
- },
- });
+ initDeleteMilestoneModal();
+ initPromoteMilestoneModal();
};
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
new file mode 100644
index 00000000000..d00f81c9094
--- /dev/null
+++ b/app/assets/javascripts/pages/milestones/shared/promote_milestone_modal_init.js
@@ -0,0 +1,82 @@
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
+import PromoteMilestoneModal from './components/promote_milestone_modal.vue';
+import eventHub from './event_hub';
+
+Vue.use(Translate);
+
+export default () => {
+ const onRequestFinished = ({ milestoneUrl, successful }) => {
+ 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}"]`);
+ button.setAttribute('disabled', '');
+ eventHub.$once('promoteMilestoneModal.requestFinished', onRequestFinished);
+ };
+
+ const onDeleteButtonClick = (event) => {
+ const button = event.currentTarget;
+ const modalProps = {
+ milestoneTitle: button.dataset.milestoneTitle,
+ url: button.dataset.url,
+ };
+ eventHub.$once('promoteMilestoneModal.requestStarted', onRequestStarted);
+ eventHub.$emit('promoteMilestoneModal.props', modalProps);
+ };
+
+ const promoteMilestoneButtons = document.querySelectorAll('.js-promote-project-milestone-button');
+ promoteMilestoneButtons.forEach((button) => {
+ button.addEventListener('click', onDeleteButtonClick);
+ });
+
+ eventHub.$once('promoteMilestoneModal.mounted', () => {
+ promoteMilestoneButtons.forEach((button) => {
+ button.removeAttribute('disabled');
+ });
+ });
+
+ const promoteMilestoneModal = document.getElementById('promote-milestone-modal');
+ let promoteMilestoneComponent;
+
+ if (promoteMilestoneModal) {
+ promoteMilestoneComponent = new Vue({
+ el: promoteMilestoneModal,
+ components: {
+ PromoteMilestoneModal,
+ },
+ data() {
+ return {
+ modalProps: {
+ milestoneTitle: '',
+ url: '',
+ },
+ };
+ },
+ mounted() {
+ eventHub.$on('promoteMilestoneModal.props', this.setModalProps);
+ eventHub.$emit('promoteMilestoneModal.mounted');
+ },
+ beforeDestroy() {
+ eventHub.$off('promoteMilestoneModal.props', this.setModalProps);
+ },
+ methods: {
+ setModalProps(modalProps) {
+ this.modalProps = modalProps;
+ },
+ },
+ render(createElement) {
+ return createElement('promote-milestone-modal', {
+ props: this.modalProps,
+ });
+ },
+ });
+ }
+
+ return promoteMilestoneComponent;
+};
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
new file mode 100644
index 00000000000..54695dfeb99
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue
@@ -0,0 +1,79 @@
+<script>
+ 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,
+ },
+ props: {
+ url: {
+ type: String,
+ required: true,
+ },
+ labelTitle: {
+ type: String,
+ required: true,
+ },
+ labelColor: {
+ type: String,
+ required: true,
+ },
+ labelTextColor: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ text() {
+ return s__(`Milestones|Promoting this label will make it available for all projects inside the group.
+ Existing project labels with the same title will be merged. This action cannot be reversed.`);
+ },
+ title() {
+ const label = `<span
+ class="label color-label"
+ style="background-color: ${this.labelColor}; color: ${this.labelTextColor};"
+ >${this.labelTitle}</span>`;
+
+ return sprintf(s__('Labels|Promote label %{labelTitle} to Group Label?'), {
+ labelTitle: label,
+ }, 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);
+ });
+ },
+ },
+ };
+</script>
+<template>
+ <gl-modal
+ id="promote-label-modal"
+ footer-primary-button-variant="warning"
+ :footer-primary-button-text="s__('Labels|Promote Label')"
+ @submit="onSubmit"
+ >
+ <div
+ slot="title"
+ v-html="title"
+ >
+ {{ title }}
+ </div>
+
+ {{ text }}
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/pages/projects/labels/event_hub.js b/app/assets/javascripts/pages/projects/labels/event_hub.js
new file mode 100644
index 00000000000..0948c2e5352
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/labels/event_hub.js
@@ -0,0 +1,3 @@
+import Vue from 'vue';
+
+export default new Vue();
diff --git a/app/assets/javascripts/pages/projects/labels/index/index.js b/app/assets/javascripts/pages/projects/labels/index/index.js
index 6e45de2a724..2abcbfab1ed 100644
--- a/app/assets/javascripts/pages/projects/labels/index/index.js
+++ b/app/assets/javascripts/pages/projects/labels/index/index.js
@@ -1,3 +1,91 @@
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
import initLabels from '~/init_labels';
+import eventHub from '../event_hub';
+import PromoteLabelModal from '../components/promote_label_modal.vue';
-document.addEventListener('DOMContentLoaded', initLabels);
+Vue.use(Translate);
+
+const initLabelIndex = () => {
+ initLabels();
+
+ const onRequestFinished = ({ labelUrl, successful }) => {
+ 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}"]`);
+ button.setAttribute('disabled', '');
+ eventHub.$once('promoteLabelModal.requestFinished', onRequestFinished);
+ };
+
+ const onDeleteButtonClick = (event) => {
+ const button = event.currentTarget;
+ const modalProps = {
+ labelTitle: button.dataset.labelTitle,
+ labelColor: button.dataset.labelColor,
+ labelTextColor: button.dataset.labelTextColor,
+ url: button.dataset.url,
+ };
+ eventHub.$once('promoteLabelModal.requestStarted', onRequestStarted);
+ eventHub.$emit('promoteLabelModal.props', modalProps);
+ };
+
+ const promoteLabelButtons = document.querySelectorAll('.js-promote-project-label-button');
+ promoteLabelButtons.forEach((button) => {
+ button.addEventListener('click', onDeleteButtonClick);
+ });
+
+ eventHub.$once('promoteLabelModal.mounted', () => {
+ promoteLabelButtons.forEach((button) => {
+ button.removeAttribute('disabled');
+ });
+ });
+
+ const promoteLabelModal = document.getElementById('promote-label-modal');
+ let promoteLabelModalComponent;
+
+ if (promoteLabelModal) {
+ promoteLabelModalComponent = new Vue({
+ el: promoteLabelModal,
+ components: {
+ PromoteLabelModal,
+ },
+ data() {
+ return {
+ modalProps: {
+ labelTitle: '',
+ labelColor: '',
+ labelTextColor: '',
+ url: '',
+ },
+ };
+ },
+ mounted() {
+ eventHub.$on('promoteLabelModal.props', this.setModalProps);
+ eventHub.$emit('promoteLabelModal.mounted');
+ },
+ beforeDestroy() {
+ eventHub.$off('promoteLabelModal.props', this.setModalProps);
+ },
+ methods: {
+ setModalProps(modalProps) {
+ this.modalProps = modalProps;
+ },
+ },
+ render(createElement) {
+ return createElement('promote-label-modal', {
+ props: this.modalProps,
+ });
+ },
+ });
+ }
+
+ return promoteLabelModalComponent;
+};
+
+document.addEventListener('DOMContentLoaded', initLabelIndex);
diff --git a/app/assets/javascripts/pipelines/components/nav_controls.vue b/app/assets/javascripts/pipelines/components/nav_controls.vue
index 383ab51fe56..eba5678e3e5 100644
--- a/app/assets/javascripts/pipelines/components/nav_controls.vue
+++ b/app/assets/javascripts/pipelines/components/nav_controls.vue
@@ -1,6 +1,11 @@
<script>
+ import LoadingButton from '../../vue_shared/components/loading_button.vue';
+
export default {
name: 'PipelineNavControls',
+ components: {
+ LoadingButton,
+ },
props: {
newPipelinePath: {
type: String,
@@ -19,6 +24,17 @@
required: false,
default: null,
},
+
+ isResetCacheButtonLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ methods: {
+ onClickResetCache() {
+ this.$emit('resetRunnersCache', this.resetCachePath);
+ },
},
};
</script>
@@ -32,14 +48,13 @@
{{ s__('Pipelines|Run Pipeline') }}
</a>
- <a
+ <loading-button
v-if="resetCachePath"
- data-method="post"
- :href="resetCachePath"
+ @click="onClickResetCache"
+ :loading="isResetCacheButtonLoading"
class="btn btn-default js-clear-cache"
- >
- {{ s__('Pipelines|Clear Runner Caches') }}
- </a>
+ :label="s__('Pipelines|Clear Runner Caches')"
+ />
<a
v-if="ciLintPath"
diff --git a/app/assets/javascripts/pipelines/components/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines.vue
index 6e5ee68eeb1..e0a7284124d 100644
--- a/app/assets/javascripts/pipelines/components/pipelines.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines.vue
@@ -1,6 +1,7 @@
<script>
import _ from 'underscore';
import { __, sprintf, s__ } from '../../locale';
+ import createFlash from '../../flash';
import PipelinesService from '../services/pipelines_service';
import pipelinesMixin from '../mixins/pipelines';
import TablePagination from '../../vue_shared/components/table_pagination.vue';
@@ -92,6 +93,7 @@
scope: getParameterByName('scope') || 'all',
page: getParameterByName('page') || '1',
requestData: {},
+ isResetCacheButtonLoading: false,
};
},
stateMap: {
@@ -265,6 +267,23 @@
this.poll.restart({ data: this.requestData });
});
},
+
+ handleResetRunnersCache(endpoint) {
+ this.isResetCacheButtonLoading = true;
+
+ this.service.postAction(endpoint)
+ .then(() => {
+ this.isResetCacheButtonLoading = false;
+ createFlash(
+ s__('Pipelines|Project cache successfully reset.'),
+ 'notice',
+ );
+ })
+ .catch(() => {
+ this.isResetCacheButtonLoading = false;
+ createFlash(s__('Pipelines|Something went wrong while cleaning runners cache.'));
+ });
+ },
},
};
</script>
@@ -301,6 +320,8 @@
:new-pipeline-path="newPipelinePath"
:reset-cache-path="resetCachePath"
:ci-lint-path="ciLintPath"
+ @resetRunnersCache="handleResetRunnersCache"
+ :is-reset-cache-button-loading="isResetCacheButtonLoading"
/>
</div>
diff --git a/app/assets/javascripts/pipelines/mixins/pipelines.js b/app/assets/javascripts/pipelines/mixins/pipelines.js
index 9fcc07abee5..522a4277bd7 100644
--- a/app/assets/javascripts/pipelines/mixins/pipelines.js
+++ b/app/assets/javascripts/pipelines/mixins/pipelines.js
@@ -51,12 +51,10 @@ export default {
}
});
- eventHub.$on('refreshPipelines', this.fetchPipelines);
eventHub.$on('postAction', this.postAction);
},
beforeDestroy() {
- eventHub.$off('refreshPipelines');
- eventHub.$on('postAction', this.postAction);
+ eventHub.$off('postAction', this.postAction);
},
destroyed() {
this.poll.stop();
@@ -92,7 +90,7 @@ export default {
},
postAction(endpoint) {
this.service.postAction(endpoint)
- .then(() => eventHub.$emit('refreshPipelines'))
+ .then(() => this.fetchPipelines())
.catch(() => Flash(__('An error occurred while making the request.')));
},
},
diff --git a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
index e8126ac573d..03bb281395a 100644
--- a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
+++ b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
@@ -1,3 +1,5 @@
+import _ from 'underscore';
+import { s__, n__, sprintf } from '~/locale';
import axios from '../lib/utils/axios_utils';
import PANEL_STATE from './constants';
import { backOff } from '../lib/utils/common_utils';
@@ -20,6 +22,7 @@ export default class PrometheusMetrics {
this.$missingEnvVarMetricsList = this.$missingEnvVarPanel.find('.js-missing-var-metrics-list');
this.activeMetricsEndpoint = this.$monitoredMetricsPanel.data('activeMetrics');
+ this.helpMetricsPath = this.$monitoredMetricsPanel.data('metrics-help-path');
this.$panelToggle.on('click', e => this.handlePanelToggle(e));
}
@@ -59,23 +62,39 @@ export default class PrometheusMetrics {
populateActiveMetrics(metrics) {
let totalMonitoredMetrics = 0;
let totalMissingEnvVarMetrics = 0;
+ let totalExporters = 0;
metrics.forEach((metric) => {
- this.$monitoredMetricsList.append(`<li>${metric.group}<span class="badge">${metric.active_metrics}</span></li>`);
- totalMonitoredMetrics += metric.active_metrics;
- if (metric.metrics_missing_requirements > 0) {
- this.$missingEnvVarMetricsList.append(`<li>${metric.group}</li>`);
- totalMissingEnvVarMetrics += 1;
+ if (metric.active_metrics > 0) {
+ totalExporters += 1;
+ 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>`);
+ totalMissingEnvVarMetrics += 1;
+ }
}
});
- this.$monitoredMetricsCount.text(totalMonitoredMetrics);
- this.showMonitoringMetricsPanelState(PANEL_STATE.LIST);
+ 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);
+ 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),
+ });
+ this.$monitoredMetricsCount.text(metricsCountText);
+ this.showMonitoringMetricsPanelState(PANEL_STATE.LIST);
- if (totalMissingEnvVarMetrics > 0) {
- this.$missingEnvVarPanel.removeClass('hidden');
- this.$missingEnvVarPanel.find('.flash-container').off('click');
- this.$missingEnvVarMetricCount.text(totalMissingEnvVarMetrics);
+ if (totalMissingEnvVarMetrics > 0) {
+ this.$missingEnvVarPanel.removeClass('hidden');
+ this.$missingEnvVarMetricCount.text(totalMissingEnvVarMetrics);
+ }
}
}
@@ -97,15 +116,15 @@ export default class PrometheusMetrics {
})
.catch(stop);
})
- .then((res) => {
- if (res && res.data && res.data.length) {
- this.populateActiveMetrics(res.data);
- } else {
+ .then((res) => {
+ if (res && res.data && res.data.length) {
+ this.populateActiveMetrics(res.data);
+ } else {
+ this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
+ }
+ })
+ .catch(() => {
this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
- }
- })
- .catch(() => {
- this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
- });
+ });
}
}
diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue
index b4906ba4ee5..a03180e80e6 100644
--- a/app/assets/javascripts/registry/components/collapsible_container.vue
+++ b/app/assets/javascripts/registry/components/collapsible_container.vue
@@ -86,6 +86,7 @@
v-if="repo.location"
:text="clipboardText"
:title="repo.location"
+ css-class="btn-default btn-transparent btn-clipboard"
/>
<div class="controls hidden-xs pull-right">
diff --git a/app/assets/javascripts/registry/components/table_registry.vue b/app/assets/javascripts/registry/components/table_registry.vue
index bef850eddc0..ee4eb3581f3 100644
--- a/app/assets/javascripts/registry/components/table_registry.vue
+++ b/app/assets/javascripts/registry/components/table_registry.vue
@@ -90,6 +90,7 @@
v-if="item.location"
:title="item.location"
:text="clipboardText(item.location)"
+ css-class="btn-default btn-transparent btn-clipboard"
/>
</td>
<td>
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.js b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
index 8269fe1281d..b58e04b5e60 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.js
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
@@ -1,3 +1,4 @@
+<script>
import Flash from '../../../flash';
import AssigneeTitle from './assignee_title';
import Assignees from './assignees.vue';
@@ -6,11 +7,9 @@ import eventHub from '../../event_hub';
export default {
name: 'SidebarAssignees',
- data() {
- return {
- store: new Store(),
- loading: false,
- };
+ components: {
+ AssigneeTitle,
+ Assignees,
},
props: {
mediator: {
@@ -27,9 +26,28 @@ export default {
default: false,
},
},
- components: {
- AssigneeTitle,
- Assignees,
+ data() {
+ return {
+ store: new Store(),
+ loading: false,
+ };
+ },
+ created() {
+ this.removeAssignee = this.store.removeAssignee.bind(this.store);
+ this.addAssignee = this.store.addAssignee.bind(this.store);
+ this.removeAllAssignees = this.store.removeAllAssignees.bind(this.store);
+
+ // Get events from glDropdown
+ eventHub.$on('sidebar.removeAssignee', this.removeAssignee);
+ eventHub.$on('sidebar.addAssignee', this.addAssignee);
+ eventHub.$on('sidebar.removeAllAssignees', this.removeAllAssignees);
+ eventHub.$on('sidebar.saveAssignees', this.saveAssignees);
+ },
+ beforeDestroy() {
+ eventHub.$off('sidebar.removeAssignee', this.removeAssignee);
+ eventHub.$off('sidebar.addAssignee', this.addAssignee);
+ eventHub.$off('sidebar.removeAllAssignees', this.removeAllAssignees);
+ eventHub.$off('sidebar.saveAssignees', this.saveAssignees);
},
methods: {
assignSelf() {
@@ -54,39 +72,24 @@ export default {
});
},
},
- created() {
- this.removeAssignee = this.store.removeAssignee.bind(this.store);
- this.addAssignee = this.store.addAssignee.bind(this.store);
- this.removeAllAssignees = this.store.removeAllAssignees.bind(this.store);
-
- // Get events from glDropdown
- eventHub.$on('sidebar.removeAssignee', this.removeAssignee);
- eventHub.$on('sidebar.addAssignee', this.addAssignee);
- eventHub.$on('sidebar.removeAllAssignees', this.removeAllAssignees);
- eventHub.$on('sidebar.saveAssignees', this.saveAssignees);
- },
- beforeDestroy() {
- eventHub.$off('sidebar.removeAssignee', this.removeAssignee);
- eventHub.$off('sidebar.addAssignee', this.addAssignee);
- eventHub.$off('sidebar.removeAllAssignees', this.removeAllAssignees);
- eventHub.$off('sidebar.saveAssignees', this.saveAssignees);
- },
- template: `
- <div>
- <assignee-title
- :number-of-assignees="store.assignees.length"
- :loading="loading || store.isFetching.assignees"
- :editable="store.editable"
- :show-toggle="!signedIn"
- />
- <assignees
- v-if="!store.isFetching.assignees"
- class="value"
- :root-path="store.rootPath"
- :users="store.assignees"
- :editable="store.editable"
- @assign-self="assignSelf"
- />
- </div>
- `,
};
+</script>
+
+<template>
+ <div>
+ <assignee-title
+ :number-of-assignees="store.assignees.length"
+ :loading="loading || store.isFetching.assignees"
+ :editable="store.editable"
+ :show-toggle="!signedIn"
+ />
+ <assignees
+ v-if="!store.isFetching.assignees"
+ class="value"
+ :root-path="store.rootPath"
+ :users="store.assignees"
+ :editable="store.editable"
+ @assign-self="assignSelf"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index 56cc78ca0ca..ef748f18301 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking';
-import SidebarAssignees from './components/assignees/sidebar_assignees';
+import SidebarAssignees from './components/assignees/sidebar_assignees.vue';
import ConfidentialIssueSidebar from './components/confidential/confidential_issue_sidebar.vue';
import SidebarMoveIssue from './lib/sidebar_move_issue';
import LockIssueSidebar from './components/lock/lock_issue_sidebar.vue';
diff --git a/app/assets/javascripts/terminal/terminal.js b/app/assets/javascripts/terminal/terminal.js
index 6b9422b1816..904b0093f7b 100644
--- a/app/assets/javascripts/terminal/terminal.js
+++ b/app/assets/javascripts/terminal/terminal.js
@@ -6,8 +6,14 @@
constructor(options) {
this.options = options || {};
- this.options.cursorBlink = options.cursorBlink || true;
- this.options.screenKeys = options.screenKeys || true;
+ if (!Object.prototype.hasOwnProperty.call(this.options, 'cursorBlink')) {
+ this.options.cursorBlink = true;
+ }
+
+ if (!Object.prototype.hasOwnProperty.call(this.options, 'screenKeys')) {
+ this.options.screenKeys = true;
+ }
+
this.container = document.querySelector(options.selector);
this.setSocketUrl();
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js b/app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue
index 69e70ba1dd6..a16f9055a6d 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue
@@ -1,11 +1,15 @@
+<script>
import statusCodes from '../../lib/utils/http_status';
import { bytesToMiB } from '../../lib/utils/number_utils';
import { backOff } from '../../lib/utils/common_utils';
-import MemoryGraph from '../../vue_shared/components/memory_graph';
+import MemoryGraph from '../../vue_shared/components/memory_graph.vue';
import MRWidgetService from '../services/mr_widget_service';
export default {
name: 'MemoryUsage',
+ components: {
+ MemoryGraph,
+ },
props: {
metricsUrl: {
type: String,
@@ -28,9 +32,6 @@ export default {
backOffRequestCounter: 0,
};
},
- components: {
- 'mr-memory-graph': MemoryGraph,
- },
computed: {
shouldShowLoading() {
return this.loadingMetrics && !this.hasMetrics && !this.loadFailed;
@@ -57,6 +58,10 @@ export default {
return 'unchanged';
},
},
+ mounted() {
+ this.loadingMetrics = true;
+ this.loadMetrics();
+ },
methods: {
getMegabytes(bytesString) {
const valueInBytes = Number(bytesString).toFixed(2);
@@ -114,40 +119,42 @@ export default {
});
},
},
- mounted() {
- this.loadingMetrics = true;
- this.loadMetrics();
- },
- template: `
- <div class="mr-info-list clearfix mr-memory-usage js-mr-memory-usage">
- <p
- v-if="shouldShowLoading"
- class="usage-info js-usage-info usage-info-loading">
- <i
- class="fa fa-spinner fa-spin usage-info-load-spinner"
- aria-hidden="true" />Loading deployment statistics
- </p>
- <p
- v-if="shouldShowMemoryGraph"
- class="usage-info js-usage-info">
- <a :href="metricsMonitoringUrl">Memory</a> usage <b>{{memoryChangeType}}</b> from {{memoryFrom}}MB to {{memoryTo}}MB
- </p>
- <p
- v-if="shouldShowLoadFailure"
- class="usage-info js-usage-info usage-info-failed">
- Failed to load deployment statistics
- </p>
- <p
- v-if="shouldShowMetricsUnavailable"
- class="usage-info js-usage-info usage-info-unavailable">
- Deployment statistics are not available currently
- </p>
- <mr-memory-graph
- v-if="shouldShowMemoryGraph"
- :metrics="memoryMetrics"
- :deploymentTime="deploymentTime"
- height="25"
- width="100" />
- </div>
- `,
};
+</script>
+
+<template>
+ <div class="mr-info-list clearfix mr-memory-usage js-mr-memory-usage">
+ <p
+ v-if="shouldShowLoading"
+ class="usage-info js-usage-info usage-info-loading">
+ <i
+ class="fa fa-spinner fa-spin usage-info-load-spinner"
+ aria-hidden="true">
+ </i>Loading deployment statistics
+ </p>
+ <p
+ v-if="shouldShowMemoryGraph"
+ class="usage-info js-usage-info">
+ <a
+ :href="metricsMonitoringUrl"
+ >Memory</a> usage <b>{{ memoryChangeType }}</b> from {{ memoryFrom }}MB to {{ memoryTo }}MB
+ </p>
+ <p
+ v-if="shouldShowLoadFailure"
+ class="usage-info js-usage-info usage-info-failed">
+ Failed to load deployment statistics
+ </p>
+ <p
+ v-if="shouldShowMetricsUnavailable"
+ class="usage-info js-usage-info usage-info-unavailable">
+ Deployment statistics are not available currently
+ </p>
+ <memory-graph
+ v-if="shouldShowMemoryGraph"
+ :metrics="memoryMetrics"
+ :deployment-time="deploymentTime"
+ height="25"
+ width="100"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js
index d174a900f63..c7f992384c8 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js
@@ -1,7 +1,7 @@
import { getTimeago } from '~/lib/utils/datetime_utility';
import { visitUrl } from '../../lib/utils/url_utility';
import Flash from '../../flash';
-import MemoryUsage from './mr_widget_memory_usage';
+import MemoryUsage from './memory_usage.vue';
import StatusIcon from './mr_widget_status_icon.vue';
import MRWidgetService from '../services/mr_widget_service';
@@ -12,8 +12,8 @@ export default {
service: { type: Object, required: true },
},
components: {
- 'mr-widget-memory-usage': MemoryUsage,
- 'status-icon': StatusIcon,
+ MemoryUsage,
+ StatusIcon,
},
methods: {
formatDate(date) {
@@ -100,7 +100,7 @@ export default {
class="btn btn-default btn-xs">
Stop environment
</button>
- <mr-widget-memory-usage
+ <memory-usage
v-if="deployment.metrics_url"
:metrics-url="deployment.metrics_url"
:metrics-monitoring-url="deployment.metrics_monitoring_url"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
index 18a3787857d..3d886e7d628 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
@@ -67,6 +67,7 @@
<clipboard-button
:text="branchNameClipboardData"
:title="__('Copy branch name to clipboard')"
+ css-class="btn-default btn-transparent btn-clipboard"
/>
{{ s__("mrWidget|into") }}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue
new file mode 100644
index 00000000000..f0298f732ea
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue
@@ -0,0 +1,20 @@
+<script>
+ export default {
+ name: 'MRWidgetMaintainerEdit',
+ props: {
+ maintainerEditAllowed: {
+ type: Boolean,
+ default: false,
+ required: false,
+ },
+ },
+ };
+</script>
+
+<template>
+ <section class="mr-info-list mr-links">
+ <p v-if="maintainerEditAllowed">
+ {{ s__("mrWidget|Allows edits from maintainers") }}
+ </p>
+ </section>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
index edb3baa39e4..a1bc28873df 100644
--- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js
+++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
@@ -15,6 +15,7 @@ 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 WidgetDeployment } from './components/mr_widget_deployment';
+export { default as WidgetMaintainerEdit } from './components/mr_widget_maintainer_edit.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';
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
index 797f0f6ec0f..df3eb86f35c 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
@@ -6,6 +6,7 @@ import {
WidgetMergeHelp,
WidgetPipeline,
WidgetDeployment,
+ WidgetMaintainerEdit,
WidgetRelatedLinks,
MergedState,
ClosedState,
@@ -211,6 +212,7 @@ export default {
'mr-widget-merge-help': WidgetMergeHelp,
'mr-widget-pipeline': WidgetPipeline,
'mr-widget-deployment': WidgetDeployment,
+ 'mr-widget-maintainer-edit': WidgetMaintainerEdit,
'mr-widget-related-links': WidgetRelatedLinks,
'mr-widget-merged': MergedState,
'mr-widget-closed': ClosedState,
@@ -251,11 +253,12 @@ export default {
:is="componentName"
:mr="mr"
:service="service" />
+ <mr-widget-maintainer-edit
+ :maintainerEditAllowed="mr.maintainerEditAllowed" />
<mr-widget-related-links
v-if="shouldRenderRelatedLinks"
:state="mr.state"
- :related-links="mr.relatedLinks"
- />
+ :related-links="mr.relatedLinks" />
</div>
<div
class="mr-widget-footer"
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 9a750ce42bd..5d07bcf1bb9 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
@@ -76,6 +76,7 @@ export default class MergeRequestStore {
this.canBeMerged = data.can_be_merged || false;
this.isMergeAllowed = data.mergeable || false;
this.mergeOngoing = data.merge_ongoing;
+ this.maintainerEditAllowed = data.allow_maintainer_to_push;
// Cherry-pick and Revert actions related
this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false;
diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
index 3b6c2da1664..cab126a7eca 100644
--- a/app/assets/javascripts/vue_shared/components/clipboard_button.vue
+++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
@@ -31,7 +31,7 @@
cssClass: {
type: String,
required: false,
- default: 'btn btn-default btn-transparent btn-clipboard',
+ default: 'btn-default',
},
},
};
@@ -40,6 +40,7 @@
<template>
<button
type="button"
+ class="btn"
:class="cssClass"
:title="title"
:data-clipboard-text="text"
diff --git a/app/assets/javascripts/vue_shared/components/memory_graph.js b/app/assets/javascripts/vue_shared/components/memory_graph.vue
index f37ef1a5ca3..b07f6b07afe 100644
--- a/app/assets/javascripts/vue_shared/components/memory_graph.js
+++ b/app/assets/javascripts/vue_shared/components/memory_graph.vue
@@ -1,3 +1,4 @@
+<script>
import { getTimeago } from '../../lib/utils/datetime_utility';
export default {
@@ -22,6 +23,9 @@ export default {
return `Deployed ${deployedSince}`;
},
},
+ mounted() {
+ this.renderGraph(this.deploymentTime, this.metrics);
+ },
methods: {
/**
* Returns metric value index in metrics array
@@ -103,15 +107,27 @@ export default {
this.dotY = dotY;
},
},
- mounted() {
- this.renderGraph(this.deploymentTime, this.metrics);
- },
- template: `
- <div class="memory-graph-container">
- <svg class="has-tooltip" :title="getFormattedMedian" :width="width" :height="height" xmlns="http://www.w3.org/2000/svg">
- <path :d="pathD" :viewBox="pathViewBox" />
- <circle r="1.5" :cx="dotX" :cy="dotY" tranform="translate(0 -1)" />
- </svg>
- </div>
- `,
};
+</script>
+
+<template>
+ <div class="memory-graph-container">
+ <svg
+ class="has-tooltip"
+ :title="getFormattedMedian"
+ :width="width"
+ :height="height"
+ xmlns="http://www.w3.org/2000/svg">
+ <path
+ :d="pathD"
+ :viewBox="pathViewBox"
+ />
+ <circle
+ r="1.5"
+ :cx="dotX"
+ :cy="dotY"
+ tranform="translate(0 -1)"
+ />
+ </svg>
+ </div>
+</template>
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index ae517c41cb2..37d33320445 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -14,6 +14,10 @@
color: $gl-text-color-secondary;
}
+.text-tertiary {
+ color: $gl-text-color-tertiary;
+}
+
.text-primary,
.text-primary:hover {
color: $brand-primary;
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 1d7b0b602cc..127583626cf 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -272,7 +272,7 @@
.divider {
height: 1px;
- margin: 6px 0;
+ margin: #{$grid-size / 2} 0;
padding: 0;
background-color: $dropdown-divider-color;
diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss
index 88ce119ee3a..cb2f71b0033 100644
--- a/app/assets/stylesheets/framework/flash.scss
+++ b/app/assets/stylesheets/framework/flash.scss
@@ -12,6 +12,12 @@
margin: 0;
}
+ .flash-warning {
+ @extend .alert;
+ @extend .alert-warning;
+ margin: 0;
+ }
+
.flash-alert {
@extend .alert;
@extend .alert-danger;
diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss
index a6b1bf9b099..48b981dd31f 100644
--- a/app/assets/stylesheets/framework/modal.scss
+++ b/app/assets/stylesheets/framework/modal.scss
@@ -2,14 +2,17 @@
background-color: $modal-body-bg;
padding: #{3 * $grid-size} #{2 * $grid-size};
- .page-title {
- margin-top: 0;
-
+ .page-title,
+ .modal-title {
.color-label {
font-size: $gl-font-size;
padding: $gl-vert-padding $label-padding-modal;
}
}
+
+ .page-title {
+ margin-top: 0;
+ }
}
.modal-body {
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
index 47672783d5a..a6ca8ed5016 100644
--- a/app/assets/stylesheets/pages/settings.scss
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -205,7 +205,8 @@
}
.badge {
- font-size: inherit;
+ font-size: 12px;
+ line-height: 12px;
}
.panel-heading .badge-count {
diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb
index db8c362f125..2753f83c3cf 100644
--- a/app/controllers/concerns/authenticates_with_two_factor.rb
+++ b/app/controllers/concerns/authenticates_with_two_factor.rb
@@ -56,6 +56,7 @@ module AuthenticatesWithTwoFactor
session.delete(:otp_user_id)
remember_me(user) if user_params[:remember_me] == '1'
+ user.save!
sign_in(user)
else
user.increment_failed_attempts!
diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb
index 6f4fdcdaa4f..b26a76d2b62 100644
--- a/app/controllers/concerns/creates_commit.rb
+++ b/app/controllers/concerns/creates_commit.rb
@@ -4,7 +4,7 @@ module CreatesCommit
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil)
- if can?(current_user, :push_code, @project)
+ if user_access(@project).can_push_to_branch?(branch_name_or_ref)
@project_to_commit_into = @project
@branch_name ||= @ref
else
@@ -50,7 +50,7 @@ module CreatesCommit
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def authorize_edit_tree!
- return if can_collaborate_with_project?
+ return if can_collaborate_with_project?(project, ref: branch_name_or_ref)
access_denied!
end
@@ -123,4 +123,8 @@ module CreatesCommit
params[:create_merge_request].present? &&
(different_project? || @start_branch != @branch_name) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
+
+ def branch_name_or_ref
+ @branch_name || @ref # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ end
end
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index 69fb8121ded..eb7d5fca367 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -42,7 +42,9 @@ class Import::GithubController < Import::BaseController
target_namespace = find_or_create_namespace(namespace_path, current_user.namespace_path)
if can?(current_user, :create_projects, target_namespace)
- project = Gitlab::LegacyGithubImport::ProjectCreator.new(repo, project_name, target_namespace, current_user, access_params, type: provider).execute
+ project = Gitlab::LegacyGithubImport::ProjectCreator
+ .new(repo, project_name, target_namespace, current_user, access_params, type: provider)
+ .execute(extra_project_attrs)
if project.persisted?
render json: ProjectSerializer.new.represent(project)
@@ -73,15 +75,15 @@ class Import::GithubController < Import::BaseController
end
def new_import_url
- public_send("new_import_#{provider}_url") # rubocop:disable GitlabSecurity/PublicSend
+ public_send("new_import_#{provider}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
end
def status_import_url
- public_send("status_import_#{provider}_url") # rubocop:disable GitlabSecurity/PublicSend
+ public_send("status_import_#{provider}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
end
def callback_import_url
- public_send("callback_import_#{provider}_url") # rubocop:disable GitlabSecurity/PublicSend
+ public_send("callback_import_#{provider}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
end
def provider_unauthorized
@@ -116,4 +118,12 @@ class Import::GithubController < Import::BaseController
def client_options
{}
end
+
+ def extra_project_attrs
+ {}
+ end
+
+ def extra_import_params
+ {}
+ end
end
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 6025a40348b..6d9b42a2c04 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -6,7 +6,7 @@ class Projects::ApplicationController < ApplicationController
before_action :repository
layout 'project'
- helper_method :repository, :can_collaborate_with_project?
+ helper_method :repository, :can_collaborate_with_project?, :user_access
private
@@ -31,11 +31,12 @@ class Projects::ApplicationController < ApplicationController
@repository ||= project.repository
end
- def can_collaborate_with_project?(project = nil)
+ def can_collaborate_with_project?(project = nil, ref: nil)
project ||= @project
can?(current_user, :push_code, project) ||
- (current_user && current_user.already_forked?(project))
+ (current_user && current_user.already_forked?(project)) ||
+ user_access(project).can_push_to_branch?(ref)
end
def authorize_action!(action)
@@ -90,4 +91,9 @@ class Projects::ApplicationController < ApplicationController
def check_issues_available!
return render_404 unless @project.feature_available?(:issues, current_user)
end
+
+ def user_access(project)
+ @user_access ||= {}
+ @user_access[project] ||= Gitlab::UserAccess.new(current_user, project: project)
+ end
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 405726c017c..0c1c286a0a4 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -9,8 +9,12 @@ class Projects::BlobController < Projects::ApplicationController
before_action :require_non_empty_project, except: [:new, :create]
before_action :authorize_download_code!
- before_action :authorize_edit_tree!, only: [:new, :create, :update, :destroy]
+
+ # We need to assign the blob vars before `authorize_edit_tree!` so we can
+ # validate access to a specific ref.
before_action :assign_blob_vars
+ before_action :authorize_edit_tree!, only: [:new, :create, :update, :destroy]
+
before_action :commit, except: [:new, :create]
before_action :blob, except: [:new, :create]
before_action :require_branch_head, only: [:edit, :update]
@@ -46,7 +50,7 @@ class Projects::BlobController < Projects::ApplicationController
end
def edit
- if can_collaborate_with_project?
+ if can_collaborate_with_project?(project, ref: @ref)
blob.load_all_data!
else
redirect_to action: 'show'
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index e0f4710175f..99790b8e7e8 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -112,12 +112,14 @@ class Projects::LabelsController < Projects::ApplicationController
begin
return render_404 unless promote_service.execute(@label)
+ flash[:notice] = "#{@label.title} promoted to group label."
respond_to do |format|
format.html do
- redirect_to(project_labels_path(@project),
- notice: 'Label was promoted to a Group Label')
+ redirect_to(project_labels_path(@project), status: 303)
+ end
+ format.json do
+ render json: { url: project_labels_path(@project) }
end
- format.js
end
rescue ActiveRecord::RecordInvalid => e
Gitlab::AppLogger.error "Failed to promote label \"#{@label.title}\" to group label"
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index 793ae03fb88..67d4ea2ca8f 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -15,6 +15,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
def merge_request_params_attributes
[
+ :allow_maintainer_to_push,
:assignee_id,
:description,
:force_remove_source_branch,
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index a1af125547c..54e7d81de6a 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -187,7 +187,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
begin
@merge_request.environments_for(current_user).map do |environment|
project = environment.project
- deployment = environment.first_deployment_for(@merge_request.diff_head_commit)
+ deployment = environment.first_deployment_for(@merge_request.diff_head_sha)
stop_url =
if environment.stop_action? && can?(current_user, :create_deployment, environment)
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 75b17d05e22..ff93147d00f 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -70,9 +70,17 @@ class Projects::MilestonesController < Projects::ApplicationController
end
def promote
- promoted_milestone = Milestones::PromoteService.new(project, current_user).execute(milestone)
- flash[:notice] = "Milestone has been promoted to group milestone."
- redirect_to group_milestone_path(project.group, promoted_milestone.iid)
+ Milestones::PromoteService.new(project, current_user).execute(milestone)
+
+ flash[:notice] = "#{milestone.title} promoted to group milestone"
+ respond_to do |format|
+ format.html do
+ redirect_to project_milestones_path(project)
+ end
+ format.json do
+ render json: { url: project_milestones_path(project) }
+ end
+ end
rescue Milestones::PromoteService::PromoteMilestoneError => error
redirect_to milestone, alert: error.message
end
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index daa5c88aae0..f14cb5f6a9f 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -3,7 +3,8 @@ class Projects::ServicesController < Projects::ApplicationController
# Authorize
before_action :authorize_admin_project!
- before_action :service, only: [:edit, :update, :test]
+ before_action :ensure_service_enabled
+ before_action :service
respond_to :html
@@ -23,26 +24,30 @@ class Projects::ServicesController < Projects::ApplicationController
end
def test
- message = {}
+ if @service.can_test?
+ render json: service_test_response, status: :ok
+ else
+ render json: {}, status: :not_found
+ end
+ end
- if @service.can_test? && @service.update_attributes(service_params[:service])
+ private
+
+ def service_test_response
+ if @service.update_attributes(service_params[:service])
data = @service.test_data(project, current_user)
outcome = @service.test(data)
- unless outcome[:success]
- message = { error: true, message: 'Test failed.', service_response: outcome[:result].to_s }
+ if outcome[:success]
+ {}
+ else
+ { error: true, message: 'Test failed.', service_response: outcome[:result].to_s }
end
-
- status = :ok
else
- status = :not_found
+ { error: true, message: 'Validations failed.', service_response: @service.errors.full_messages.join(',') }
end
-
- render json: message, status: status
end
- private
-
def success_message
if @service.active?
"#{@service.title} activated."
@@ -54,4 +59,8 @@ class Projects::ServicesController < Projects::ApplicationController
def service
@service ||= @project.find_or_initialize_service(params[:id])
end
+
+ def ensure_service_enabled
+ render_404 unless service
+ end
end
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index 86717bb7242..259809f3429 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -13,12 +13,14 @@ module Projects
def reset_cache
if ResetProjectCacheService.new(@project, current_user).execute
- flash[:notice] = _("Project cache successfully reset.")
+ respond_to do |format|
+ format.json { head :ok }
+ end
else
- flash[:error] = _("Unable to reset project cache.")
+ respond_to do |format|
+ format.json { head :bad_request }
+ end
end
-
- redirect_to project_pipelines_path(@project)
end
private
diff --git a/app/finders/user_recent_events_finder.rb b/app/finders/user_recent_events_finder.rb
index 6f7f7c30d92..65d6e019746 100644
--- a/app/finders/user_recent_events_finder.rb
+++ b/app/finders/user_recent_events_finder.rb
@@ -12,6 +12,8 @@ class UserRecentEventsFinder
attr_reader :current_user, :target_user, :params
+ LIMIT = 20
+
def initialize(current_user, target_user, params = {})
@current_user = current_user
@target_user = target_user
@@ -19,15 +21,44 @@ class UserRecentEventsFinder
end
def execute
- target_user
- .recent_events
- .merge(projects_for_current_user)
- .references(:project)
+ recent_events(params[:offset] || 0)
+ .joins(:project)
.with_associations
- .limit_recent(20, params[:offset])
+ .limit_recent(LIMIT, params[:offset])
+ end
+
+ private
+
+ def recent_events(offset)
+ sql = <<~SQL
+ (#{projects}) AS projects_for_join
+ JOIN (#{target_events.to_sql}) AS #{Event.table_name}
+ ON #{Event.table_name}.project_id = projects_for_join.id
+ SQL
+
+ # Workaround for https://github.com/rails/rails/issues/24193
+ Event.from([Arel.sql(sql)])
end
- def projects_for_current_user
- ProjectsFinder.new(current_user: current_user).execute
+ def target_events
+ Event.where(author: target_user)
+ end
+
+ def projects
+ # Compile a list of projects `current_user` interacted with
+ # and `target_user` is allowed to see.
+
+ authorized = target_user
+ .project_interactions
+ .joins(:project_authorizations)
+ .where(project_authorizations: { user: current_user })
+ .select(:id)
+
+ visible = target_user
+ .project_interactions
+ .where(visibility_level: [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC])
+ .select(:id)
+
+ Gitlab::SQL::Union.new([authorized, visible]).to_sql
end
end
diff --git a/app/helpers/import_helper.rb b/app/helpers/import_helper.rb
index b484a868f92..9149d79ecb8 100644
--- a/app/helpers/import_helper.rb
+++ b/app/helpers/import_helper.rb
@@ -36,6 +36,42 @@ module ImportHelper
_('Please wait while we import the repository for you. Refresh at will.')
end
+ def import_github_title
+ _('Import repositories from GitHub')
+ end
+
+ def import_github_authorize_message
+ _('To import GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories:')
+ end
+
+ def import_github_personal_access_token_message
+ personal_access_token_link = link_to _('Personal Access Token'), 'https://github.com/settings/tokens'
+
+ if github_import_configured?
+ _('Alternatively, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import.').html_safe % { personal_access_token_link: personal_access_token_link }
+ else
+ _('To import GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import.').html_safe % { personal_access_token_link: personal_access_token_link }
+ end
+ end
+
+ def import_configure_github_admin_message
+ github_integration_link = link_to 'GitHub integration', help_page_path('integration/github')
+
+ if current_user.admin?
+ _('Note: As an administrator you may like to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token.').html_safe % { github_integration_link: github_integration_link }
+ else
+ _('Note: Consider asking your GitLab administrator to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token.').html_safe % { github_integration_link: github_integration_link }
+ end
+ end
+
+ def import_githubish_choose_repository_message
+ _('Choose which repositories you want to import.')
+ end
+
+ def import_all_githubish_repositories_button_label
+ _('Import all repositories')
+ end
+
private
def github_project_url(full_path)
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index ce57422f45d..fb4fe1c40b7 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -125,6 +125,19 @@ module MergeRequestsHelper
link_to(url[merge_request.project, merge_request], data: data_attrs, &block)
end
+ def allow_maintainer_push_unavailable_reason(merge_request)
+ return if merge_request.can_allow_maintainer_to_push?(current_user)
+
+ minimum_visibility = [merge_request.target_project.visibility_level,
+ merge_request.source_project.visibility_level].min
+
+ if minimum_visibility < Gitlab::VisibilityLevel::INTERNAL
+ _('Not available for private projects')
+ elsif ProtectedBranch.protected?(merge_request.source_project, merge_request.source_branch)
+ _('Not available for protected branches')
+ end
+ end
+
def merge_params_ee(merge_request)
{}
end
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index f6a6d9bebde..b64be89c181 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -49,15 +49,13 @@ module TreeHelper
return false unless on_top_of_branch?(project, ref)
- can_collaborate_with_project?(project)
+ can_collaborate_with_project?(project, ref: ref)
end
def tree_edit_branch(project = @project, ref = @ref)
return unless can_edit_tree?(project, ref)
- project = project.present(current_user: current_user)
-
- if project.can_current_user_push_to_branch?(ref)
+ if user_access(project).can_push_to_branch?(ref)
ref
else
project = tree_edit_project(project)
@@ -88,7 +86,16 @@ module TreeHelper
end
def commit_in_fork_help
- "A new branch will be created in your fork and a new merge request will be started."
+ _("A new branch will be created in your fork and a new merge request will be started.")
+ end
+
+ def commit_in_single_accessible_branch
+ branch_name = html_escape(selected_branch)
+
+ message = _("Your changes can be committed to %{branch_name} because a merge "\
+ "request is open.") % { branch_name: "<strong>#{branch_name}</strong>" }
+
+ message.html_safe
end
def path_breadcrumbs(max_links = 6)
@@ -125,4 +132,8 @@ module TreeHelper
return tree.name
end
end
+
+ def selected_branch
+ @branch_name || tree_edit_branch
+ end
end
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 45d4fb451d8..e4212775956 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -117,7 +117,7 @@ class Notify < BaseMailer
if Gitlab::IncomingEmail.enabled? && @sent_notification
address = Mail::Address.new(Gitlab::IncomingEmail.reply_address(reply_key))
- address.display_name = @project.name_with_namespace
+ address.display_name = @project.full_name
headers['Reply-To'] = address
diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb
index 89d0474a596..faa94204e33 100644
--- a/app/models/concerns/deployment_platform.rb
+++ b/app/models/concerns/deployment_platform.rb
@@ -1,5 +1,6 @@
module DeploymentPlatform
- def deployment_platform
+ # EE would override this and utilize the extra argument
+ def deployment_platform(environment: nil)
@deployment_platform ||=
find_cluster_platform_kubernetes ||
find_kubernetes_service_integration ||
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 4560bc23193..5a566f3ac02 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -223,6 +223,10 @@ module Issuable
def to_ability_name
model_name.singular
end
+
+ def parent_class
+ ::Project
+ end
end
def today?
diff --git a/app/models/cycle_analytics/summary.rb b/app/models/cycle_analytics/summary.rb
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/app/models/cycle_analytics/summary.rb
+++ /dev/null
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 24d4f1d8761..2b0a88ac5b4 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -99,8 +99,8 @@ class Environment < ActiveRecord::Base
folder_name == "production"
end
- def first_deployment_for(commit)
- ref = project.repository.ref_name_for_sha(ref_path, commit.sha)
+ def first_deployment_for(commit_sha)
+ ref = project.repository.ref_name_for_sha(ref_path, commit_sha)
return nil unless ref
@@ -225,7 +225,7 @@ class Environment < ActiveRecord::Base
end
def deployment_platform
- project.deployment_platform
+ project.deployment_platform(environment: self)
end
private
diff --git a/app/models/event.rb b/app/models/event.rb
index be0fc7efa9a..17a198d52c7 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -65,6 +65,7 @@ class Event < ActiveRecord::Base
# Callbacks
after_create :reset_project_activity
after_create :set_last_repository_updated_at, if: :push?
+ after_create :track_user_interacted_projects
# Scopes
scope :recent, -> { reorder(id: :desc) }
@@ -389,4 +390,11 @@ class Event < ActiveRecord::Base
Project.unscoped.where(id: project_id)
.update_all(last_repository_updated_at: created_at)
end
+
+ def track_user_interacted_projects
+ # Note the call to .available? is due to earlier migrations
+ # that would otherwise conflict with the call to .track
+ # (because the table does not exist yet).
+ UserInteractedProject.track(self) if UserInteractedProject.available?
+ end
end
diff --git a/app/models/member.rb b/app/models/member.rb
index 408e8b2d704..36090676051 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -85,6 +85,7 @@ class Member < ActiveRecord::Base
after_create :create_notification_setting, unless: [:pending?, :importing?]
after_create :post_create_hook, unless: [:pending?, :importing?]
after_update :post_update_hook, unless: [:pending?, :importing?]
+ after_destroy :destroy_notification_setting
after_destroy :post_destroy_hook, unless: :pending?
after_commit :refresh_member_authorized_projects
@@ -315,6 +316,10 @@ class Member < ActiveRecord::Base
user.notification_settings.find_or_create_for(source)
end
+ def destroy_notification_setting
+ notification_setting&.destroy
+ end
+
def notification_setting
@notification_setting ||= user&.notification_settings_for(source)
end
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index b6f1dd272cd..1c7ed4a96df 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -13,8 +13,6 @@ class ProjectMember < Member
scope :in_project, ->(project) { where(source_id: project.id) }
- before_destroy :delete_member_todos
-
class << self
# Add users to projects with passed access option
#
@@ -93,10 +91,6 @@ class ProjectMember < Member
private
- def delete_member_todos
- user.todos.where(project_id: source_id).destroy_all if user
- end
-
def send_invite
notification_service.invite_project_member(self, @raw_invite_token)
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 5bec68ce4f6..c2bae379a94 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -375,15 +375,27 @@ class MergeRequest < ActiveRecord::Base
end
def diff_start_sha
- diff_start_commit.try(:sha)
+ if persisted?
+ merge_request_diff.start_commit_sha
+ else
+ target_branch_head.try(:sha)
+ end
end
def diff_base_sha
- diff_base_commit.try(:sha)
+ if persisted?
+ merge_request_diff.base_commit_sha
+ else
+ branch_merge_base_commit.try(:sha)
+ end
end
def diff_head_sha
- diff_head_commit.try(:sha)
+ if persisted?
+ merge_request_diff.head_commit_sha
+ else
+ source_branch_head.try(:sha)
+ end
end
# When importing a pull request from GitHub, the old and new branches may no
@@ -646,7 +658,7 @@ class MergeRequest < ActiveRecord::Base
!ProtectedBranch.protected?(source_project, source_branch) &&
!source_project.root_ref?(source_branch) &&
Ability.allowed?(current_user, :push_code, source_project) &&
- diff_head_commit == source_branch_head
+ diff_head_sha == source_branch_head.try(:sha)
end
def should_remove_source_branch?
@@ -853,7 +865,7 @@ class MergeRequest < ActiveRecord::Base
def can_be_merged_by?(user)
access = ::Gitlab::UserAccess.new(user, project: project)
- access.can_push_to_branch?(target_branch) || access.can_merge_to_branch?(target_branch)
+ access.can_update_branch?(target_branch)
end
def can_be_merged_via_command_line_by?(user)
@@ -1075,4 +1087,22 @@ class MergeRequest < ActiveRecord::Base
project.merge_requests.merged.where(author_id: author_id).empty?
end
+
+ def allow_maintainer_to_push
+ maintainer_push_possible? && super
+ end
+
+ alias_method :allow_maintainer_to_push?, :allow_maintainer_to_push
+
+ def maintainer_push_possible?
+ source_project.present? && for_fork? &&
+ target_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE &&
+ source_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE &&
+ !ProtectedBranch.protected?(source_project, source_branch)
+ end
+
+ def can_allow_maintainer_to_push?(user)
+ maintainer_push_possible? &&
+ Ability.allowed?(user, :push_code, source_project)
+ end
end
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 06aa67c600f..c1c27ccf3e5 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -197,6 +197,10 @@ class MergeRequestDiff < ActiveRecord::Base
CompareService.new(project, head_commit_sha).execute(project, sha, straight: true)
end
+ def commits_count
+ super || merge_request_diff_commits.size
+ end
+
private
def create_merge_request_diff_files(diffs)
diff --git a/app/models/note.rb b/app/models/note.rb
index d7a67ec277c..787a80f0196 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -81,7 +81,7 @@ class Note < ActiveRecord::Base
validates :author, presence: true
validates :discussion_id, presence: true, format: { with: /\A\h{40}\z/ }
- validate unless: [:for_commit?, :importing?, :for_personal_snippet?] do |note|
+ validate unless: [:for_commit?, :importing?, :skip_project_check?] do |note|
unless note.noteable.try(:project) == note.project
errors.add(:project, 'does not match noteable project')
end
@@ -228,7 +228,7 @@ class Note < ActiveRecord::Base
end
def skip_project_check?
- for_personal_snippet?
+ !for_project_noteable?
end
def commit
@@ -308,6 +308,11 @@ class Note < ActiveRecord::Base
self.noteable.supports_discussions? && !part_of_discussion?
end
+ def can_create_todo?
+ # Skip system notes, and notes on project snippet
+ !system? && !for_snippet?
+ end
+
def discussion_class(noteable = nil)
# When commit notes are rendered on an MR's Discussion page, they are
# displayed in one discussion instead of individually.
diff --git a/app/models/project.rb b/app/models/project.rb
index 5cd1da43645..5f9d9785d64 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -150,6 +150,7 @@ class Project < ActiveRecord::Base
# Merge Requests for target project should be removed with it
has_many :merge_requests, foreign_key: 'target_project_id'
+ has_many :source_of_merge_requests, foreign_key: 'source_project_id', class_name: 'MergeRequest'
has_many :issues
has_many :labels, class_name: 'ProjectLabel'
has_many :services
@@ -1799,6 +1800,33 @@ class Project < ActiveRecord::Base
Badge.where("id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
end
+ def merge_requests_allowing_push_to_user(user)
+ return MergeRequest.none unless user
+
+ developer_access_exists = user.project_authorizations
+ .where('access_level >= ? ', Gitlab::Access::DEVELOPER)
+ .where('project_authorizations.project_id = merge_requests.target_project_id')
+ .limit(1)
+ .select(1)
+ source_of_merge_requests.opened
+ .where(allow_maintainer_to_push: true)
+ .where('EXISTS (?)', developer_access_exists)
+ end
+
+ def branch_allows_maintainer_push?(user, branch_name)
+ return false unless user
+
+ cache_key = "user:#{user.id}:#{branch_name}:branch_allows_push"
+
+ memoized_results = strong_memoize(:branch_allows_maintainer_push) do
+ Hash.new do |result, cache_key|
+ result[cache_key] = fetch_branch_allows_maintainer_push?(user, branch_name)
+ end
+ end
+
+ memoized_results[cache_key]
+ end
+
private
def storage
@@ -1921,4 +1949,22 @@ class Project < ActiveRecord::Base
raise ex
end
+
+ def fetch_branch_allows_maintainer_push?(user, branch_name)
+ check_access = -> do
+ merge_request = source_of_merge_requests.opened
+ .where(allow_maintainer_to_push: true)
+ .find_by(source_branch: branch_name)
+
+ merge_request&.can_be_merged_by?(user)
+ end
+
+ if RequestStore.active?
+ RequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_maintainer_push") do
+ check_access.call
+ end
+ else
+ check_access.call
+ end
+ end
end
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index a9e5cfb8240..33280eda0b9 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -85,6 +85,15 @@ class ProjectTeam
@masters ||= fetch_members(Gitlab::Access::MASTER)
end
+ def owners
+ @owners ||=
+ if group
+ group.owners
+ else
+ [project.owner]
+ end
+ end
+
def import(source_project, current_user = nil)
target_project = project
diff --git a/app/models/repository.rb b/app/models/repository.rb
index f5b223b8b8f..42f1ac43e29 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -36,7 +36,7 @@ class Repository
CACHED_METHODS = %i(size commit_count rendered_readme contribution_guide
changelog license_blob license_key gitignore koding_yml
gitlab_ci_yml branch_names tag_names branch_count
- tag_count avatar exists? empty? root_ref has_visible_content?
+ tag_count avatar exists? root_ref has_visible_content?
issue_template_names merge_request_template_names).freeze
# Methods that use cache_method but only memoize the value
@@ -334,7 +334,7 @@ class Repository
def expire_emptiness_caches
return unless empty?
- expire_method_caches(%i(empty? has_visible_content?))
+ expire_method_caches(%i(has_visible_content?))
end
def lookup_cache
@@ -480,12 +480,14 @@ class Repository
end
cache_method :exists?
+ # We don't need to cache the output of this method because both exists? and
+ # has_visible_content? are already memoized and cached. There's no guarantee
+ # that the values are expired and loaded atomically.
def empty?
return true unless exists?
!has_visible_content?
end
- cache_method :empty?
# The size of this repository in megabytes.
def size
@@ -625,14 +627,15 @@ class Repository
end
def last_commit_for_path(sha, path)
- commit_by(oid: last_commit_id_for_path(sha, path))
+ commit = raw_repository.last_commit_for_path(sha, path)
+ ::Commit.new(commit, @project) if commit
end
def last_commit_id_for_path(sha, path)
key = path.blank? ? "last_commit_id_for_path:#{sha}" : "last_commit_id_for_path:#{sha}:#{Digest::SHA1.hexdigest(path)}"
cache.fetch(key) do
- raw_repository.last_commit_id_for_path(sha, path)
+ last_commit_for_path(sha, path)&.id
end
end
@@ -840,20 +843,20 @@ class Repository
raw_repository.ancestor?(ancestor_id, descendant_id)
end
- def fetch_as_mirror(url, forced: false, refmap: :all_refs, remote_name: nil)
+ def fetch_as_mirror(url, forced: false, refmap: :all_refs, remote_name: nil, prune: true)
unless remote_name
remote_name = "tmp-#{SecureRandom.hex}"
tmp_remote_name = true
end
add_remote(remote_name, url, mirror_refmap: refmap)
- fetch_remote(remote_name, forced: forced)
+ fetch_remote(remote_name, forced: forced, prune: prune)
ensure
remove_remote(remote_name) if tmp_remote_name
end
- def fetch_remote(remote, forced: false, ssh_auth: nil, no_tags: false)
- gitlab_shell.fetch_remote(raw_repository, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags)
+ def fetch_remote(remote, forced: false, ssh_auth: nil, no_tags: false, prune: true)
+ gitlab_shell.fetch_remote(raw_repository, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, prune: prune)
end
def fetch_source_branch!(source_repository, source_branch, local_ref)
diff --git a/app/models/service.rb b/app/models/service.rb
index 369cae2e85f..99bf757ae44 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -129,6 +129,17 @@ class Service < ActiveRecord::Base
fields
end
+ def configurable_events
+ events = self.class.supported_events
+
+ # No need to disable individual triggers when there is only one
+ if events.count == 1
+ []
+ else
+ events
+ end
+ end
+
def supported_events
self.class.supported_events
end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index a58c208279e..644120453cf 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -168,5 +168,9 @@ class Snippet < ActiveRecord::Base
def search_code(query)
fuzzy_search(query, [:content])
end
+
+ def parent_class
+ ::Project
+ end
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 9c60adf0c90..b8c55205ab8 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -114,13 +114,15 @@ class User < ActiveRecord::Base
has_many :project_authorizations
has_many :authorized_projects, through: :project_authorizations, source: :project
+ has_many :user_interacted_projects
+ has_many :project_interactions, through: :user_interacted_projects, source: :project, class_name: 'Project'
+
has_many :snippets, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :notes, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :issues, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :merge_requests, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :events, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :subscriptions, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
- has_many :recent_events, -> { order "id DESC" }, foreign_key: :author_id, class_name: "Event"
has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :abuse_report, dependent: :destroy, foreign_key: :user_id # rubocop:disable Cop/ActiveRecordDependent
has_many :reported_abuse_reports, dependent: :destroy, foreign_key: :reporter_id, class_name: "AbuseReport" # rubocop:disable Cop/ActiveRecordDependent
@@ -1035,14 +1037,33 @@ class User < ActiveRecord::Base
end
end
+ def todos_done_count(force: false)
+ Rails.cache.fetch(['users', id, 'todos_done_count'], force: force, expires_in: 20.minutes) do
+ TodosFinder.new(self, state: :done).execute.count
+ end
+ end
+
+ def todos_pending_count(force: false)
+ Rails.cache.fetch(['users', id, 'todos_pending_count'], force: force, expires_in: 20.minutes) do
+ TodosFinder.new(self, state: :pending).execute.count
+ end
+ end
+
def update_cache_counts
assigned_open_merge_requests_count(force: true)
assigned_open_issues_count(force: true)
end
+ def update_todos_count_cache
+ todos_done_count(force: true)
+ todos_pending_count(force: true)
+ end
+
def invalidate_cache_counts
invalidate_issue_cache_counts
invalidate_merge_request_cache_counts
+ invalidate_todos_done_count
+ invalidate_todos_pending_count
end
def invalidate_issue_cache_counts
@@ -1053,21 +1074,12 @@ class User < ActiveRecord::Base
Rails.cache.delete(['users', id, 'assigned_open_merge_requests_count'])
end
- def todos_done_count(force: false)
- Rails.cache.fetch(['users', id, 'todos_done_count'], force: force, expires_in: 20.minutes) do
- TodosFinder.new(self, state: :done).execute.count
- end
+ def invalidate_todos_done_count
+ Rails.cache.delete(['users', id, 'todos_done_count'])
end
- def todos_pending_count(force: false)
- Rails.cache.fetch(['users', id, 'todos_pending_count'], force: force, expires_in: 20.minutes) do
- TodosFinder.new(self, state: :pending).execute.count
- end
- end
-
- def update_todos_count_cache
- todos_done_count(force: true)
- todos_pending_count(force: true)
+ def invalidate_todos_pending_count
+ Rails.cache.delete(['users', id, 'todos_pending_count'])
end
# This is copied from Devise::Models::Lockable#valid_for_authentication?, as our auth
diff --git a/app/models/user_interacted_project.rb b/app/models/user_interacted_project.rb
new file mode 100644
index 00000000000..dd55a6acb79
--- /dev/null
+++ b/app/models/user_interacted_project.rb
@@ -0,0 +1,59 @@
+class UserInteractedProject < ActiveRecord::Base
+ belongs_to :user
+ belongs_to :project
+
+ validates :project_id, presence: true
+ validates :user_id, presence: true
+
+ CACHE_EXPIRY_TIME = 1.day
+
+ # Schema version required for this model
+ REQUIRED_SCHEMA_VERSION = 20180223120443
+
+ class << self
+ def track(event)
+ # For events without a project, we simply don't care.
+ # An example of this is the creation of a snippet (which
+ # is not related to any project).
+ return unless event.project_id
+
+ attributes = {
+ project_id: event.project_id,
+ user_id: event.author_id
+ }
+
+ cached_exists?(attributes) do
+ transaction(requires_new: true) do
+ begin
+ where(attributes).select(1).first || create!(attributes)
+ true # not caching the whole record here for now
+ rescue ActiveRecord::RecordNotUnique
+ # Note, above queries are not atomic and prone
+ # to race conditions (similar like #find_or_create!).
+ # In the case where we hit this, the record we want
+ # already exists - shortcut and return.
+ true
+ end
+ end
+ end
+ end
+
+ # Check if we can safely call .track (table exists)
+ def available?
+ @available_flag ||= ActiveRecord::Migrator.current_version >= REQUIRED_SCHEMA_VERSION # rubocop:disable Gitlab/PredicateMemoization
+ end
+
+ # Flushes cached information about schema
+ def reset_column_information
+ @available_flag = nil
+ super
+ end
+
+ private
+
+ def cached_exists?(project_id:, user_id:, &block)
+ cache_key = "user_interacted_projects:#{project_id}:#{user_id}"
+ Rails.cache.fetch(cache_key, expires_in: CACHE_EXPIRY_TIME, &block)
+ end
+ end
+end
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 3b0550b4dd6..57ab0c23dcd 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -61,6 +61,11 @@ class ProjectPolicy < BasePolicy
desc "Project has request access enabled"
condition(:request_access_enabled, scope: :subject) { project.request_access_enabled }
+ desc "Has merge requests allowing pushes to user"
+ condition(:has_merge_requests_allowing_pushes, scope: :subject) do
+ project.merge_requests_allowing_push_to_user(user).any?
+ end
+
features = %w[
merge_requests
issues
@@ -291,6 +296,15 @@ class ProjectPolicy < BasePolicy
prevent :read_issue
end
+ # These rules are included to allow maintainers of projects to push to certain
+ # to run pipelines for the branches they have access to.
+ rule { can?(:public_access) & has_merge_requests_allowing_pushes }.policy do
+ enable :create_build
+ enable :update_build
+ enable :create_pipeline
+ enable :update_pipeline
+ end
+
private
def team_member?
diff --git a/app/presenters/merge_request_presenter.rb b/app/presenters/merge_request_presenter.rb
index 08ae49562c7..9f3f2637183 100644
--- a/app/presenters/merge_request_presenter.rb
+++ b/app/presenters/merge_request_presenter.rb
@@ -78,7 +78,7 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end
def rebase_path
- if !rebase_in_progress? && should_be_rebased? && user_can_push_to_source_branch?
+ if !rebase_in_progress? && should_be_rebased? && can_push_to_source_branch?
rebase_project_merge_request_path(project, merge_request)
end
end
@@ -160,7 +160,11 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end
def can_push_to_source_branch?
- source_branch_exists? && user_can_push_to_source_branch?
+ return false unless source_branch_exists?
+
+ !!::Gitlab::UserAccess
+ .new(current_user, project: source_project)
+ .can_push_to_branch?(source_branch)
end
private
@@ -191,17 +195,10 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end.sort.to_sentence
end
- def user_can_push_to_source_branch?
- return false unless source_branch_exists?
-
- ::Gitlab::UserAccess
- .new(current_user, project: source_project)
- .can_push_to_branch?(source_branch)
- end
-
def user_can_collaborate_with_project?
can?(current_user, :push_code, project) ||
- (current_user && current_user.already_forked?(project))
+ (current_user && current_user.already_forked?(project)) ||
+ can_push_to_source_branch?
end
def user_can_fork_project?
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index 4e8ef320af2..4a812e39ee1 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -11,6 +11,7 @@ class MergeRequestWidgetEntity < IssuableEntity
expose :source_project_id
expose :target_branch
expose :target_project_id
+ expose :allow_maintainer_to_push
expose :should_be_rebased?, as: :should_be_rebased
expose :ff_only_enabled do |merge_request|
@@ -29,6 +30,7 @@ class MergeRequestWidgetEntity < IssuableEntity
expose :can_push_to_source_branch do |merge_request|
presenter(merge_request).can_push_to_source_branch?
end
+
expose :rebase_path do |merge_request|
presenter(merge_request).rebase_path
end
@@ -38,7 +40,7 @@ class MergeRequestWidgetEntity < IssuableEntity
# Diff sha's
expose :diff_head_sha do |merge_request|
- merge_request.diff_head_sha if merge_request.diff_head_commit
+ merge_request.diff_head_sha.presence
end
expose :merge_commit_message
@@ -136,8 +138,8 @@ class MergeRequestWidgetEntity < IssuableEntity
end
expose :new_blob_path do |merge_request|
- if can?(current_user, :push_code, merge_request.project)
- project_new_blob_path(merge_request.project, merge_request.source_branch)
+ if presenter(merge_request).can_push_to_source_branch?
+ project_new_blob_path(merge_request.source_project, merge_request.source_branch)
end
end
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index c8b112132b3..3b3d9239086 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -81,7 +81,7 @@ module Ci
end
def related_merge_requests
- MergeRequest.opened.where(source_project: pipeline.project, source_branch: pipeline.ref)
+ pipeline.project.source_of_merge_requests.opened.where(source_branch: pipeline.ref)
end
end
end
diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb
index b141bfd5fbc..5b51e1982f1 100644
--- a/app/services/members/destroy_service.rb
+++ b/app/services/members/destroy_service.rb
@@ -5,12 +5,9 @@ module Members
return member if member.is_a?(GroupMember) && member.source.last_owner?(member.user)
- Member.transaction do
- unassign_issues_and_merge_requests(member) unless member.invite?
- member.notification_setting&.destroy
+ member.destroy
- member.destroy
- end
+ member.user&.invalidate_cache_counts
if member.request? && member.user != current_user
notification_service.decline_access_request(member)
@@ -37,38 +34,5 @@ module Members
raise "Unknown member type: #{member}!"
end
end
-
- def unassign_issues_and_merge_requests(member)
- if member.is_a?(GroupMember)
- issues = Issue.unscoped.select(1)
- .joins(:project)
- .where('issues.id = issue_assignees.issue_id AND projects.namespace_id = ?', member.source_id)
-
- # DELETE FROM issue_assignees WHERE user_id = X AND EXISTS (...)
- IssueAssignee.unscoped
- .where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues)
- .delete_all
-
- MergeRequestsFinder.new(current_user, group_id: member.source_id, assignee_id: member.user_id)
- .execute
- .update_all(assignee_id: nil)
- else
- project = member.source
-
- # SELECT 1 FROM issues WHERE issues.id = issue_assignees.issue_id AND issues.project_id = X
- issues = Issue.unscoped.select(1)
- .where('issues.id = issue_assignees.issue_id')
- .where(project_id: project.id)
-
- # DELETE FROM issue_assignees WHERE user_id = X AND EXISTS (...)
- IssueAssignee.unscoped
- .where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues)
- .delete_all
-
- project.merge_requests.opened.assigned_to(member.user).update_all(assignee_id: nil)
- end
-
- member.user.invalidate_cache_counts
- end
end
end
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index 23262b62615..231ab76fde4 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -35,6 +35,14 @@ module MergeRequests
end
end
+ def filter_params(merge_request)
+ super
+
+ unless merge_request.can_allow_maintainer_to_push?(current_user)
+ params.delete(:allow_maintainer_to_push)
+ end
+ end
+
def merge_request_metrics_service(merge_request)
MergeRequestMetricsService.new(merge_request.metrics)
end
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index 4b186d93772..a98bbdf74dd 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -6,6 +6,7 @@ module MergeRequests
@params_issue_iid = params.delete(:issue_iid)
self.merge_request = MergeRequest.new(params)
+ merge_request.author = current_user
merge_request.compare_commits = []
merge_request.source_project = find_source_project
merge_request.target_project = find_target_project
diff --git a/app/services/notes/build_service.rb b/app/services/notes/build_service.rb
index abf25bb778b..77e7b8a5ea7 100644
--- a/app/services/notes/build_service.rb
+++ b/app/services/notes/build_service.rb
@@ -26,14 +26,19 @@ module Notes
if project
project.notes.find_discussion(discussion_id)
else
- # only PersonalSnippets can have discussions without project association
discussion = Note.find_discussion(discussion_id)
noteable = discussion.noteable
- return nil unless noteable.is_a?(PersonalSnippet) && can?(current_user, :comment_personal_snippet, noteable)
+ return nil unless noteable_without_project?(noteable)
discussion
end
end
+
+ def noteable_without_project?(noteable)
+ return true if noteable.is_a?(PersonalSnippet) && can?(current_user, :comment_personal_snippet, noteable)
+
+ false
+ end
end
end
diff --git a/app/services/notes/post_process_service.rb b/app/services/notes/post_process_service.rb
index 6a10e172483..ad3dcc5010b 100644
--- a/app/services/notes/post_process_service.rb
+++ b/app/services/notes/post_process_service.rb
@@ -11,7 +11,7 @@ module Notes
unless @note.system?
EventCreateService.new.leave_note(@note, @note.author)
- return if @note.for_personal_snippet?
+ return unless @note.for_project_noteable?
@note.create_cross_references!
execute_note_hooks
diff --git a/app/services/notification_recipient_service.rb b/app/services/notification_recipient_service.rb
index 6835b14648b..e4be953e810 100644
--- a/app/services/notification_recipient_service.rb
+++ b/app/services/notification_recipient_service.rb
@@ -280,7 +280,7 @@ module NotificationRecipientService
add_participants(note.author)
add_mentions(note.author, target: note)
- unless note.for_personal_snippet?
+ if note.for_project_noteable?
# Merge project watchers
add_project_watchers
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 01838ec6b5d..7fa1387084c 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -85,7 +85,7 @@ module Projects
end
def after_create_actions
- log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"")
+ log_info("#{@project.owner.name} created a new project \"#{@project.full_name}\"")
unless @project.gitlab_project_import?
@project.write_repository_config
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index 379a8068023..5f2615a2c01 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -58,7 +58,7 @@ module Projects
def enabling_wiki?
return false if @project.wiki_enabled?
- params[:project_feature_attributes][:wiki_access_level].to_i > ProjectFeature::DISABLED
+ params.dig(:project_feature_attributes, :wiki_access_level).to_i > ProjectFeature::DISABLED
end
def ensure_wiki_exists
diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb
index c2ca404b179..ffd48e842c2 100644
--- a/app/services/todo_service.rb
+++ b/app/services/todo_service.rb
@@ -241,8 +241,7 @@ class TodoService
end
def handle_note(note, author, skip_users = [])
- # Skip system notes, and notes on project snippet
- return if note.system? || note.for_snippet?
+ return unless note.can_create_todo?
project = note.project
target = note.noteable
diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb
index b71002433d6..06b604dad4d 100644
--- a/app/services/users/destroy_service.rb
+++ b/app/services/users/destroy_service.rb
@@ -49,6 +49,8 @@ module Users
::Projects::DestroyService.new(project, current_user, skip_repo: project.legacy_storage?).execute
end
+ yield(user) if block_given?
+
MigrateToGhostUserService.new(user).execute unless options[:hard_delete]
# Destroy the namespace after destroying the user since certain methods may depend on the namespace existing
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 68788134b8e..81d7db04a3c 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -657,9 +657,11 @@
.checkbox
= f.label :version_check_enabled do
= f.check_box :version_check_enabled
- Version check enabled
+ Enable version check
.help-block
- Let GitLab inform you when an update is available.
+ GitLab will inform you if a new version is available.
+ = link_to 'Learn more', help_page_path("user/admin_area/settings/usage_statistics", anchor: "version-check")
+ about what information is shared with GitLab Inc.
.form-group
.col-sm-offset-2.col-sm-10
- can_be_configured = @application_setting.usage_ping_can_be_configured?
diff --git a/app/views/admin/hooks/_form.html.haml b/app/views/admin/hooks/_form.html.haml
index d8f96ed5b0d..a6324a97fd5 100644
--- a/app/views/admin/hooks/_form.html.haml
+++ b/app/views/admin/hooks/_form.html.haml
@@ -1,21 +1,20 @@
= form_errors(hook)
.form-group
- = form.label :url, 'URL', class: 'control-label'
- .col-sm-10
- = form.text_field :url, class: 'form-control'
+ = form.label :url, 'URL', class: 'label-light'
+ = form.text_field :url, class: 'form-control'
.form-group
- = form.label :token, 'Secret Token', class: 'control-label'
- .col-sm-10
- = form.text_field :token, class: 'form-control'
- %p.help-block
- Use this token to validate received payloads
+ = form.label :token, 'Secret Token', class: 'label-light'
+ = form.text_field :token, class: 'form-control'
+ %p.help-block
+ Use this token to validate received payloads
.form-group
- = form.label :url, 'Trigger', class: 'control-label'
- .col-sm-10.prepend-top-10
- %div
- System hook will be triggered on set of events like creating project
- or adding ssh key. But you can also enable extra triggers like Push events.
+ = form.label :url, 'Trigger', class: 'label-light'
+ %ul.list-unstyled
+ %li
+ .help-block
+ System hook will be triggered on set of events like creating project
+ or adding ssh key. But you can also enable extra triggers like Push events.
.prepend-top-default
= form.check_box :repository_update_events, class: 'pull-left'
@@ -24,21 +23,21 @@
%strong Repository update events
%p.light
This URL will be triggered when repository is updated
- %div
+ %li
= form.check_box :push_events, class: 'pull-left'
.prepend-left-20
= form.label :push_events, class: 'list-label' do
%strong Push events
%p.light
This URL will be triggered for each branch updated to the repository
- %div
+ %li
= form.check_box :tag_push_events, class: 'pull-left'
.prepend-left-20
= form.label :tag_push_events, class: 'list-label' do
%strong Tag push events
%p.light
This URL will be triggered when a new tag is pushed to the repository
- %div
+ %li
= form.check_box :merge_requests_events, class: 'pull-left'
.prepend-left-20
= form.label :merge_requests_events, class: 'list-label' do
@@ -46,9 +45,8 @@
%p.light
This URL will be triggered when a merge request is created/updated/merged
.form-group
- = form.label :enable_ssl_verification, 'SSL verification', class: 'control-label checkbox'
- .col-sm-10
- .checkbox
- = form.label :enable_ssl_verification do
- = form.check_box :enable_ssl_verification
- %strong Enable SSL verification
+ = form.label :enable_ssl_verification, 'SSL verification', class: 'label-light checkbox'
+ .checkbox
+ = form.label :enable_ssl_verification do
+ = form.check_box :enable_ssl_verification
+ %strong Enable SSL verification
diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml
index bc02d9969d6..d9e2ce5e74c 100644
--- a/app/views/admin/hooks/index.html.haml
+++ b/app/views/admin/hooks/index.html.haml
@@ -1,33 +1,35 @@
- page_title 'System Hooks'
-%h3.page-title
- System hooks
+.row.prepend-top-default
+ .col-lg-4
+ %h4.prepend-top-0
+ = page_title
+ %p
+ #{link_to 'System hooks ', help_page_path('system_hooks/system_hooks'), class: 'vlink'} can be
+ used for binding events when GitLab creates a User or Project.
-%p.light
- #{link_to 'System hooks ', help_page_path('system_hooks/system_hooks'), class: 'vlink'} can be
- used for binding events when GitLab creates a User or Project.
+ .col-lg-8.append-bottom-default
+ = form_for @hook, as: :hook, url: admin_hooks_path do |f|
+ = render partial: 'form', locals: { form: f, hook: @hook }
+ = f.submit 'Add system hook', class: 'btn btn-create'
-%hr
+ %hr
-= form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-horizontal' } do |f|
- = render partial: 'form', locals: { form: f, hook: @hook }
- .form-actions
- = f.submit 'Add system hook', class: 'btn btn-create'
-%hr
+ - if @hooks.any?
+ .panel.panel-default
+ .panel-heading
+ System hooks (#{@hooks.count})
+ %ul.content-list
+ - @hooks.each do |hook|
+ %li
+ .controls
+ = render 'shared/web_hooks/test_button', triggers: SystemHook.triggers, hook: hook, button_class: 'btn-sm'
+ = link_to 'Edit', edit_admin_hook_path(hook), class: 'btn btn-sm'
+ = link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-remove btn-sm'
+ .monospace= hook.url
+ %div
+ - SystemHook.triggers.each_value do |event|
+ - if hook.public_send(event)
+ %span.label.label-gray= event.to_s.titleize
+ %span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? 'enabled' : 'disabled'}
-- if @hooks.any?
- .panel.panel-default
- .panel-heading
- System hooks (#{@hooks.count})
- %ul.content-list
- - @hooks.each do |hook|
- %li
- .controls
- = render 'shared/web_hooks/test_button', triggers: SystemHook.triggers, hook: hook, button_class: 'btn-sm'
- = link_to 'Edit', edit_admin_hook_path(hook), class: 'btn btn-sm'
- = link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-remove btn-sm'
- .monospace= hook.url
- %div
- - SystemHook.triggers.each_value do |event|
- - if hook.public_send(event)
- %span.label.label-gray= event.to_s.titleize
- %span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? 'enabled' : 'disabled'}
+= render 'shared/plugins/index'
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index ca3f018c5e6..36df03302e8 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -2,9 +2,6 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@group.name} issues")
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag 'common_vue'
-
- if group_issues_count(state: 'all').zero?
= render 'shared/empty_states/issues', project_select_button: true
- else
diff --git a/app/views/import/_githubish_status.html.haml b/app/views/import/_githubish_status.html.haml
index e9a04e6c122..638c8b5a672 100644
--- a/app/views/import/_githubish_status.html.haml
+++ b/app/views/import/_githubish_status.html.haml
@@ -2,11 +2,11 @@
- provider_title = Gitlab::ImportSources.title(provider)
%p.light
- Select projects you want to import.
+ = import_githubish_choose_repository_message
%hr
%p
= button_tag class: "btn btn-import btn-success js-import-all" do
- Import all projects
+ = import_all_githubish_repositories_button_label
= icon("spinner spin", class: "loading-icon")
.table-responsive
@@ -16,9 +16,9 @@
%colgroup.import-jobs-status-col
%thead
%tr
- %th From #{provider_title}
- %th To GitLab
- %th Status
+ %th= _('From %{provider_title}') % { provider_title: provider_title }
+ %th= _('To GitLab')
+ %th= _('Status')
%tbody
- @already_added_projects.each do |project|
%tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" }
@@ -30,10 +30,12 @@
- if project.import_status == 'finished'
%span
%i.fa.fa-check
- done
+ = _('Done')
- elsif project.import_status == 'started'
%i.fa.fa-spinner.fa-spin
- started
+ = _('Started')
+ - elsif project.import_status == 'failed'
+ = _('Failed')
- else
= project.human_import_status_name
@@ -55,7 +57,9 @@
= text_field_tag :path, repo.name, class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
%td.import-actions.job-status
= button_tag class: "btn btn-import js-add-to-import" do
- Import
+ = has_ci_cd_only_params? ? _('Connect') : _('Import')
= icon("spinner spin", class: "loading-icon")
-.js-importer-status{ data: { jobs_import_path: "#{url_for([:jobs, :import, provider])}", import_path: "#{url_for([:import, provider])}" } }
+.js-importer-status{ data: { jobs_import_path: "#{url_for([:jobs, :import, provider])}",
+ import_path: "#{url_for([:import, provider])}",
+ ci_cd_only: "#{has_ci_cd_only_params?}" } }
diff --git a/app/views/import/github/new.html.haml b/app/views/import/github/new.html.haml
index 9c2da3a3eec..ca47ab5f274 100644
--- a/app/views/import/github/new.html.haml
+++ b/app/views/import/github/new.html.haml
@@ -1,43 +1,31 @@
-- page_title "GitHub Import"
+- title = has_ci_cd_only_params? ? _('Connect repositories from GitHub') : _('GitHub import')
+- page_title title
+- breadcrumb_title title
- header_title "Projects", root_path
%h3.page-title
- = icon 'github', text: 'Import Projects from GitHub'
+ = icon 'github', text: import_github_title
- if github_import_configured?
%p
- To import a GitHub project, you first need to authorize GitLab to access
- the list of your GitHub repositories:
+ = import_github_authorize_message
- = link_to 'List your GitHub repositories', status_import_github_path, class: 'btn btn-success'
+ = link_to _('List your GitHub repositories'), status_import_github_path, class: 'btn btn-success'
%hr
%p
- - if github_import_configured?
- Alternatively,
- - else
- To import a GitHub project,
- you can use a
- = succeed '.' do
- = link_to 'Personal Access Token', 'https://github.com/settings/tokens'
- When you create your Personal Access Token,
- you will need to select the <code>repo</code> scope, so we can display a
- list of your public and private repositories which are available for import.
+ = import_github_personal_access_token_message
= form_tag personal_access_token_import_github_path, method: :post, class: 'form-inline' do
.form-group
- = text_field_tag :personal_access_token, '', class: 'form-control', placeholder: "Personal Access Token", size: 40
- = submit_tag 'List your GitHub repositories', class: 'btn btn-success'
+ = text_field_tag :personal_access_token, '', class: 'form-control', placeholder: _('Personal Access Token'), size: 40
+ = submit_tag _('List your GitHub repositories'), class: 'btn btn-success'
+
+ -# EE-specific start
+ -# EE-specific end
- unless github_import_configured?
%hr
%p
- Note:
- - if current_user.admin?
- As an administrator you may like to configure
- - else
- Consider asking your GitLab administrator to configure
- = link_to 'GitHub integration', help_page_path("integration/github")
- which will allow login via GitHub and allow importing projects without
- generating a Personal Access Token.
+ = import_configure_github_admin_message
diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml
index 0fe578a0036..b00b972d9c9 100644
--- a/app/views/import/github/status.html.haml
+++ b/app/views/import/github/status.html.haml
@@ -1,6 +1,8 @@
-- page_title "GitHub Import"
+- title = has_ci_cd_only_params? ? _('Connect repositories from GitHub') : _('GitHub import')
+- page_title title
+- breadcrumb_title title
- header_title "Projects", root_path
%h3.page-title
- = icon 'github', text: 'Import Projects from GitHub'
+ = icon 'github', text: import_github_title
= render 'import/githubish_status', provider: 'github'
diff --git a/app/views/projects/_commit_button.html.haml b/app/views/projects/_commit_button.html.haml
index b55dc3dce5c..b387e38c1a6 100644
--- a/app/views/projects/_commit_button.html.haml
+++ b/app/views/projects/_commit_button.html.haml
@@ -3,6 +3,4 @@
= link_to 'Cancel', cancel_path,
class: 'btn btn-cancel', data: {confirm: leave_edit_message}
- - unless can?(current_user, :push_code, @project)
- .inline.prepend-left-10
- = commit_in_fork_help
+ = render 'shared/projects/edit_information'
diff --git a/app/views/projects/blob/_new_dir.html.haml b/app/views/projects/blob/_new_dir.html.haml
index 5d48a35dc4c..48ff66900be 100644
--- a/app/views/projects/blob/_new_dir.html.haml
+++ b/app/views/projects/blob/_new_dir.html.haml
@@ -17,6 +17,4 @@
= submit_tag _("Create directory"), class: 'btn btn-create'
= link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
- - unless can?(current_user, :push_code, @project)
- .inline.prepend-left-10
- = commit_in_fork_help
+ = render 'shared/projects/edit_information'
diff --git a/app/views/projects/blob/_upload.html.haml b/app/views/projects/blob/_upload.html.haml
index f1324c61500..182d02376bf 100644
--- a/app/views/projects/blob/_upload.html.haml
+++ b/app/views/projects/blob/_upload.html.haml
@@ -24,6 +24,4 @@
= button_title
= link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal"
- - unless can?(current_user, :push_code, @project)
- .inline.prepend-left-10
- = commit_in_fork_help
+ = render 'shared/projects/edit_information'
diff --git a/app/views/projects/clusters/_integration_form.html.haml b/app/views/projects/clusters/_integration_form.html.haml
index d4c0cd82ce3..db97203a2aa 100644
--- a/app/views/projects/clusters/_integration_form.html.haml
+++ b/app/views/projects/clusters/_integration_form.html.haml
@@ -21,6 +21,12 @@
= sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked')
.form-group
+ %h5= s_('ClusterIntegration|Security')
+ %p
+ = s_("ClusterIntegration|The default cluster configuration grants access to a wide set of functionalities needed to successfully build and deploy a containerised application.")
+ = link_to s_("ClusterIntegration|Learn more about security configuration"), help_page_path('user/project/clusters/index.md', anchor: 'security-implications')
+
+ .form-group
%h5= s_('ClusterIntegration|Environment scope')
%p
= s_("ClusterIntegration|Choose which of your project's environments will use this Kubernetes cluster.")
diff --git a/app/views/projects/commit/_change.html.haml b/app/views/projects/commit/_change.html.haml
index 93407956f56..21e4664d4e4 100644
--- a/app/views/projects/commit/_change.html.haml
+++ b/app/views/projects/commit/_change.html.haml
@@ -35,6 +35,4 @@
= submit_tag label, class: 'btn btn-create'
= link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal"
- - unless can?(current_user, :push_code, @project)
- .inline.prepend-left-10
- = commit_in_fork_help
+ = render 'shared/projects/edit_information'
diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml
index 02395b6eb9b..5041f322612 100644
--- a/app/views/projects/cycle_analytics/show.html.haml
+++ b/app/views/projects/cycle_analytics/show.html.haml
@@ -1,7 +1,5 @@
- @no_container = true
- page_title "Cycle Analytics"
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag('common_vue')
#cycle-analytics{ class: container_class, "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } }
- if @cycle_analytics_no_data
diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml
index 0d656b25bc8..7ebe617766f 100644
--- a/app/views/projects/environments/index.html.haml
+++ b/app/views/projects/environments/index.html.haml
@@ -2,9 +2,6 @@
- page_title "Environments"
- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag("common_vue")
-
#environments-list-view{ data: { environments_data: environments_list_data,
"can-create-deployment" => can?(current_user, :create_deployment, @project).to_s,
"can-read-environment" => can?(current_user, :read_environment, @project).to_s,
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index fb06ba58c27..c427a9eedc2 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -4,9 +4,6 @@
- page_title "Issues"
- new_issue_email = @project.new_issuable_address(current_user, 'issue')
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag 'common_vue'
-
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@project.name} issues")
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index 80e4dce1a80..9c78bade254 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -4,6 +4,7 @@
- can_admin_label = can?(current_user, :admin_label, @project)
- if @labels.exists? || @prioritized_labels.exists?
+ #promote-label-modal
%div{ class: container_class }
.top-area.adjust
.nav-text
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index 720ba236434..b2c0d9e1cfa 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -6,9 +6,6 @@
- page_title "Merge Requests"
- new_merge_request_email = @project.new_issuable_address(current_user, 'merge_request')
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag 'common_vue'
-
%div{ class: container_class }
= render 'projects/last_push'
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index 6a7bc4b1888..5b0197ed58c 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -13,6 +13,7 @@
.milestones
#delete-milestone-modal
+ #promote-milestone-modal
%ul.content-list
= render @milestones
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index de381d489c6..b423888c875 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -27,8 +27,15 @@
Edit
- if @project.group
- = link_to promote_project_milestone_path(@milestone.project, @milestone), title: "Promote to Group Milestone", class: 'btn btn-grouped', data: { confirm: "Promoting #{@milestone.title} will make it available for all projects inside #{@project.group.name}. Existing project milestones with the same name will be merged. This action cannot be reversed.", toggle: "tooltip" }, method: :post do
- Promote
+ %button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal',
+ target: '#promote-milestone-modal',
+ milestone_title: @milestone.title,
+ url: promote_project_milestone_path(@milestone.project, @milestone),
+ container: 'body' },
+ disabled: true,
+ type: 'button' }
+ = _('Promote')
+ #promote-milestone-modal
- if @milestone.active?
= link_to 'Close milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-nr btn-grouped"
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 1d31b58a2cc..8cdb0a6aff4 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -73,7 +73,7 @@
= icon('gitlab', text: 'GitLab export')
%div
- if github_import_enabled?
- = link_to new_import_github_path, class: 'btn import_github' do
+ = link_to new_import_github_path, class: 'btn js-import-github' do
= icon('github', text: 'GitHub')
%div
- if bitbucket_import_enabled?
diff --git a/app/views/projects/pipelines/show.html.haml b/app/views/projects/pipelines/show.html.haml
index ffb0ae95f9b..a7d7c923957 100644
--- a/app/views/projects/pipelines/show.html.haml
+++ b/app/views/projects/pipelines/show.html.haml
@@ -10,6 +10,3 @@
= render "projects/pipelines/with_tabs", pipeline: @pipeline
.js-pipeline-details-vue{ data: { endpoint: project_pipeline_path(@project, @pipeline, format: :json) } }
-
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag('common_vue')
diff --git a/app/views/projects/registry/repositories/index.html.haml b/app/views/projects/registry/repositories/index.html.haml
index 27e1f9fba3e..12d56e244ce 100644
--- a/app/views/projects/registry/repositories/index.html.haml
+++ b/app/views/projects/registry/repositories/index.html.haml
@@ -14,8 +14,6 @@
.col-lg-12
#js-vue-registry-images{ data: { endpoint: project_container_registry_index_path(@project, format: :json) } }
- = webpack_bundle_tag('common_vue')
-
.row.prepend-top-10
.col-lg-12
.panel.panel-default
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index 17e804d682b..053ea24b848 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -5,6 +5,9 @@
= boolean_to_icon @service.activated?
%p= @service.description
+
+ - if @service.respond_to?(:detailed_description)
+ %p= @service.detailed_description
.col-lg-9
= form_for(@service, as: :service, url: project_service_path(@project, @service.to_param), method: :put, html: { class: 'gl-show-field-errors form-horizontal integration-settings-form js-integration-settings-form', data: { 'can-test' => @service.can_test?, 'test-url' => test_project_service_path(@project, @service) } }) do |form|
= render 'shared/service_settings', form: form, subject: @service
diff --git a/app/views/projects/services/prometheus/_show.html.haml b/app/views/projects/services/prometheus/_show.html.haml
index 6dc2b85fd32..43e6a173108 100644
--- a/app/views/projects/services/prometheus/_show.html.haml
+++ b/app/views/projects/services/prometheus/_show.html.haml
@@ -7,21 +7,19 @@
= link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus')
.col-lg-9
- .panel.panel-default.js-panel-monitored-metrics{ data: { active_metrics: active_common_project_prometheus_metrics_path(@project, :json) } }
+ .panel.panel-default.js-panel-monitored-metrics{ data: { active_metrics: active_common_project_prometheus_metrics_path(@project, :json), metrics_help_path: help_page_path('user/project/integrations/prometheus_library/metrics') } }
.panel-heading
%h3.panel-title
- = s_('PrometheusService|Monitored')
+ = s_('PrometheusService|Common metrics')
%span.badge.js-monitored-count 0
.panel-body
- .loading-metrics.text-center.js-loading-metrics
- = icon('spinner spin 3x', class: 'metrics-load-spinner')
- %p
+ .loading-metrics.js-loading-metrics
+ %p.prepend-top-10.prepend-left-10
+ = icon('spinner spin', class: 'metrics-load-spinner')
= s_('PrometheusService|Finding and configuring metrics...')
- .empty-metrics.text-center.hidden.js-empty-metrics
- = custom_icon('icon_empty_metrics')
- %p
- = s_('PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment.')
- = link_to s_('PrometheusService|View environments'), project_environments_path(@project), class: 'btn btn-success'
+ .empty-metrics.hidden.js-empty-metrics
+ %p.text-tertiary.prepend-top-10.prepend-left-10
+ = s_('PrometheusService|Waiting for your first deployment to an environment to find common metrics')
%ul.list-unstyled.metrics-list.hidden.js-metrics-list
.panel.panel-default.hidden.js-panel-missing-env-vars
diff --git a/app/views/projects/settings/repository/show.html.haml b/app/views/projects/settings/repository/show.html.haml
index 235d532bf98..6bef4d19434 100644
--- a/app/views/projects/settings/repository/show.html.haml
+++ b/app/views/projects/settings/repository/show.html.haml
@@ -2,9 +2,6 @@
- page_title "Repository"
- @content_class = "limit-container-width" unless fluid_layout
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag('common_vue')
-
-# Protected branches & tags use a lot of nested partials.
-# The shared parts of the views can be found in the `shared` directory.
-# Those are used throughout the actual views. These `shared` views are then
diff --git a/app/views/shared/_label.html.haml b/app/views/shared/_label.html.haml
index 8847d11f623..5afbc78df53 100644
--- a/app/views/shared/_label.html.haml
+++ b/app/views/shared/_label.html.haml
@@ -48,8 +48,16 @@
.pull-right.hidden-xs.hidden-sm
- if label.is_a?(ProjectLabel) && label.project.group && can?(current_user, :admin_label, label.project.group)
- = link_to promote_project_label_path(label.project, label), title: "Promote to Group Label", class: 'btn btn-transparent btn-action', data: {confirm: "Promoting #{label.title} will make it available for all projects inside #{label.project.group.name}. Existing project labels with the same name will be merged. This action cannot be reversed.", toggle: "tooltip"}, method: :post do
- %span.sr-only Promote to Group
+ %button.js-promote-project-label-button.btn.btn-transparent.btn-action.has-tooltip{ title: _('Promote to Group Label'),
+ disabled: true,
+ type: 'button',
+ data: { url: promote_project_label_path(label.project, label),
+ label_title: label.title,
+ label_color: label.color,
+ label_text_color: label.text_color,
+ target: '#promote-label-modal',
+ container: 'body',
+ toggle: 'modal' } }
= sprite_icon('level-up')
- if can?(current_user, :admin_label, label)
= link_to edit_label_path(label), title: "Edit", class: 'btn btn-transparent btn-action', data: {toggle: "tooltip"} do
diff --git a/app/views/shared/_new_commit_form.html.haml b/app/views/shared/_new_commit_form.html.haml
index 0a4a24ae807..9221fd1e025 100644
--- a/app/views/shared/_new_commit_form.html.haml
+++ b/app/views/shared/_new_commit_form.html.haml
@@ -1,3 +1,6 @@
+- project = @project.present(current_user: current_user)
+- branch_name = selected_branch
+
= render 'shared/commit_message_container', placeholder: placeholder
- if @project.empty_repo?
@@ -7,12 +10,14 @@
.form-group.branch
= label_tag 'branch_name', _('Target Branch'), class: 'control-label'
.col-sm-10
- = text_field_tag 'branch_name', @branch_name || tree_edit_branch, required: true, class: "form-control js-branch-name ref-name"
+ = text_field_tag 'branch_name', branch_name, required: true, class: "form-control js-branch-name ref-name"
.js-create-merge-request-container
= render 'shared/new_merge_request_checkbox'
+ - elsif project.can_current_user_push_to_branch?(branch_name)
+ = hidden_field_tag 'branch_name', branch_name
- else
- = hidden_field_tag 'branch_name', @branch_name || tree_edit_branch
+ = hidden_field_tag 'branch_name', branch_name
= hidden_field_tag 'create_merge_request', 1
= hidden_field_tag 'original_branch', @ref, class: 'js-original-branch'
diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml
index 61b39afb5d4..355b3ac75ae 100644
--- a/app/views/shared/_service_settings.html.haml
+++ b/app/views/shared/_service_settings.html.haml
@@ -13,12 +13,12 @@
.col-sm-10
= form.check_box :active, disabled: disable_fields_service?(@service)
- - if @service.supported_events.present?
+ - if @service.configurable_events.present?
.form-group
= form.label :url, "Trigger", class: 'control-label'
.col-sm-10
- - @service.supported_events.each do |event|
+ - @service.configurable_events.each do |event|
%div
= form.check_box service_event_field_name(event), class: 'pull-left'
.prepend-left-20
diff --git a/app/views/shared/boards/_show.html.haml b/app/views/shared/boards/_show.html.haml
index 3ac4245a61b..44b09545a61 100644
--- a/app/views/shared/boards/_show.html.haml
+++ b/app/views/shared/boards/_show.html.haml
@@ -7,7 +7,6 @@
- page_title "Boards"
- content_for :page_specific_javascripts do
- = webpack_bundle_tag 'common_vue'
-# haml-lint:disable InlineJavaScript
%script#js-board-template{ type: "text/x-template" }= render "shared/boards/components/board"
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 6dfabd7ba4c..4c8f03f1498 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -33,6 +33,8 @@
= render 'shared/issuable/form/merge_params', issuable: issuable
+= render 'shared/issuable/form/contribution', issuable: issuable, form: form
+
- if @merge_request_to_resolve_discussions_of
.form-group
.col-sm-10.col-sm-offset-2
diff --git a/app/views/shared/issuable/form/_contribution.html.haml b/app/views/shared/issuable/form/_contribution.html.haml
new file mode 100644
index 00000000000..0f2d313a5cc
--- /dev/null
+++ b/app/views/shared/issuable/form/_contribution.html.haml
@@ -0,0 +1,20 @@
+- issuable = local_assigns.fetch(:issuable)
+- form = local_assigns.fetch(:form)
+
+- return unless issuable.is_a?(MergeRequest)
+- return unless issuable.for_fork?
+- return unless can?(current_user, :push_code, issuable.source_project)
+
+%hr
+
+.form-group
+ .control-label
+ = _('Contribution')
+ .col-sm-10
+ .checkbox
+ = form.label :allow_maintainer_to_push do
+ = form.check_box :allow_maintainer_to_push, disabled: !issuable.can_allow_maintainer_to_push?(current_user)
+ = _('Allow edits from maintainers')
+ = link_to 'About this feature', help_page_path('user/project/merge_requests/maintainer_access')
+ .help-block
+ = allow_maintainer_push_unavailable_reason(issuable)
diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml
index da01fc02d07..5926867e2d7 100644
--- a/app/views/shared/milestones/_milestone.html.haml
+++ b/app/views/shared/milestones/_milestone.html.haml
@@ -51,18 +51,25 @@
\
- if @project.group
- = link_to promote_project_milestone_path(milestone.project, milestone), title: "Promote to Group Milestone", class: 'btn btn-xs btn-grouped', data: { confirm: "Promoting #{milestone.title} will make it available for all projects inside #{@project.group.name}. Existing project milestones with the same name will be merged. This action cannot be reversed.", toggle: "tooltip" }, method: :post do
- Promote
+ %button.js-promote-project-milestone-button.btn.btn-xs.btn-grouped.has-tooltip{ title: _('Promote to Group Milestone'),
+ disabled: true,
+ type: 'button',
+ data: { url: promote_project_milestone_path(milestone.project, milestone),
+ milestone_title: milestone.title,
+ target: '#promote-milestone-modal',
+ container: 'body',
+ toggle: 'modal' } }
+ = _('Promote')
= link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-xs btn-close btn-grouped"
- %button.js-delete-milestone-button.btn.btn-xs.btn-grouped.btn-danger{ data: { toggle: 'modal',
- target: '#delete-milestone-modal',
- milestone_id: milestone.id,
- milestone_title: markdown_field(milestone, :title),
- milestone_url: project_milestone_path(milestone.project, milestone),
- milestone_issue_count: milestone.issues.count,
- milestone_merge_request_count: milestone.merge_requests.count },
- disabled: true }
- = _('Delete')
- = icon('spin spinner', class: 'js-loading-icon hidden' )
+ %button.js-delete-milestone-button.btn.btn-xs.btn-grouped.btn-danger{ data: { toggle: 'modal',
+ target: '#delete-milestone-modal',
+ milestone_id: milestone.id,
+ milestone_title: markdown_field(milestone, :title),
+ milestone_url: project_milestone_path(milestone.project, milestone),
+ milestone_issue_count: milestone.issues.count,
+ milestone_merge_request_count: milestone.merge_requests.count },
+ disabled: true }
+ = _('Delete')
+ = icon('spin spinner', class: 'js-loading-icon hidden' )
diff --git a/app/views/shared/plugins/_index.html.haml b/app/views/shared/plugins/_index.html.haml
new file mode 100644
index 00000000000..fc643c3ecc2
--- /dev/null
+++ b/app/views/shared/plugins/_index.html.haml
@@ -0,0 +1,23 @@
+- plugins = Gitlab::Plugin.files
+
+.row.prepend-top-default
+ .col-lg-4
+ %h4.prepend-top-0
+ Plugins
+ %p
+ #{link_to 'Plugins', help_page_path('administration/plugins')} are similar to
+ system hooks but are executed as files instead of sending data to a URL.
+
+ .col-lg-8.append-bottom-default
+ - if plugins.any?
+ .panel.panel-default
+ .panel-heading
+ Plugins (#{plugins.count})
+ %ul.content-list
+ - plugins.each do |file|
+ %li
+ .monospace
+ = File.basename(file)
+ - else
+ %p.light-well.text-center
+ No plugins found.
diff --git a/app/views/shared/projects/_edit_information.html.haml b/app/views/shared/projects/_edit_information.html.haml
new file mode 100644
index 00000000000..ec9dc8f62c2
--- /dev/null
+++ b/app/views/shared/projects/_edit_information.html.haml
@@ -0,0 +1,6 @@
+- unless can?(current_user, :push_code, @project)
+ .inline.prepend-left-10
+ - if @project.branch_allows_maintainer_push?(current_user, selected_branch)
+ = commit_in_single_accessible_branch
+ - else
+ = commit_in_fork_help
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index 21da27973fe..2a4d65b5cb3 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -66,7 +66,7 @@ class EmailsOnPushWorker
# These are input errors and won't be corrected even if Sidekiq retries
rescue Net::SMTPFatalError, Net::SMTPSyntaxError => e
- logger.info("Failed to send e-mail for project '#{project.name_with_namespace}' to #{recipient}: #{e}")
+ logger.info("Failed to send e-mail for project '#{project.full_name}' to #{recipient}: #{e}")
end
end
ensure
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index f2b2c4428d3..3909dbf7d7f 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -55,7 +55,7 @@ class PostReceive
end
def process_wiki_changes(post_received)
- # Nothing defined here yet.
+ post_received.project.touch(:last_activity_at, :last_repository_updated_at)
end
def log(message)
diff --git a/changelogs/unreleased/39444-make-margin-around-dropdown-dividers-4px.yml b/changelogs/unreleased/39444-make-margin-around-dropdown-dividers-4px.yml
new file mode 100644
index 00000000000..da65cfff799
--- /dev/null
+++ b/changelogs/unreleased/39444-make-margin-around-dropdown-dividers-4px.yml
@@ -0,0 +1,5 @@
+---
+title: Set margins around dropdown dividers to 4px
+merge_request: 17517
+author:
+type: fixed
diff --git a/changelogs/unreleased/40525-listing-user-activity-timeouts.yml b/changelogs/unreleased/40525-listing-user-activity-timeouts.yml
new file mode 100644
index 00000000000..39ce873dba6
--- /dev/null
+++ b/changelogs/unreleased/40525-listing-user-activity-timeouts.yml
@@ -0,0 +1,5 @@
+---
+title: Improve database response time for user activity listing.
+merge_request: 17454
+author:
+type: performance
diff --git a/changelogs/unreleased/42921-ci-charts-include-current-day.yml b/changelogs/unreleased/42921-ci-charts-include-current-day.yml
new file mode 100644
index 00000000000..d0de6665735
--- /dev/null
+++ b/changelogs/unreleased/42921-ci-charts-include-current-day.yml
@@ -0,0 +1,5 @@
+---
+title: CI charts now include the current day
+merge_request: 17032
+author: Dakkaron
+type: changed
diff --git a/changelogs/unreleased/43261-fix-prometheus-installation.yml b/changelogs/unreleased/43261-fix-prometheus-installation.yml
deleted file mode 100644
index b5fc7980390..00000000000
--- a/changelogs/unreleased/43261-fix-prometheus-installation.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow Prometheus application to be installed from Cluster applications
-merge_request: 17372
-author:
-type: fixed
diff --git a/changelogs/unreleased/43460-track-projects-a-user-interacted-with.yml b/changelogs/unreleased/43460-track-projects-a-user-interacted-with.yml
new file mode 100644
index 00000000000..99b6ac76a3e
--- /dev/null
+++ b/changelogs/unreleased/43460-track-projects-a-user-interacted-with.yml
@@ -0,0 +1,5 @@
+---
+title: Keep track of projects a user interacted with.
+merge_request: 17327
+author:
+type: other
diff --git a/changelogs/unreleased/43510-merge-requests-and-issues-don-t-show-for-all-subgroups.yml b/changelogs/unreleased/43510-merge-requests-and-issues-don-t-show-for-all-subgroups.yml
deleted file mode 100644
index e163c04f430..00000000000
--- a/changelogs/unreleased/43510-merge-requests-and-issues-don-t-show-for-all-subgroups.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Ensure group issues and merge requests pages show results from subgroups when
- there are no results from the current group
-merge_request: 17312
-author:
-type: fixed
diff --git a/changelogs/unreleased/43531-500-error-searching-wiki-incompatible-character-encodings-utf-8-and-ascii-8bit.yml b/changelogs/unreleased/43531-500-error-searching-wiki-incompatible-character-encodings-utf-8-and-ascii-8bit.yml
deleted file mode 100644
index 173710412a5..00000000000
--- a/changelogs/unreleased/43531-500-error-searching-wiki-incompatible-character-encodings-utf-8-and-ascii-8bit.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix code and wiki search results pages when non-ASCII text is displayed
-merge_request: 17413
-author:
-type: fixed
diff --git a/changelogs/unreleased/43532-error-on-admin-applications-prometheus-template.yml b/changelogs/unreleased/43532-error-on-admin-applications-prometheus-template.yml
deleted file mode 100644
index 25bcbf2fbab..00000000000
--- a/changelogs/unreleased/43532-error-on-admin-applications-prometheus-template.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixes Prometheus admin configuration page
-merge_request: 17377
-author:
-type: fixed
diff --git a/changelogs/unreleased/43780-add-a-paragraph-about-clusters-security-implications.yml b/changelogs/unreleased/43780-add-a-paragraph-about-clusters-security-implications.yml
new file mode 100644
index 00000000000..0fa21a2013c
--- /dev/null
+++ b/changelogs/unreleased/43780-add-a-paragraph-about-clusters-security-implications.yml
@@ -0,0 +1,5 @@
+---
+title: Add a paragraph about security implications on Cluster's page
+merge_request: 17486
+author:
+type: added
diff --git a/changelogs/unreleased/43802-ensure-foreign-keys-on-clusters-applications.yml b/changelogs/unreleased/43802-ensure-foreign-keys-on-clusters-applications.yml
new file mode 100644
index 00000000000..860a8becd65
--- /dev/null
+++ b/changelogs/unreleased/43802-ensure-foreign-keys-on-clusters-applications.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure foreign keys on clusters applications
+merge_request: 17488
+author:
+type: other
diff --git a/changelogs/unreleased/43949-verify-job-artifacts.yml b/changelogs/unreleased/43949-verify-job-artifacts.yml
new file mode 100644
index 00000000000..45e1916ae17
--- /dev/null
+++ b/changelogs/unreleased/43949-verify-job-artifacts.yml
@@ -0,0 +1,5 @@
+---
+title: Implement foreground verification of CI artifacts
+merge_request: 17578
+author:
+type: added
diff --git a/changelogs/unreleased/bvl-allow-maintainer-to-push.yml b/changelogs/unreleased/bvl-allow-maintainer-to-push.yml
new file mode 100644
index 00000000000..a3fefc2889a
--- /dev/null
+++ b/changelogs/unreleased/bvl-allow-maintainer-to-push.yml
@@ -0,0 +1,5 @@
+---
+title: Allow maintainers to push to forks of their projects when a merge request is open
+merge_request: 17395
+author:
+type: added
diff --git a/changelogs/unreleased/ce-jej-github-project-service-for-ci.yml b/changelogs/unreleased/ce-jej-github-project-service-for-ci.yml
new file mode 100644
index 00000000000..6102b7ecd93
--- /dev/null
+++ b/changelogs/unreleased/ce-jej-github-project-service-for-ci.yml
@@ -0,0 +1,5 @@
+---
+title: Hook data for pipelines includes detailed_status
+merge_request: 17607
+author:
+type: changed
diff --git a/changelogs/unreleased/ce-jej-integrations-can-hide-trigger-checkboxes.yml b/changelogs/unreleased/ce-jej-integrations-can-hide-trigger-checkboxes.yml
new file mode 100644
index 00000000000..771df06e7a6
--- /dev/null
+++ b/changelogs/unreleased/ce-jej-integrations-can-hide-trigger-checkboxes.yml
@@ -0,0 +1,6 @@
+---
+title: Avoid showing unnecessary Trigger checkboxes for project Integrations with
+ only one event
+merge_request: 17607
+author:
+type: changed
diff --git a/changelogs/unreleased/discussions-api.yml b/changelogs/unreleased/discussions-api.yml
new file mode 100644
index 00000000000..110df3aa414
--- /dev/null
+++ b/changelogs/unreleased/discussions-api.yml
@@ -0,0 +1,5 @@
+---
+title: Add discussions API for Issues and Snippets
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/dz-plugins-project-integrations.yml b/changelogs/unreleased/dz-plugins-project-integrations.yml
new file mode 100644
index 00000000000..9dbe82f9af8
--- /dev/null
+++ b/changelogs/unreleased/dz-plugins-project-integrations.yml
@@ -0,0 +1,5 @@
+---
+title: Add plugins list to the system hooks page
+merge_request: 17518
+author:
+type: added
diff --git a/changelogs/unreleased/feature--43691-count-diff-note-calendar-activity.yml b/changelogs/unreleased/feature--43691-count-diff-note-calendar-activity.yml
index 768686aeda8..d8020592897 100644
--- a/changelogs/unreleased/feature--43691-count-diff-note-calendar-activity.yml
+++ b/changelogs/unreleased/feature--43691-count-diff-note-calendar-activity.yml
@@ -1,5 +1,5 @@
---
-title: Count comments on diffs as contributions for the contributions calendar
+title: Count comments on diffs and discussions as contributions for the contributions calendar
merge_request: 17418
author: Riccardo Padovani
type: fixed
diff --git a/changelogs/unreleased/fix-mattermost-delete-team.yml b/changelogs/unreleased/fix-mattermost-delete-team.yml
new file mode 100644
index 00000000000..d14ae023114
--- /dev/null
+++ b/changelogs/unreleased/fix-mattermost-delete-team.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed group deletion linked to Mattermost
+merge_request: 16209
+author: Julien Millau
+type: fixed
diff --git a/changelogs/unreleased/fix-sm-fix_pages_worker.yml b/changelogs/unreleased/fix-sm-fix_pages_worker.yml
deleted file mode 100644
index 190c7d3e83e..00000000000
--- a/changelogs/unreleased/fix-sm-fix_pages_worker.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix pages flaky failure by reloading stale object
-merge_request: 17522
-author:
-type: fixed
diff --git a/changelogs/unreleased/grpc-unavailable-restart.yml b/changelogs/unreleased/grpc-unavailable-restart.yml
deleted file mode 100644
index 5ce08d66004..00000000000
--- a/changelogs/unreleased/grpc-unavailable-restart.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Restart Unicorn and Sidekiq when GRPC throws 14:Endpoint read failed
-merge_request: 17293
-author:
-type: fixed
diff --git a/changelogs/unreleased/issue-edit-shortcut.yml b/changelogs/unreleased/issue-edit-shortcut.yml
deleted file mode 100644
index 2b29b2bc03f..00000000000
--- a/changelogs/unreleased/issue-edit-shortcut.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed issue edit shortcut not opening edit form
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/jivl-new-modal-project-labels-milestones.yml b/changelogs/unreleased/jivl-new-modal-project-labels-milestones.yml
new file mode 100644
index 00000000000..6b7e14c6cfc
--- /dev/null
+++ b/changelogs/unreleased/jivl-new-modal-project-labels-milestones.yml
@@ -0,0 +1,5 @@
+---
+title: Added new design for promotion modals
+merge_request: 17197
+author:
+type: other
diff --git a/changelogs/unreleased/minimal-fix-for-artifacts-service.yml b/changelogs/unreleased/minimal-fix-for-artifacts-service.yml
deleted file mode 100644
index 11f5bc17759..00000000000
--- a/changelogs/unreleased/minimal-fix-for-artifacts-service.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Prevent trace artifact migration to incur data loss
-merge_request: 17313
-author:
-type: fixed
diff --git a/changelogs/unreleased/mk-fix-error-code-for-repo-does-not-exist.yml b/changelogs/unreleased/mk-fix-error-code-for-repo-does-not-exist.yml
deleted file mode 100644
index a761d610da1..00000000000
--- a/changelogs/unreleased/mk-fix-error-code-for-repo-does-not-exist.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Return a 404 instead of 403 if the repository does not exist on disk
-merge_request: 17341
-author:
-type: fixed
diff --git a/changelogs/unreleased/mr-commit-optimization.yml b/changelogs/unreleased/mr-commit-optimization.yml
new file mode 100644
index 00000000000..522d8951b18
--- /dev/null
+++ b/changelogs/unreleased/mr-commit-optimization.yml
@@ -0,0 +1,5 @@
+---
+title: Use persisted/memoized value for MRs shas instead of doing git lookups
+merge_request: 17555
+author:
+type: performance
diff --git a/changelogs/unreleased/refactor-move-mr-widget-memory-usage-and-graph-components.yml b/changelogs/unreleased/refactor-move-mr-widget-memory-usage-and-graph-components.yml
new file mode 100644
index 00000000000..96e63343963
--- /dev/null
+++ b/changelogs/unreleased/refactor-move-mr-widget-memory-usage-and-graph-components.yml
@@ -0,0 +1,5 @@
+---
+title: Move MemoryGraph and MemoryUsage vue components
+merge_request: 17533
+author: George Tsiolis
+type: performance
diff --git a/changelogs/unreleased/refactor-move-sidebar-assignee-vue-component.yml b/changelogs/unreleased/refactor-move-sidebar-assignee-vue-component.yml
new file mode 100644
index 00000000000..e77b651363e
--- /dev/null
+++ b/changelogs/unreleased/refactor-move-sidebar-assignee-vue-component.yml
@@ -0,0 +1,5 @@
+---
+title: Move SidebarAssignees vue component
+merge_request: 17398
+author: George Tsiolis
+type: performance
diff --git a/changelogs/unreleased/remove-projects-finder-from-todos-finder.yml b/changelogs/unreleased/remove-projects-finder-from-todos-finder.yml
deleted file mode 100644
index 0a3fc751edb..00000000000
--- a/changelogs/unreleased/remove-projects-finder-from-todos-finder.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Don't use ProjectsFinder in TodosFinder
-merge_request:
-author:
-type: performance
diff --git a/changelogs/unreleased/replace_redcarpet_with_cmark.yml b/changelogs/unreleased/replace_redcarpet_with_cmark.yml
new file mode 100644
index 00000000000..7ce848b0bbd
--- /dev/null
+++ b/changelogs/unreleased/replace_redcarpet_with_cmark.yml
@@ -0,0 +1,5 @@
+---
+title: Add CommonMark markdown engine (experimental)
+merge_request: 14835
+author: blackst0ne
+type: added
diff --git a/changelogs/unreleased/revert-project-visibility-changes.yml b/changelogs/unreleased/revert-project-visibility-changes.yml
deleted file mode 100644
index df44fdb79b1..00000000000
--- a/changelogs/unreleased/revert-project-visibility-changes.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Revert Project.public_or_visible_to_user changes and only apply to snippets
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-add-missing-acts-as-taggable-indices.yml b/changelogs/unreleased/sh-add-missing-acts-as-taggable-indices.yml
new file mode 100644
index 00000000000..d9a1a0db9e8
--- /dev/null
+++ b/changelogs/unreleased/sh-add-missing-acts-as-taggable-indices.yml
@@ -0,0 +1,5 @@
+---
+title: Adding missing indexes on taggings table
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-add-section-name-index.yml b/changelogs/unreleased/sh-add-section-name-index.yml
new file mode 100644
index 00000000000..c822b4e851b
--- /dev/null
+++ b/changelogs/unreleased/sh-add-section-name-index.yml
@@ -0,0 +1,5 @@
+---
+title: Add index on section_name_id on ci_build_trace_sections table
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-fix-otp-backup-code-invalidation.yml b/changelogs/unreleased/sh-fix-otp-backup-code-invalidation.yml
new file mode 100644
index 00000000000..cedb09c9a7a
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-otp-backup-code-invalidation.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure that OTP backup codes are always invalidated
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/sh-make-prune-optional-in-git-fetch.yml b/changelogs/unreleased/sh-make-prune-optional-in-git-fetch.yml
new file mode 100644
index 00000000000..e961a23a031
--- /dev/null
+++ b/changelogs/unreleased/sh-make-prune-optional-in-git-fetch.yml
@@ -0,0 +1,5 @@
+---
+title: Make --prune a configurable parameter in fetching a git remote
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-remove-double-caching-repo-empty.yml b/changelogs/unreleased/sh-remove-double-caching-repo-empty.yml
new file mode 100644
index 00000000000..1684be4e5e3
--- /dev/null
+++ b/changelogs/unreleased/sh-remove-double-caching-repo-empty.yml
@@ -0,0 +1,5 @@
+---
+title: Remove double caching of Repository#empty?
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/unassign-when-leaving.yml b/changelogs/unreleased/unassign-when-leaving.yml
new file mode 100644
index 00000000000..c00a87b1749
--- /dev/null
+++ b/changelogs/unreleased/unassign-when-leaving.yml
@@ -0,0 +1,5 @@
+---
+title: Don't delete todos or unassign issues and MRs when a user leaves a project
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/upgrade-workhorse-4-0-0.yml b/changelogs/unreleased/upgrade-workhorse-4-0-0.yml
new file mode 100644
index 00000000000..f9dbdc7fc56
--- /dev/null
+++ b/changelogs/unreleased/upgrade-workhorse-4-0-0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade GitLab Workhorse to 4.0.0
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/zj-gitaly-encoding-issue.yml b/changelogs/unreleased/zj-gitaly-encoding-issue.yml
deleted file mode 100644
index 073d8f38e4b..00000000000
--- a/changelogs/unreleased/zj-gitaly-encoding-issue.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Encode branch name as binary before creating a RPC request to copy attributes
-merge_request: 17291
-author:
-type: fixed
diff --git a/changelogs/unreleased/zj-move-opt-out-ruby-endpoints.yml b/changelogs/unreleased/zj-move-opt-out-ruby-endpoints.yml
new file mode 100644
index 00000000000..0ddb42bc80a
--- /dev/null
+++ b/changelogs/unreleased/zj-move-opt-out-ruby-endpoints.yml
@@ -0,0 +1,5 @@
+---
+title: Move Ruby endpoints to OPT_OUT
+merge_request:
+author:
+type: other
diff --git a/config/application.rb b/config/application.rb
index 74fe3e439ed..ac6e4be4282 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -194,4 +194,10 @@ module Gitlab
Gitlab::Routing.add_helpers(MilestonesRoutingHelper)
end
end
+
+ # This method is used for smooth upgrading from the current Rails 4.x to Rails 5.0.
+ # https://gitlab.com/gitlab-org/gitlab-ce/issues/14286
+ def self.rails5?
+ ENV["RAILS5"].in?(%w[1 true])
+ end
end
diff --git a/config/initializers/8_metrics.rb b/config/initializers/8_metrics.rb
index 45b39b2a38d..7cdf49159b4 100644
--- a/config/initializers/8_metrics.rb
+++ b/config/initializers/8_metrics.rb
@@ -94,6 +94,7 @@ def instrument_classes(instrumentation)
instrumentation.instrument_instance_methods(RepositoryCheck::SingleRepositoryWorker)
+ instrumentation.instrument_instance_methods(Rouge::Plugins::CommonMark)
instrumentation.instrument_instance_methods(Rouge::Plugins::Redcarpet)
instrumentation.instrument_instance_methods(Rouge::Formatters::HTMLGitlab)
diff --git a/config/routes/git_http.rb b/config/routes/git_http.rb
index ff51823897d..ec5c68f81df 100644
--- a/config/routes/git_http.rb
+++ b/config/routes/git_http.rb
@@ -40,7 +40,7 @@ scope(path: '*namespace_id/:project_id',
# /info/refs?service=git-receive-pack, but nothing else.
#
git_http_handshake = lambda do |request|
- ProjectUrlConstrainer.new.matches?(request) &&
+ ::Constraints::ProjectUrlConstrainer.new.matches?(request) &&
(request.query_string.blank? ||
request.query_string.match(/\Aservice=git-(upload|receive)-pack\z/))
end
diff --git a/config/routes/group.rb b/config/routes/group.rb
index 710f12e33ad..d89a714c7d6 100644
--- a/config/routes/group.rb
+++ b/config/routes/group.rb
@@ -1,10 +1,8 @@
-require 'constraints/group_url_constrainer'
-
resources :groups, only: [:index, :new, :create] do
post :preview_markdown
end
-constraints(GroupUrlConstrainer.new) do
+constraints(::Constraints::GroupUrlConstrainer.new) do
scope(path: 'groups/*id',
controller: :groups,
constraints: { id: Gitlab::PathRegex.full_namespace_route_regex, format: /(html|json|atom)/ }) do
diff --git a/config/routes/project.rb b/config/routes/project.rb
index cb46c439415..b82ed27664c 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -1,10 +1,8 @@
-require 'constraints/project_url_constrainer'
-
resources :projects, only: [:index, :new, :create]
draw :git_http
-constraints(ProjectUrlConstrainer.new) do
+constraints(::Constraints::ProjectUrlConstrainer.new) do
# If the route has a wildcard segment, the segment has a regex constraint,
# the segment is potentially followed by _another_ wildcard segment, and
# the `format` option is not set to false, we need to specify that
@@ -69,7 +67,7 @@ constraints(ProjectUrlConstrainer.new) do
end
end
- resources :services, constraints: { id: %r{[^/]+} }, only: [:index, :edit, :update] do
+ resources :services, constraints: { id: %r{[^/]+} }, only: [:edit, :update] do
member do
put :test
end
diff --git a/config/routes/user.rb b/config/routes/user.rb
index 733a3f6ce9a..57fb37530bb 100644
--- a/config/routes/user.rb
+++ b/config/routes/user.rb
@@ -1,5 +1,3 @@
-require 'constraints/user_url_constrainer'
-
devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks,
registrations: :registrations,
passwords: :passwords,
@@ -35,7 +33,7 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d
get '/u/:username/contributed', to: redirect('users/%{username}/contributed')
end
-constraints(UserUrlConstrainer.new) do
+constraints(::Constraints::UserUrlConstrainer.new) do
# Get all keys of user
get ':username.keys' => 'profiles/keys#get_keys', constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 19eeb497a14..3403c0c207d 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -44,8 +44,6 @@ function generateEntries() {
const manualEntries = {
common: './commons/index.js',
- common_vue: './vue_shared/vue_resource_interceptor.js',
- locale: './locale/index.js',
main: './main.js',
raven: './raven/index.js',
webpack_runtime: './webpack.js',
diff --git a/db/migrate/20180221151752_add_allow_maintainer_to_push_to_merge_requests.rb b/db/migrate/20180221151752_add_allow_maintainer_to_push_to_merge_requests.rb
new file mode 100644
index 00000000000..81acfbc3655
--- /dev/null
+++ b/db/migrate/20180221151752_add_allow_maintainer_to_push_to_merge_requests.rb
@@ -0,0 +1,18 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddAllowMaintainerToPushToMergeRequests < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column :merge_requests, :allow_maintainer_to_push, :boolean
+ end
+
+ def down
+ remove_column :merge_requests, :allow_maintainer_to_push
+ end
+end
diff --git a/db/migrate/20180223120443_create_user_interacted_projects_table.rb b/db/migrate/20180223120443_create_user_interacted_projects_table.rb
new file mode 100644
index 00000000000..20749940b1e
--- /dev/null
+++ b/db/migrate/20180223120443_create_user_interacted_projects_table.rb
@@ -0,0 +1,18 @@
+class CreateUserInteractedProjectsTable < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ create_table :user_interacted_projects, id: false do |t|
+ t.references :user, null: false
+ t.references :project, null: false
+ end
+ end
+
+ def down
+ drop_table :user_interacted_projects
+ end
+end
diff --git a/db/migrate/20180227182112_add_group_id_to_boards.rb b/db/migrate/20180227182112_add_group_id_to_boards_ce.rb
index 8e5460d44c9..f54dd8d7687 100644
--- a/db/migrate/20180227182112_add_group_id_to_boards.rb
+++ b/db/migrate/20180227182112_add_group_id_to_boards_ce.rb
@@ -1,4 +1,4 @@
-class AddGroupIdToBoards < ActiveRecord::Migration
+class AddGroupIdToBoardsCe < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
diff --git a/db/migrate/20180302152117_ensure_foreign_keys_on_clusters_applications.rb b/db/migrate/20180302152117_ensure_foreign_keys_on_clusters_applications.rb
new file mode 100644
index 00000000000..8298979e96a
--- /dev/null
+++ b/db/migrate/20180302152117_ensure_foreign_keys_on_clusters_applications.rb
@@ -0,0 +1,50 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class EnsureForeignKeysOnClustersApplications < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ existing = Clusters::Cluster
+ .joins(:application_ingress)
+ .where('clusters.id = clusters_applications_ingress.cluster_id')
+
+ Clusters::Applications::Ingress.where('NOT EXISTS (?)', existing).in_batches do |batch|
+ batch.delete_all
+ end
+
+ unless foreign_keys_for(:clusters_applications_ingress, :cluster_id).any?
+ add_concurrent_foreign_key :clusters_applications_ingress, :clusters,
+ column: :cluster_id,
+ on_delete: :cascade
+ end
+
+ existing = Clusters::Cluster
+ .joins(:application_prometheus)
+ .where('clusters.id = clusters_applications_prometheus.cluster_id')
+
+ Clusters::Applications::Ingress.where('NOT EXISTS (?)', existing).in_batches do |batch|
+ batch.delete_all
+ end
+
+ unless foreign_keys_for(:clusters_applications_prometheus, :cluster_id).any?
+ add_concurrent_foreign_key :clusters_applications_prometheus, :clusters,
+ column: :cluster_id,
+ on_delete: :cascade
+ end
+ end
+
+ def down
+ if foreign_keys_for(:clusters_applications_ingress, :cluster_id).any?
+ remove_foreign_key :clusters_applications_ingress, column: :cluster_id
+ end
+
+ if foreign_keys_for(:clusters_applications_prometheus, :cluster_id).any?
+ remove_foreign_key :clusters_applications_prometheus, column: :cluster_id
+ end
+ end
+end
diff --git a/db/migrate/20180304204842_clean_commits_count_migration.rb b/db/migrate/20180304204842_clean_commits_count_migration.rb
deleted file mode 100644
index ace4c6aa1cf..00000000000
--- a/db/migrate/20180304204842_clean_commits_count_migration.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class CleanCommitsCountMigration < ActiveRecord::Migration
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- Gitlab::BackgroundMigration.steal('AddMergeRequestDiffCommitsCount')
- end
-
- def down
- end
-end
diff --git a/db/migrate/20180306134842_add_missing_indexes_acts_as_taggable_on_engine.rb b/db/migrate/20180306134842_add_missing_indexes_acts_as_taggable_on_engine.rb
new file mode 100644
index 00000000000..06e402adcd7
--- /dev/null
+++ b/db/migrate/20180306134842_add_missing_indexes_acts_as_taggable_on_engine.rb
@@ -0,0 +1,21 @@
+# This migration comes from acts_as_taggable_on_engine (originally 6)
+#
+# It has been modified to handle no-downtime GitLab migrations. Several
+# indexes have been removed since they are not needed for GitLab.
+class AddMissingIndexesActsAsTaggableOnEngine < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :taggings, :tag_id unless index_exists? :taggings, :tag_id
+ add_concurrent_index :taggings, [:taggable_id, :taggable_type] unless index_exists? :taggings, [:taggable_id, :taggable_type]
+ end
+
+ def down
+ remove_concurrent_index :taggings, :tag_id
+ remove_concurrent_index :taggings, [:taggable_id, :taggable_type]
+ end
+end
diff --git a/db/migrate/20180308052825_add_section_name_id_index_on_ci_build_trace_sections.rb b/db/migrate/20180308052825_add_section_name_id_index_on_ci_build_trace_sections.rb
new file mode 100644
index 00000000000..0cf665ac935
--- /dev/null
+++ b/db/migrate/20180308052825_add_section_name_id_index_on_ci_build_trace_sections.rb
@@ -0,0 +1,22 @@
+class AddSectionNameIdIndexOnCiBuildTraceSections < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ # MySQL may already have this as a foreign key
+ unless index_exists?(:ci_build_trace_sections, :section_name_id)
+ add_concurrent_index :ci_build_trace_sections, :section_name_id
+ end
+ end
+
+ def down
+ # We cannot remove index for MySQL because it's needed for foreign key
+ if Gitlab::Database.postgresql?
+ remove_concurrent_index :ci_build_trace_sections, :section_name_id
+ end
+ end
+end
diff --git a/db/post_migrate/20180223124427_build_user_interacted_projects_table.rb b/db/post_migrate/20180223124427_build_user_interacted_projects_table.rb
new file mode 100644
index 00000000000..5e729b1aa53
--- /dev/null
+++ b/db/post_migrate/20180223124427_build_user_interacted_projects_table.rb
@@ -0,0 +1,124 @@
+class BuildUserInteractedProjectsTable < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ if Gitlab::Database.postgresql?
+ PostgresStrategy.new
+ else
+ MysqlStrategy.new
+ end.up
+
+ unless index_exists?(:user_interacted_projects, [:project_id, :user_id])
+ add_concurrent_index :user_interacted_projects, [:project_id, :user_id], unique: true
+ end
+
+ unless foreign_key_exists?(:user_interacted_projects, :user_id)
+ add_concurrent_foreign_key :user_interacted_projects, :users, column: :user_id, on_delete: :cascade
+ end
+
+ unless foreign_key_exists?(:user_interacted_projects, :project_id)
+ add_concurrent_foreign_key :user_interacted_projects, :projects, column: :project_id, on_delete: :cascade
+ end
+ end
+
+ def down
+ execute "TRUNCATE user_interacted_projects"
+
+ if foreign_key_exists?(:user_interacted_projects, :user_id)
+ remove_foreign_key :user_interacted_projects, :users
+ end
+
+ if foreign_key_exists?(:user_interacted_projects, :project_id)
+ remove_foreign_key :user_interacted_projects, :projects
+ end
+
+ if index_exists_by_name?(:user_interacted_projects, 'index_user_interacted_projects_on_project_id_and_user_id')
+ remove_concurrent_index_by_name :user_interacted_projects, 'index_user_interacted_projects_on_project_id_and_user_id'
+ end
+ end
+
+ private
+
+ # Rails' index_exists? doesn't work when you only give it a table and index
+ # name. As such we have to use some extra code to check if an index exists for
+ # a given name.
+ def index_exists_by_name?(table, index)
+ indexes_for_table[table].include?(index)
+ end
+
+ def indexes_for_table
+ @indexes_for_table ||= Hash.new do |hash, table_name|
+ hash[table_name] = indexes(table_name).map(&:name)
+ end
+ end
+
+ def foreign_key_exists?(table, column)
+ foreign_keys(table).any? do |key|
+ key.options[:column] == column.to_s
+ end
+ end
+
+ class PostgresStrategy < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ BATCH_SIZE = 100_000
+ SLEEP_TIME = 5
+
+ def up
+ with_index(:events, [:author_id, :project_id], name: 'events_user_interactions_temp', where: 'project_id IS NOT NULL') do
+ iteration = 0
+ records = 0
+ begin
+ Rails.logger.info "Building user_interacted_projects table, batch ##{iteration}"
+ result = execute <<~SQL
+ INSERT INTO user_interacted_projects (user_id, project_id)
+ SELECT e.user_id, e.project_id
+ FROM (SELECT DISTINCT author_id AS user_id, project_id FROM events WHERE project_id IS NOT NULL) AS e
+ LEFT JOIN user_interacted_projects ucp USING (user_id, project_id)
+ WHERE ucp.user_id IS NULL
+ LIMIT #{BATCH_SIZE}
+ SQL
+ iteration += 1
+ records += result.cmd_tuples
+ Rails.logger.info "Building user_interacted_projects table, batch ##{iteration} complete, created #{records} overall"
+ Kernel.sleep(SLEEP_TIME) if result.cmd_tuples > 0
+ rescue ActiveRecord::InvalidForeignKey => e
+ Rails.logger.info "Retry on InvalidForeignKey: #{e}"
+ retry
+ end while result.cmd_tuples > 0
+ end
+
+ execute "ANALYZE user_interacted_projects"
+
+ end
+
+ private
+
+ def with_index(*args)
+ add_concurrent_index(*args) unless index_exists?(*args)
+ yield
+ ensure
+ remove_concurrent_index(*args) if index_exists?(*args)
+ end
+ end
+
+ class MysqlStrategy < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ def up
+ execute <<~SQL
+ INSERT INTO user_interacted_projects (user_id, project_id)
+ SELECT e.user_id, e.project_id
+ FROM (SELECT DISTINCT author_id AS user_id, project_id FROM events WHERE project_id IS NOT NULL) AS e
+ LEFT JOIN user_interacted_projects ucp USING (user_id, project_id)
+ WHERE ucp.user_id IS NULL
+ SQL
+ end
+ end
+
+end
diff --git a/db/schema.rb b/db/schema.rb
index d49bf022d0b..75a094bbbb6 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20180307012445) do
+ActiveRecord::Schema.define(version: 20180308052825) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -264,6 +264,7 @@ ActiveRecord::Schema.define(version: 20180307012445) do
add_index "ci_build_trace_sections", ["build_id", "section_name_id"], name: "index_ci_build_trace_sections_on_build_id_and_section_name_id", unique: true, using: :btree
add_index "ci_build_trace_sections", ["project_id"], name: "index_ci_build_trace_sections_on_project_id", using: :btree
+ add_index "ci_build_trace_sections", ["section_name_id"], name: "index_ci_build_trace_sections_on_section_name_id", using: :btree
create_table "ci_builds", force: :cascade do |t|
t.string "status"
@@ -1145,6 +1146,7 @@ ActiveRecord::Schema.define(version: 20180307012445) do
t.boolean "discussion_locked"
t.integer "latest_merge_request_diff_id"
t.string "rebase_commit_sha"
+ t.boolean "allow_maintainer_to_push"
end
add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
@@ -1732,7 +1734,9 @@ ActiveRecord::Schema.define(version: 20180307012445) do
end
add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true, using: :btree
+ add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id", using: :btree
add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree
+ add_index "taggings", ["taggable_id", "taggable_type"], name: "index_taggings_on_taggable_id_and_taggable_type", using: :btree
create_table "tags", force: :cascade do |t|
t.string "name"
@@ -1843,6 +1847,13 @@ ActiveRecord::Schema.define(version: 20180307012445) do
add_index "user_custom_attributes", ["key", "value"], name: "index_user_custom_attributes_on_key_and_value", using: :btree
add_index "user_custom_attributes", ["user_id", "key"], name: "index_user_custom_attributes_on_user_id_and_key", unique: true, using: :btree
+ create_table "user_interacted_projects", id: false, force: :cascade do |t|
+ t.integer "user_id", null: false
+ t.integer "project_id", null: false
+ end
+
+ add_index "user_interacted_projects", ["project_id", "user_id"], name: "index_user_interacted_projects_on_project_id_and_user_id", unique: true, using: :btree
+
create_table "user_synced_attributes_metadata", force: :cascade do |t|
t.boolean "name_synced", default: false
t.boolean "email_synced", default: false
@@ -2021,6 +2032,8 @@ ActiveRecord::Schema.define(version: 20180307012445) do
add_foreign_key "cluster_providers_gcp", "clusters", on_delete: :cascade
add_foreign_key "clusters", "users", on_delete: :nullify
add_foreign_key "clusters_applications_helm", "clusters", on_delete: :cascade
+ add_foreign_key "clusters_applications_ingress", "clusters", name: "fk_753a7b41c1", on_delete: :cascade
+ add_foreign_key "clusters_applications_prometheus", "clusters", name: "fk_557e773639", on_delete: :cascade
add_foreign_key "clusters_applications_runners", "ci_runners", column: "runner_id", name: "fk_02de2ded36", on_delete: :nullify
add_foreign_key "clusters_applications_runners", "clusters", on_delete: :cascade
add_foreign_key "container_repositories", "projects"
@@ -2115,6 +2128,8 @@ ActiveRecord::Schema.define(version: 20180307012445) do
add_foreign_key "u2f_registrations", "users"
add_foreign_key "user_callouts", "users", on_delete: :cascade
add_foreign_key "user_custom_attributes", "users", on_delete: :cascade
+ add_foreign_key "user_interacted_projects", "projects", name: "fk_722ceba4f7", on_delete: :cascade
+ add_foreign_key "user_interacted_projects", "users", name: "fk_0894651f08", on_delete: :cascade
add_foreign_key "user_synced_attributes_metadata", "users", on_delete: :cascade
add_foreign_key "users_star_projects", "projects", name: "fk_22cd27ddfc", on_delete: :cascade
add_foreign_key "web_hook_logs", "web_hooks", on_delete: :cascade
diff --git a/doc/administration/monitoring/index.md b/doc/administration/monitoring/index.md
index b6320aba83e..d18dddf09c0 100644
--- a/doc/administration/monitoring/index.md
+++ b/doc/administration/monitoring/index.md
@@ -7,3 +7,4 @@ Explore our features to monitor your GitLab instance:
- [GitHub imports](github_imports.md): Monitor the health and progress of GitLab's GitHub importer with various Prometheus metrics.
- [Monitoring uptime](../../user/admin_area/monitoring/health_check.md): Check the server status using the health check endpoint.
- [IP whitelists](ip_whitelist.md): Configure GitLab for monitoring endpoints that provide health check information when probed.
+- [nginx_status](https://docs.gitlab.com/omnibus/settings/nginx.html#enabling-disabling-nginx_status): Monitor your Nginx server status
diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md
index d73d9422d2c..51c62742d01 100644
--- a/doc/administration/raketasks/check.md
+++ b/doc/administration/raketasks/check.md
@@ -84,12 +84,14 @@ checks using those checksums can be run. These checks also detect missing files.
Currently, integrity checks are supported for the following types of file:
+* CI artifacts
* LFS objects
* User uploads
**Omnibus Installation**
```
+sudo gitlab-rake gitlab:artifacts:check
sudo gitlab-rake gitlab:lfs:check
sudo gitlab-rake gitlab:uploads:check
```
@@ -97,6 +99,7 @@ sudo gitlab-rake gitlab:uploads:check
**Source Installation**
```bash
+sudo -u git -H bundle exec rake gitlab:artifacts:check RAILS_ENV=production
sudo -u git -H bundle exec rake gitlab:lfs:check RAILS_ENV=production
sudo -u git -H bundle exec rake gitlab:uploads:check RAILS_ENV=production
```
@@ -112,6 +115,7 @@ Variable | Type | Description
`VERBOSE` | boolean | Causes failures to be listed individually, rather than being summarized.
```bash
+sudo gitlab-rake gitlab:artifacts:check BATCH=100 ID_FROM=50 ID_TO=250
sudo gitlab-rake gitlab:lfs:check BATCH=100 ID_FROM=50 ID_TO=250
sudo gitlab-rake gitlab:uploads:check BATCH=100 ID_FROM=50 ID_TO=250
```
diff --git a/doc/api/README.md b/doc/api/README.md
index b67500a9b9e..ae4481b400e 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -37,6 +37,7 @@ following locations:
- [Group milestones](group_milestones.md)
- [Namespaces](namespaces.md)
- [Notes](notes.md) (comments)
+- [Discussions](discussions.md) (threaded comments)
- [Notification settings](notification_settings.md)
- [Open source license templates](templates/licenses.md)
- [Pages Domains](pages_domains.md)
diff --git a/doc/api/discussions.md b/doc/api/discussions.md
new file mode 100644
index 00000000000..c341b7f2009
--- /dev/null
+++ b/doc/api/discussions.md
@@ -0,0 +1,411 @@
+# Discussions API
+
+Discussions are set of related notes on snippets or issues.
+
+## Issues
+
+### List project issue discussions
+
+Gets a list of all discussions for a single issue.
+
+```
+GET /projects/:id/issues/:issue_iid/discussions
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | ------------ |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+
+```json
+[
+ {
+ "id": "6a9c1750b37d513a43987b574953fceb50b03ce7",
+ "individual_note": false,
+ "notes": [
+ {
+ "id": 1126,
+ "type": "DiscussionNote",
+ "body": "discussion text",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-03T21:54:39.668Z",
+ "updated_at": "2018-03-03T21:54:39.668Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Issue",
+ "noteable_iid": null
+ },
+ {
+ "id": 1129,
+ "type": "DiscussionNote",
+ "body": "reply to the discussion",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-04T13:38:02.127Z",
+ "updated_at": "2018-03-04T13:38:02.127Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Issue",
+ "noteable_iid": null
+ }
+ ]
+ },
+ {
+ "id": "87805b7c09016a7058e91bdbe7b29d1f284a39e6",
+ "individual_note": true,
+ "notes": [
+ {
+ "id": 1128,
+ "type": null,
+ "body": "a single comment",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-04T09:17:22.520Z",
+ "updated_at": "2018-03-04T09:17:22.520Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Issue",
+ "noteable_iid": null
+ }
+ ]
+ }
+]
+```
+
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions
+```
+
+### Get single issue discussion
+
+Returns a single discussion for a specific project issue
+
+```
+GET /projects/:id/issues/:issue_iid/discussions/:discussion_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+| `discussion_id` | integer | yes | The ID of a discussion |
+
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
+```
+
+### Create new issue discussion
+
+Creates a new discussion to a single project issue. This is similar to creating
+a note but but another comments (replies) can be added to it later.
+
+```
+POST /projects/:id/issues/:issue_iid/discussions
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+| `body` | string | yes | The content of a discussion |
+| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions?body=comment
+```
+
+### Add note to existing issue discussion
+
+Adds a new note to the discussion.
+
+```
+POST /projects/:id/issues/:issue_iid/discussions/:discussion_id/notes
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+| `body` | string | yes | The content of a discussion |
+| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
+```
+
+### Modify existing issue discussion note
+
+Modify existing discussion note of an issue.
+
+```
+PUT /projects/:id/issues/:issue_iid/discussions/:discussion_id/notes/:note_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+| `body` | string | yes | The content of a discussion |
+
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
+```
+
+### Delete an issue discussion note
+
+Deletes an existing discussion note of an issue.
+
+```
+DELETE /projects/:id/issues/:issue_iid/discussions/:discussion_id/notes/:note_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+
+```bash
+curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/636
+```
+
+## Snippets
+
+### List project snippet discussions
+
+Gets a list of all discussions for a single snippet.
+
+```
+GET /projects/:id/snippets/:snippet_id/discussions
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | ------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+
+```json
+[
+ {
+ "id": "6a9c1750b37d513a43987b574953fceb50b03ce7",
+ "individual_note": false,
+ "notes": [
+ {
+ "id": 1126,
+ "type": "DiscussionNote",
+ "body": "discussion text",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-03T21:54:39.668Z",
+ "updated_at": "2018-03-03T21:54:39.668Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Snippet",
+ "noteable_id": null
+ },
+ {
+ "id": 1129,
+ "type": "DiscussionNote",
+ "body": "reply to the discussion",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-04T13:38:02.127Z",
+ "updated_at": "2018-03-04T13:38:02.127Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Snippet",
+ "noteable_id": null
+ }
+ ]
+ },
+ {
+ "id": "87805b7c09016a7058e91bdbe7b29d1f284a39e6",
+ "individual_note": true,
+ "notes": [
+ {
+ "id": 1128,
+ "type": null,
+ "body": "a single comment",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-04T09:17:22.520Z",
+ "updated_at": "2018-03-04T09:17:22.520Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Snippet",
+ "noteable_id": null
+ }
+ ]
+ }
+]
+```
+
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions
+```
+
+### Get single snippet discussion
+
+Returns a single discussion for a specific project snippet
+
+```
+GET /projects/:id/snippets/:snippet_id/discussions/:discussion_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+| `discussion_id` | integer | yes | The ID of a discussion |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
+```
+
+### Create new snippet discussion
+
+Creates a new discussion to a single project snippet. This is similar to creating
+a note but but another comments (replies) can be added to it later.
+
+```
+POST /projects/:id/snippets/:snippet_id/discussions
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+| `body` | string | yes | The content of a discussion |
+| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions?body=comment
+```
+
+### Add note to existing snippet discussion
+
+Adds a new note to the discussion.
+
+```
+POST /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+| `body` | string | yes | The content of a discussion |
+| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
+```
+
+### Modify existing snippet discussion note
+
+Modify existing discussion note of an snippet.
+
+```
+PUT /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes/:note_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+| `body` | string | yes | The content of a discussion |
+
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
+```
+
+### Delete an snippet discussion note
+
+Deletes an existing discussion note of an snippet.
+
+```
+DELETE /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes/:note_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+
+```bash
+curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/636
+```
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 25b0807eb18..b9a4f661777 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -529,18 +529,19 @@ Creates a new merge request.
POST /projects/:id/merge_requests
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `source_branch` | string | yes | The source branch |
-| `target_branch` | string | yes | The target branch |
-| `title` | string | yes | Title of MR |
-| `assignee_id` | integer | no | Assignee user ID |
-| `description` | string | no | Description of MR |
-| `target_project_id` | integer | no | The target project (numeric id) |
-| `labels` | string | no | Labels for MR as a comma-separated list |
-| `milestone_id` | integer | no | The ID of a milestone |
-| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `source_branch` | string | yes | The source branch |
+| `target_branch` | string | yes | The target branch |
+| `title` | string | yes | Title of MR |
+| `assignee_id` | integer | no | Assignee user ID |
+| `description` | string | no | Description of MR |
+| `target_project_id` | integer | no | The target project (numeric id) |
+| `labels` | string | no | Labels for MR as a comma-separated list |
+| `milestone_id` | integer | no | The ID of a milestone |
+| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
+| `allow_maintainer_to_push` | boolean | no | Whether or not a maintainer of the target project can push to the source branch |
```json
{
@@ -548,7 +549,7 @@ POST /projects/:id/merge_requests
"iid": 1,
"target_branch": "master",
"source_branch": "test1",
- "project_id": 3,
+ "project_id": 4,
"title": "test1",
"state": "opened",
"upvotes": 0,
@@ -569,7 +570,7 @@ POST /projects/:id/merge_requests
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
- "source_project_id": 4,
+ "source_project_id": 3,
"target_project_id": 4,
"labels": [ ],
"description": "fixed login page css paddings",
@@ -596,6 +597,7 @@ POST /projects/:id/merge_requests
"force_remove_source_branch": false,
"web_url": "http://example.com/example/example/merge_requests/1",
"discussion_locked": false,
+ "allow_maintainer_to_push": false,
"time_stats": {
"time_estimate": 0,
"total_time_spent": 0,
@@ -613,19 +615,20 @@ Updates an existing merge request. You can change the target branch, title, or e
PUT /projects/:id/merge_requests/:merge_request_iid
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `merge_request_iid` | integer | yes | The ID of a merge request |
-| `target_branch` | string | no | The target branch |
-| `title` | string | no | Title of MR |
-| `assignee_id` | integer | no | The ID of the user to assign the merge request to. Set to `0` or provide an empty value to unassign all assignees. |
-| `milestone_id` | integer | no | The ID of a milestone to assign the merge request to. Set to `0` or provide an empty value to unassign a milestone.|
-| `labels` | string | no | Comma-separated label names for a merge request. Set to an empty string to unassign all labels. |
-| `description` | string | no | Description of MR |
-| `state_event` | string | no | New state (close/reopen) |
-| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
-| `discussion_locked` | boolean | no | Flag indicating if the merge request's discussion is locked. If the discussion is locked only project members can add, edit or resolve comments. |
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `merge_request_iid` | integer | yes | The ID of a merge request |
+| `target_branch` | string | no | The target branch |
+| `title` | string | no | Title of MR |
+| `assignee_id` | integer | no | The ID of the user to assign the merge request to. Set to `0` or provide an empty value to unassign all assignees. |
+| `milestone_id` | integer | no | The ID of a milestone to assign the merge request to. Set to `0` or provide an empty value to unassign a milestone.|
+| `labels` | string | no | Comma-separated label names for a merge request. Set to an empty string to unassign all labels. |
+| `description` | string | no | Description of MR |
+| `state_event` | string | no | New state (close/reopen) |
+| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
+| `discussion_locked` | boolean | no | Flag indicating if the merge request's discussion is locked. If the discussion is locked only project members can add, edit or resolve comments. |
+| `allow_maintainer_to_push` | boolean | no | Whether or not a maintainer of the target project can push to the source branch |
Must include at least one non-required attribute from above.
@@ -634,7 +637,7 @@ Must include at least one non-required attribute from above.
"id": 1,
"iid": 1,
"target_branch": "master",
- "project_id": 3,
+ "project_id": 4,
"title": "test1",
"state": "opened",
"upvotes": 0,
@@ -655,7 +658,7 @@ Must include at least one non-required attribute from above.
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
- "source_project_id": 4,
+ "source_project_id": 3,
"target_project_id": 4,
"labels": [ ],
"description": "description1",
@@ -682,6 +685,7 @@ Must include at least one non-required attribute from above.
"force_remove_source_branch": false,
"web_url": "http://example.com/example/example/merge_requests/1",
"discussion_locked": false,
+ "allow_maintainer_to_push": false,
"time_stats": {
"time_estimate": 0,
"total_time_spent": 0,
diff --git a/doc/api/notes.md b/doc/api/notes.md
index 1b68bd99ce2..aa38d22845c 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -15,7 +15,7 @@ GET /projects/:id/issues/:issue_iid/notes?sort=asc&order_by=updated_at
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
| `issue_iid` | integer | yes | The IID of an issue
| `sort` | string | no | Return issue notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return issue notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
@@ -63,6 +63,10 @@ GET /projects/:id/issues/:issue_iid/notes?sort=asc&order_by=updated_at
]
```
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes
+```
+
### Get single issue note
Returns a single note for a specific project issue
@@ -73,14 +77,17 @@ GET /projects/:id/issues/:issue_iid/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `issue_iid` (required) - The IID of a project issue
- `note_id` (required) - The ID of an issue note
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes/1
+```
+
### Create new issue note
-Creates a new note to a single project issue. If you create a note where the body
-only contains an Award Emoji, you'll receive this object back.
+Creates a new note to a single project issue.
```
POST /projects/:id/issues/:issue_iid/notes
@@ -88,11 +95,15 @@ POST /projects/:id/issues/:issue_iid/notes
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `issue_id` (required) - The IID of an issue
- `body` (required) - The content of a note
- `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes?body=note
+```
+
### Modify existing issue note
Modify existing note of an issue.
@@ -103,11 +114,15 @@ PUT /projects/:id/issues/:issue_iid/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `issue_iid` (required) - The IID of an issue
- `note_id` (required) - The ID of a note
- `body` (required) - The content of a note
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes?body=note
+```
+
### Delete an issue note
Deletes an existing note of an issue.
@@ -120,7 +135,7 @@ Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `issue_iid` | integer | yes | The IID of an issue |
| `note_id` | integer | yes | The ID of a note |
@@ -141,11 +156,15 @@ GET /projects/:id/snippets/:snippet_id/notes?sort=asc&order_by=updated_at
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
| `snippet_id` | integer | yes | The ID of a project snippet
| `sort` | string | no | Return snippet notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return snippet notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes
+```
+
### Get single snippet note
Returns a single note for a given snippet.
@@ -156,7 +175,7 @@ GET /projects/:id/snippets/:snippet_id/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `snippet_id` (required) - The ID of a project snippet
- `note_id` (required) - The ID of a snippet note
@@ -179,6 +198,10 @@ Parameters:
}
```
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes/11
+```
+
### Create new snippet note
Creates a new note for a single snippet. Snippet notes are comments users can post to a snippet.
@@ -190,10 +213,14 @@ POST /projects/:id/snippets/:snippet_id/notes
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `snippet_id` (required) - The ID of a snippet
- `body` (required) - The content of a note
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippet/11/notes?body=note
+```
+
### Modify existing snippet note
Modify existing note of a snippet.
@@ -204,11 +231,15 @@ PUT /projects/:id/snippets/:snippet_id/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `snippet_id` (required) - The ID of a snippet
- `note_id` (required) - The ID of a note
- `body` (required) - The content of a note
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes?body=note
+```
+
### Delete a snippet note
Deletes an existing note of a snippet.
@@ -221,7 +252,7 @@ Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `snippet_id` | integer | yes | The ID of a snippet |
| `note_id` | integer | yes | The ID of a note |
@@ -242,11 +273,15 @@ GET /projects/:id/merge_requests/:merge_request_iid/notes?sort=asc&order_by=upda
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
| `merge_request_iid` | integer | yes | The IID of a project merge request
| `sort` | string | no | Return merge request notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return merge request notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes
+```
+
### Get single merge request note
Returns a single note for a given merge request.
@@ -257,7 +292,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `merge_request_iid` (required) - The IID of a project merge request
- `note_id` (required) - The ID of a merge request note
@@ -283,6 +318,10 @@ Parameters:
}
```
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes/1
+```
+
### Create new merge request note
Creates a new note for a single merge request.
@@ -295,7 +334,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/notes
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `merge_request_iid` (required) - The IID of a merge request
- `body` (required) - The content of a note
@@ -309,11 +348,15 @@ PUT /projects/:id/merge_requests/:merge_request_iid/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `merge_request_iid` (required) - The IID of a merge request
- `note_id` (required) - The ID of a note
- `body` (required) - The content of a note
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes?body=note
+```
+
### Delete a merge request note
Deletes an existing note of a merge request.
@@ -326,7 +369,7 @@ Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `merge_request_iid` | integer | yes | The IID of a merge request |
| `note_id` | integer | yes | The ID of a note |
diff --git a/doc/ci/runners/README.md b/doc/ci/runners/README.md
index 03aa6ff8e7c..f879ed62010 100644
--- a/doc/ci/runners/README.md
+++ b/doc/ci/runners/README.md
@@ -163,8 +163,7 @@ in your `.gitlab-ci.yml`.
Behind the scenes, this works by increasing a counter in the database, and the
value of that counter is used to create the key for the cache. After a push, a
-new key is generated and the old cache is not valid anymore. Eventually, the
-Runner's garbage collector will remove it form the filesystem.
+new key is generated and the old cache is not valid anymore.
## How shared Runners pick jobs
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index c0ce49eb40b..856ef882453 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -45,7 +45,7 @@ We basically have 4 types of files:
1. Ruby files: basically Models and Controllers.
1. HAML files: these are the view files.
1. ERB files: used for email templates.
-1. JavaScript files: we mostly need to work with VUE JS templates.
+1. JavaScript files: we mostly need to work with Vue templates.
### Ruby files
diff --git a/doc/development/new_fe_guide/dependencies.md b/doc/development/new_fe_guide/dependencies.md
new file mode 100644
index 00000000000..3417d77a06d
--- /dev/null
+++ b/doc/development/new_fe_guide/dependencies.md
@@ -0,0 +1,3 @@
+# Dependencies
+
+> TODO: Add Dependencies \ No newline at end of file
diff --git a/doc/development/new_fe_guide/development/accessibility.md b/doc/development/new_fe_guide/development/accessibility.md
new file mode 100644
index 00000000000..ed35f08432f
--- /dev/null
+++ b/doc/development/new_fe_guide/development/accessibility.md
@@ -0,0 +1,3 @@
+# Accessibility
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/components.md b/doc/development/new_fe_guide/development/components.md
new file mode 100644
index 00000000000..637099d1e83
--- /dev/null
+++ b/doc/development/new_fe_guide/development/components.md
@@ -0,0 +1,3 @@
+# Components
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/design_patterns.md b/doc/development/new_fe_guide/development/design_patterns.md
new file mode 100644
index 00000000000..ee06566ed30
--- /dev/null
+++ b/doc/development/new_fe_guide/development/design_patterns.md
@@ -0,0 +1,3 @@
+# Design patterns
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/index.md b/doc/development/new_fe_guide/development/index.md
new file mode 100644
index 00000000000..cee8e43ebad
--- /dev/null
+++ b/doc/development/new_fe_guide/development/index.md
@@ -0,0 +1,29 @@
+# Development
+
+## [Design patterns](design_patterns.md)
+
+Examples of proven design patterns used in our codebase.
+
+## [Components](components.md)
+
+Documentation on existing components and how to best create a new component.
+
+## [Accessibility](accessibility.md)
+
+Learn how to implement an accessible frontend.
+
+## [Network requests](network_requests.md)
+
+Learn how to handle network requests in our codebase.
+
+## [Security](security.md)
+
+Learn how to ensure that our frontend is secure.
+
+## [Performance](performance.md)
+
+Learn how to keep our frontend performant.
+
+## [Testing](testing.md)
+
+Learn how to keep our frontend tested.
diff --git a/doc/development/new_fe_guide/development/network_requests.md b/doc/development/new_fe_guide/development/network_requests.md
new file mode 100644
index 00000000000..047c00313bc
--- /dev/null
+++ b/doc/development/new_fe_guide/development/network_requests.md
@@ -0,0 +1,3 @@
+# Network requests
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/performance.md b/doc/development/new_fe_guide/development/performance.md
new file mode 100644
index 00000000000..26b07874f0f
--- /dev/null
+++ b/doc/development/new_fe_guide/development/performance.md
@@ -0,0 +1,3 @@
+# Performance
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/security.md b/doc/development/new_fe_guide/development/security.md
new file mode 100644
index 00000000000..debda7de0c6
--- /dev/null
+++ b/doc/development/new_fe_guide/development/security.md
@@ -0,0 +1,3 @@
+# Security
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/testing.md b/doc/development/new_fe_guide/development/testing.md
new file mode 100644
index 00000000000..c359bd83ed1
--- /dev/null
+++ b/doc/development/new_fe_guide/development/testing.md
@@ -0,0 +1,3 @@
+# Testing
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/index.md b/doc/development/new_fe_guide/index.md
new file mode 100644
index 00000000000..08c6a266e7f
--- /dev/null
+++ b/doc/development/new_fe_guide/index.md
@@ -0,0 +1,28 @@
+# Frontend Development Guidelines
+
+This guide contains all the information to successfully contribute to GitLab's frontend.
+This is a living document, and we welcome contributions, feedback and suggestions.
+
+## [Principles](principles.md)
+
+Ensure that your frontend contribution starts off in the right direction.
+
+## [Initiatives](initiatives.md)
+
+High level overview of where we are going from a frontend perspective.
+
+## [Development](development/index.md)
+
+Guidance on topics related to development.
+
+## [Dependencies](dependencies.md)
+
+Learn about all the dependencies that make up our frontend, including some of our own custom built libraries.
+
+## [Style](style/index.md)
+
+Style guides to keep our code consistent.
+
+## [Tips](tips.md)
+
+Tips from our frontend team to develop more efficiently and effectively.
diff --git a/doc/development/new_fe_guide/initiatives.md b/doc/development/new_fe_guide/initiatives.md
new file mode 100644
index 00000000000..c81ed3579f0
--- /dev/null
+++ b/doc/development/new_fe_guide/initiatives.md
@@ -0,0 +1,3 @@
+# Initiatives
+
+> TODO: Add Initiatives
diff --git a/doc/development/new_fe_guide/principles.md b/doc/development/new_fe_guide/principles.md
new file mode 100644
index 00000000000..2126d202a7e
--- /dev/null
+++ b/doc/development/new_fe_guide/principles.md
@@ -0,0 +1,3 @@
+# Principles
+
+> TODO: Add principles
diff --git a/doc/development/new_fe_guide/style/html.md b/doc/development/new_fe_guide/style/html.md
new file mode 100644
index 00000000000..5489def5d6e
--- /dev/null
+++ b/doc/development/new_fe_guide/style/html.md
@@ -0,0 +1,3 @@
+# HTML style guide
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/style/index.md b/doc/development/new_fe_guide/style/index.md
new file mode 100644
index 00000000000..d2d576b3b46
--- /dev/null
+++ b/doc/development/new_fe_guide/style/index.md
@@ -0,0 +1,9 @@
+# Style
+
+## [HTML style guide](html.md)
+
+## [SCSS style guide](scss.md)
+
+## [JavaScript style guide](javascript.md)
+
+## [Vue style guide](vue.md)
diff --git a/doc/development/new_fe_guide/style/javascript.md b/doc/development/new_fe_guide/style/javascript.md
new file mode 100644
index 00000000000..480d50a211f
--- /dev/null
+++ b/doc/development/new_fe_guide/style/javascript.md
@@ -0,0 +1,3 @@
+# JavaScript style guide
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/style/scss.md b/doc/development/new_fe_guide/style/scss.md
new file mode 100644
index 00000000000..6f5e818d7db
--- /dev/null
+++ b/doc/development/new_fe_guide/style/scss.md
@@ -0,0 +1,3 @@
+# SCSS style guide
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/style/vue.md b/doc/development/new_fe_guide/style/vue.md
new file mode 100644
index 00000000000..fd9353e0d3f
--- /dev/null
+++ b/doc/development/new_fe_guide/style/vue.md
@@ -0,0 +1,3 @@
+# Vue style guide
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/tips.md b/doc/development/new_fe_guide/tips.md
new file mode 100644
index 00000000000..f0cdf52d618
--- /dev/null
+++ b/doc/development/new_fe_guide/tips.md
@@ -0,0 +1,3 @@
+# Tips
+
+> TODO: Add tips
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 170d92faa09..6eb767b00b3 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -299,9 +299,9 @@ sudo usermod -aG redis git
### Clone the Source
# Clone GitLab repository
- sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 10-5-stable gitlab
+ sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 10-6-stable gitlab
-**Note:** You can change `10-5-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `10-6-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 5f5ba2b69bc..ec091549c05 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -309,6 +309,18 @@ enable them.
You can make use of [environment variables](#helm-chart-variables) to automatically
scale your pod replicas.
+It's important to note that when a project is deployed to a Kubernetes cluster,
+it relies on a Docker image that has been pushed to the
+[GitLab Container Registry](../../user/project/container_registry.md). Kubernetes
+fetches this image and uses it to run the application. If the project is public,
+the image can be accessed by Kubernetes without any authentication, allowing us
+to have deployments more usable. If the project is private/internal, the
+Registry requires credentials to pull the image. Currently, this is addressed
+by providing `CI_JOB_TOKEN` as the password that can be used, but this token will
+no longer be valid as soon as the deployment job finishes. This means that
+Kubernetes can run the application, but in case it should be restarted or
+executed somewhere else, it cannot be accessed again.
+
### Auto Monitoring
NOTE: **Note:**
diff --git a/doc/update/10.5-to-10.6.md b/doc/update/10.5-to-10.6.md
new file mode 100644
index 00000000000..af8343b5958
--- /dev/null
+++ b/doc/update/10.5-to-10.6.md
@@ -0,0 +1,361 @@
+---
+comments: false
+---
+
+# From 10.5 to 10.6
+
+Make sure you view this update guide from the tag (version) of GitLab you would
+like to install. In most cases this should be the highest numbered production
+tag (without rc in it). You can select the tag in the version dropdown at the
+top left corner of GitLab (below the menu bar).
+
+If the highest number stable branch is unclear please check the
+[GitLab Blog](https://about.gitlab.com/blog/archives.html) for installation
+guide links by version.
+
+### 1. Stop server
+
+```bash
+sudo service gitlab stop
+```
+
+### 2. Backup
+
+NOTE: If you installed GitLab from source, make sure `rsync` is installed.
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 3. Update Ruby
+
+NOTE: GitLab 9.0 and higher only support Ruby 2.3.x and dropped support for Ruby 2.1.x. Be
+sure to upgrade your interpreter if necessary.
+
+You can check which version you are running with `ruby -v`.
+
+Download and compile Ruby:
+
+```bash
+mkdir /tmp/ruby && cd /tmp/ruby
+curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.6.tar.gz
+echo '4e6a0f828819e15d274ae58485585fc8b7caace0 ruby-2.3.6.tar.gz' | shasum -c - && tar xzf ruby-2.3.6.tar.gz
+cd ruby-2.3.6
+./configure --disable-install-rdoc
+make
+sudo make install
+```
+
+Install Bundler:
+
+```bash
+sudo gem install bundler --no-ri --no-rdoc
+```
+
+### 4. Update Node
+
+GitLab now runs [webpack](http://webpack.js.org) to compile frontend assets.
+We require a minimum version of node v6.0.0.
+
+You can check which version you are running with `node -v`. If you are running
+a version older than `v6.0.0` you will need to update to a newer version. You
+can find instructions to install from community maintained packages or compile
+from source at the nodejs.org website.
+
+<https://nodejs.org/en/download/>
+
+Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage
+JavaScript dependencies.
+
+```bash
+curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
+echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
+sudo apt-get update
+sudo apt-get install yarn
+```
+
+More information can be found on the [yarn website](https://yarnpkg.com/en/docs/install).
+
+### 5. Update Go
+
+NOTE: GitLab 9.2 and higher only supports Go 1.8.3 and dropped support for Go
+1.5.x through 1.7.x. Be sure to upgrade your installation if necessary.
+
+You can check which version you are running with `go version`.
+
+Download and install Go:
+
+```bash
+# Remove former Go installation folder
+sudo rm -rf /usr/local/go
+
+curl --remote-name --progress https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz
+echo '1862f4c3d3907e59b04a757cfda0ea7aa9ef39274af99a784f5be843c80c6772 go1.8.3.linux-amd64.tar.gz' | shasum -a256 -c - && \
+ sudo tar -C /usr/local -xzf go1.8.3.linux-amd64.tar.gz
+sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/
+rm go1.8.3.linux-amd64.tar.gz
+```
+
+### 6. Get latest code
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
+sudo -u git -H git checkout -- locale
+```
+
+For GitLab Community Edition:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git checkout 10-6-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git checkout 10-6-stable-ee
+```
+
+### 7. Update gitlab-shell
+
+```bash
+cd /home/git/gitlab-shell
+
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_SHELL_VERSION)
+sudo -u git -H bin/compile
+```
+
+### 8. Update gitlab-workhorse
+
+Install and compile gitlab-workhorse. GitLab-Workhorse uses
+[GNU Make](https://www.gnu.org/software/make/).
+If you are not using Linux you may have to run `gmake` instead of
+`make` below.
+
+```bash
+cd /home/git/gitlab-workhorse
+
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_WORKHORSE_VERSION)
+sudo -u git -H make
+```
+
+### 9. Update Gitaly
+
+#### New Gitaly configuration options required
+
+In order to function Gitaly needs some additional configuration information. Below we assume you installed Gitaly in `/home/git/gitaly` and GitLab Shell in `/home/git/gitlab-shell`.
+
+```shell
+echo '
+[gitaly-ruby]
+dir = "/home/git/gitaly/ruby"
+
+[gitlab-shell]
+dir = "/home/git/gitlab-shell"
+' | sudo -u git tee -a /home/git/gitaly/config.toml
+```
+
+#### Check Gitaly configuration
+
+Due to a bug in the `rake gitlab:gitaly:install` script your Gitaly
+configuration file may contain syntax errors. The block name
+`[[storages]]`, which may occur more than once in your `config.toml`
+file, should be `[[storage]]` instead.
+
+```shell
+sudo -u git -H sed -i.pre-10.1 's/\[\[storages\]\]/[[storage]]/' /home/git/gitaly/config.toml
+```
+
+#### Compile Gitaly
+
+```shell
+cd /home/git/gitaly
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITALY_SERVER_VERSION)
+sudo -u git -H make
+```
+
+### 10. Update MySQL permissions
+
+If you are using MySQL you need to grant the GitLab user the necessary
+permissions on the database:
+
+```bash
+mysql -u root -p -e "GRANT TRIGGER ON \`gitlabhq_production\`.* TO 'git'@'localhost';"
+```
+
+If you use MySQL with replication, or just have MySQL configured with binary logging,
+you will need to also run the following on all of your MySQL servers:
+
+```bash
+mysql -u root -p -e "SET GLOBAL log_bin_trust_function_creators = 1;"
+```
+
+You can make this setting permanent by adding it to your `my.cnf`:
+
+```
+log_bin_trust_function_creators=1
+```
+
+### 11. Update configuration files
+
+#### New configuration options for `gitlab.yml`
+
+There might be configuration options available for [`gitlab.yml`][yaml]. View them with the command below and apply them manually to your current `gitlab.yml`:
+
+```sh
+cd /home/git/gitlab
+
+git diff origin/10-5-stable:config/gitlab.yml.example origin/10-6-stable:config/gitlab.yml.example
+```
+
+#### Nginx configuration
+
+Ensure you're still up-to-date with the latest NGINX configuration changes:
+
+```sh
+cd /home/git/gitlab
+
+# For HTTPS configurations
+git diff origin/10-5-stable:lib/support/nginx/gitlab-ssl origin/10-6-stable:lib/support/nginx/gitlab-ssl
+
+# For HTTP configurations
+git diff origin/10-5-stable:lib/support/nginx/gitlab origin/10-6-stable:lib/support/nginx/gitlab
+```
+
+If you are using Strict-Transport-Security in your installation to continue using it you must enable it in your Nginx
+configuration as GitLab application no longer handles setting it.
+
+If you are using Apache instead of NGINX please see the updated [Apache templates].
+Also note that because Apache does not support upstreams behind Unix sockets you
+will need to let gitlab-workhorse listen on a TCP port. You can do this
+via [/etc/default/gitlab].
+
+[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
+[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-6-stable/lib/support/init.d/gitlab.default.example#L38
+
+#### SMTP configuration
+
+If you're installing from source and use SMTP to deliver mail, you will need to add the following line
+to config/initializers/smtp_settings.rb:
+
+```ruby
+ActionMailer::Base.delivery_method = :smtp
+```
+
+See [smtp_settings.rb.sample] as an example.
+
+[smtp_settings.rb.sample]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-6-stable/config/initializers/smtp_settings.rb.sample#L13
+
+#### Init script
+
+There might be new configuration options available for [`gitlab.default.example`][gl-example]. View them with the command below and apply them manually to your current `/etc/default/gitlab`:
+
+```sh
+cd /home/git/gitlab
+
+git diff origin/10-5-stable:lib/support/init.d/gitlab.default.example origin/10-6-stable:lib/support/init.d/gitlab.default.example
+```
+
+Ensure you're still up-to-date with the latest init script changes:
+
+```bash
+cd /home/git/gitlab
+
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
+For Ubuntu 16.04.1 LTS:
+
+```bash
+sudo systemctl daemon-reload
+```
+
+### 12. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without postgres')
+sudo -u git -H bundle install --without postgres development test --deployment
+
+# PostgreSQL installations (note: the line below states '--without mysql')
+sudo -u git -H bundle install --without mysql development test --deployment
+
+# Optional: clean up old gems
+sudo -u git -H bundle clean
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Compile GetText PO files
+
+sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production
+
+# Update node dependencies and recompile assets
+sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production
+
+# Clean up cache
+sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
+```
+
+**MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md).
+
+### 13. Start application
+
+```bash
+sudo service gitlab start
+sudo service nginx restart
+```
+
+### 14. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+```
+
+To make sure you didn't miss anything run a more thorough check:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+```
+
+If all items are green, then congratulations, the upgrade is complete!
+
+## Things went south? Revert to previous version (10.5)
+
+### 1. Revert the code to the previous version
+
+Follow the [upgrade guide from 10.4 to 10.5](10.4-to-10.5.md), except for the
+database migration (the backup is already migrated to the previous version).
+
+### 2. Restore from the backup
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+
+If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above.
+
+[yaml]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-6-stable/config/gitlab.yml.example
+[gl-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-6-stable/lib/support/init.d/gitlab.default.example
diff --git a/doc/user/admin_area/settings/img/update-available.png b/doc/user/admin_area/settings/img/update-available.png
new file mode 100644
index 00000000000..0dafdad618e
--- /dev/null
+++ b/doc/user/admin_area/settings/img/update-available.png
Binary files differ
diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md
index d874688cc29..381efdf5d67 100644
--- a/doc/user/admin_area/settings/usage_statistics.md
+++ b/doc/user/admin_area/settings/usage_statistics.md
@@ -8,20 +8,26 @@ under **Admin area > Settings > Usage statistics**.
## Version check
-GitLab can inform you when an update is available and the importance of it.
+If enabled, version check will inform you if a new version is available and the
+importance of it through a status. This is shown on the help page (i.e. `/help`)
+for all signed in users, and on the admin pages. The statuses are:
-No information other than the GitLab version and the instance's hostname (through the HTTP referer)
-are collected.
+* Green: You are running the latest version of GitLab.
+* Orange: An updated version of GitLab is available.
+* Red: The version of GitLab you are running is vulnerable. You should install
+ the latest version with security fixes as soon as possible.
-In the **Overview** tab you can see if your GitLab version is up to date. There
-are three cases: 1) you are up to date (green), 2) there is an update available
-(yellow) and 3) your version is vulnerable and a security fix is released (red).
+![Orange version check example](img/update-available.png)
-In any case, you will see a message informing you of the state and the
-importance of the update.
+GitLab Inc. collects your instance's version and hostname (through the HTTP
+referer) as part of the version check. No other information is collected.
-If enabled, the version status will also be shown in the help page (`/help`)
-for all signed in users.
+This information is used, among other things, to identify to which versions
+patches will need to be back ported, making sure active GitLab instances remain
+secure.
+
+If you disable version check, this information will not be collected. Enable or
+disable the version check at **Admin area > Settings > Usage statistics**.
## Usage ping
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 914a80bcd6a..a520279c29e 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -25,7 +25,8 @@ The following table depicts the various user permission levels in a project.
| Create confidential issue | ✓ [^1] | ✓ | ✓ | ✓ | ✓ |
| View confidential issues | (✓) [^2] | ✓ | ✓ | ✓ | ✓ |
| Leave comments | ✓ [^1] | ✓ | ✓ | ✓ | ✓ |
-| Lock discussions (issues and merge requests) | | | | ✓ | ✓ |
+| Lock issue discussions | | ✓ | ✓ | ✓ | ✓ |
+| Lock merge request discussions | | | ✓ | ✓ | ✓ |
| See a list of jobs | ✓ [^3] | ✓ | ✓ | ✓ | ✓ |
| See a job log | ✓ [^3] | ✓ | ✓ | ✓ | ✓ |
| Download and browse job artifacts | ✓ [^3] | ✓ | ✓ | ✓ | ✓ |
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 4ac54f96aa2..661697aaeb7 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -109,6 +109,41 @@ you will be notified.
You can now proceed to install some pre-defined applications and then
enable the Kubernetes cluster integration.
+## Security implications
+
+CAUTION: **Important:**
+The whole cluster security is based on a model where [developers](../../permissions.md)
+are trusted, so **only trusted users should be allowed to control your clusters**.
+
+The default cluster configuration grants access to a wide set of
+functionalities needed to successfully build and deploy a containerized
+application. Bare in mind that the same credentials are used for all the
+applications running on the cluster.
+
+When GitLab creates the cluster, it enables and uses the legacy
+[Attribute-based access control (ABAC)](https://kubernetes.io/docs/admin/authorization/abac/).
+The newer [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)
+authorization will be supported in a
+[future release](https://gitlab.com/gitlab-org/gitlab-ce/issues/29398).
+
+### Security of GitLab Runners
+
+GitLab Runners have the [privileged mode](https://docs.gitlab.com/runner/executors/docker.html#the-privileged-mode)
+enabled by default, which allows them to execute special commands and running
+Docker in Docker. This functionality is needed to run some of the [Auto DevOps]
+jobs. This implies the containers are running in privileged mode and you should,
+therefore, be aware of some important details.
+
+The privileged flag gives all capabilities to the running container, which in
+turn can do almost everything that the host can do. Be aware of the
+inherent security risk associated with performing `docker run` operations on
+arbitrary images as they effectively have root access.
+
+If you don't want to use GitLab Runner in privileged mode, first make sure that
+you don't have it installed via the applications, and then use the
+[Runner's Helm chart](../../../install/kubernetes/gitlab_runner_chart.md) to
+install it manually.
+
## Installing applications
GitLab provides a one-click install for various applications which will be
@@ -118,16 +153,16 @@ added directly to your configured cluster. Those applications are needed for
| Application | GitLab version | Description |
| ----------- | :------------: | ----------- |
| [Helm Tiller](https://docs.helm.sh/) | 10.2+ | Helm is a package manager for Kubernetes and is required to install all the other applications. It will be automatically installed as a dependency when you try to install a different app. It is installed in its own pod inside the cluster which can run the `helm` CLI in a safe environment. |
-| [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) | 10.2+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps](../../../topics/autodevops/index.md) or deploy your own web apps. |
+| [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) | 10.2+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps] or deploy your own web apps. |
| [Prometheus](https://prometheus.io/docs/introduction/overview/) | 10.4+ | Prometheus is an open-source monitoring and alerting system useful to supervise your deployed applications |
-| [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. |
+| [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. |
## Getting the external IP address
NOTE: **Note:**
You need a load balancer installed in your cluster in order to obtain the
external IP address with the following procedure. It can be deployed using the
-[**Ingress** application](#installing-appplications).
+[**Ingress** application](#installing-applications).
In order to publish your web application, you first need to find the external IP
address associated to your load balancer.
@@ -329,3 +364,4 @@ the deployment variables above, ensuring any pods you create are labelled with
[permissions]: ../../permissions.md
[ee]: https://about.gitlab.com/products/
+[Auto DevOps]: ../../../topics/autodevops/index.md
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index 550ad4a8b1f..d403d5698a9 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -245,6 +245,17 @@ navigation level. A group-level issue board allows you to view all issues from a
boards. When updating milestones and labels for an issue through the sidebar update mechanism, again only
group-level objects are available.
+## Features per tier
+
+Different issue board features are available in different [GitLab tiers](https://about.gitlab.com/pricing/), as shown in the following table:
+
+| Tier | Number of project issue boards | Board with configuration in project issue boards | Number of group issue boards | Board with configuration in group issue boards |
+| --- | --- | --- | --- | --- |
+| Libre | 1 | No | 1 | No |
+| Starter | Multiple | Yes | 1 | No |
+| Premium | Multiple | Yes | Multiple | Yes |
+| Ultimate | Multiple | Yes | Multiple | Yes |
+
## Tips
A few things to remember:
diff --git a/doc/user/project/merge_requests/img/allow_maintainer_push.png b/doc/user/project/merge_requests/img/allow_maintainer_push.png
new file mode 100644
index 00000000000..1631527071b
--- /dev/null
+++ b/doc/user/project/merge_requests/img/allow_maintainer_push.png
Binary files differ
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index d3220598933..10d67729734 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -28,6 +28,7 @@ With GitLab merge requests, you can:
- Enable [fast-forward merge requests](#fast-forward-merge-requests)
- Enable [semi-linear history merge requests](#semi-linear-history-merge-requests) as another security layer to guarantee the pipeline is passing in the target branch
- [Create new merge requests by email](#create-new-merge-requests-by-email)
+- Allow maintainers of the target project to push directly to the fork by [allowing edits from maintainers](maintainer_access.md)
With **[GitLab Enterprise Edition][ee]**, you can also:
diff --git a/doc/user/project/merge_requests/maintainer_access.md b/doc/user/project/merge_requests/maintainer_access.md
new file mode 100644
index 00000000000..7feccc28f6b
--- /dev/null
+++ b/doc/user/project/merge_requests/maintainer_access.md
@@ -0,0 +1,13 @@
+# Allow maintainer pushes for merge requests across forks
+
+This feature is available for merge requests across forked projects that are
+publicly accessible. It makes it easier for maintainers of projects to collaborate
+on merge requests across forks.
+
+When enabling this feature for a merge request, you give can give members with push access to the target project rights to edit files on the source branch of the merge request.
+
+The feature can only be enabled by users who already have push access to the source project. And only lasts while the merge request is open.
+
+Enable this functionality while creating a merge request:
+
+![Enable maintainer edits](./img/allow_maintainer_push.png)
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index 5ddeb014b30..dedf102fc37 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -31,8 +31,7 @@ with all their related data and be moved into a new GitLab instance.
| GitLab version | Import/Export version |
| ---------------- | --------------------- |
-| 10.6 to current | 0.2.3 |
-| 10.4 | 0.2.2 |
+| 10.4 to current | 0.2.2 |
| 10.3 | 0.2.1 |
| 10.0 | 0.2.0 |
| 9.4.0 | 0.1.8 |
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index affbccccdf9..07a0e2e072c 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -82,7 +82,7 @@ module SharedProject
step 'I should see project "Shop" activity feed' do
project = Project.find_by(name: "Shop")
- expect(page).to have_content "#{@user.name} pushed new branch fix at #{project.name_with_namespace}"
+ expect(page).to have_content "#{@user.name} pushed new branch fix at #{project.full_name}"
end
step 'I should see project settings' do
@@ -113,12 +113,12 @@ module SharedProject
step 'I should not see project "Archive"' do
project = Project.find_by(name: "Archive")
- expect(page).not_to have_content project.name_with_namespace
+ expect(page).not_to have_content project.full_name
end
step 'I should see project "Archive"' do
project = Project.find_by(name: "Archive")
- expect(page).to have_content project.name_with_namespace
+ expect(page).to have_content project.full_name
end
# ----------------------------------------
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 5e93c129bc8..62ffebeacb0 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -136,6 +136,7 @@ module API
mount ::API::MergeRequests
mount ::API::Namespaces
mount ::API::Notes
+ mount ::API::Discussions
mount ::API::NotificationSettings
mount ::API::PagesDomains
mount ::API::Pipelines
diff --git a/lib/api/discussions.rb b/lib/api/discussions.rb
new file mode 100644
index 00000000000..6abd575b6ad
--- /dev/null
+++ b/lib/api/discussions.rb
@@ -0,0 +1,195 @@
+module API
+ class Discussions < Grape::API
+ include PaginationParams
+ helpers ::API::Helpers::NotesHelpers
+
+ before { authenticate! }
+
+ NOTEABLE_TYPES = [Issue, Snippet].freeze
+
+ NOTEABLE_TYPES.each do |noteable_type|
+ parent_type = noteable_type.parent_class.to_s.underscore
+ noteables_str = noteable_type.to_s.underscore.pluralize
+
+ params do
+ requires :id, type: String, desc: "The ID of a #{parent_type}"
+ end
+ resource parent_type.pluralize.to_sym, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
+ desc "Get a list of #{noteable_type.to_s.downcase} discussions" do
+ success Entities::Discussion
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ use :pagination
+ end
+ get ":id/#{noteables_str}/:noteable_id/discussions" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+
+ return not_found!("Discussions") unless can?(current_user, noteable_read_ability_name(noteable), noteable)
+
+ notes = noteable.notes
+ .inc_relations_for_view
+ .includes(:noteable)
+ .fresh
+
+ notes = notes.reject { |n| n.cross_reference_not_visible_for?(current_user) }
+ discussions = Kaminari.paginate_array(Discussion.build_collection(notes, noteable))
+
+ present paginate(discussions), with: Entities::Discussion
+ end
+
+ desc "Get a single #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Discussion
+ end
+ params do
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ end
+ get ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+ notes = readable_discussion_notes(noteable, params[:discussion_id])
+
+ if notes.empty? || !can?(current_user, noteable_read_ability_name(noteable), noteable)
+ return not_found!("Discussion")
+ end
+
+ discussion = Discussion.build(notes, noteable)
+
+ present discussion, with: Entities::Discussion
+ end
+
+ desc "Create a new #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Discussion
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :body, type: String, desc: 'The content of a note'
+ optional :created_at, type: String, desc: 'The creation date of the note'
+ end
+ post ":id/#{noteables_str}/:noteable_id/discussions" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+
+ opts = {
+ note: params[:body],
+ created_at: params[:created_at],
+ type: 'DiscussionNote',
+ noteable_type: noteables_str.classify,
+ noteable_id: noteable.id
+ }
+
+ note = create_note(noteable, opts)
+
+ if note.valid?
+ present note.discussion, with: Entities::Discussion
+ else
+ bad_request!("Note #{note.errors.messages}")
+ end
+ end
+
+ desc "Get comments in a single #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Discussion
+ end
+ params do
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ end
+ get ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id/notes" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+ notes = readable_discussion_notes(noteable, params[:discussion_id])
+
+ if notes.empty? || !can?(current_user, noteable_read_ability_name(noteable), noteable)
+ return not_found!("Notes")
+ end
+
+ present notes, with: Entities::Note
+ end
+
+ desc "Add a comment to a #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :body, type: String, desc: 'The content of a note'
+ optional :created_at, type: String, desc: 'The creation date of the note'
+ end
+ post ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id/notes" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+ notes = readable_discussion_notes(noteable, params[:discussion_id])
+
+ return not_found!("Discussion") if notes.empty?
+ return bad_request!("Discussion is an individual note.") unless notes.first.part_of_discussion?
+
+ opts = {
+ note: params[:body],
+ type: 'DiscussionNote',
+ in_reply_to_discussion_id: params[:discussion_id],
+ created_at: params[:created_at]
+ }
+ note = create_note(noteable, opts)
+
+ if note.valid?
+ present note, with: Entities::Note
+ else
+ bad_request!("Note #{note.errors.messages}")
+ end
+ end
+
+ desc "Get a comment in a #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :note_id, type: Integer, desc: 'The ID of a note'
+ end
+ get ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+
+ get_note(noteable, params[:note_id])
+ end
+
+ desc "Edit a comment in a #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :note_id, type: Integer, desc: 'The ID of a note'
+ requires :body, type: String, desc: 'The content of a note'
+ end
+ put ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+
+ update_note(noteable, params[:note_id])
+ end
+
+ desc "Delete a comment in a #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :note_id, type: Integer, desc: 'The ID of a note'
+ end
+ delete ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+
+ delete_note(noteable, params[:note_id])
+ end
+ end
+ end
+
+ helpers do
+ def readable_discussion_notes(noteable, discussion_id)
+ notes = noteable.notes
+ .where(discussion_id: discussion_id)
+ .inc_relations_for_view
+ .includes(:noteable)
+ .fresh
+
+ notes.reject { |n| n.cross_reference_not_visible_for?(current_user) }
+ end
+ end
+ end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index f39906270d8..16147ee90c9 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -547,6 +547,7 @@ module API
expose :discussion_locked
expose :should_remove_source_branch?, as: :should_remove_source_branch
expose :force_remove_source_branch?, as: :force_remove_source_branch
+ expose :allow_maintainer_to_push, if: -> (merge_request, _) { merge_request.for_fork? }
expose :web_url do |merge_request, options|
Gitlab::UrlBuilder.build(merge_request)
@@ -644,6 +645,7 @@ module API
NOTEABLE_TYPES_WITH_IID = %w(Issue MergeRequest).freeze
expose :id
+ expose :type
expose :note, as: :body
expose :attachment_identifier, as: :attachment
expose :author, using: Entities::UserBasic
@@ -655,6 +657,12 @@ module API
expose(:noteable_iid) { |note| note.noteable.iid if NOTEABLE_TYPES_WITH_IID.include?(note.noteable_type) }
end
+ class Discussion < Grape::Entity
+ expose :id
+ expose :individual_note?, as: :individual_note
+ expose :notes, using: Entities::Note
+ end
+
class AwardEmoji < Grape::Entity
expose :id
expose :name
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index cd59da6fc70..4b564cfdef2 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -111,13 +111,6 @@ module API
def gitaly_payload(action)
return unless %w[git-receive-pack git-upload-pack].include?(action)
- if action == 'git-receive-pack'
- return unless Gitlab::GitalyClient.feature_enabled?(
- :ssh_receive_pack,
- status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT
- )
- end
-
{
repository: repository.gitaly_repository,
address: Gitlab::GitalyClient.address(project.repository_storage),
diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb
new file mode 100644
index 00000000000..cd91df1ecd8
--- /dev/null
+++ b/lib/api/helpers/notes_helpers.rb
@@ -0,0 +1,76 @@
+module API
+ module Helpers
+ module NotesHelpers
+ def update_note(noteable, note_id)
+ note = noteable.notes.find(params[:note_id])
+
+ authorize! :admin_note, note
+
+ opts = {
+ note: params[:body]
+ }
+ parent = noteable_parent(noteable)
+ project = parent if parent.is_a?(Project)
+
+ note = ::Notes::UpdateService.new(project, current_user, opts).execute(note)
+
+ if note.valid?
+ present note, with: Entities::Note
+ else
+ bad_request!("Failed to save note #{note.errors.messages}")
+ end
+ end
+
+ def delete_note(noteable, note_id)
+ note = noteable.notes.find(note_id)
+
+ authorize! :admin_note, note
+
+ parent = noteable_parent(noteable)
+ project = parent if parent.is_a?(Project)
+ destroy_conditionally!(note) do |note|
+ ::Notes::DestroyService.new(project, current_user).execute(note)
+ end
+ end
+
+ def get_note(noteable, note_id)
+ note = noteable.notes.with_metadata.find(params[:note_id])
+ can_read_note = can?(current_user, noteable_read_ability_name(noteable), noteable) && !note.cross_reference_not_visible_for?(current_user)
+
+ if can_read_note
+ present note, with: Entities::Note
+ else
+ not_found!("Note")
+ end
+ end
+
+ def noteable_read_ability_name(noteable)
+ "read_#{noteable.class.to_s.underscore}".to_sym
+ end
+
+ def find_noteable(parent, noteables_str, noteable_id)
+ public_send("find_#{parent}_#{noteables_str.singularize}", noteable_id) # rubocop:disable GitlabSecurity/PublicSend
+ end
+
+ def noteable_parent(noteable)
+ public_send("user_#{noteable.class.parent_class.to_s.underscore}") # rubocop:disable GitlabSecurity/PublicSend
+ end
+
+ def create_note(noteable, opts)
+ noteables_str = noteable.model_name.to_s.underscore.pluralize
+
+ return not_found!(noteables_str) unless can?(current_user, noteable_read_ability_name(noteable), noteable)
+
+ authorize! :create_note, noteable
+
+ parent = noteable_parent(noteable)
+ if opts[:created_at]
+ opts.delete(:created_at) unless current_user.admin? || parent.owner == current_user
+ end
+
+ project = parent if parent.is_a?(Project)
+ ::Notes::CreateService.new(project, current_user, opts).execute
+ end
+ end
+ end
+end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index ead1bb7957b..3264a26f7d2 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -144,6 +144,7 @@ module API
optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign the merge request'
optional :labels, type: String, desc: 'Comma-separated list of label names'
optional :remove_source_branch, type: Boolean, desc: 'Remove source branch when merging'
+ optional :allow_maintainer_to_push, type: Boolean, desc: 'Whether a maintainer of the target project can push to the source project'
use :optional_params_ee
end
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 3588dc85c9e..69f1df6b341 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -1,19 +1,23 @@
module API
class Notes < Grape::API
include PaginationParams
+ helpers ::API::Helpers::NotesHelpers
before { authenticate! }
NOTEABLE_TYPES = [Issue, MergeRequest, Snippet].freeze
- params do
- requires :id, type: String, desc: 'The ID of a project'
- end
- resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
- NOTEABLE_TYPES.each do |noteable_type|
+ NOTEABLE_TYPES.each do |noteable_type|
+ parent_type = noteable_type.parent_class.to_s.underscore
+ noteables_str = noteable_type.to_s.underscore.pluralize
+
+ params do
+ requires :id, type: String, desc: "The ID of a #{parent_type}"
+ end
+ resource parent_type.pluralize.to_sym, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
noteables_str = noteable_type.to_s.underscore.pluralize
- desc 'Get a list of project +noteable+ notes' do
+ desc "Get a list of #{noteable_type.to_s.downcase} notes" do
success Entities::Note
end
params do
@@ -25,7 +29,7 @@ module API
use :pagination
end
get ":id/#{noteables_str}/:noteable_id/notes" do
- noteable = find_project_noteable(noteables_str, params[:noteable_id])
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
if can?(current_user, noteable_read_ability_name(noteable), noteable)
# We exclude notes that are cross-references and that cannot be viewed
@@ -46,7 +50,7 @@ module API
end
end
- desc 'Get a single +noteable+ note' do
+ desc "Get a single #{noteable_type.to_s.downcase} note" do
success Entities::Note
end
params do
@@ -54,18 +58,11 @@ module API
requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
end
get ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
- noteable = find_project_noteable(noteables_str, params[:noteable_id])
- note = noteable.notes.with_metadata.find(params[:note_id])
- can_read_note = can?(current_user, noteable_read_ability_name(noteable), noteable) && !note.cross_reference_not_visible_for?(current_user)
-
- if can_read_note
- present note, with: Entities::Note
- else
- not_found!("Note")
- end
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+ get_note(noteable, params[:note_id])
end
- desc 'Create a new +noteable+ note' do
+ desc "Create a new #{noteable_type.to_s.downcase} note" do
success Entities::Note
end
params do
@@ -74,34 +71,25 @@ module API
optional :created_at, type: String, desc: 'The creation date of the note'
end
post ":id/#{noteables_str}/:noteable_id/notes" do
- noteable = find_project_noteable(noteables_str, params[:noteable_id])
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
opts = {
note: params[:body],
noteable_type: noteables_str.classify,
- noteable_id: noteable.id
+ noteable_id: noteable.id,
+ created_at: params[:created_at]
}
- if can?(current_user, noteable_read_ability_name(noteable), noteable)
- authorize! :create_note, noteable
+ note = create_note(noteable, opts)
- if params[:created_at] && (current_user.admin? || user_project.owner == current_user)
- opts[:created_at] = params[:created_at]
- end
-
- note = ::Notes::CreateService.new(user_project, current_user, opts).execute
-
- if note.valid?
- present note, with: Entities.const_get(note.class.name)
- else
- not_found!("Note #{note.errors.messages}")
- end
+ if note.valid?
+ present note, with: Entities.const_get(note.class.name)
else
- not_found!("Note")
+ bad_request!("Note #{note.errors.messages}")
end
end
- desc 'Update an existing +noteable+ note' do
+ desc "Update an existing #{noteable_type.to_s.downcase} note" do
success Entities::Note
end
params do
@@ -110,24 +98,12 @@ module API
requires :body, type: String, desc: 'The content of a note'
end
put ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
- note = user_project.notes.find(params[:note_id])
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
- authorize! :admin_note, note
-
- opts = {
- note: params[:body]
- }
-
- note = ::Notes::UpdateService.new(user_project, current_user, opts).execute(note)
-
- if note.valid?
- present note, with: Entities::Note
- else
- render_api_error!("Failed to save note #{note.errors.messages}", 400)
- end
+ update_note(noteable, params[:note_id])
end
- desc 'Delete a +noteable+ note' do
+ desc "Delete a #{noteable_type.to_s.downcase} note" do
success Entities::Note
end
params do
@@ -135,25 +111,11 @@ module API
requires :note_id, type: Integer, desc: 'The ID of a note'
end
delete ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
- note = user_project.notes.find(params[:note_id])
-
- authorize! :admin_note, note
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
- destroy_conditionally!(note) do |note|
- ::Notes::DestroyService.new(user_project, current_user).execute(note)
- end
+ delete_note(noteable, params[:note_id])
end
end
end
-
- helpers do
- def find_project_noteable(noteables_str, noteable_id)
- public_send("find_project_#{noteables_str.singularize}", noteable_id) # rubocop:disable GitlabSecurity/PublicSend
- end
-
- def noteable_read_ability_name(noteable)
- "read_#{noteable.class.to_s.underscore}".to_sym
- end
- end
end
end
diff --git a/lib/banzai/filter/commit_reference_filter.rb b/lib/banzai/filter/commit_reference_filter.rb
index eedb95197aa..43bf4fc6565 100644
--- a/lib/banzai/filter/commit_reference_filter.rb
+++ b/lib/banzai/filter/commit_reference_filter.rb
@@ -18,7 +18,8 @@ module Banzai
def find_object(project, id)
if project && project.valid_repo?
- project.commit(id)
+ # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/43894
+ Gitlab::GitalyClient.allow_n_plus_1_calls { project.commit(id) }
end
end
diff --git a/lib/banzai/filter/markdown_engines/common_mark.rb b/lib/banzai/filter/markdown_engines/common_mark.rb
new file mode 100644
index 00000000000..bc9597df894
--- /dev/null
+++ b/lib/banzai/filter/markdown_engines/common_mark.rb
@@ -0,0 +1,45 @@
+# `CommonMark` markdown engine for GitLab's Banzai markdown filter.
+# This module is used in Banzai::Filter::MarkdownFilter.
+# Used gem is `commonmarker` which is a ruby wrapper for libcmark (CommonMark parser)
+# including GitHub's GFM extensions.
+# Homepage: https://github.com/gjtorikian/commonmarker
+
+module Banzai
+ module Filter
+ module MarkdownEngines
+ class CommonMark
+ EXTENSIONS = [
+ :autolink, # provides support for automatically converting URLs to anchor tags.
+ :strikethrough, # provides support for strikethroughs.
+ :table, # provides support for tables.
+ :tagfilter # strips out several "unsafe" HTML tags from being used: https://github.github.com/gfm/#disallowed-raw-html-extension-
+ ].freeze
+
+ PARSE_OPTIONS = [
+ :FOOTNOTES, # parse footnotes.
+ :STRIKETHROUGH_DOUBLE_TILDE, # parse strikethroughs by double tildes (as redcarpet does).
+ :VALIDATE_UTF8 # replace illegal sequences with the replacement character U+FFFD.
+ ].freeze
+
+ # The `:GITHUB_PRE_LANG` option is not used intentionally because
+ # it renders a fence block with language as `<pre lang="LANG"><code>some code\n</code></pre>`
+ # while GitLab's syntax is `<pre><code lang="LANG">some code\n</code></pre>`.
+ # If in the future the syntax is about to be made GitHub-compatible, please, add `:GITHUB_PRE_LANG` render option below
+ # and remove `code_block` method from `lib/banzai/renderer/common_mark/html.rb`.
+ RENDER_OPTIONS = [
+ :DEFAULT # default rendering system. Nothing special.
+ ].freeze
+
+ def initialize
+ @renderer = Banzai::Renderer::CommonMark::HTML.new(options: RENDER_OPTIONS)
+ end
+
+ def render(text)
+ doc = CommonMarker.render_doc(text, PARSE_OPTIONS, EXTENSIONS)
+
+ @renderer.render(doc)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/markdown_engines/redcarpet.rb b/lib/banzai/filter/markdown_engines/redcarpet.rb
new file mode 100644
index 00000000000..ac99941fefa
--- /dev/null
+++ b/lib/banzai/filter/markdown_engines/redcarpet.rb
@@ -0,0 +1,32 @@
+# `Redcarpet` markdown engine for GitLab's Banzai markdown filter.
+# This module is used in Banzai::Filter::MarkdownFilter.
+# Used gem is `redcarpet` which is a ruby library for markdown processing.
+# Homepage: https://github.com/vmg/redcarpet
+
+module Banzai
+ module Filter
+ module MarkdownEngines
+ class Redcarpet
+ OPTIONS = {
+ fenced_code_blocks: true,
+ footnotes: true,
+ lax_spacing: true,
+ no_intra_emphasis: true,
+ space_after_headers: true,
+ strikethrough: true,
+ superscript: true,
+ tables: true
+ }.freeze
+
+ def initialize
+ html_renderer = Banzai::Renderer::Redcarpet::HTML.new
+ @renderer = ::Redcarpet::Markdown.new(html_renderer, OPTIONS)
+ end
+
+ def render(text)
+ @renderer.render(text)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/markdown_filter.rb b/lib/banzai/filter/markdown_filter.rb
index 9cac303e645..c1e2b680240 100644
--- a/lib/banzai/filter/markdown_filter.rb
+++ b/lib/banzai/filter/markdown_filter.rb
@@ -1,34 +1,31 @@
module Banzai
module Filter
class MarkdownFilter < HTML::Pipeline::TextFilter
- # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
- REDCARPET_OPTIONS = {
- fenced_code_blocks: true,
- footnotes: true,
- lax_spacing: true,
- no_intra_emphasis: true,
- space_after_headers: true,
- strikethrough: true,
- superscript: true,
- tables: true
- }.freeze
-
def initialize(text, context = nil, result = nil)
- super text, context, result
- @text = @text.delete "\r"
+ super(text, context, result)
+
+ @renderer = renderer(context[:markdown_engine]).new
+ @text = @text.delete("\r")
end
def call
- html = self.class.renderer.render(@text)
- html.rstrip!
- html
+ @renderer.render(@text).rstrip
+ end
+
+ private
+
+ DEFAULT_ENGINE = :redcarpet
+
+ def engine(engine_from_context)
+ engine_from_context ||= DEFAULT_ENGINE
+
+ engine_from_context.to_s.classify
end
- def self.renderer
- Thread.current[:banzai_markdown_renderer] ||= begin
- renderer = Banzai::Renderer::HTML.new
- Redcarpet::Markdown.new(renderer, REDCARPET_OPTIONS)
- end
+ def renderer(engine_from_context)
+ "Banzai::Filter::MarkdownEngines::#{engine(engine_from_context)}".constantize
+ rescue NameError
+ raise NameError, "`#{engine_from_context}` is unknown markdown engine"
end
end
end
diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb
index 0ac7e231b5b..6dbf0d68fe8 100644
--- a/lib/banzai/filter/syntax_highlight_filter.rb
+++ b/lib/banzai/filter/syntax_highlight_filter.rb
@@ -1,3 +1,4 @@
+require 'rouge/plugins/common_mark'
require 'rouge/plugins/redcarpet'
module Banzai
diff --git a/lib/banzai/renderer/common_mark/html.rb b/lib/banzai/renderer/common_mark/html.rb
new file mode 100644
index 00000000000..c7a54629f31
--- /dev/null
+++ b/lib/banzai/renderer/common_mark/html.rb
@@ -0,0 +1,21 @@
+module Banzai
+ module Renderer
+ module CommonMark
+ class HTML < CommonMarker::HtmlRenderer
+ def code_block(node)
+ block do
+ code = node.string_content
+ lang = node.fence_info
+ lang_attr = lang.present? ? %Q{ lang="#{lang}"} : ''
+ result =
+ "<pre>" \
+ "<code#{lang_attr}>#{html_escape(code)}</code>" \
+ "</pre>"
+
+ out(result)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/banzai/renderer/html.rb b/lib/banzai/renderer/html.rb
deleted file mode 100644
index 252caa35947..00000000000
--- a/lib/banzai/renderer/html.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-module Banzai
- module Renderer
- class HTML < Redcarpet::Render::HTML
- def block_code(code, lang)
- lang_attr = lang ? %Q{ lang="#{lang}"} : ''
-
- "\n<pre>" \
- "<code#{lang_attr}>#{html_escape(code)}</code>" \
- "</pre>"
- end
- end
- end
-end
diff --git a/lib/banzai/renderer/redcarpet/html.rb b/lib/banzai/renderer/redcarpet/html.rb
new file mode 100644
index 00000000000..94df5d8b1e1
--- /dev/null
+++ b/lib/banzai/renderer/redcarpet/html.rb
@@ -0,0 +1,15 @@
+module Banzai
+ module Renderer
+ module Redcarpet
+ class HTML < ::Redcarpet::Render::HTML
+ def block_code(code, lang)
+ lang_attr = lang ? %Q{ lang="#{lang}"} : ''
+
+ "\n<pre>" \
+ "<code#{lang_attr}>#{html_escape(code)}</code>" \
+ "</pre>"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/constraints/group_url_constrainer.rb b/lib/constraints/group_url_constrainer.rb
index fd2ac2db0a9..87649c50424 100644
--- a/lib/constraints/group_url_constrainer.rb
+++ b/lib/constraints/group_url_constrainer.rb
@@ -1,9 +1,11 @@
-class GroupUrlConstrainer
- def matches?(request)
- full_path = request.params[:group_id] || request.params[:id]
+module Constraints
+ class GroupUrlConstrainer
+ def matches?(request)
+ full_path = request.params[:group_id] || request.params[:id]
- return false unless NamespacePathValidator.valid_path?(full_path)
+ return false unless NamespacePathValidator.valid_path?(full_path)
- Group.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ Group.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ end
end
end
diff --git a/lib/constraints/project_url_constrainer.rb b/lib/constraints/project_url_constrainer.rb
index e90ecb5ec69..32aea98f0f7 100644
--- a/lib/constraints/project_url_constrainer.rb
+++ b/lib/constraints/project_url_constrainer.rb
@@ -1,13 +1,15 @@
-class ProjectUrlConstrainer
- def matches?(request)
- namespace_path = request.params[:namespace_id]
- project_path = request.params[:project_id] || request.params[:id]
- full_path = [namespace_path, project_path].join('/')
+module Constraints
+ class ProjectUrlConstrainer
+ def matches?(request)
+ namespace_path = request.params[:namespace_id]
+ project_path = request.params[:project_id] || request.params[:id]
+ full_path = [namespace_path, project_path].join('/')
- return false unless ProjectPathValidator.valid_path?(full_path)
+ return false unless ProjectPathValidator.valid_path?(full_path)
- # We intentionally allow SELECT(*) here so result of this query can be used
- # as cache for further Project.find_by_full_path calls within request
- Project.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ # We intentionally allow SELECT(*) here so result of this query can be used
+ # as cache for further Project.find_by_full_path calls within request
+ Project.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ end
end
end
diff --git a/lib/constraints/user_url_constrainer.rb b/lib/constraints/user_url_constrainer.rb
index 3b3ed1c6ddb..8afa04d29a4 100644
--- a/lib/constraints/user_url_constrainer.rb
+++ b/lib/constraints/user_url_constrainer.rb
@@ -1,9 +1,11 @@
-class UserUrlConstrainer
- def matches?(request)
- full_path = request.params[:username]
+module Constraints
+ class UserUrlConstrainer
+ def matches?(request)
+ full_path = request.params[:username]
- return false unless NamespacePathValidator.valid_path?(full_path)
+ return false unless NamespacePathValidator.valid_path?(full_path)
- User.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ User.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ end
end
end
diff --git a/lib/declarative_policy.rb b/lib/declarative_policy.rb
index b1949d693ad..1dd2855063d 100644
--- a/lib/declarative_policy.rb
+++ b/lib/declarative_policy.rb
@@ -1,6 +1,8 @@
require_dependency 'declarative_policy/cache'
require_dependency 'declarative_policy/condition'
-require_dependency 'declarative_policy/dsl'
+require_dependency 'declarative_policy/delegate_dsl'
+require_dependency 'declarative_policy/policy_dsl'
+require_dependency 'declarative_policy/rule_dsl'
require_dependency 'declarative_policy/preferred_scope'
require_dependency 'declarative_policy/rule'
require_dependency 'declarative_policy/runner'
diff --git a/lib/declarative_policy/delegate_dsl.rb b/lib/declarative_policy/delegate_dsl.rb
new file mode 100644
index 00000000000..f544dffe888
--- /dev/null
+++ b/lib/declarative_policy/delegate_dsl.rb
@@ -0,0 +1,16 @@
+module DeclarativePolicy
+ # Used when the name of a delegate is mentioned in
+ # the rule DSL.
+ class DelegateDsl
+ def initialize(rule_dsl, delegate_name)
+ @rule_dsl = rule_dsl
+ @delegate_name = delegate_name
+ end
+
+ def method_missing(m, *a, &b)
+ return super unless a.empty? && !block_given?
+
+ @rule_dsl.delegate(@delegate_name, m)
+ end
+ end
+end
diff --git a/lib/declarative_policy/dsl.rb b/lib/declarative_policy/dsl.rb
deleted file mode 100644
index 6ba1e7a3c5c..00000000000
--- a/lib/declarative_policy/dsl.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-module DeclarativePolicy
- # The DSL evaluation context inside rule { ... } blocks.
- # Responsible for creating and combining Rule objects.
- #
- # See Base.rule
- class RuleDsl
- def initialize(context_class)
- @context_class = context_class
- end
-
- def can?(ability)
- Rule::Ability.new(ability)
- end
-
- def all?(*rules)
- Rule::And.make(rules)
- end
-
- def any?(*rules)
- Rule::Or.make(rules)
- end
-
- def none?(*rules)
- ~Rule::Or.new(rules)
- end
-
- def cond(condition)
- Rule::Condition.new(condition)
- end
-
- def delegate(delegate_name, condition)
- Rule::DelegatedCondition.new(delegate_name, condition)
- end
-
- def method_missing(m, *a, &b)
- return super unless a.size == 0 && !block_given?
-
- if @context_class.delegations.key?(m)
- DelegateDsl.new(self, m)
- else
- cond(m.to_sym)
- end
- end
- end
-
- # Used when the name of a delegate is mentioned in
- # the rule DSL.
- class DelegateDsl
- def initialize(rule_dsl, delegate_name)
- @rule_dsl = rule_dsl
- @delegate_name = delegate_name
- end
-
- def method_missing(m, *a, &b)
- return super unless a.size == 0 && !block_given?
-
- @rule_dsl.delegate(@delegate_name, m)
- end
- end
-
- # The return value of a rule { ... } declaration.
- # Can call back to register rules with the containing
- # Policy class (context_class here). See Base.rule
- #
- # Note that the #policy method just performs an #instance_eval,
- # which is useful for multiple #enable or #prevent callse.
- #
- # Also provides a #method_missing proxy to the context
- # class's class methods, so that helper methods can be
- # defined and used in a #policy { ... } block.
- class PolicyDsl
- def initialize(context_class, rule)
- @context_class = context_class
- @rule = rule
- end
-
- def policy(&b)
- instance_eval(&b)
- end
-
- def enable(*abilities)
- @context_class.enable_when(abilities, @rule)
- end
-
- def prevent(*abilities)
- @context_class.prevent_when(abilities, @rule)
- end
-
- def prevent_all
- @context_class.prevent_all_when(@rule)
- end
-
- def method_missing(m, *a, &b)
- return super unless @context_class.respond_to?(m)
-
- @context_class.__send__(m, *a, &b) # rubocop:disable GitlabSecurity/PublicSend
- end
-
- def respond_to_missing?(m)
- @context_class.respond_to?(m) || super
- end
- end
-end
diff --git a/lib/declarative_policy/policy_dsl.rb b/lib/declarative_policy/policy_dsl.rb
new file mode 100644
index 00000000000..f11b6e9f730
--- /dev/null
+++ b/lib/declarative_policy/policy_dsl.rb
@@ -0,0 +1,44 @@
+module DeclarativePolicy
+ # The return value of a rule { ... } declaration.
+ # Can call back to register rules with the containing
+ # Policy class (context_class here). See Base.rule
+ #
+ # Note that the #policy method just performs an #instance_eval,
+ # which is useful for multiple #enable or #prevent callse.
+ #
+ # Also provides a #method_missing proxy to the context
+ # class's class methods, so that helper methods can be
+ # defined and used in a #policy { ... } block.
+ class PolicyDsl
+ def initialize(context_class, rule)
+ @context_class = context_class
+ @rule = rule
+ end
+
+ def policy(&b)
+ instance_eval(&b)
+ end
+
+ def enable(*abilities)
+ @context_class.enable_when(abilities, @rule)
+ end
+
+ def prevent(*abilities)
+ @context_class.prevent_when(abilities, @rule)
+ end
+
+ def prevent_all
+ @context_class.prevent_all_when(@rule)
+ end
+
+ def method_missing(m, *a, &b)
+ return super unless @context_class.respond_to?(m)
+
+ @context_class.__send__(m, *a, &b) # rubocop:disable GitlabSecurity/PublicSend
+ end
+
+ def respond_to_missing?(m)
+ @context_class.respond_to?(m) || super
+ end
+ end
+end
diff --git a/lib/declarative_policy/preferred_scope.rb b/lib/declarative_policy/preferred_scope.rb
index b0754098149..5c214408dd0 100644
--- a/lib/declarative_policy/preferred_scope.rb
+++ b/lib/declarative_policy/preferred_scope.rb
@@ -1,4 +1,4 @@
-module DeclarativePolicy
+module DeclarativePolicy # rubocop:disable Naming/FileName
PREFERRED_SCOPE_KEY = :"DeclarativePolicy.preferred_scope"
class << self
diff --git a/lib/declarative_policy/rule_dsl.rb b/lib/declarative_policy/rule_dsl.rb
new file mode 100644
index 00000000000..e948b7f2de1
--- /dev/null
+++ b/lib/declarative_policy/rule_dsl.rb
@@ -0,0 +1,45 @@
+module DeclarativePolicy
+ # The DSL evaluation context inside rule { ... } blocks.
+ # Responsible for creating and combining Rule objects.
+ #
+ # See Base.rule
+ class RuleDsl
+ def initialize(context_class)
+ @context_class = context_class
+ end
+
+ def can?(ability)
+ Rule::Ability.new(ability)
+ end
+
+ def all?(*rules)
+ Rule::And.make(rules)
+ end
+
+ def any?(*rules)
+ Rule::Or.make(rules)
+ end
+
+ def none?(*rules)
+ ~Rule::Or.new(rules)
+ end
+
+ def cond(condition)
+ Rule::Condition.new(condition)
+ end
+
+ def delegate(delegate_name, condition)
+ Rule::DelegatedCondition.new(delegate_name, condition)
+ end
+
+ def method_missing(m, *a, &b)
+ return super unless a.empty? && !block_given?
+
+ if @context_class.delegations.key?(m)
+ DelegateDsl.new(self, m)
+ else
+ cond(m.to_sym)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/result.rb b/lib/gitlab/auth/result.rb
index 75451cf8aa9..00cdc94a9ef 100644
--- a/lib/gitlab/auth/result.rb
+++ b/lib/gitlab/auth/result.rb
@@ -1,4 +1,4 @@
-module Gitlab
+module Gitlab # rubocop:disable Naming/FileName
module Auth
Result = Struct.new(:actor, :project, :type, :authentication_abilities) do
def ci?(for_project)
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
index d48ae17aeaf..bffbcb86137 100644
--- a/lib/gitlab/bitbucket_import/importer.rb
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -135,7 +135,7 @@ module Gitlab
if label.valid?
@labels[label_params[:title]] = label
else
- raise "Failed to create label \"#{label_params[:title]}\" for project \"#{project.name_with_namespace}\""
+ raise "Failed to create label \"#{label_params[:title]}\" for project \"#{project.full_name}\""
end
end
end
diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb
index 3ce5f807989..51ba09aa129 100644
--- a/lib/gitlab/checks/change_access.rb
+++ b/lib/gitlab/checks/change_access.rb
@@ -47,7 +47,7 @@ module Gitlab
protected
def push_checks
- if user_access.cannot_do_action?(:push_code)
+ unless can_push?
raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:push_code]
end
end
@@ -183,6 +183,11 @@ module Gitlab
def commits
@commits ||= project.repository.new_commits(newrev)
end
+
+ def can_push?
+ user_access.can_do_action?(:push_code) ||
+ user_access.can_push_to_branch?(branch_name)
+ end
end
end
end
diff --git a/lib/gitlab/ci/charts.rb b/lib/gitlab/ci/charts.rb
index 525563a97f5..46ed330dbbf 100644
--- a/lib/gitlab/ci/charts.rb
+++ b/lib/gitlab/ci/charts.rb
@@ -68,10 +68,11 @@ module Gitlab
class YearChart < Chart
include MonthlyInterval
+ attr_reader :to, :from
def initialize(*)
- @to = Date.today.end_of_month
- @from = @to.years_ago(1).beginning_of_month
+ @to = Date.today.end_of_month.end_of_day
+ @from = @to.years_ago(1).beginning_of_month.beginning_of_day
@format = '%d %B %Y'
super
@@ -80,10 +81,11 @@ module Gitlab
class MonthChart < Chart
include DailyInterval
+ attr_reader :to, :from
def initialize(*)
- @to = Date.today
- @from = @to - 30.days
+ @to = Date.today.end_of_day
+ @from = 1.month.ago.beginning_of_day
@format = '%d %B'
super
@@ -92,10 +94,11 @@ module Gitlab
class WeekChart < Chart
include DailyInterval
+ attr_reader :to, :from
def initialize(*)
- @to = Date.today
- @from = @to - 7.days
+ @to = Date.today.end_of_day
+ @from = 1.week.ago.beginning_of_day
@format = '%d %B'
super
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index 7b19b10e05b..a1849b01c5d 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -1,4 +1,4 @@
-module Gitlab
+module Gitlab # rubocop:disable Naming/FileName
module Ci
module Pipeline
module Chain
diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb
index 02d3763514e..d7369060cc5 100644
--- a/lib/gitlab/contributions_calendar.rb
+++ b/lib/gitlab/contributions_calendar.rb
@@ -23,7 +23,7 @@ module Gitlab
mr_events = event_counts(date_from, :merge_requests)
.having(action: [Event::MERGED, Event::CREATED, Event::CLOSED], target_type: "MergeRequest")
note_events = event_counts(date_from, :merge_requests)
- .having(action: [Event::COMMENTED], target_type: %w(Note DiffNote))
+ .having(action: [Event::COMMENTED])
union = Gitlab::SQL::Union.new([repo_events, issue_events, mr_events, note_events])
events = Event.find_by_sql(union.to_sql).map(&:attributes)
diff --git a/lib/gitlab/data_builder/build.rb b/lib/gitlab/data_builder/build.rb
index 8e74e18a311..2f1445a050a 100644
--- a/lib/gitlab/data_builder/build.rb
+++ b/lib/gitlab/data_builder/build.rb
@@ -31,7 +31,7 @@ module Gitlab
# TODO: do we still need it?
project_id: project.id,
- project_name: project.name_with_namespace,
+ project_name: project.full_name,
user: {
id: user.try(:id),
diff --git a/lib/gitlab/data_builder/pipeline.rb b/lib/gitlab/data_builder/pipeline.rb
index e47fb85b5ee..1e283cc092b 100644
--- a/lib/gitlab/data_builder/pipeline.rb
+++ b/lib/gitlab/data_builder/pipeline.rb
@@ -22,6 +22,7 @@ module Gitlab
sha: pipeline.sha,
before_sha: pipeline.before_sha,
status: pipeline.status,
+ detailed_status: pipeline.detailed_status(nil).label,
stages: pipeline.stages_names,
created_at: pipeline.created_at,
finished_at: pipeline.finished_at,
diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb
index 594b6a9cbc5..93037ed8d90 100644
--- a/lib/gitlab/git/commit.rb
+++ b/lib/gitlab/git/commit.rb
@@ -347,7 +347,7 @@ module Gitlab
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/324
def to_diff
- Gitlab::GitalyClient.migrate(:commit_patch) do |is_enabled|
+ Gitlab::GitalyClient.migrate(:commit_patch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
@repository.gitaly_commit_client.patch(id)
else
diff --git a/lib/gitlab/git/gitlab_projects.rb b/lib/gitlab/git/gitlab_projects.rb
index e5a747cb987..5e1e22ae65c 100644
--- a/lib/gitlab/git/gitlab_projects.rb
+++ b/lib/gitlab/git/gitlab_projects.rb
@@ -63,11 +63,12 @@ module Gitlab
end
end
- def fetch_remote(name, timeout, force:, tags:, ssh_key: nil, known_hosts: nil)
+ def fetch_remote(name, timeout, force:, tags:, ssh_key: nil, known_hosts: nil, prune: true)
tags_option = tags ? '--tags' : '--no-tags'
logger.info "Fetching remote #{name} for repository #{repository_absolute_path}."
- cmd = %W(git fetch #{name} --prune --quiet)
+ cmd = %W(git fetch #{name} --quiet)
+ cmd << '--prune' if prune
cmd << '--force' if force
cmd << tags_option
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 21c79a7a550..fbc93542619 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -228,7 +228,7 @@ module Gitlab
end
def has_local_branches?
- gitaly_migrate(:has_local_branches) do |is_enabled|
+ gitaly_migrate(:has_local_branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_repository_client.has_local_branches?
else
@@ -715,7 +715,7 @@ module Gitlab
end
def add_branch(branch_name, user:, target:)
- gitaly_migrate(:operation_user_create_branch) do |is_enabled|
+ gitaly_migrate(:operation_user_create_branch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_add_branch(branch_name, user, target)
else
@@ -725,7 +725,7 @@ module Gitlab
end
def add_tag(tag_name, user:, target:, message: nil)
- gitaly_migrate(:operation_user_add_tag) do |is_enabled|
+ gitaly_migrate(:operation_user_add_tag, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_add_tag(tag_name, user: user, target: target, message: message)
else
@@ -735,7 +735,7 @@ module Gitlab
end
def rm_branch(branch_name, user:)
- gitaly_migrate(:operation_user_delete_branch) do |is_enabled|
+ gitaly_migrate(:operation_user_delete_branch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_operations_client.user_delete_branch(branch_name, user)
else
@@ -810,7 +810,7 @@ module Gitlab
end
def revert(user:, commit:, branch_name:, message:, start_branch_name:, start_repository:)
- gitaly_migrate(:revert) do |is_enabled|
+ gitaly_migrate(:revert, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
args = {
user: user,
commit: commit,
@@ -876,7 +876,7 @@ module Gitlab
# Delete the specified branch from the repository
def delete_branch(branch_name)
- gitaly_migrate(:delete_branch) do |is_enabled|
+ gitaly_migrate(:delete_branch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_ref_client.delete_branch(branch_name)
else
@@ -903,7 +903,7 @@ module Gitlab
# create_branch("feature")
# create_branch("other-feature", "master")
def create_branch(ref, start_point = "HEAD")
- gitaly_migrate(:create_branch) do |is_enabled|
+ gitaly_migrate(:create_branch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_ref_client.create_branch(ref, start_point)
else
@@ -1010,7 +1010,7 @@ module Gitlab
end
def languages(ref = nil)
- Gitlab::GitalyClient.migrate(:commit_languages) do |is_enabled|
+ gitaly_migrate(:commit_languages, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_commit_client.languages(ref)
else
@@ -1189,15 +1189,9 @@ module Gitlab
end
def fsck
- gitaly_migrate(:git_fsck) do |is_enabled|
- msg, status = if is_enabled
- gitaly_fsck
- else
- shell_fsck
- end
+ msg, status = gitaly_repository_client.fsck
- raise GitError.new("Could not fsck repository: #{msg}") unless status.zero?
- end
+ raise GitError.new("Could not fsck repository: #{msg}") unless status.zero?
end
def create_from_bundle(bundle_path)
@@ -1433,22 +1427,12 @@ module Gitlab
output
end
- def can_be_merged?(source_sha, target_branch)
- gitaly_migrate(:can_be_merged) do |is_enabled|
- if is_enabled
- gitaly_can_be_merged?(source_sha, find_branch(target_branch).target)
- else
- rugged_can_be_merged?(source_sha, target_branch)
- end
- end
- end
-
- def last_commit_id_for_path(sha, path)
+ def last_commit_for_path(sha, path)
gitaly_migrate(:last_commit_for_path) do |is_enabled|
if is_enabled
- last_commit_for_path_by_gitaly(sha, path).id
+ last_commit_for_path_by_gitaly(sha, path)
else
- last_commit_id_for_path_by_shelling_out(sha, path)
+ last_commit_for_path_by_rugged(sha, path)
end
end
end
@@ -1606,14 +1590,6 @@ module Gitlab
File.write(File.join(worktree_info_path, 'sparse-checkout'), files)
end
- def gitaly_fsck
- gitaly_repository_client.fsck
- end
-
- def shell_fsck
- run_git(%W[--git-dir=#{path} fsck], nice: true)
- end
-
def rugged_fetch_source_branch(source_repository, source_branch, local_ref)
with_repo_branch_commit(source_repository, source_branch) do |commit|
if commit
@@ -1896,7 +1872,7 @@ module Gitlab
end
def last_commit_for_path_by_rugged(sha, path)
- sha = last_commit_id_for_path(sha, path)
+ sha = last_commit_id_for_path_by_shelling_out(sha, path)
commit(sha)
end
@@ -2404,14 +2380,6 @@ module Gitlab
.map { |c| commit(c) }
end
- def gitaly_can_be_merged?(their_commit, our_commit)
- !gitaly_conflicts_client(our_commit, their_commit).conflicts?
- end
-
- def rugged_can_be_merged?(their_commit, our_commit)
- !rugged.merge_commits(our_commit, their_commit).conflicts?
- end
-
def last_commit_for_path_by_gitaly(sha, path)
gitaly_commit_client.last_commit_for_path(sha, path)
end
diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb
index fdb3247cf4d..e1bc2f9ab61 100644
--- a/lib/gitlab/gitaly_client/repository_service.rb
+++ b/lib/gitlab/gitaly_client/repository_service.rb
@@ -45,10 +45,10 @@ module Gitlab
GitalyClient.call(@storage, :repository_service, :apply_gitattributes, request)
end
- def fetch_remote(remote, ssh_auth:, forced:, no_tags:, timeout:)
+ def fetch_remote(remote, ssh_auth:, forced:, no_tags:, timeout:, prune: true)
request = Gitaly::FetchRemoteRequest.new(
repository: @gitaly_repo, remote: remote, force: forced,
- no_tags: no_tags, timeout: timeout
+ no_tags: no_tags, timeout: timeout, no_prune: !prune
)
if ssh_auth&.ssh_import?
diff --git a/lib/gitlab/health_checks/metric.rb b/lib/gitlab/health_checks/metric.rb
index 1a2eab0b005..d62d9136886 100644
--- a/lib/gitlab/health_checks/metric.rb
+++ b/lib/gitlab/health_checks/metric.rb
@@ -1,3 +1,3 @@
-module Gitlab::HealthChecks
+module Gitlab::HealthChecks # rubocop:disable Naming/FileName
Metric = Struct.new(:name, :value, :labels)
end
diff --git a/lib/gitlab/health_checks/result.rb b/lib/gitlab/health_checks/result.rb
index 8086760023e..e323e2c9723 100644
--- a/lib/gitlab/health_checks/result.rb
+++ b/lib/gitlab/health_checks/result.rb
@@ -1,3 +1,3 @@
-module Gitlab::HealthChecks
+module Gitlab::HealthChecks # rubocop:disable Naming/FileName
Result = Struct.new(:success, :message, :labels)
end
diff --git a/lib/gitlab/import_export.rb b/lib/gitlab/import_export.rb
index b713fa7e1cd..af203ff711d 100644
--- a/lib/gitlab/import_export.rb
+++ b/lib/gitlab/import_export.rb
@@ -3,7 +3,7 @@ module Gitlab
extend self
# For every version update, the version history in import_export.md has to be kept up to date.
- VERSION = '0.2.3'.freeze
+ VERSION = '0.2.2'.freeze
FILENAME_LIMIT = 50
def export_path(relative_path:)
diff --git a/lib/gitlab/legacy_github_import/project_creator.rb b/lib/gitlab/legacy_github_import/project_creator.rb
index cbabe5454ca..3ce245a8050 100644
--- a/lib/gitlab/legacy_github_import/project_creator.rb
+++ b/lib/gitlab/legacy_github_import/project_creator.rb
@@ -12,9 +12,8 @@ module Gitlab
@type = type
end
- def execute
- ::Projects::CreateService.new(
- current_user,
+ def execute(extra_attrs = {})
+ attrs = {
name: name,
path: name,
description: repo.description,
@@ -24,7 +23,9 @@ module Gitlab
import_source: repo.full_name,
import_url: import_url,
skip_wiki: skip_wiki
- ).execute
+ }.merge!(extra_attrs)
+
+ ::Projects::CreateService.new(current_user, attrs).execute
end
private
diff --git a/lib/gitlab/middleware/release_env.rb b/lib/gitlab/middleware/release_env.rb
index f8d0a135965..bfe8e113b5e 100644
--- a/lib/gitlab/middleware/release_env.rb
+++ b/lib/gitlab/middleware/release_env.rb
@@ -1,4 +1,4 @@
-module Gitlab
+module Gitlab # rubocop:disable Naming/FileName
module Middleware
# Some of middleware would hold env for no good reason even after the
# request had already been processed, and we could not garbage collect
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 4ba44e0feef..dda7afc0999 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -125,13 +125,13 @@ module Gitlab
# Ex.
# fetch_remote(my_repo, "upstream")
#
- def fetch_remote(repository, remote, ssh_auth: nil, forced: false, no_tags: false)
+ def fetch_remote(repository, remote, ssh_auth: nil, forced: false, no_tags: false, prune: true)
gitaly_migrate(:fetch_remote) do |is_enabled|
if is_enabled
- repository.gitaly_repository_client.fetch_remote(remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, timeout: git_timeout)
+ repository.gitaly_repository_client.fetch_remote(remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, timeout: git_timeout, prune: prune)
else
storage_path = Gitlab.config.repositories.storages[repository.storage]["path"]
- local_fetch_remote(storage_path, repository.relative_path, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags)
+ local_fetch_remote(storage_path, repository.relative_path, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, prune: prune)
end
end
end
@@ -428,8 +428,8 @@ module Gitlab
)
end
- def local_fetch_remote(storage_path, repository_relative_path, remote, ssh_auth: nil, forced: false, no_tags: false)
- vars = { force: forced, tags: !no_tags }
+ def local_fetch_remote(storage_path, repository_relative_path, remote, ssh_auth: nil, forced: false, no_tags: false, prune: true)
+ vars = { force: forced, tags: !no_tags, prune: prune }
if ssh_auth&.ssh_import?
if ssh_auth.ssh_key_auth? && ssh_auth.ssh_private_key.present?
diff --git a/lib/gitlab/slash_commands/presenters/issue_new.rb b/lib/gitlab/slash_commands/presenters/issue_new.rb
index 86490a39cc1..5964bfe9960 100644
--- a/lib/gitlab/slash_commands/presenters/issue_new.rb
+++ b/lib/gitlab/slash_commands/presenters/issue_new.rb
@@ -38,7 +38,7 @@ module Gitlab
end
def project_link
- "[#{project.name_with_namespace}](#{project.web_url})"
+ "[#{project.full_name}](#{project.web_url})"
end
def author_profile_link
diff --git a/lib/gitlab/slash_commands/presenters/issue_show.rb b/lib/gitlab/slash_commands/presenters/issue_show.rb
index c99316df667..562f15f403c 100644
--- a/lib/gitlab/slash_commands/presenters/issue_show.rb
+++ b/lib/gitlab/slash_commands/presenters/issue_show.rb
@@ -53,7 +53,7 @@ module Gitlab
end
def pretext
- "Issue *#{@resource.to_reference}* from #{project.name_with_namespace}"
+ "Issue *#{@resource.to_reference}* from #{project.full_name}"
end
end
end
diff --git a/lib/gitlab/slash_commands/result.rb b/lib/gitlab/slash_commands/result.rb
index 7021b4b01b2..3669dedf0fe 100644
--- a/lib/gitlab/slash_commands/result.rb
+++ b/lib/gitlab/slash_commands/result.rb
@@ -1,4 +1,4 @@
-module Gitlab
+module Gitlab # rubocop:disable Naming/FileName
module SlashCommands
Result = Struct.new(:type, :message)
end
diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb
index 91b8bb2a83f..24393f96d96 100644
--- a/lib/gitlab/user_access.rb
+++ b/lib/gitlab/user_access.rb
@@ -63,13 +63,12 @@ module Gitlab
request_cache def can_push_to_branch?(ref)
return false unless can_access_git?
+ return false unless user.can?(:push_code, project) || project.branch_allows_maintainer_push?(user, ref)
if protected?(ProtectedBranch, project, ref)
- return true if project.user_can_push_to_empty_repo?(user)
-
- protected_branch_accessible_to?(ref, action: :push)
+ project.user_can_push_to_empty_repo?(user) || protected_branch_accessible_to?(ref, action: :push)
else
- user.can?(:push_code, project)
+ true
end
end
diff --git a/lib/gitlab/utils.rb b/lib/gitlab/utils.rb
index fa22f0e37b2..dc9391f32cf 100644
--- a/lib/gitlab/utils.rb
+++ b/lib/gitlab/utils.rb
@@ -67,5 +67,13 @@ module Gitlab
nil
end
+
+ # Used in EE
+ # Accepts either an Array or a String and returns an array
+ def ensure_array_from_string(string_or_array)
+ return string_or_array if string_or_array.is_a?(Array)
+
+ string_or_array.split(',').map(&:strip)
+ end
end
end
diff --git a/lib/gitlab/verify/job_artifacts.rb b/lib/gitlab/verify/job_artifacts.rb
new file mode 100644
index 00000000000..03500a61074
--- /dev/null
+++ b/lib/gitlab/verify/job_artifacts.rb
@@ -0,0 +1,27 @@
+module Gitlab
+ module Verify
+ class JobArtifacts < BatchVerifier
+ def name
+ 'Job artifacts'
+ end
+
+ def describe(object)
+ "Job artifact: #{object.id}"
+ end
+
+ private
+
+ def relation
+ ::Ci::JobArtifact.all
+ end
+
+ def expected_checksum(artifact)
+ artifact.file_sha256
+ end
+
+ def actual_checksum(artifact)
+ Digest::SHA256.file(artifact.file.path).hexdigest
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index 823df67ea39..0b0d667d4fd 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -10,6 +10,7 @@ module Gitlab
INTERNAL_API_CONTENT_TYPE = 'application/vnd.gitlab-workhorse+json'.freeze
INTERNAL_API_REQUEST_HEADER = 'Gitlab-Workhorse-Api-Request'.freeze
NOTIFICATION_CHANNEL = 'workhorse:notifications'.freeze
+ ALLOWED_GIT_HTTP_ACTIONS = %w[git_receive_pack git_upload_pack info_refs].freeze
# Supposedly the effective key size for HMAC-SHA256 is 256 bits, i.e. 32
# bytes https://tools.ietf.org/html/rfc4868#section-2.6
@@ -17,6 +18,8 @@ module Gitlab
class << self
def git_http_ok(repository, is_wiki, user, action, show_all_refs: false)
+ raise "Unsupported action: #{action}" unless ALLOWED_GIT_HTTP_ACTIONS.include?(action.to_s)
+
project = repository.project
repo_path = repository.path_to_repo
params = {
@@ -31,24 +34,7 @@ module Gitlab
token: Gitlab::GitalyClient.token(project.repository_storage)
}
params[:Repository] = repository.gitaly_repository.to_h
-
- feature_enabled = case action.to_s
- when 'git_receive_pack'
- Gitlab::GitalyClient.feature_enabled?(
- :post_receive_pack,
- status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT
- )
- when 'git_upload_pack'
- true
- when 'info_refs'
- true
- else
- raise "Unsupported action: #{action}"
- end
-
- if feature_enabled
- params[:GitalyServer] = server
- end
+ params[:GitalyServer] = server
params
end
diff --git a/lib/haml_lint/inline_javascript.rb b/lib/haml_lint/inline_javascript.rb
index 4f776330e80..adbed20f152 100644
--- a/lib/haml_lint/inline_javascript.rb
+++ b/lib/haml_lint/inline_javascript.rb
@@ -1,4 +1,4 @@
-unless Rails.env.production?
+unless Rails.env.production? # rubocop:disable Naming/FileName
require 'haml_lint/haml_visitor'
require 'haml_lint/linter'
require 'haml_lint/linter_registry'
diff --git a/lib/mattermost/session.rb b/lib/mattermost/session.rb
index ef08bd46e17..65ccdb3c347 100644
--- a/lib/mattermost/session.rb
+++ b/lib/mattermost/session.rb
@@ -83,6 +83,12 @@ module Mattermost
end
end
+ def delete(path, options = {})
+ handle_exceptions do
+ self.class.delete(path, options.merge(headers: @headers))
+ end
+ end
+
private
def create
diff --git a/lib/mattermost/team.rb b/lib/mattermost/team.rb
index b2511f3af1d..75513a9ba04 100644
--- a/lib/mattermost/team.rb
+++ b/lib/mattermost/team.rb
@@ -16,10 +16,9 @@ module Mattermost
end
# The deletion is done async, so the response is fast.
- # On the mattermost side, this triggers an soft deletion first, after which
- # the actuall data is removed
+ # On the mattermost side, this triggers an soft deletion
def destroy(team_id:)
- session_delete("/api/v4/teams/#{team_id}?permanent=true")
+ session_delete("/api/v4/teams/#{team_id}")
end
end
end
diff --git a/lib/rouge/plugins/common_mark.rb b/lib/rouge/plugins/common_mark.rb
new file mode 100644
index 00000000000..8f9de061124
--- /dev/null
+++ b/lib/rouge/plugins/common_mark.rb
@@ -0,0 +1,20 @@
+# A rouge plugin for CommonMark markdown engine.
+# Used to highlight code generated by CommonMark.
+
+module Rouge
+ module Plugins
+ module CommonMark
+ def code_block(code, language)
+ lexer = Lexer.find_fancy(language, code) || Lexers::PlainText
+
+ formatter = rouge_formatter(lexer)
+ formatter.format(lexer.lex(code))
+ end
+
+ # override this method for custom formatting behavior
+ def rouge_formatter(lexer)
+ Formatters::HTMLLegacy.new(css_class: "highlight #{lexer.tag}")
+ end
+ end
+ end
+end
diff --git a/lib/system_check/helpers.rb b/lib/system_check/helpers.rb
index 914ed794601..6227e461d24 100644
--- a/lib/system_check/helpers.rb
+++ b/lib/system_check/helpers.rb
@@ -50,7 +50,7 @@ module SystemCheck
if should_sanitize?
"#{project.namespace_id.to_s.color(:yellow)}/#{project.id.to_s.color(:yellow)} ... "
else
- "#{project.name_with_namespace.color(:yellow)} ... "
+ "#{project.full_name.color(:yellow)} ... "
end
end
diff --git a/lib/tasks/gitlab/artifacts/check.rake b/lib/tasks/gitlab/artifacts/check.rake
new file mode 100644
index 00000000000..a105261ed51
--- /dev/null
+++ b/lib/tasks/gitlab/artifacts/check.rake
@@ -0,0 +1,8 @@
+namespace :gitlab do
+ namespace :artifacts do
+ desc 'GitLab | Artifacts | Check integrity of uploaded job artifacts'
+ task check: :environment do
+ Gitlab::Verify::RakeTask.run!(Gitlab::Verify::JobArtifacts)
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 8a2176a4d72..3f05e878cc8 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-03-05 13:02-0600\n"
-"PO-Revision-Date: 2018-03-05 13:02-0600\n"
+"POT-Creation-Date: 2018-03-06 17:36+0100\n"
+"PO-Revision-Date: 2018-03-06 17:36+0100\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
@@ -59,6 +59,9 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{loadingIcon} Started"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -102,6 +105,9 @@ msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
msgstr ""
+msgid "A new branch will be created in your fork and a new merge request will be started."
+msgstr ""
+
msgid "A project is where you house your files (repository), plan your work (issues), and publish your documentation (wiki), %{among_other_things_link}."
msgstr ""
@@ -207,9 +213,15 @@ msgstr ""
msgid "All features are enabled for blank projects, from templates, or when importing, but you can disable them afterward in the project settings."
msgstr ""
+msgid "Allow edits from maintainers"
+msgstr ""
+
msgid "Allows you to add and manage Kubernetes clusters."
msgstr ""
+msgid "Alternatively, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import."
+msgstr ""
+
msgid "An error occurred previewing the blob"
msgstr ""
@@ -288,9 +300,6 @@ msgstr ""
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr ""
-msgid "Are you sure you want to discard your changes?"
-msgstr ""
-
msgid "Are you sure you want to reset registration token?"
msgstr ""
@@ -392,9 +401,6 @@ msgstr[1] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr ""
-
msgid "Branch is already taken"
msgstr ""
@@ -410,6 +416,15 @@ msgstr ""
msgid "Branches"
msgstr ""
+msgid "Branches|Active"
+msgstr ""
+
+msgid "Branches|Active branches"
+msgstr ""
+
+msgid "Branches|All"
+msgstr ""
+
msgid "Branches|Cant find HEAD commit for this branch"
msgstr ""
@@ -455,12 +470,39 @@ msgstr ""
msgid "Branches|Only a project master or owner can delete a protected branch"
msgstr ""
-msgid "Branches|Protected branches can be managed in %{project_settings_link}"
+msgid "Branches|Overview"
+msgstr ""
+
+msgid "Branches|Protected branches can be managed in %{project_settings_link}."
+msgstr ""
+
+msgid "Branches|Show active branches"
+msgstr ""
+
+msgid "Branches|Show all branches"
+msgstr ""
+
+msgid "Branches|Show more active branches"
+msgstr ""
+
+msgid "Branches|Show more stale branches"
+msgstr ""
+
+msgid "Branches|Show overview of the branches"
+msgstr ""
+
+msgid "Branches|Show stale branches"
msgstr ""
msgid "Branches|Sort by"
msgstr ""
+msgid "Branches|Stale"
+msgstr ""
+
+msgid "Branches|Stale branches"
+msgstr ""
+
msgid "Branches|The default branch cannot be deleted"
msgstr ""
@@ -512,9 +554,6 @@ msgstr ""
msgid "Cancel"
msgstr ""
-msgid "Cancel edit"
-msgstr ""
-
msgid "Cannot modify managed Kubernetes cluster"
msgstr ""
@@ -569,6 +608,9 @@ msgstr ""
msgid "Choose file..."
msgstr ""
+msgid "Choose which repositories you want to import."
+msgstr ""
+
msgid "CiStatusLabel|canceled"
msgstr ""
@@ -662,6 +704,9 @@ msgstr ""
msgid "Clone repository"
msgstr ""
+msgid "Close"
+msgstr ""
+
msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
msgstr ""
@@ -1032,6 +1077,12 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
+msgid "Connect"
+msgstr ""
+
+msgid "Connect repositories from GitHub"
+msgstr ""
+
msgid "Container Registry"
msgstr ""
@@ -1077,6 +1128,9 @@ msgstr ""
msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images."
msgstr ""
+msgid "Contribution"
+msgstr ""
+
msgid "Contribution guide"
msgstr ""
@@ -1128,9 +1182,6 @@ msgstr ""
msgid "Create empty bare repository"
msgstr ""
-msgid "Create file"
-msgstr ""
-
msgid "Create lists from labels. Issues with that label appear in that list."
msgstr ""
@@ -1140,15 +1191,6 @@ msgstr ""
msgid "Create merge request and branch"
msgstr ""
-msgid "Create new branch"
-msgstr ""
-
-msgid "Create new directory"
-msgstr ""
-
-msgid "Create new file"
-msgstr ""
-
msgid "Create new label"
msgstr ""
@@ -1238,15 +1280,15 @@ msgstr ""
msgid "Directory name"
msgstr ""
-msgid "Discard changes"
-msgstr ""
-
msgid "Dismiss Cycle Analytics introduction box"
msgstr ""
msgid "Don't show again"
msgstr ""
+msgid "Done"
+msgstr ""
+
msgid "Download"
msgstr ""
@@ -1397,6 +1439,9 @@ msgstr ""
msgid "Explore public groups"
msgstr ""
+msgid "Failed"
+msgstr ""
+
msgid "Failed Jobs"
msgstr ""
@@ -1421,9 +1466,6 @@ msgstr ""
msgid "Fields on this page are now uneditable, you can configure"
msgstr ""
-msgid "File name"
-msgstr ""
-
msgid "Files"
msgstr ""
@@ -1439,6 +1481,9 @@ msgstr ""
msgid "Find file"
msgstr ""
+msgid "Finished"
+msgstr ""
+
msgid "FirstPushedBy|First"
msgstr ""
@@ -1462,6 +1507,9 @@ msgstr ""
msgid "Format"
msgstr ""
+msgid "From %{provider_title}"
+msgstr ""
+
msgid "From issue creation until deploy to production"
msgstr ""
@@ -1489,12 +1537,18 @@ msgstr ""
msgid "Git version"
msgstr ""
+msgid "GitHub import"
+msgstr ""
+
msgid "GitLab Runner section"
msgstr ""
msgid "Gitaly Servers"
msgstr ""
+msgid "Go back"
+msgstr ""
+
msgid "Go to your fork"
msgstr ""
@@ -1608,9 +1662,18 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>."
msgstr ""
+msgid "Import"
+msgstr ""
+
+msgid "Import all repositories"
+msgstr ""
+
msgid "Import in progress"
msgstr ""
+msgid "Import repositories from GitHub"
+msgstr ""
+
msgid "Import repository"
msgstr ""
@@ -1701,6 +1764,15 @@ msgstr ""
msgid "LFSStatus|Enabled"
msgstr ""
+msgid "Label"
+msgstr ""
+
+msgid "LabelSelect|%{firstLabelName} +%{remainingLabelCount} more"
+msgstr ""
+
+msgid "LabelSelect|%{labelsString}, and %{remainingLabelCount} more"
+msgstr ""
+
msgid "Labels"
msgstr ""
@@ -1760,7 +1832,7 @@ msgstr ""
msgid "Leave project"
msgstr ""
-msgid "Loading the GitLab IDE..."
+msgid "List your GitHub repositories"
msgstr ""
msgid "Lock"
@@ -1945,6 +2017,12 @@ msgstr ""
msgid "Not available"
msgstr ""
+msgid "Not available for private projects"
+msgstr ""
+
+msgid "Not available for protected branches"
+msgstr ""
+
msgid "Not confidential"
msgstr ""
@@ -1954,6 +2032,12 @@ msgstr ""
msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
msgstr ""
+msgid "Note: As an administrator you may like to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token."
+msgstr ""
+
+msgid "Note: Consider asking your GitLab administrator to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token."
+msgstr ""
+
msgid "Notification events"
msgstr ""
@@ -2071,6 +2155,12 @@ msgstr ""
msgid "Password"
msgstr ""
+msgid "Pending"
+msgstr ""
+
+msgid "Personal Access Token"
+msgstr ""
+
msgid "Pipeline"
msgstr ""
@@ -2149,9 +2239,30 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|CI Lint"
+msgstr ""
+
+msgid "Pipelines|Clear Runner Caches"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipelines|Loading Pipelines"
+msgstr ""
+
+msgid "Pipelines|Run Pipeline"
+msgstr ""
+
+msgid "Pipelines|There are currently no %{scope} pipelines."
+msgstr ""
+
+msgid "Pipelines|There are currently no pipelines."
+msgstr ""
+
+msgid "Pipelines|This project is not currently set up to run pipelines."
+msgstr ""
+
msgid "Pipeline|Retry pipeline"
msgstr ""
@@ -2404,6 +2515,9 @@ msgstr ""
msgid "Public - The project can be accessed without any authentication."
msgstr ""
+msgid "Push access to this project is necessary in order to enable this option"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -2490,6 +2604,9 @@ msgstr ""
msgid "Revert this merge request"
msgstr ""
+msgid "Running"
+msgstr ""
+
msgid "SSH Keys"
msgstr ""
@@ -2505,12 +2622,18 @@ msgstr ""
msgid "Schedule a new pipeline"
msgstr ""
+msgid "Scheduled"
+msgstr ""
+
msgid "Schedules"
msgstr ""
msgid "Scheduling Pipelines"
msgstr ""
+msgid "Search"
+msgstr ""
+
msgid "Search branches and tags"
msgstr ""
@@ -2753,6 +2876,12 @@ msgstr ""
msgid "Start the Runner!"
msgstr ""
+msgid "Started"
+msgstr ""
+
+msgid "Status"
+msgstr ""
+
msgid "Stopped"
msgstr ""
@@ -3170,6 +3299,15 @@ msgstr ""
msgid "Tip:"
msgstr ""
+msgid "To GitLab"
+msgstr ""
+
+msgid "To import GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import."
+msgstr ""
+
+msgid "To import GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories:"
+msgstr ""
+
msgid "To import an SVN repository, check out %{svn_link}."
msgstr ""
@@ -3278,9 +3416,6 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "Web IDE"
-msgstr ""
-
msgid "Wiki"
msgstr ""
@@ -3395,13 +3530,13 @@ msgstr ""
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to remove %{project_name_with_namespace}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?"
+msgid "You are going to remove %{project_full_name}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are on a read-only GitLab instance."
@@ -3467,6 +3602,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes can be committed to %{branch_name} because a merge request is open."
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -3497,6 +3635,9 @@ msgstr ""
msgid "confidentiality|You are going to turn on the confidentiality. This means that only team members with <strong>at least Reporter access</strong> are able to see and leave comments on the issue."
msgstr ""
+msgid "connecting"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] ""
@@ -3505,6 +3646,9 @@ msgstr[1] ""
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "importing"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
@@ -3513,6 +3657,9 @@ msgstr[1] ""
msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
msgstr ""
+msgid "mrWidget|Allows edits from maintainers"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
diff --git a/package.json b/package.json
index cbad55b4c85..48954e071da 100644
--- a/package.json
+++ b/package.json
@@ -91,7 +91,7 @@
"worker-loader": "^1.1.0"
},
"devDependencies": {
- "@gitlab-org/gitlab-svgs": "^1.8.0",
+ "@gitlab-org/gitlab-svgs": "^1.13.0",
"axios-mock-adapter": "^1.10.0",
"babel-eslint": "^8.0.2",
"babel-plugin-istanbul": "^4.1.5",
diff --git a/qa/qa/page/project/settings/ci_cd.rb b/qa/qa/page/project/settings/ci_cd.rb
index 99be21bbe89..17a1bc904e4 100644
--- a/qa/qa/page/project/settings/ci_cd.rb
+++ b/qa/qa/page/project/settings/ci_cd.rb
@@ -1,4 +1,4 @@
-module QA
+module QA # rubocop:disable Naming/FileName
module Page
module Project
module Settings
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index 9110237c538..b36a3f9c8a0 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Naming/FileName
require_relative 'cop/gitlab/module_with_instance_variables'
require_relative 'cop/gitlab/predicate_memoization'
require_relative 'cop/include_sidekiq_worker'
diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb
index 00cf464ec5b..306094f7ffb 100644
--- a/spec/controllers/projects/milestones_controller_spec.rb
+++ b/spec/controllers/projects/milestones_controller_spec.rb
@@ -98,10 +98,8 @@ describe Projects::MilestonesController do
it 'shows group milestone' do
post :promote, namespace_id: project.namespace.id, project_id: project.id, id: milestone.iid
- group_milestone = assigns(:milestone)
-
- expect(response).to redirect_to(group_milestone_path(project.group, group_milestone.iid))
- expect(flash[:notice]).to eq('Milestone has been promoted to group milestone.')
+ expect(flash[:notice]).to eq("#{milestone.title} promoted to group milestone")
+ expect(response).to redirect_to(project_milestones_path(project))
end
end
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index 847ac6f2be0..e4dc61b3a68 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -23,6 +23,18 @@ describe Projects::ServicesController do
end
end
+ context 'when validations fail' do
+ let(:service_params) { { active: 'true', token: '' } }
+
+ it 'returns error messages in JSON response' do
+ put :test, namespace_id: project.namespace, project_id: project, id: :hipchat, service: service_params
+
+ expect(json_response['message']).to eq "Validations failed."
+ expect(json_response['service_response']).to eq "Token can't be blank"
+ expect(response).to have_gitlab_http_status(200)
+ end
+ end
+
context 'success' do
context 'with empty project' do
let(:project) { create(:project) }
diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
index 0202149f335..293e76798ae 100644
--- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb
+++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
@@ -27,7 +27,7 @@ describe Projects::Settings::CiCdController do
allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true)
end
- subject { post :reset_cache, namespace_id: project.namespace, project_id: project }
+ subject { post :reset_cache, namespace_id: project.namespace, project_id: project, format: :json }
it 'calls reset project cache service' do
expect(ResetProjectCacheService).to receive_message_chain(:new, :execute)
@@ -35,19 +35,11 @@ describe Projects::Settings::CiCdController do
subject
end
- it 'redirects to project pipelines path' do
- subject
-
- expect(response).to have_gitlab_http_status(:redirect)
- expect(response).to redirect_to(project_pipelines_path(project))
- end
-
context 'when service returns successfully' do
- it 'sets the flash notice variable' do
+ it 'returns a success header' do
subject
- expect(controller).to set_flash[:notice]
- expect(controller).not_to set_flash[:error]
+ expect(response).to have_gitlab_http_status(:ok)
end
end
@@ -56,11 +48,10 @@ describe Projects::Settings::CiCdController do
allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(false)
end
- it 'sets the flash error variable' do
+ it 'returns an error header' do
subject
- expect(controller).not_to set_flash[:notice]
- expect(controller).to set_flash[:error]
+ expect(response).to have_gitlab_http_status(:bad_request)
end
end
end
diff --git a/spec/factories/ci/job_artifacts.rb b/spec/factories/ci/job_artifacts.rb
index 7ee379ca2ec..8544d54ccaa 100644
--- a/spec/factories/ci/job_artifacts.rb
+++ b/spec/factories/ci/job_artifacts.rb
@@ -35,5 +35,11 @@ FactoryBot.define do
Rails.root.join('spec/fixtures/trace/sample_trace'), 'text/plain')
end
end
+
+ trait :correct_checksum do
+ after(:build) do |artifact, evaluator|
+ artifact.file_sha256 = Digest::SHA256.file(artifact.file.path).hexdigest
+ end
+ end
end
end
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index 3f4e408b3a6..857333f222d 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -16,6 +16,8 @@ FactoryBot.define do
factory :note_on_personal_snippet, traits: [:on_personal_snippet]
factory :system_note, traits: [:system]
+ factory :discussion_note, class: DiscussionNote
+
factory :discussion_note_on_merge_request, traits: [:on_merge_request], class: DiscussionNote do
association :project, :repository
@@ -31,6 +33,8 @@ FactoryBot.define do
factory :discussion_note_on_personal_snippet, traits: [:on_personal_snippet], class: DiscussionNote
+ factory :discussion_note_on_snippet, traits: [:on_snippet], class: DiscussionNote
+
factory :legacy_diff_note_on_commit, traits: [:on_commit, :legacy_diff_note], class: LegacyDiffNote
factory :legacy_diff_note_on_merge_request, traits: [:on_merge_request, :legacy_diff_note], class: LegacyDiffNote do
@@ -96,6 +100,10 @@ FactoryBot.define do
noteable { create(:issue, project: project) }
end
+ trait :on_snippet do
+ noteable { create(:snippet, project: project) }
+ end
+
trait :on_merge_request do
noteable { create(:merge_request, source_project: project) }
end
diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb
index f266f2ecc54..25ed3bdc88e 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/features/admin/admin_hooks_spec.rb
@@ -24,6 +24,16 @@ describe 'Admin::Hooks' do
visit admin_hooks_path
expect(page).to have_content(system_hook.url)
end
+
+ it 'renders plugins list as well' do
+ allow(Gitlab::Plugin).to receive(:files).and_return(['foo.rb', 'bar.clj'])
+
+ visit admin_hooks_path
+
+ expect(page).to have_content('Plugins')
+ expect(page).to have_content('foo.rb')
+ expect(page).to have_content('bar.clj')
+ end
end
describe 'New Hook' do
diff --git a/spec/features/merge_request/maintainer_edits_fork_spec.rb b/spec/features/merge_request/maintainer_edits_fork_spec.rb
new file mode 100644
index 00000000000..a3323da1b1f
--- /dev/null
+++ b/spec/features/merge_request/maintainer_edits_fork_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe 'a maintainer edits files on a source-branch of an MR from a fork', :js do
+ include ProjectForksHelper
+ let(:user) { create(:user, username: 'the-maintainer') }
+ let(:target_project) { create(:project, :public, :repository) }
+ let(:author) { create(:user, username: 'mr-authoring-machine') }
+ let(:source_project) { fork_project(target_project, author, repository: true) }
+
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: source_project,
+ target_project: target_project,
+ source_branch: 'fix',
+ target_branch: 'master',
+ author: author,
+ allow_maintainer_to_push: true)
+ end
+
+ before do
+ target_project.add_master(user)
+ sign_in(user)
+
+ visit project_merge_request_path(target_project, merge_request)
+ click_link 'Changes'
+ wait_for_requests
+ first('.js-file-title').click_link 'Edit'
+ wait_for_requests
+ end
+
+ it 'mentions commits will go to the source branch' do
+ expect(page).to have_content('Your changes can be committed to fix because a merge request is open.')
+ end
+
+ it 'allows committing to the source branch' do
+ find('.ace_text-input', visible: false).send_keys('Updated the readme')
+
+ click_button 'Commit changes'
+ wait_for_requests
+
+ expect(page).to have_content('Your changes have been successfully committed')
+ expect(page).to have_content('Updated the readme')
+ end
+end
diff --git a/spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb b/spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb
new file mode 100644
index 00000000000..eb41d7de8ed
--- /dev/null
+++ b/spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb
@@ -0,0 +1,85 @@
+require 'spec_helper'
+
+describe 'create a merge request that allows maintainers to push', :js do
+ include ProjectForksHelper
+ let(:user) { create(:user) }
+ let(:target_project) { create(:project, :public, :repository) }
+ let(:source_project) { fork_project(target_project, user, repository: true, namespace: user.namespace) }
+
+ def visit_new_merge_request
+ visit project_new_merge_request_path(
+ source_project,
+ merge_request: {
+ source_project_id: source_project.id,
+ target_project_id: target_project.id,
+ source_branch: 'fix',
+ target_branch: 'master'
+ })
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ it 'allows setting maintainer push possible' do
+ visit_new_merge_request
+
+ check 'Allow edits from maintainers'
+
+ click_button 'Submit merge request'
+
+ wait_for_requests
+
+ expect(page).to have_content('Allows edits from maintainers')
+ end
+
+ it 'shows a message when one of the projects is private' do
+ source_project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+
+ visit_new_merge_request
+
+ expect(page).to have_content('Not available for private projects')
+ end
+
+ it 'shows a message when the source branch is protected' do
+ create(:protected_branch, project: source_project, name: 'fix')
+
+ visit_new_merge_request
+
+ expect(page).to have_content('Not available for protected branches')
+ end
+
+ context 'when the merge request is being created within the same project' do
+ let(:source_project) { target_project }
+
+ it 'hides the checkbox if the merge request is being created within the same project' do
+ target_project.add_developer(user)
+
+ visit_new_merge_request
+
+ expect(page).not_to have_content('Allows edits from maintainers')
+ end
+ end
+
+ context 'when a maintainer tries to edit the option' do
+ let(:maintainer) { create(:user) }
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: source_project,
+ target_project: target_project,
+ source_branch: 'fixes')
+ end
+
+ before do
+ target_project.add_master(maintainer)
+
+ sign_in(maintainer)
+ end
+
+ it 'it hides the option from maintainers' do
+ visit edit_project_merge_request_path(target_project, merge_request)
+
+ expect(page).not_to have_content('Allows edits from maintainers')
+ end
+ end
+end
diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb
index cc12a1005ba..19152bf1f0f 100644
--- a/spec/features/milestone_spec.rb
+++ b/spec/features/milestone_spec.rb
@@ -97,4 +97,15 @@ feature 'Milestone' do
end
end
end
+
+ feature 'Deleting a milestone' do
+ scenario "The delete milestone button does not show for unauthorized users" do
+ create(:milestone, project: project, title: 8.7)
+ sign_out(user)
+
+ visit group_milestones_path(group)
+
+ expect(page).to have_selector('.js-delete-milestone-button', count: 0)
+ end
+ end
end
diff --git a/spec/features/projects/import_export/test_project_export.tar.gz b/spec/features/projects/import_export/test_project_export.tar.gz
index 12bfcc177c7..0cc68aff494 100644
--- a/spec/features/projects/import_export/test_project_export.tar.gz
+++ b/spec/features/projects/import_export/test_project_export.tar.gz
Binary files differ
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index fd561288091..a5954fec54b 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -173,11 +173,11 @@ feature 'New project' do
context 'from GitHub' do
before do
- first('.import_github').click
+ first('.js-import-github').click
end
it 'shows import instructions' do
- expect(page).to have_content('Import Projects from GitHub')
+ expect(page).to have_content('Import repositories from GitHub')
expect(current_path).to eq new_import_github_path
end
end
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 849d85061df..33ad59abfdf 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -557,7 +557,7 @@ describe 'Pipelines', :js do
end
it 'has a clear caches button' do
- expect(page).to have_link 'Clear Runner Caches'
+ expect(page).to have_button 'Clear Runner Caches'
end
describe 'user clicks the button' do
@@ -567,14 +567,16 @@ describe 'Pipelines', :js do
end
it 'increments jobs_cache_index' do
- click_link 'Clear Runner Caches'
+ click_button 'Clear Runner Caches'
+ wait_for_requests
expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
end
end
context 'when project does not have jobs_cache_index' do
it 'sets jobs_cache_index to 1' do
- click_link 'Clear Runner Caches'
+ click_button 'Clear Runner Caches'
+ wait_for_requests
expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
end
end
diff --git a/spec/features/projects/services/disable_triggers_spec.rb b/spec/features/projects/services/disable_triggers_spec.rb
new file mode 100644
index 00000000000..1a13fe03a67
--- /dev/null
+++ b/spec/features/projects/services/disable_triggers_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+describe 'Disable individual triggers' do
+ let(:project) { create(:project) }
+ let(:user) { project.owner }
+ let(:checkbox_selector) { 'input[type=checkbox][id$=_events]' }
+
+ before do
+ sign_in(user)
+
+ visit(project_settings_integrations_path(project))
+
+ click_link(service_name)
+ end
+
+ context 'service has multiple supported events' do
+ let(:service_name) { 'HipChat' }
+
+ it 'shows trigger checkboxes' do
+ event_count = HipchatService.supported_events.count
+
+ expect(page).to have_content "Trigger"
+ expect(page).to have_css(checkbox_selector, count: event_count)
+ end
+ end
+
+ context 'services only has one supported event' do
+ let(:service_name) { 'Asana' }
+
+ it "doesn't show unnecessary Trigger checkboxes" do
+ expect(page).not_to have_content "Trigger"
+ expect(page).not_to have_css(checkbox_selector)
+ end
+ end
+end
diff --git a/spec/features/projects/user_creates_files_spec.rb b/spec/features/projects/user_creates_files_spec.rb
index 7a935dd2477..8993533676b 100644
--- a/spec/features/projects/user_creates_files_spec.rb
+++ b/spec/features/projects/user_creates_files_spec.rb
@@ -133,13 +133,20 @@ describe 'User creates files' do
before do
project2.add_reporter(user)
visit(project2_tree_path_root_ref)
- end
- it 'creates and commit new file in forked project', :js do
find('.add-to-tree').click
click_link('New file')
+ end
+
+ it 'shows a message saying the file will be committed in a fork' do
+ message = "A new branch will be created in your fork and a new merge request will be started."
+ expect(page).to have_content(message)
+ end
+
+ it 'creates and commit new file in forked project', :js do
expect(page).to have_selector('.file-editor')
+ expect(page).to have_content
find('#editor')
execute_script("ace.edit('editor').setValue('*.rbca')")
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 6ef235cf870..bc75dc5d19b 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -145,6 +145,18 @@ feature 'Login' do
expect { enter_code(codes.sample) }
.to change { user.reload.otp_backup_codes.size }.by(-1)
end
+
+ it 'invalidates backup codes twice in a row' do
+ random_code = codes.delete(codes.sample)
+ expect { enter_code(random_code) }
+ .to change { user.reload.otp_backup_codes.size }.by(-1)
+
+ gitlab_sign_out
+ gitlab_sign_in(user)
+
+ expect { enter_code(codes.sample) }
+ .to change { user.reload.otp_backup_codes.size }.by(-1)
+ end
end
context 'with invalid code' do
diff --git a/spec/fixtures/api/schemas/entities/merge_request_basic.json b/spec/fixtures/api/schemas/entities/merge_request_basic.json
index f1199468d53..46031961cca 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_basic.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_basic.json
@@ -12,7 +12,8 @@
"rebase_in_progress": { "type": "boolean" },
"assignee_id": { "type": ["integer", "null"] },
"subscribed": { "type": ["boolean", "null"] },
- "participants": { "type": "array" }
+ "participants": { "type": "array" },
+ "allow_maintainer_to_push": { "type": "boolean"}
},
"additionalProperties": false
}
diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json
index cfbeec58a45..a622bf88b13 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_widget.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json
@@ -30,6 +30,7 @@
"source_project_id": { "type": "integer" },
"target_branch": { "type": "string" },
"target_project_id": { "type": "integer" },
+ "allow_maintainer_to_push": { "type": "boolean"},
"metrics": {
"oneOf": [
{ "type": "null" },
diff --git a/spec/fixtures/api/schemas/public_api/v4/merge_requests.json b/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
index e86176e5316..0dc2eabec5d 100644
--- a/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
+++ b/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
@@ -80,7 +80,8 @@
"total_time_spent": { "type": "integer" },
"human_time_estimate": { "type": ["string", "null"] },
"human_total_time_spent": { "type": ["string", "null"] }
- }
+ },
+ "allow_maintainer_to_push": { "type": ["boolean", "null"] }
},
"required": [
"id", "iid", "project_id", "title", "description",
diff --git a/spec/fixtures/api/schemas/public_api/v4/notes.json b/spec/fixtures/api/schemas/public_api/v4/notes.json
index 6525f7c2c80..4c4ca3b582f 100644
--- a/spec/fixtures/api/schemas/public_api/v4/notes.json
+++ b/spec/fixtures/api/schemas/public_api/v4/notes.json
@@ -4,6 +4,7 @@
"type": "object",
"properties" : {
"id": { "type": "integer" },
+ "type": { "type": ["string", "null"] },
"body": { "type": "string" },
"attachment": { "type": ["string", "null"] },
"author": {
diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb
index d3b1be599dd..ccac6e29447 100644
--- a/spec/helpers/tree_helper_spec.rb
+++ b/spec/helpers/tree_helper_spec.rb
@@ -62,4 +62,13 @@ describe TreeHelper do
end
end
end
+
+ describe '#commit_in_single_accessible_branch' do
+ it 'escapes HTML from the branch name' do
+ helper.instance_variable_set(:@branch_name, "<script>alert('escape me!');</script>")
+ escaped_branch_name = '&lt;script&gt;alert(&#39;escape me!&#39;);&lt;/script&gt;'
+
+ expect(helper.commit_in_single_accessible_branch).to include(escaped_branch_name)
+ end
+ end
end
diff --git a/spec/javascripts/environments/environments_app_spec.js b/spec/javascripts/environments/environments_app_spec.js
index 5bb37304372..e4c3bf2bef1 100644
--- a/spec/javascripts/environments/environments_app_spec.js
+++ b/spec/javascripts/environments/environments_app_spec.js
@@ -61,6 +61,7 @@ describe('Environment', () => {
});
describe('with paginated environments', () => {
+ let backupInterceptors;
const environmentsResponseInterceptor = (request, next) => {
next((response) => {
response.headers.set('X-nExt-pAge', '2');
@@ -84,16 +85,16 @@ describe('Environment', () => {
};
beforeEach(() => {
- Vue.http.interceptors.push(environmentsResponseInterceptor);
- Vue.http.interceptors.push(headersInterceptor);
+ backupInterceptors = Vue.http.interceptors;
+ Vue.http.interceptors = [
+ environmentsResponseInterceptor,
+ headersInterceptor,
+ ];
component = mountComponent(EnvironmentsComponent, mockData);
});
afterEach(() => {
- Vue.http.interceptors = _.without(
- Vue.http.interceptors, environmentsResponseInterceptor,
- );
- Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
+ Vue.http.interceptors = backupInterceptors;
});
it('should render a table with environments', (done) => {
diff --git a/spec/javascripts/importer_status_spec.js b/spec/javascripts/importer_status_spec.js
index 71a2cd51f63..0575d02886d 100644
--- a/spec/javascripts/importer_status_spec.js
+++ b/spec/javascripts/importer_status_spec.js
@@ -29,7 +29,10 @@ describe('Importer Status', () => {
`);
spyOn(ImporterStatus.prototype, 'initStatusPage').and.callFake(() => {});
spyOn(ImporterStatus.prototype, 'setAutoUpdate').and.callFake(() => {});
- instance = new ImporterStatus('', importUrl);
+ instance = new ImporterStatus({
+ jobsUrl: '',
+ importUrl,
+ });
});
it('sets table row to active after post request', (done) => {
@@ -65,7 +68,9 @@ describe('Importer Status', () => {
spyOn(ImporterStatus.prototype, 'initStatusPage').and.callFake(() => {});
spyOn(ImporterStatus.prototype, 'setAutoUpdate').and.callFake(() => {});
- instance = new ImporterStatus(jobsUrl);
+ instance = new ImporterStatus({
+ jobsUrl,
+ });
});
function setupMock(importStatus) {
@@ -86,17 +91,17 @@ describe('Importer Status', () => {
it('sets the job status to done', (done) => {
setupMock('finished');
- expectJobStatus(done, 'done');
+ expectJobStatus(done, 'Done');
});
it('sets the job status to scheduled', (done) => {
setupMock('scheduled');
- expectJobStatus(done, 'scheduled');
+ expectJobStatus(done, 'Scheduled');
});
it('sets the job status to started', (done) => {
setupMock('started');
- expectJobStatus(done, 'started');
+ expectJobStatus(done, 'Started');
});
it('sets the job status to custom status', (done) => {
diff --git a/spec/javascripts/pages/labels/components/promote_label_modal_spec.js b/spec/javascripts/pages/labels/components/promote_label_modal_spec.js
new file mode 100644
index 00000000000..ba2e07f02f7
--- /dev/null
+++ b/spec/javascripts/pages/labels/components/promote_label_modal_spec.js
@@ -0,0 +1,88 @@
+import Vue from 'vue';
+import promoteLabelModal from '~/pages/projects/labels/components/promote_label_modal.vue';
+import eventHub from '~/pages/projects/labels/event_hub';
+import axios from '~/lib/utils/axios_utils';
+import mountComponent from '../../../helpers/vue_mount_component_helper';
+
+describe('Promote label modal', () => {
+ let vm;
+ const Component = Vue.extend(promoteLabelModal);
+ const labelMockData = {
+ labelTitle: 'Documentation',
+ labelColor: '#5cb85c',
+ labelTextColor: '#ffffff',
+ url: `${gl.TEST_HOST}/dummy/promote/labels`,
+ };
+
+ describe('Modal title and description', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, labelMockData);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('contains the proper description', () => {
+ expect(vm.text).toContain('Promoting this label will make it available for all projects inside the group');
+ });
+
+ it('contains a label span with the color', () => {
+ const labelFromTitle = vm.$el.querySelector('.modal-header .label.color-label');
+
+ expect(labelFromTitle.style.backgroundColor).not.toBe(null);
+ expect(labelFromTitle.textContent).toContain(vm.labelTitle);
+ });
+ });
+
+ describe('When requesting a label promotion', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ ...labelMockData,
+ });
+ spyOn(eventHub, '$emit');
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('redirects when a label is promoted', (done) => {
+ const responseURL = `${gl.TEST_HOST}/dummy/endpoint`;
+ spyOn(axios, 'post').and.callFake((url) => {
+ expect(url).toBe(labelMockData.url);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteLabelModal.requestStarted', labelMockData.url);
+ return Promise.resolve({
+ request: {
+ responseURL,
+ },
+ });
+ });
+
+ vm.onSubmit()
+ .then(() => {
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteLabelModal.requestFinished', { labelUrl: labelMockData.url, successful: true });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('displays an error if promoting a label failed', (done) => {
+ const dummyError = new Error('promoting label failed');
+ dummyError.response = { status: 500 };
+ spyOn(axios, 'post').and.callFake((url) => {
+ expect(url).toBe(labelMockData.url);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteLabelModal.requestStarted', labelMockData.url);
+ return Promise.reject(dummyError);
+ });
+
+ vm.onSubmit()
+ .catch((error) => {
+ expect(error).toBe(dummyError);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteLabelModal.requestFinished', { labelUrl: labelMockData.url, successful: false });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js b/spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js
new file mode 100644
index 00000000000..bf044fe8fb5
--- /dev/null
+++ b/spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js
@@ -0,0 +1,83 @@
+import Vue from 'vue';
+import promoteMilestoneModal from '~/pages/milestones/shared/components/promote_milestone_modal.vue';
+import eventHub from '~/pages/milestones/shared/event_hub';
+import axios from '~/lib/utils/axios_utils';
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+describe('Promote milestone modal', () => {
+ let vm;
+ const Component = Vue.extend(promoteMilestoneModal);
+ const milestoneMockData = {
+ milestoneTitle: 'v1.0',
+ url: `${gl.TEST_HOST}/dummy/promote/milestones`,
+ };
+
+ describe('Modal title and description', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, milestoneMockData);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('contains the proper description', () => {
+ expect(vm.text).toContain('Promoting this milestone will make it available for all projects inside the group.');
+ });
+
+ it('contains the correct title', () => {
+ expect(vm.title).toEqual('Promote v1.0 to group milestone?');
+ });
+ });
+
+ describe('When requesting a milestone promotion', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ ...milestoneMockData,
+ });
+ spyOn(eventHub, '$emit');
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('redirects when a milestone is promoted', (done) => {
+ const responseURL = `${gl.TEST_HOST}/dummy/endpoint`;
+ spyOn(axios, 'post').and.callFake((url) => {
+ expect(url).toBe(milestoneMockData.url);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteMilestoneModal.requestStarted', milestoneMockData.url);
+ return Promise.resolve({
+ request: {
+ responseURL,
+ },
+ });
+ });
+
+ vm.onSubmit()
+ .then(() => {
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteMilestoneModal.requestFinished', { milestoneUrl: milestoneMockData.url, successful: true });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('displays an error if promoting a milestone failed', (done) => {
+ const dummyError = new Error('promoting milestone failed');
+ dummyError.response = { status: 500 };
+ spyOn(axios, 'post').and.callFake((url) => {
+ expect(url).toBe(milestoneMockData.url);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteMilestoneModal.requestStarted', milestoneMockData.url);
+ return Promise.reject(dummyError);
+ });
+
+ vm.onSubmit()
+ .catch((error) => {
+ expect(error).toBe(dummyError);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteMilestoneModal.requestFinished', { milestoneUrl: milestoneMockData.url, successful: false });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/javascripts/pipelines/nav_controls_spec.js b/spec/javascripts/pipelines/nav_controls_spec.js
index 77c5258f74c..d6232f5c567 100644
--- a/spec/javascripts/pipelines/nav_controls_spec.js
+++ b/spec/javascripts/pipelines/nav_controls_spec.js
@@ -39,19 +39,6 @@ describe('Pipelines Nav Controls', () => {
expect(component.$el.querySelector('.js-run-pipeline')).toEqual(null);
});
- it('should render link for resetting runner caches', () => {
- const mockData = {
- newPipelinePath: 'foo',
- ciLintPath: 'foo',
- resetCachePath: 'foo',
- };
-
- component = mountComponent(NavControlsComponent, mockData);
-
- expect(component.$el.querySelector('.js-clear-cache').textContent.trim()).toContain('Clear Runner Caches');
- expect(component.$el.querySelector('.js-clear-cache').getAttribute('href')).toEqual(mockData.resetCachePath);
- });
-
it('should render link for CI lint', () => {
const mockData = {
newPipelinePath: 'foo',
@@ -65,4 +52,28 @@ describe('Pipelines Nav Controls', () => {
expect(component.$el.querySelector('.js-ci-lint').textContent.trim()).toContain('CI Lint');
expect(component.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(mockData.ciLintPath);
});
+
+ describe('Reset Runners Cache', () => {
+ beforeEach(() => {
+ const mockData = {
+ newPipelinePath: 'foo',
+ ciLintPath: 'foo',
+ resetCachePath: 'foo',
+ };
+
+ component = mountComponent(NavControlsComponent, mockData);
+ });
+
+ it('should render button for resetting runner caches', () => {
+ expect(component.$el.querySelector('.js-clear-cache').textContent.trim()).toContain('Clear Runner Caches');
+ });
+
+ it('should emit postAction event when reset runner cache button is clicked', () => {
+ spyOn(component, '$emit');
+
+ component.$el.querySelector('.js-clear-cache').click();
+
+ expect(component.$emit).toHaveBeenCalledWith('resetRunnersCache', 'foo');
+ });
+ });
});
diff --git a/spec/javascripts/pipelines/pipelines_spec.js b/spec/javascripts/pipelines/pipelines_spec.js
index 84fd0329f08..7e242eb45e1 100644
--- a/spec/javascripts/pipelines/pipelines_spec.js
+++ b/spec/javascripts/pipelines/pipelines_spec.js
@@ -95,16 +95,16 @@ describe('Pipelines', () => {
expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
});
- it('renders Run Pipeline button', () => {
+ it('renders Run Pipeline link', () => {
expect(vm.$el.querySelector('.js-run-pipeline').getAttribute('href')).toEqual(paths.newPipelinePath);
});
- it('renders CI Lint button', () => {
+ it('renders CI Lint link', () => {
expect(vm.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(paths.ciLintPath);
});
it('renders Clear Runner Cache button', () => {
- expect(vm.$el.querySelector('.js-clear-cache').getAttribute('href')).toEqual(paths.resetCachePath);
+ expect(vm.$el.querySelector('.js-clear-cache').textContent.trim()).toEqual('Clear Runner Caches');
});
it('renders pipelines table', () => {
@@ -139,16 +139,16 @@ describe('Pipelines', () => {
expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
});
- it('renders Run Pipeline button', () => {
+ it('renders Run Pipeline link', () => {
expect(vm.$el.querySelector('.js-run-pipeline').getAttribute('href')).toEqual(paths.newPipelinePath);
});
- it('renders CI Lint button', () => {
+ it('renders CI Lint link', () => {
expect(vm.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(paths.ciLintPath);
});
it('renders Clear Runner Cache button', () => {
- expect(vm.$el.querySelector('.js-clear-cache').getAttribute('href')).toEqual(paths.resetCachePath);
+ expect(vm.$el.querySelector('.js-clear-cache').textContent.trim()).toEqual('Clear Runner Caches');
});
it('renders tab empty state', () => {
@@ -218,7 +218,7 @@ describe('Pipelines', () => {
it('renders buttons', () => {
expect(vm.$el.querySelector('.js-run-pipeline').getAttribute('href')).toEqual(paths.newPipelinePath);
expect(vm.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(paths.ciLintPath);
- expect(vm.$el.querySelector('.js-clear-cache').getAttribute('href')).toEqual(paths.resetCachePath);
+ expect(vm.$el.querySelector('.js-clear-cache').textContent.trim()).toEqual('Clear Runner Caches');
});
it('renders error state', () => {
diff --git a/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js
index f6c0f51cf62..955ec6a531c 100644
--- a/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js
+++ b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js
@@ -85,7 +85,7 @@ describe('PrometheusMetrics', () => {
expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBeFalsy();
- expect(prometheusMetrics.$monitoredMetricsCount.text()).toEqual('12');
+ expect(prometheusMetrics.$monitoredMetricsCount.text()).toEqual('3 exporters with 12 metrics were found');
expect($metricsListLi.length).toEqual(metrics.length);
expect($metricsListLi.first().find('.badge').text()).toEqual(`${metrics[0].active_metrics}`);
});
diff --git a/spec/javascripts/sidebar/sidebar_assignees_spec.js b/spec/javascripts/sidebar/sidebar_assignees_spec.js
index 2fbb7268e0b..ebaaa6e806b 100644
--- a/spec/javascripts/sidebar/sidebar_assignees_spec.js
+++ b/spec/javascripts/sidebar/sidebar_assignees_spec.js
@@ -1,6 +1,6 @@
import _ from 'underscore';
import Vue from 'vue';
-import SidebarAssignees from '~/sidebar/components/assignees/sidebar_assignees';
+import SidebarAssignees from '~/sidebar/components/assignees/sidebar_assignees.vue';
import SidebarMediator from '~/sidebar/sidebar_mediator';
import SidebarService from '~/sidebar/services/sidebar_service';
import SidebarStore from '~/sidebar/stores/sidebar_store';
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js
new file mode 100644
index 00000000000..cee22d5342a
--- /dev/null
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js
@@ -0,0 +1,40 @@
+import Vue from 'vue';
+import maintainerEditComponent from '~/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue';
+import mountComponent from 'spec/helpers/vue_mount_component_helper';
+
+describe('RWidgetMaintainerEdit', () => {
+ let Component;
+ let vm;
+
+ beforeEach(() => {
+ Component = Vue.extend(maintainerEditComponent);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('when a maintainer is allowed to edit', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ maintainerEditAllowed: true,
+ });
+ });
+
+ it('it renders the message', () => {
+ expect(vm.$el.textContent.trim()).toEqual('Allows edits from maintainers');
+ });
+ });
+
+ describe('when a maintainer is not allowed to edit', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ maintainerEditAllowed: false,
+ });
+ });
+
+ it('hides the message', () => {
+ expect(vm.$el.textContent.trim()).toEqual('');
+ });
+ });
+});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js
index 07ed7f7f532..31710551399 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import memoryUsageComponent from '~/vue_merge_request_widget/components/mr_widget_memory_usage';
+import MemoryUsage from '~/vue_merge_request_widget/components/memory_usage.vue';
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
const url = '/root/acets-review-apps/environments/15/deployments/1/metrics';
@@ -34,7 +34,7 @@ const metricsMockData = {
};
const createComponent = () => {
- const Component = Vue.extend(memoryUsageComponent);
+ const Component = Vue.extend(MemoryUsage);
return new Component({
el: document.createElement('div'),
@@ -67,21 +67,9 @@ describe('MemoryUsage', () => {
el = vm.$el;
});
- describe('props', () => {
- it('should have props with defaults', () => {
- const { metricsUrl } = memoryUsageComponent.props;
- const MetricsUrlTypeClass = metricsUrl.type;
-
- Vue.nextTick(() => {
- expect(new MetricsUrlTypeClass() instanceof String).toBeTruthy();
- expect(metricsUrl.required).toBeTruthy();
- });
- });
- });
-
describe('data', () => {
it('should have default data', () => {
- const data = memoryUsageComponent.data();
+ const data = MemoryUsage.data();
expect(Array.isArray(data.memoryMetrics)).toBeTruthy();
expect(data.memoryMetrics.length).toBe(0);
diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
index 18ba34b55a5..ebe151ac3b1 100644
--- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
+++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
@@ -349,6 +349,7 @@ describe('mrWidgetOptions', () => {
expect(comps['mr-widget-pipeline-blocked']).toBeDefined();
expect(comps['mr-widget-pipeline-failed']).toBeDefined();
expect(comps['mr-widget-merge-when-pipeline-succeeds']).toBeDefined();
+ expect(comps['mr-widget-maintainer-edit']).toBeDefined();
});
});
diff --git a/spec/javascripts/vue_shared/components/clipboard_button_spec.js b/spec/javascripts/vue_shared/components/clipboard_button_spec.js
index d0fc10d69ea..f598b1afa74 100644
--- a/spec/javascripts/vue_shared/components/clipboard_button_spec.js
+++ b/spec/javascripts/vue_shared/components/clipboard_button_spec.js
@@ -10,6 +10,7 @@ describe('clipboard button', () => {
vm = mountComponent(Component, {
text: 'copy me',
title: 'Copy this value into Clipboard!',
+ cssClass: 'btn-danger',
});
});
@@ -28,4 +29,8 @@ describe('clipboard button', () => {
expect(vm.$el.getAttribute('data-placement')).toEqual('top');
expect(vm.$el.getAttribute('data-container')).toEqual(null);
});
+
+ it('should render provided classname', () => {
+ expect(vm.$el.classList).toContain('btn-danger');
+ });
});
diff --git a/spec/javascripts/vue_shared/components/memory_graph_spec.js b/spec/javascripts/vue_shared/components/memory_graph_spec.js
index d46a3f2328e..73a69df019e 100644
--- a/spec/javascripts/vue_shared/components/memory_graph_spec.js
+++ b/spec/javascripts/vue_shared/components/memory_graph_spec.js
@@ -1,12 +1,12 @@
import Vue from 'vue';
-import memoryGraphComponent from '~/vue_shared/components/memory_graph';
+import MemoryGraph from '~/vue_shared/components/memory_graph.vue';
import { mockMetrics, mockMedian, mockMedianIndex } from './mock_data';
const defaultHeight = '25';
const defaultWidth = '100';
const createComponent = () => {
- const Component = Vue.extend(memoryGraphComponent);
+ const Component = Vue.extend(MemoryGraph);
return new Component({
el: document.createElement('div'),
@@ -32,29 +32,9 @@ describe('MemoryGraph', () => {
el = vm.$el;
});
- describe('props', () => {
- it('should have props with defaults', (done) => {
- const { metrics, deploymentTime, width, height } = memoryGraphComponent.props;
-
- Vue.nextTick(() => {
- const typeClassMatcher = (propItem, expectedType) => {
- const PropItemTypeClass = propItem.type;
- expect(new PropItemTypeClass() instanceof expectedType).toBeTruthy();
- expect(propItem.required).toBeTruthy();
- };
-
- typeClassMatcher(metrics, Array);
- typeClassMatcher(deploymentTime, Number);
- typeClassMatcher(width, String);
- typeClassMatcher(height, String);
- done();
- });
- });
- });
-
describe('data', () => {
it('should have default data', () => {
- const data = memoryGraphComponent.data();
+ const data = MemoryGraph.data();
const dataValidator = (dataItem, expectedType, defaultVal) => {
expect(typeof dataItem).toBe(expectedType);
expect(dataItem).toBe(defaultVal);
diff --git a/spec/lib/constraints/group_url_constrainer_spec.rb b/spec/lib/constraints/group_url_constrainer_spec.rb
index 4dab58b26a0..ff295068ba9 100644
--- a/spec/lib/constraints/group_url_constrainer_spec.rb
+++ b/spec/lib/constraints/group_url_constrainer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GroupUrlConstrainer do
+describe Constraints::GroupUrlConstrainer do
let!(:group) { create(:group, path: 'gitlab') }
describe '#matches?' do
diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb
index 92331eb2e5d..c96e7ab8495 100644
--- a/spec/lib/constraints/project_url_constrainer_spec.rb
+++ b/spec/lib/constraints/project_url_constrainer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProjectUrlConstrainer do
+describe Constraints::ProjectUrlConstrainer do
let!(:project) { create(:project) }
let!(:namespace) { project.namespace }
diff --git a/spec/lib/constraints/user_url_constrainer_spec.rb b/spec/lib/constraints/user_url_constrainer_spec.rb
index cb3b4ff1391..e2c85bb27bb 100644
--- a/spec/lib/constraints/user_url_constrainer_spec.rb
+++ b/spec/lib/constraints/user_url_constrainer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe UserUrlConstrainer do
+describe Constraints::UserUrlConstrainer do
let!(:user) { create(:user, username: 'dz') }
describe '#matches?' do
diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb
index b49ddbfc780..48e9902027c 100644
--- a/spec/lib/gitlab/checks/change_access_spec.rb
+++ b/spec/lib/gitlab/checks/change_access_spec.rb
@@ -30,9 +30,10 @@ describe Gitlab::Checks::ChangeAccess do
end
end
- context 'when the user is not allowed to push code' do
+ context 'when the user is not allowed to push to the repo' do
it 'raises an error' do
expect(user_access).to receive(:can_do_action?).with(:push_code).and_return(false)
+ expect(user_access).to receive(:can_push_to_branch?).with('master').and_return(false)
expect { subject.exec }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to push code to this project.')
end
diff --git a/spec/lib/gitlab/ci/charts_spec.rb b/spec/lib/gitlab/ci/charts_spec.rb
index f8188675013..1668d3bbaac 100644
--- a/spec/lib/gitlab/ci/charts_spec.rb
+++ b/spec/lib/gitlab/ci/charts_spec.rb
@@ -1,6 +1,51 @@
require 'spec_helper'
describe Gitlab::Ci::Charts do
+ context "yearchart" do
+ let(:project) { create(:project) }
+ let(:chart) { Gitlab::Ci::Charts::YearChart.new(project) }
+
+ subject { chart.to }
+
+ it 'goes until the end of the current month (including the whole last day of the month)' do
+ is_expected.to eq(Date.today.end_of_month.end_of_day)
+ end
+
+ it 'starts at the beginning of the current year' do
+ expect(chart.from).to eq(chart.to.years_ago(1).beginning_of_month.beginning_of_day)
+ end
+ end
+
+ context "monthchart" do
+ let(:project) { create(:project) }
+ let(:chart) { Gitlab::Ci::Charts::MonthChart.new(project) }
+
+ subject { chart.to }
+
+ it 'includes the whole current day' do
+ is_expected.to eq(Date.today.end_of_day)
+ end
+
+ it 'starts one month ago' do
+ expect(chart.from).to eq(1.month.ago.beginning_of_day)
+ end
+ end
+
+ context "weekchart" do
+ let(:project) { create(:project) }
+ let(:chart) { Gitlab::Ci::Charts::WeekChart.new(project) }
+
+ subject { chart.to }
+
+ it 'includes the whole current day' do
+ is_expected.to eq(Date.today.end_of_day)
+ end
+
+ it 'starts one week ago' do
+ expect(chart.from).to eq(1.week.ago.beginning_of_day)
+ end
+ end
+
context "pipeline_times" do
let(:project) { create(:project) }
let(:chart) { Gitlab::Ci::Charts::PipelineTime.new(project) }
diff --git a/spec/lib/gitlab/contributions_calendar_spec.rb b/spec/lib/gitlab/contributions_calendar_spec.rb
index 167876ca158..2c63f3b0455 100644
--- a/spec/lib/gitlab/contributions_calendar_spec.rb
+++ b/spec/lib/gitlab/contributions_calendar_spec.rb
@@ -77,6 +77,13 @@ describe Gitlab::ContributionsCalendar do
expect(calendar(contributor).activity_dates[today]).to eq(1)
end
+ it "counts the discussions on merge requests and issues" do
+ create_event(public_project, today, 0, Event::COMMENTED, :discussion_note_on_merge_request)
+ create_event(public_project, today, 2, Event::COMMENTED, :discussion_note_on_issue)
+
+ expect(calendar(contributor).activity_dates[today]).to eq(2)
+ end
+
context "when events fall under different dates depending on the time zone" do
before do
create_event(public_project, today, 1)
diff --git a/spec/lib/gitlab/data_builder/pipeline_spec.rb b/spec/lib/gitlab/data_builder/pipeline_spec.rb
index f13041e498c..9ca960502c8 100644
--- a/spec/lib/gitlab/data_builder/pipeline_spec.rb
+++ b/spec/lib/gitlab/data_builder/pipeline_spec.rb
@@ -26,6 +26,7 @@ describe Gitlab::DataBuilder::Pipeline do
it { expect(attributes[:tag]).to eq(pipeline.tag) }
it { expect(attributes[:id]).to eq(pipeline.id) }
it { expect(attributes[:status]).to eq(pipeline.status) }
+ it { expect(attributes[:detailed_status]).to eq('passed') }
it { expect(build_data).to be_a(Hash) }
it { expect(build_data[:id]).to eq(build.id) }
diff --git a/spec/lib/gitlab/git/gitlab_projects_spec.rb b/spec/lib/gitlab/git/gitlab_projects_spec.rb
index f4b964e1ee9..45bcd730332 100644
--- a/spec/lib/gitlab/git/gitlab_projects_spec.rb
+++ b/spec/lib/gitlab/git/gitlab_projects_spec.rb
@@ -61,10 +61,11 @@ describe Gitlab::Git::GitlabProjects do
let(:remote_name) { 'remote-name' }
let(:branch_name) { 'master' }
let(:force) { false }
+ let(:prune) { true }
let(:tags) { true }
- let(:args) { { force: force, tags: tags }.merge(extra_args) }
+ let(:args) { { force: force, tags: tags, prune: prune }.merge(extra_args) }
let(:extra_args) { {} }
- let(:cmd) { %W(git fetch #{remote_name} --prune --quiet --tags) }
+ let(:cmd) { %W(git fetch #{remote_name} --quiet --prune --tags) }
subject { gl_projects.fetch_remote(remote_name, 600, args) }
@@ -97,7 +98,7 @@ describe Gitlab::Git::GitlabProjects do
context 'with --force' do
let(:force) { true }
- let(:cmd) { %W(git fetch #{remote_name} --prune --quiet --force --tags) }
+ let(:cmd) { %W(git fetch #{remote_name} --quiet --prune --force --tags) }
it 'executes the command with forced option' do
stub_spawn(cmd, 600, tmp_repo_path, {}, success: true)
@@ -108,7 +109,18 @@ describe Gitlab::Git::GitlabProjects do
context 'with --no-tags' do
let(:tags) { false }
- let(:cmd) { %W(git fetch #{remote_name} --prune --quiet --no-tags) }
+ let(:cmd) { %W(git fetch #{remote_name} --quiet --prune --no-tags) }
+
+ it 'executes the command' do
+ stub_spawn(cmd, 600, tmp_repo_path, {}, success: true)
+
+ is_expected.to be_truthy
+ end
+ end
+
+ context 'with no prune' do
+ let(:prune) { false }
+ let(:cmd) { %W(git fetch #{remote_name} --quiet --tags) }
it 'executes the command' do
stub_spawn(cmd, 600, tmp_repo_path, {}, success: true)
diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
index c50e73cecfc..1c41dbcb9ef 100644
--- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
@@ -85,6 +85,20 @@ describe Gitlab::GitalyClient::RepositoryService do
end
end
+ describe '#fetch_remote' do
+ let(:ssh_auth) { double(:ssh_auth, ssh_import?: true, ssh_key_auth?: false, ssh_known_hosts: nil) }
+ let(:import_url) { 'ssh://example.com' }
+
+ it 'sends a fetch_remote_request message' do
+ expect_any_instance_of(Gitaly::RepositoryService::Stub)
+ .to receive(:fetch_remote)
+ .with(gitaly_request_with_params(no_prune: false), kind_of(Hash))
+ .and_return(double(value: true))
+
+ client.fetch_remote(import_url, ssh_auth: ssh_auth, forced: false, no_tags: false, timeout: 60)
+ end
+ end
+
describe '#rebase_in_progress?' do
let(:rebase_id) { 1 }
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index b20cc34dd5c..bece82e531a 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -278,6 +278,7 @@ project:
- custom_attributes
- lfs_file_locks
- project_badges
+- source_of_merge_requests
award_emoji:
- awardable
- user
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index ddcbb7a0033..0b938892da5 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -168,6 +168,7 @@ MergeRequest:
- last_edited_by_id
- head_pipeline_id
- discussion_locked
+- allow_maintainer_to_push
MergeRequestDiff:
- id
- state
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 4506cbc3982..56b45d8da3c 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -508,8 +508,8 @@ describe Gitlab::Shell do
end
shared_examples 'fetch_remote' do |gitaly_on|
- def fetch_remote(ssh_auth = nil)
- gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', ssh_auth: ssh_auth)
+ def fetch_remote(ssh_auth = nil, prune = true)
+ gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', ssh_auth: ssh_auth, prune: prune)
end
def expect_gitlab_projects(fail = false, options = {})
@@ -555,27 +555,33 @@ describe Gitlab::Shell do
end
it 'returns true when the command succeeds' do
- expect_call(false, force: false, tags: true)
+ expect_call(false, force: false, tags: true, prune: true)
expect(fetch_remote).to be_truthy
end
+ it 'returns true when the command succeeds' do
+ expect_call(false, force: false, tags: true, prune: false)
+
+ expect(fetch_remote(nil, false)).to be_truthy
+ end
+
it 'raises an exception when the command fails' do
- expect_call(true, force: false, tags: true)
+ expect_call(true, force: false, tags: true, prune: true)
expect { fetch_remote }.to raise_error(Gitlab::Shell::Error)
end
it 'allows forced and no_tags to be changed' do
- expect_call(false, force: true, tags: false)
+ expect_call(false, force: true, tags: false, prune: true)
- result = gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', forced: true, no_tags: true)
+ result = gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', forced: true, no_tags: true, prune: true)
expect(result).to be_truthy
end
context 'SSH auth' do
it 'passes the SSH key if specified' do
- expect_call(false, force: false, tags: true, ssh_key: 'foo')
+ expect_call(false, force: false, tags: true, prune: true, ssh_key: 'foo')
ssh_auth = build_ssh_auth(ssh_key_auth?: true, ssh_private_key: 'foo')
@@ -583,7 +589,7 @@ describe Gitlab::Shell do
end
it 'does not pass an empty SSH key' do
- expect_call(false, force: false, tags: true)
+ expect_call(false, force: false, tags: true, prune: true)
ssh_auth = build_ssh_auth(ssh_key_auth: true, ssh_private_key: '')
@@ -591,7 +597,7 @@ describe Gitlab::Shell do
end
it 'does not pass the key unless SSH key auth is to be used' do
- expect_call(false, force: false, tags: true)
+ expect_call(false, force: false, tags: true, prune: true)
ssh_auth = build_ssh_auth(ssh_key_auth: false, ssh_private_key: 'foo')
@@ -599,7 +605,7 @@ describe Gitlab::Shell do
end
it 'passes the known_hosts data if specified' do
- expect_call(false, force: false, tags: true, known_hosts: 'foo')
+ expect_call(false, force: false, tags: true, prune: true, known_hosts: 'foo')
ssh_auth = build_ssh_auth(ssh_known_hosts: 'foo')
@@ -607,7 +613,7 @@ describe Gitlab::Shell do
end
it 'does not pass empty known_hosts data' do
- expect_call(false, force: false, tags: true)
+ expect_call(false, force: false, tags: true, prune: true)
ssh_auth = build_ssh_auth(ssh_known_hosts: '')
@@ -615,7 +621,7 @@ describe Gitlab::Shell do
end
it 'does not pass known_hosts data unless SSH is to be used' do
- expect_call(false, force: false, tags: true)
+ expect_call(false, force: false, tags: true, prune: true)
ssh_auth = build_ssh_auth(ssh_import?: false, ssh_known_hosts: 'foo')
@@ -642,7 +648,7 @@ describe Gitlab::Shell do
it 'passes the correct params to the gitaly service' do
expect(repository.gitaly_repository_client).to receive(:fetch_remote)
- .with(remote_name, ssh_auth: ssh_auth, forced: true, no_tags: true, timeout: timeout)
+ .with(remote_name, ssh_auth: ssh_auth, forced: true, no_tags: true, prune: true, timeout: timeout)
subject
end
diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb
index 7280acb6c82..40c8286b1b9 100644
--- a/spec/lib/gitlab/user_access_spec.rb
+++ b/spec/lib/gitlab/user_access_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe Gitlab::UserAccess do
+ include ProjectForksHelper
+
let(:access) { described_class.new(user, project: project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
@@ -118,6 +120,39 @@ describe Gitlab::UserAccess do
end
end
+ describe 'allowing pushes to maintainers of forked projects' do
+ let(:canonical_project) { create(:project, :public, :repository) }
+ let(:project) { fork_project(canonical_project, create(:user), repository: true) }
+
+ before do
+ create(
+ :merge_request,
+ target_project: canonical_project,
+ source_project: project,
+ source_branch: 'awesome-feature',
+ allow_maintainer_to_push: true
+ )
+ end
+
+ it 'allows users that have push access to the canonical project to push to the MR branch' do
+ canonical_project.add_developer(user)
+
+ expect(access.can_push_to_branch?('awesome-feature')).to be_truthy
+ end
+
+ it 'does not allow the user to push to other branches' do
+ canonical_project.add_developer(user)
+
+ expect(access.can_push_to_branch?('master')).to be_falsey
+ end
+
+ it 'does not allow the user to push if he does not have push access to the canonical project' do
+ canonical_project.add_guest(user)
+
+ expect(access.can_push_to_branch?('awesome-feature')).to be_falsey
+ end
+ end
+
describe 'merge to protected branch if allowed for developers' do
before do
@branch = create :protected_branch, :developers_can_merge, project: project
diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb
index bda239b7871..71a743495a2 100644
--- a/spec/lib/gitlab/utils_spec.rb
+++ b/spec/lib/gitlab/utils_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Utils do
- delegate :to_boolean, :boolean_to_yes_no, :slugify, :random_string, :which, to: :described_class
+ delegate :to_boolean, :boolean_to_yes_no, :slugify, :random_string, :which, :ensure_array_from_string, to: :described_class
describe '.slugify' do
{
@@ -83,4 +83,18 @@ describe Gitlab::Utils do
expect(which('sh', 'PATH' => '/bin')).to eq('/bin/sh')
end
end
+
+ describe '.ensure_array_from_string' do
+ it 'returns the same array if given one' do
+ arr = ['a', 4, true, { test: 1 }]
+
+ expect(ensure_array_from_string(arr)).to eq(arr)
+ end
+
+ it 'turns comma-separated strings into arrays' do
+ str = 'seven, eight, 9, 10'
+
+ expect(ensure_array_from_string(str)).to eq(%w[seven eight 9 10])
+ end
+ end
end
diff --git a/spec/lib/gitlab/verify/job_artifacts_spec.rb b/spec/lib/gitlab/verify/job_artifacts_spec.rb
new file mode 100644
index 00000000000..ec490bdfde2
--- /dev/null
+++ b/spec/lib/gitlab/verify/job_artifacts_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+describe Gitlab::Verify::JobArtifacts do
+ include GitlabVerifyHelpers
+
+ it_behaves_like 'Gitlab::Verify::BatchVerifier subclass' do
+ let!(:objects) { create_list(:ci_job_artifact, 3, :archive) }
+ end
+
+ describe '#run_batches' do
+ let(:failures) { collect_failures }
+ let(:failure) { failures[artifact] }
+
+ let!(:artifact) { create(:ci_job_artifact, :archive, :correct_checksum) }
+
+ it 'passes artifacts with the correct file' do
+ expect(failures).to eq({})
+ end
+
+ it 'fails artifacts with a missing file' do
+ FileUtils.rm_f(artifact.file.path)
+
+ expect(failures.keys).to contain_exactly(artifact)
+ expect(failure).to be_a(Errno::ENOENT)
+ expect(failure.to_s).to include(artifact.file.path)
+ end
+
+ it 'fails artifacts with a mismatched checksum' do
+ File.truncate(artifact.file.path, 0)
+
+ expect(failures.keys).to contain_exactly(artifact)
+ expect(failure.to_s).to include('Checksum mismatch')
+ end
+ end
+end
diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb
index e638ad7a2c9..3c8206031cf 100644
--- a/spec/lib/mattermost/team_spec.rb
+++ b/spec/lib/mattermost/team_spec.rb
@@ -64,4 +64,108 @@ describe Mattermost::Team do
end
end
end
+
+ describe '#create' do
+ subject { described_class.new(nil).create(name: "devteam", display_name: "Dev Team", type: "O") }
+
+ context 'for a new team' do
+ let(:response) do
+ {
+ "id" => "cuojfcetjty7tb4pxe47pwpndo",
+ "create_at" => 1517688728701,
+ "update_at" => 1517688728701,
+ "delete_at" => 0,
+ "display_name" => "Dev Team",
+ "name" => "devteam",
+ "description" => "",
+ "email" => "admin@example.com",
+ "type" => "O",
+ "company_name" => "",
+ "allowed_domains" => "",
+ "invite_id" => "7mp9d3ayaj833ymmkfnid8js6w",
+ "allow_open_invite" => false
+ }
+ end
+
+ before do
+ stub_request(:post, "http://mattermost.example.com/api/v3/teams/create")
+ .to_return(
+ status: 200,
+ body: response.to_json,
+ headers: { 'Content-Type' => 'application/json' }
+ )
+ end
+
+ it 'returns the new team' do
+ is_expected.to eq(response)
+ end
+ end
+
+ context 'for existing team' do
+ before do
+ stub_request(:post, 'http://mattermost.example.com/api/v3/teams/create')
+ .to_return(
+ status: 400,
+ headers: { 'Content-Type' => 'application/json' },
+ body: {
+ id: "store.sql_team.save.domain_exists.app_error",
+ message: "A team with that name already exists",
+ detailed_error: "",
+ request_id: "1hsb5bxs97r8bdggayy7n9gxaw",
+ status_code: 400
+ }.to_json
+ )
+ end
+
+ it 'raises an error with message' do
+ expect { subject }.to raise_error(Mattermost::Error, 'A team with that name already exists')
+ end
+ end
+ end
+
+ describe '#delete' do
+ subject { described_class.new(nil).destroy(team_id: "cuojfcetjty7tb4pxe47pwpndo") }
+
+ context 'for an existing team' do
+ let(:response) do
+ {
+ "status" => "OK"
+ }
+ end
+
+ before do
+ stub_request(:delete, "http://mattermost.example.com/api/v4/teams/cuojfcetjty7tb4pxe47pwpndo")
+ .to_return(
+ status: 200,
+ body: response.to_json,
+ headers: { 'Content-Type' => 'application/json' }
+ )
+ end
+
+ it 'returns team status' do
+ is_expected.to eq(response)
+ end
+ end
+
+ context 'for an unknown team' do
+ before do
+ stub_request(:delete, "http://mattermost.example.com/api/v4/teams/cuojfcetjty7tb4pxe47pwpndo")
+ .to_return(
+ status: 404,
+ body: {
+ id: "store.sql_team.get.find.app_error",
+ message: "We couldn't find the existing team",
+ detailed_error: "",
+ request_id: "my114ab5nbnui8c9pes4kz8mza",
+ status_code: 404
+ }.to_json,
+ headers: { 'Content-Type' => 'application/json' }
+ )
+ end
+
+ it 'raises an error with message' do
+ expect { subject }.to raise_error(Mattermost::Error, "We couldn't find the existing team")
+ end
+ end
+ end
end
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index ceb570ac777..412eca4a56b 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -142,15 +142,15 @@ describe Environment do
let(:commit) { project.commit.parent }
it 'returns deployment id for the environment' do
- expect(environment.first_deployment_for(commit)).to eq deployment1
+ expect(environment.first_deployment_for(commit.id)).to eq deployment1
end
it 'return nil when no deployment is found' do
- expect(environment.first_deployment_for(head_commit)).to eq nil
+ expect(environment.first_deployment_for(head_commit.id)).to eq nil
end
it 'returns a UTF-8 ref' do
- expect(environment.first_deployment_for(commit).ref).to be_utf8
+ expect(environment.first_deployment_for(commit.id).ref).to be_utf8
end
end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index 67f49348acb..8ea92410022 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -49,6 +49,22 @@ describe Event do
end
end
end
+
+ describe 'after_create :track_user_interacted_projects' do
+ let(:event) { build(:push_event, project: project, author: project.owner) }
+
+ it 'passes event to UserInteractedProject.track' do
+ expect(UserInteractedProject).to receive(:available?).and_return(true)
+ expect(UserInteractedProject).to receive(:track).with(event)
+ event.save
+ end
+
+ it 'does not call UserInteractedProject.track if its not yet available' do
+ expect(UserInteractedProject).to receive(:available?).and_return(false)
+ expect(UserInteractedProject).not_to receive(:track)
+ event.save
+ end
+ end
end
describe "Push event" do
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index 3e46fa36375..b8b0e63f92e 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -45,14 +45,6 @@ describe ProjectMember do
let(:project) { owner.project }
let(:master) { create(:project_member, project: project) }
- let(:owner_todos) { (0...2).map { create(:todo, user: owner.user, project: project) } }
- let(:master_todos) { (0...3).map { create(:todo, user: master.user, project: project) } }
-
- before do
- owner_todos
- master_todos
- end
-
it "creates an expired event when left due to expiry" do
expired = create(:project_member, project: project, expires_at: Time.now - 6.days)
expired.destroy
@@ -63,21 +55,6 @@ describe ProjectMember do
master.destroy
expect(Event.recent.first.action).to eq(Event::LEFT)
end
-
- it "destroys itself and delete associated todos" do
- expect(owner.user.todos.size).to eq(2)
- expect(master.user.todos.size).to eq(3)
- expect(Todo.count).to eq(5)
-
- master_todo_ids = master_todos.map(&:id)
- master.destroy
-
- expect(owner.user.todos.size).to eq(2)
- expect(Todo.count).to eq(2)
- master_todo_ids.each do |id|
- expect(Todo.exists?(id)).to eq(false)
- end
- end
end
describe '.import_team' do
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 243eeddc7a8..7986aa31e16 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -2084,4 +2084,82 @@ describe MergeRequest do
it_behaves_like 'checking whether a rebase is in progress'
end
end
+
+ describe '#allow_maintainer_to_push' do
+ let(:merge_request) do
+ build(:merge_request, source_branch: 'fixes', allow_maintainer_to_push: true)
+ end
+
+ it 'is false when pushing by a maintainer is not possible' do
+ expect(merge_request).to receive(:maintainer_push_possible?) { false }
+
+ expect(merge_request.allow_maintainer_to_push).to be_falsy
+ end
+
+ it 'is true when pushing by a maintainer is possible' do
+ expect(merge_request).to receive(:maintainer_push_possible?) { true }
+
+ expect(merge_request.allow_maintainer_to_push).to be_truthy
+ end
+ end
+
+ describe '#maintainer_push_possible?' do
+ let(:merge_request) do
+ build(:merge_request, source_branch: 'fixes')
+ end
+
+ before do
+ allow(ProtectedBranch).to receive(:protected?) { false }
+ end
+
+ it 'does not allow maintainer to push if the source project is the same as the target' do
+ merge_request.target_project = merge_request.source_project = create(:project, :public)
+
+ expect(merge_request.maintainer_push_possible?).to be_falsy
+ end
+
+ it 'allows maintainer to push when both source and target are public' do
+ merge_request.target_project = build(:project, :public)
+ merge_request.source_project = build(:project, :public)
+
+ expect(merge_request.maintainer_push_possible?).to be_truthy
+ end
+
+ it 'is not available for protected branches' do
+ merge_request.target_project = build(:project, :public)
+ merge_request.source_project = build(:project, :public)
+
+ expect(ProtectedBranch).to receive(:protected?)
+ .with(merge_request.source_project, 'fixes')
+ .and_return(true)
+
+ expect(merge_request.maintainer_push_possible?).to be_falsy
+ end
+ end
+
+ describe '#can_allow_maintainer_to_push?' do
+ let(:target_project) { create(:project, :public) }
+ let(:source_project) { fork_project(target_project) }
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: source_project,
+ source_branch: 'fixes',
+ target_project: target_project)
+ end
+ let(:user) { create(:user) }
+
+ before do
+ allow(merge_request).to receive(:maintainer_push_possible?) { true }
+ end
+
+ it 'is false if the user does not have push access to the source project' do
+ expect(merge_request.can_allow_maintainer_to_push?(user)).to be_falsy
+ end
+
+ it 'is true when the user has push access to the source project' do
+ source_project.add_developer(user)
+
+ expect(merge_request.can_allow_maintainer_to_push?(user)).to be_truthy
+ end
+ end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index b1c9e6754b9..e970cd7dfdb 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe Project do
+ include ProjectForksHelper
+
describe 'associations' do
it { is_expected.to belong_to(:group) }
it { is_expected.to belong_to(:namespace) }
@@ -3378,4 +3380,103 @@ describe Project do
end
end
end
+
+ context 'with cross project merge requests' do
+ let(:user) { create(:user) }
+ let(:target_project) { create(:project, :repository) }
+ let(:project) { fork_project(target_project, nil, repository: true) }
+ let!(:merge_request) do
+ create(
+ :merge_request,
+ target_project: target_project,
+ target_branch: 'target-branch',
+ source_project: project,
+ source_branch: 'awesome-feature-1',
+ allow_maintainer_to_push: true
+ )
+ end
+
+ before do
+ target_project.add_developer(user)
+ end
+
+ describe '#merge_requests_allowing_push_to_user' do
+ it 'returns open merge requests for which the user has developer access to the target project' do
+ expect(project.merge_requests_allowing_push_to_user(user)).to include(merge_request)
+ end
+
+ it 'does not include closed merge requests' do
+ merge_request.close
+
+ expect(project.merge_requests_allowing_push_to_user(user)).to be_empty
+ end
+
+ it 'does not include merge requests for guest users' do
+ guest = create(:user)
+ target_project.add_guest(guest)
+
+ expect(project.merge_requests_allowing_push_to_user(guest)).to be_empty
+ end
+
+ it 'does not include the merge request for other users' do
+ other_user = create(:user)
+
+ expect(project.merge_requests_allowing_push_to_user(other_user)).to be_empty
+ end
+
+ it 'is empty when no user is passed' do
+ expect(project.merge_requests_allowing_push_to_user(nil)).to be_empty
+ end
+ end
+
+ describe '#branch_allows_maintainer_push?' do
+ it 'allows access if the user can merge the merge request' do
+ expect(project.branch_allows_maintainer_push?(user, 'awesome-feature-1'))
+ .to be_truthy
+ end
+
+ it 'does not allow guest users access' do
+ guest = create(:user)
+ target_project.add_guest(guest)
+
+ expect(project.branch_allows_maintainer_push?(guest, 'awesome-feature-1'))
+ .to be_falsy
+ end
+
+ it 'does not allow access to branches for which the merge request was closed' do
+ create(:merge_request, :closed,
+ target_project: target_project,
+ target_branch: 'target-branch',
+ source_project: project,
+ source_branch: 'rejected-feature-1',
+ allow_maintainer_to_push: true)
+
+ expect(project.branch_allows_maintainer_push?(user, 'rejected-feature-1'))
+ .to be_falsy
+ end
+
+ it 'does not allow access if the user cannot merge the merge request' do
+ create(:protected_branch, :masters_can_push, project: target_project, name: 'target-branch')
+
+ expect(project.branch_allows_maintainer_push?(user, 'awesome-feature-1'))
+ .to be_falsy
+ end
+
+ it 'caches the result' do
+ control = ActiveRecord::QueryRecorder.new { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') }
+
+ expect { 3.times { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') } }
+ .not_to exceed_query_limit(control)
+ end
+
+ context 'when the requeststore is active', :request_store do
+ it 'only queries per project across instances' do
+ control = ActiveRecord::QueryRecorder.new { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') }
+
+ expect { 2.times { described_class.find(project.id).branch_allows_maintainer_push?(user, 'awesome-feature-1') } }
+ .not_to exceed_query_limit(control).with_threshold(2)
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 0808997a31f..5bc972bca14 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1004,7 +1004,7 @@ describe Repository do
end
end
- context 'with Gitaly disabled', :skip_gitaly_mock do
+ context 'with Gitaly disabled', :disable_gitaly do
context 'when pre hooks were successful' do
it 'runs without errors' do
hook = double(trigger: [true, nil])
@@ -1447,7 +1447,6 @@ describe Repository do
it 'expires the caches for an empty repository' do
allow(repository).to receive(:empty?).and_return(true)
- expect(cache).to receive(:expire).with(:empty?)
expect(cache).to receive(:expire).with(:has_visible_content?)
repository.expire_emptiness_caches
@@ -1456,7 +1455,6 @@ describe Repository do
it 'does not expire the cache for a non-empty repository' do
allow(repository).to receive(:empty?).and_return(false)
- expect(cache).not_to receive(:expire).with(:empty?)
expect(cache).not_to receive(:expire).with(:has_visible_content?)
repository.expire_emptiness_caches
@@ -1896,7 +1894,7 @@ describe Repository do
it_behaves_like 'adding tag'
end
- context 'when Gitaly operation_user_add_tag feature is disabled', :skip_gitaly_mock do
+ context 'when Gitaly operation_user_add_tag feature is disabled', :disable_gitaly do
it_behaves_like 'adding tag'
it 'passes commit SHA to pre-receive and update hooks and tag SHA to post-receive hook' do
@@ -1955,7 +1953,7 @@ describe Repository do
end
end
- context 'with gitaly disabled', :skip_gitaly_mock do
+ context 'with gitaly disabled', :disable_gitaly do
it_behaves_like "user deleting a branch"
let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature
diff --git a/spec/models/user_interacted_project_spec.rb b/spec/models/user_interacted_project_spec.rb
new file mode 100644
index 00000000000..cb4bb3372d4
--- /dev/null
+++ b/spec/models/user_interacted_project_spec.rb
@@ -0,0 +1,60 @@
+require 'spec_helper'
+
+describe UserInteractedProject do
+ describe '.track' do
+ subject { described_class.track(event) }
+ let(:event) { build(:event) }
+
+ Event::ACTIONS.each do |action|
+ context "for all actions (event types)" do
+ let(:event) { build(:event, action: action) }
+ it 'creates a record' do
+ expect { subject }.to change { described_class.count }.from(0).to(1)
+ end
+ end
+ end
+
+ it 'sets project accordingly' do
+ subject
+ expect(described_class.first.project).to eq(event.project)
+ end
+
+ it 'sets user accordingly' do
+ subject
+ expect(described_class.first.user).to eq(event.author)
+ end
+
+ it 'only creates a record once per user/project' do
+ expect do
+ subject
+ described_class.track(event)
+ end.to change { described_class.count }.from(0).to(1)
+ end
+
+ describe 'with an event without a project' do
+ let(:event) { build(:event, project: nil) }
+
+ it 'ignores the event' do
+ expect { subject }.not_to change { described_class.count }
+ end
+ end
+ end
+
+ describe '.available?' do
+ before do
+ described_class.instance_variable_set('@available_flag', nil)
+ end
+
+ it 'checks schema version and properly caches positive result' do
+ expect(ActiveRecord::Migrator).to receive(:current_version).and_return(described_class::REQUIRED_SCHEMA_VERSION - 1 - rand(1000))
+ expect(described_class.available?).to be_falsey
+ expect(ActiveRecord::Migrator).to receive(:current_version).and_return(described_class::REQUIRED_SCHEMA_VERSION + rand(1000))
+ expect(described_class.available?).to be_truthy
+ expect(ActiveRecord::Migrator).not_to receive(:current_version)
+ expect(described_class.available?).to be_truthy # cached response
+ end
+ end
+
+ it { is_expected.to validate_presence_of(:project_id) }
+ it { is_expected.to validate_presence_of(:user_id) }
+end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 00b5226d874..5680eb24985 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -27,7 +27,6 @@ describe User do
it { is_expected.to have_many(:keys).dependent(:destroy) }
it { is_expected.to have_many(:deploy_keys).dependent(:destroy) }
it { is_expected.to have_many(:events).dependent(:destroy) }
- it { is_expected.to have_many(:recent_events).class_name('Event') }
it { is_expected.to have_many(:issues).dependent(:destroy) }
it { is_expected.to have_many(:notes).dependent(:destroy) }
it { is_expected.to have_many(:merge_requests).dependent(:destroy) }
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 129344f105f..ea76e604153 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -308,4 +308,41 @@ describe ProjectPolicy do
it_behaves_like 'project policies as master'
it_behaves_like 'project policies as owner'
it_behaves_like 'project policies as admin'
+
+ context 'when a public project has merge requests allowing access' do
+ include ProjectForksHelper
+ let(:user) { create(:user) }
+ let(:target_project) { create(:project, :public) }
+ let(:project) { fork_project(target_project) }
+ let!(:merge_request) do
+ create(
+ :merge_request,
+ target_project: target_project,
+ source_project: project,
+ allow_maintainer_to_push: true
+ )
+ end
+ let(:maintainer_abilities) do
+ %w(create_build update_build create_pipeline update_pipeline)
+ end
+
+ subject { described_class.new(user, project) }
+
+ it 'does not allow pushing code' do
+ expect_disallowed(*maintainer_abilities)
+ end
+
+ it 'allows pushing if the user is a member with push access to the target project' do
+ target_project.add_developer(user)
+
+ expect_allowed(*maintainer_abilities)
+ end
+
+ it 'dissallows abilities to a maintainer if the merge request was closed' do
+ target_project.add_developer(user)
+ merge_request.close!
+
+ expect_disallowed(*maintainer_abilities)
+ end
+ end
end
diff --git a/spec/requests/api/discussions_spec.rb b/spec/requests/api/discussions_spec.rb
new file mode 100644
index 00000000000..4a44b219a67
--- /dev/null
+++ b/spec/requests/api/discussions_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe API::Discussions do
+ let(:user) { create(:user) }
+ let!(:project) { create(:project, :public, namespace: user.namespace) }
+ let(:private_user) { create(:user) }
+
+ before do
+ project.add_reporter(user)
+ end
+
+ context "when noteable is an Issue" do
+ let!(:issue) { create(:issue, project: project, author: user) }
+ let!(:issue_note) { create(:discussion_note_on_issue, noteable: issue, project: project, author: user) }
+
+ it_behaves_like "discussions API", 'projects', 'issues', 'iid' do
+ let(:parent) { project }
+ let(:noteable) { issue }
+ let(:note) { issue_note }
+ end
+ end
+
+ context "when noteable is a Snippet" do
+ let!(:snippet) { create(:project_snippet, project: project, author: user) }
+ let!(:snippet_note) { create(:discussion_note_on_snippet, noteable: snippet, project: project, author: user) }
+
+ it_behaves_like "discussions API", 'projects', 'snippets', 'id' do
+ let(:parent) { project }
+ let(:noteable) { snippet }
+ let(:note) { snippet_note }
+ end
+ end
+end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 827f4c04324..ca0aac87ba9 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -335,21 +335,8 @@ describe API::Internal do
end
context "git push" do
- context "gitaly disabled", :disable_gitaly do
- it "has the correct payload" do
- push(key, project)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response["status"]).to be_truthy
- expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
- expect(json_response["gl_repository"]).to eq("project-#{project.id}")
- expect(json_response["gitaly"]).to be_nil
- expect(user).not_to have_an_activity_record
- end
- end
-
- context "gitaly enabled" do
- it "has the correct payload" do
+ context 'project as namespace/project' do
+ it do
push(key, project)
expect(response).to have_gitlab_http_status(200)
@@ -365,17 +352,6 @@ describe API::Internal do
expect(user).not_to have_an_activity_record
end
end
-
- context 'project as namespace/project' do
- it do
- push(key, project)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response["status"]).to be_truthy
- expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
- expect(json_response["gl_repository"]).to eq("project-#{project.id}")
- end
- end
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 484322752c0..3764aec0c71 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -616,6 +616,25 @@ describe API::MergeRequests do
expect(json_response['changes_count']).to eq('5+')
end
end
+
+ context 'for forked projects' do
+ let(:user2) { create(:user) }
+ let(:project) { create(:project, :public, :repository) }
+ let(:forked_project) { fork_project(project, user2, repository: true) }
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: forked_project,
+ target_project: project,
+ source_branch: 'fixes',
+ allow_maintainer_to_push: true)
+ end
+
+ it 'includes the `allow_maintainer_to_push` field' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user)
+
+ expect(json_response['allow_maintainer_to_push']).to be_truthy
+ end
+ end
end
describe 'GET /projects/:id/merge_requests/:merge_request_iid/participants' do
@@ -815,6 +834,7 @@ describe API::MergeRequests do
context 'forked projects' do
let!(:user2) { create(:user) }
+ let(:project) { create(:project, :public, :repository) }
let!(:forked_project) { fork_project(project, user2, repository: true) }
let!(:unrelated_project) { create(:project, namespace: create(:user).namespace, creator_id: user2.id) }
@@ -872,6 +892,14 @@ describe API::MergeRequests do
expect(response).to have_gitlab_http_status(400)
end
+ it 'allows setting `allow_maintainer_to_push`' do
+ post api("/projects/#{forked_project.id}/merge_requests", user2),
+ title: 'Test merge_request', source_branch: "feature_conflict", target_branch: "master",
+ author: user2, target_project_id: project.id, allow_maintainer_to_push: true
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['allow_maintainer_to_push']).to be_truthy
+ end
+
context 'when target_branch and target_project_id is specified' do
let(:params) do
{ title: 'Test merge_request',
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 981c9c27325..dd568c24c72 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -3,117 +3,86 @@ require 'spec_helper'
describe API::Notes do
let(:user) { create(:user) }
let!(:project) { create(:project, :public, namespace: user.namespace) }
- let!(:issue) { create(:issue, project: project, author: user) }
- let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
- let!(:snippet) { create(:project_snippet, project: project, author: user) }
- let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) }
- let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
- let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) }
-
- # For testing the cross-reference of a private issue in a public issue
let(:private_user) { create(:user) }
- let(:private_project) do
- create(:project, namespace: private_user.namespace)
- .tap { |p| p.add_master(private_user) }
- end
- let(:private_issue) { create(:issue, project: private_project) }
-
- let(:ext_proj) { create(:project, :public) }
- let(:ext_issue) { create(:issue, project: ext_proj) }
-
- let!(:cross_reference_note) do
- create :note,
- noteable: ext_issue, project: ext_proj,
- note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
- system: true
- end
before do
project.add_reporter(user)
end
- describe "GET /projects/:id/noteable/:noteable_id/notes" do
- context "when noteable is an Issue" do
- context 'sorting' do
- before do
- create_list(:note, 3, noteable: issue, project: project, author: user)
- end
-
- it 'sorts by created_at in descending order by default' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by ascending order when requested' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes?sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
-
- it 'sorts by updated_at in descending order when requested' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes?order_by=updated_at", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
+ context "when noteable is an Issue" do
+ let!(:issue) { create(:issue, project: project, author: user) }
+ let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) }
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
+ it_behaves_like "noteable API", 'projects', 'issues', 'iid' do
+ let(:parent) { project }
+ let(:noteable) { issue }
+ let(:note) { issue_note }
+ end
- it 'sorts by updated_at in ascending order when requested' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes??order_by=updated_at&sort=asc", user)
+ context 'when user does not have access to create noteable' do
+ let(:private_issue) { create(:issue, project: create(:project, :private)) }
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
+ ##
+ # We are posting to project user has access to, but we use issue id
+ # from a different project, see #15577
+ #
+ before do
+ post api("/projects/#{private_issue.project.id}/issues/#{private_issue.iid}/notes", user),
+ body: 'Hi!'
+ end
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
+ it 'responds with resource not found error' do
+ expect(response.status).to eq 404
end
- it "returns an array of issue notes" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
+ it 'does not create new note' do
+ expect(private_issue.notes.reload).to be_empty
+ end
+ end
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.first['body']).to eq(issue_note.note)
+ context "when referencing other project" do
+ # For testing the cross-reference of a private issue in a public project
+ let(:private_project) do
+ create(:project, namespace: private_user.namespace)
+ .tap { |p| p.add_master(private_user) }
end
+ let(:private_issue) { create(:issue, project: private_project) }
- it "returns a 404 error when issue id not found" do
- get api("/projects/#{project.id}/issues/12345/notes", user)
+ let(:ext_proj) { create(:project, :public) }
+ let(:ext_issue) { create(:issue, project: ext_proj) }
- expect(response).to have_gitlab_http_status(404)
+ let!(:cross_reference_note) do
+ create :note,
+ noteable: ext_issue, project: ext_proj,
+ note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
+ system: true
end
- context "and current user cannot view the notes" do
- it "returns an empty array" do
- get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response).to be_empty
- end
+ describe "GET /projects/:id/noteable/:noteable_id/notes" do
+ context "current user cannot view the notes" do
+ it "returns an empty array" do
+ get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
- context "and issue is confidential" do
- before do
- ext_issue.update_attributes(confidential: true)
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response).to be_empty
end
- it "returns 404" do
- get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
+ context "issue is confidential" do
+ before do
+ ext_issue.update_attributes(confidential: true)
+ end
- expect(response).to have_gitlab_http_status(404)
+ it "returns 404" do
+ get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
end
end
- context "and current user can view the note" do
+ context "current user can view the note" do
it "returns an empty array" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", private_user)
@@ -124,172 +93,29 @@ describe API::Notes do
end
end
end
- end
-
- context "when noteable is a Snippet" do
- context 'sorting' do
- before do
- create_list(:note, 3, noteable: snippet, project: project, author: user)
- end
-
- it 'sorts by created_at in descending order by default' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by ascending order when requested' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes?sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
-
- it 'sorts by updated_at in descending order when requested' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes?order_by=updated_at", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
- it 'sorts by updated_at in ascending order when requested' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes??order_by=updated_at&sort=asc", user)
+ describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do
+ context "current user cannot view the notes" do
+ it "returns a 404 error" do
+ get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes/#{cross_reference_note.id}", user)
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
- end
- it "returns an array of snippet notes" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.first['body']).to eq(snippet_note.note)
- end
-
- it "returns a 404 error when snippet id not found" do
- get api("/projects/#{project.id}/snippets/42/notes", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it "returns 404 when not authorized" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", private_user)
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
-
- context "when noteable is a Merge Request" do
- context 'sorting' do
- before do
- create_list(:note, 3, noteable: merge_request, project: project, author: user)
- end
-
- it 'sorts by created_at in descending order by default' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by ascending order when requested' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes?sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
-
- it 'sorts by updated_at in descending order when requested' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes?order_by=updated_at", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by updated_at in ascending order when requested' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes??order_by=updated_at&sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
- end
- it "returns an array of merge_requests notes" do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.first['body']).to eq(merge_request_note.note)
- end
-
- it "returns a 404 error if merge request id not found" do
- get api("/projects/#{project.id}/merge_requests/4444/notes", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it "returns 404 when not authorized" do
- get api("/projects/#{project.id}/merge_requests/4444/notes", private_user)
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
- end
-
- describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do
- context "when noteable is an Issue" do
- it "returns an issue note by id" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq(issue_note.note)
- end
-
- it "returns a 404 error if issue note not found" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- context "and current user cannot view the note" do
- it "returns a 404 error" do
- get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes/#{cross_reference_note.id}", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- context "when issue is confidential" do
- before do
- issue.update_attributes(confidential: true)
+ expect(response).to have_gitlab_http_status(404)
end
- it "returns 404" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", private_user)
+ context "when issue is confidential" do
+ before do
+ issue.update_attributes(confidential: true)
+ end
- expect(response).to have_gitlab_http_status(404)
+ it "returns 404" do
+ get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", private_user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
end
end
- context "and current user can view the note" do
+ context "current user can view the note" do
it "returns an issue note by id" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes/#{cross_reference_note.id}", private_user)
@@ -299,132 +125,27 @@ describe API::Notes do
end
end
end
-
- context "when noteable is a Snippet" do
- it "returns a snippet note by id" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq(snippet_note.note)
- end
-
- it "returns a 404 error if snippet note not found" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
end
- describe "POST /projects/:id/noteable/:noteable_id/notes" do
- context "when noteable is an Issue" do
- it "creates a new issue note" do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user), body: 'hi!'
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq('hi!')
- expect(json_response['author']['username']).to eq(user.username)
- end
-
- it "returns a 400 bad request error if body not given" do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
-
- expect(response).to have_gitlab_http_status(400)
- end
-
- it "returns a 401 unauthorized error if user not authenticated" do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes"), body: 'hi!'
-
- expect(response).to have_gitlab_http_status(401)
- end
-
- context 'when an admin or owner makes the request' do
- it 'accepts the creation date to be set' do
- creation_time = 2.weeks.ago
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user),
- body: 'hi!', created_at: creation_time
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq('hi!')
- expect(json_response['author']['username']).to eq(user.username)
- expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
- end
- end
-
- context 'when the user is posting an award emoji on an issue created by someone else' do
- let(:issue2) { create(:issue, project: project) }
-
- it 'creates a new issue note' do
- post api("/projects/#{project.id}/issues/#{issue2.iid}/notes", user), body: ':+1:'
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq(':+1:')
- end
- end
-
- context 'when the user is posting an award emoji on his/her own issue' do
- it 'creates a new issue note' do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user), body: ':+1:'
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq(':+1:')
- end
- end
- end
-
- context "when noteable is a Snippet" do
- it "creates a new snippet note" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user), body: 'hi!'
+ context "when noteable is a Snippet" do
+ let!(:snippet) { create(:project_snippet, project: project, author: user) }
+ let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) }
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq('hi!')
- expect(json_response['author']['username']).to eq(user.username)
- end
-
- it "returns a 400 bad request error if body not given" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
-
- expect(response).to have_gitlab_http_status(400)
- end
-
- it "returns a 401 unauthorized error if user not authenticated" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes"), body: 'hi!'
-
- expect(response).to have_gitlab_http_status(401)
- end
+ it_behaves_like "noteable API", 'projects', 'snippets', 'id' do
+ let(:parent) { project }
+ let(:noteable) { snippet }
+ let(:note) { snippet_note }
end
+ end
- context 'when user does not have access to read the noteable' do
- it 'responds with 404' do
- project = create(:project, :private) { |p| p.add_guest(user) }
- issue = create(:issue, :confidential, project: project)
-
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user),
- body: 'Foo'
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
-
- context 'when user does not have access to create noteable' do
- let(:private_issue) { create(:issue, project: create(:project, :private)) }
-
- ##
- # We are posting to project user has access to, but we use issue id
- # from a different project, see #15577
- #
- before do
- post api("/projects/#{private_issue.project.id}/issues/#{private_issue.iid}/notes", user),
- body: 'Hi!'
- end
-
- it 'responds with resource not found error' do
- expect(response.status).to eq 404
- end
+ context "when noteable is a Merge Request" do
+ let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
+ let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
- it 'does not create new note' do
- expect(private_issue.notes.reload).to be_empty
- end
+ it_behaves_like "noteable API", 'projects', 'merge_requests', 'iid' do
+ let(:parent) { project }
+ let(:noteable) { merge_request }
+ let(:note) { merge_request_note }
end
context 'when the merge request discussion is locked' do
@@ -461,145 +182,4 @@ describe API::Notes do
end
end
end
-
- describe "POST /projects/:id/noteable/:noteable_id/notes to test observer on create" do
- it "creates an activity event when an issue note is created" do
- expect(Event).to receive(:create!)
-
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user), body: 'hi!'
- end
- end
-
- describe 'PUT /projects/:id/noteable/:noteable_id/notes/:note_id' do
- context 'when noteable is an Issue' do
- it 'returns modified note' do
- put api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user), body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq('Hello!')
- end
-
- it 'returns a 404 error when note id not found' do
- put api("/projects/#{project.id}/issues/#{issue.iid}/notes/12345", user),
- body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 400 bad request error if body not given' do
- put api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user)
-
- expect(response).to have_gitlab_http_status(400)
- end
- end
-
- context 'when noteable is a Snippet' do
- it 'returns modified note' do
- put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/#{snippet_note.id}", user), body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq('Hello!')
- end
-
- it 'returns a 404 error when note id not found' do
- put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/12345", user), body: "Hello!"
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
-
- context 'when noteable is a Merge Request' do
- it 'returns modified note' do
- put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/"\
- "notes/#{merge_request_note.id}", user), body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq('Hello!')
- end
-
- it 'returns a 404 error when note id not found' do
- put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/"\
- "notes/12345", user), body: "Hello!"
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
- end
-
- describe 'DELETE /projects/:id/noteable/:noteable_id/notes/:note_id' do
- context 'when noteable is an Issue' do
- it 'deletes a note' do
- delete api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user)
-
- expect(response).to have_gitlab_http_status(204)
- # Check if note is really deleted
- delete api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user)
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 404 error when note id not found' do
- delete api("/projects/#{project.id}/issues/#{issue.iid}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it_behaves_like '412 response' do
- let(:request) { api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", user) }
- end
- end
-
- context 'when noteable is a Snippet' do
- it 'deletes a note' do
- delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/#{snippet_note.id}", user)
-
- expect(response).to have_gitlab_http_status(204)
- # Check if note is really deleted
- delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/#{snippet_note.id}", user)
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 404 error when note id not found' do
- delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it_behaves_like '412 response' do
- let(:request) { api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user) }
- end
- end
-
- context 'when noteable is a Merge Request' do
- it 'deletes a note' do
- delete api("/projects/#{project.id}/merge_requests/"\
- "#{merge_request.iid}/notes/#{merge_request_note.id}", user)
-
- expect(response).to have_gitlab_http_status(204)
- # Check if note is really deleted
- delete api("/projects/#{project.id}/merge_requests/"\
- "#{merge_request.iid}/notes/#{merge_request_note.id}", user)
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 404 error when note id not found' do
- delete api("/projects/#{project.id}/merge_requests/"\
- "#{merge_request.iid}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it_behaves_like '412 response' do
- let(:request) { api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes/#{merge_request_note.id}", user) }
- end
- end
- end
end
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index 56d025f0176..9345671a1a7 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -9,7 +9,7 @@ require 'spec_helper'
# user_calendar_activities GET /u/:username/calendar_activities(.:format)
describe UsersController, "routing" do
it "to #show" do
- allow_any_instance_of(UserUrlConstrainer).to receive(:matches?).and_return(true)
+ allow_any_instance_of(::Constraints::UserUrlConstrainer).to receive(:matches?).and_return(true)
expect(get("/User")).to route_to('users#show', username: 'User')
end
@@ -210,7 +210,7 @@ describe Profiles::KeysController, "routing" do
# get all the ssh-keys of a user
it "to #get_keys" do
- allow_any_instance_of(UserUrlConstrainer).to receive(:matches?).and_return(true)
+ allow_any_instance_of(::Constraints::UserUrlConstrainer).to receive(:matches?).and_return(true)
expect(get("/foo.keys")).to route_to('profiles/keys#get_keys', username: 'foo')
end
diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb
index 80a271ba7fb..d2072198d83 100644
--- a/spec/serializers/merge_request_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_widget_entity_spec.rb
@@ -147,9 +147,9 @@ describe MergeRequestWidgetEntity do
allow(resource).to receive(:diff_head_sha) { 'sha' }
end
- context 'when no diff head commit' do
+ context 'when diff head commit is empty' do
it 'returns nil' do
- allow(resource).to receive(:diff_head_commit) { nil }
+ allow(resource).to receive(:diff_head_sha) { '' }
expect(subject[:diff_head_sha]).to be_nil
end
@@ -157,8 +157,6 @@ describe MergeRequestWidgetEntity do
context 'when diff head commit present' do
it 'returns diff head commit short id' do
- allow(resource).to receive(:diff_head_commit) { double }
-
expect(subject[:diff_head_sha]).to eq('sha')
end
end
diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb
index 10c264a90c5..36b6e5a701e 100644
--- a/spec/services/members/destroy_service_spec.rb
+++ b/spec/services/members/destroy_service_spec.rb
@@ -19,32 +19,11 @@ describe Members::DestroyService do
end
end
- def number_of_assigned_issuables(user)
- Issue.assigned_to(user).count + MergeRequest.assigned_to(user).count
- end
-
shared_examples 'a service destroying a member' do
it 'destroys the member' do
expect { described_class.new(current_user).execute(member, opts) }.to change { member.source.members_and_requesters.count }.by(-1)
end
- it 'unassigns issues and merge requests' do
- if member.invite?
- expect { described_class.new(current_user).execute(member, opts) }
- .not_to change { number_of_assigned_issuables(member_user) }
- else
- create :issue, assignees: [member_user]
- issue = create :issue, project: group_project, assignees: [member_user]
- merge_request = create :merge_request, target_project: group_project, source_project: group_project, assignee: member_user
-
- expect { described_class.new(current_user).execute(member, opts) }
- .to change { number_of_assigned_issuables(member_user) }.from(3).to(1)
-
- expect(issue.reload.assignee_ids).to be_empty
- expect(merge_request.reload.assignee_id).to be_nil
- end
- end
-
it 'destroys member notification_settings' do
if member_user.notification_settings.any?
expect { described_class.new(current_user).execute(member, opts) }
@@ -56,6 +35,29 @@ describe Members::DestroyService do
end
end
+ shared_examples 'a service destroying a member with access' do
+ it_behaves_like 'a service destroying a member'
+
+ it 'invalidates cached counts for todos and assigned issues and merge requests', :aggregate_failures do
+ create(:issue, project: group_project, assignees: [member_user])
+ create(:merge_request, source_project: group_project, assignee: member_user)
+ create(:todo, :pending, project: group_project, user: member_user)
+ create(:todo, :done, project: group_project, user: member_user)
+
+ expect(member_user.assigned_open_merge_requests_count).to be(1)
+ expect(member_user.assigned_open_issues_count).to be(1)
+ expect(member_user.todos_pending_count).to be(1)
+ expect(member_user.todos_done_count).to be(1)
+
+ described_class.new(current_user).execute(member, opts)
+
+ expect(member_user.assigned_open_merge_requests_count).to be(0)
+ expect(member_user.assigned_open_issues_count).to be(0)
+ expect(member_user.todos_pending_count).to be(0)
+ expect(member_user.todos_done_count).to be(0)
+ end
+ end
+
shared_examples 'a service destroying an access requester' do
it_behaves_like 'a service destroying a member'
@@ -74,29 +76,39 @@ describe Members::DestroyService do
end
end
- context 'with a member' do
+ context 'with a member with access' do
before do
- group_project.add_developer(member_user)
- group.add_developer(member_user)
+ group_project.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
+ group.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
end
context 'when current user cannot destroy the given member' do
- it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
+ context 'with a project member' do
let(:member) { group_project.members.find_by(user_id: member_user.id) }
- end
- it_behaves_like 'a service destroying a member' do
- let(:opts) { { skip_authorization: true } }
- let(:member) { group_project.members.find_by(user_id: member_user.id) }
- end
+ before do
+ group_project.add_developer(member_user)
+ end
- it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
- let(:member) { group.members.find_by(user_id: member_user.id) }
+ it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError'
+
+ it_behaves_like 'a service destroying a member with access' do
+ let(:opts) { { skip_authorization: true } }
+ end
end
- it_behaves_like 'a service destroying a member' do
- let(:opts) { { skip_authorization: true } }
+ context 'with a group member' do
let(:member) { group.members.find_by(user_id: member_user.id) }
+
+ before do
+ group.add_developer(member_user)
+ end
+
+ it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError'
+
+ it_behaves_like 'a service destroying a member with access' do
+ let(:opts) { { skip_authorization: true } }
+ end
end
end
@@ -106,12 +118,24 @@ describe Members::DestroyService do
group.add_owner(current_user)
end
- it_behaves_like 'a service destroying a member' do
+ context 'with a project member' do
let(:member) { group_project.members.find_by(user_id: member_user.id) }
+
+ before do
+ group_project.add_developer(member_user)
+ end
+
+ it_behaves_like 'a service destroying a member with access'
end
- it_behaves_like 'a service destroying a member' do
+ context 'with a group member' do
let(:member) { group.members.find_by(user_id: member_user.id) }
+
+ before do
+ group.add_developer(member_user)
+ end
+
+ it_behaves_like 'a service destroying a member with access'
end
end
end
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index c31259239ee..5279ea6164e 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe MergeRequests::UpdateService, :mailer do
+ include ProjectForksHelper
+
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
@@ -538,5 +540,40 @@ describe MergeRequests::UpdateService, :mailer do
let(:open_issuable) { merge_request }
let(:closed_issuable) { create(:closed_merge_request, source_project: project) }
end
+
+ context 'setting `allow_maintainer_to_push`' do
+ let(:target_project) { create(:project, :public) }
+ let(:source_project) { fork_project(target_project) }
+ let(:user) { create(:user) }
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: source_project,
+ source_branch: 'fixes',
+ target_project: target_project)
+ end
+
+ before do
+ allow(ProtectedBranch).to receive(:protected?).with(source_project, 'fixes') { false }
+ end
+
+ it 'does not allow a maintainer of the target project to set `allow_maintainer_to_push`' do
+ target_project.add_developer(user)
+
+ update_merge_request(allow_maintainer_to_push: true, title: 'Updated title')
+
+ expect(merge_request.title).to eq('Updated title')
+ expect(merge_request.allow_maintainer_to_push).to be_falsy
+ end
+
+ it 'is allowed by a user that can push to the source and can update the merge request' do
+ merge_request.update!(assignee: user)
+ source_project.add_developer(user)
+
+ update_merge_request(allow_maintainer_to_push: true, title: 'Updated title')
+
+ expect(merge_request.title).to eq('Updated title')
+ expect(merge_request.allow_maintainer_to_push).to be_truthy
+ end
+ end
end
end
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index ad5a289290c..d454ac0bda5 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -132,6 +132,15 @@ describe Projects::UpdateService do
expect(result).to eq({ status: :success })
expect(project.wiki_repository_exists?).to be false
end
+
+ it 'handles empty project feature attributes' do
+ project.project_feature.update(wiki_access_level: ProjectFeature::DISABLED)
+
+ result = update_project(project, user, { name: 'test1' })
+
+ expect(result).to eq({ status: :success })
+ expect(project.wiki_repository_exists?).to be false
+ end
end
context 'when enabling a wiki' do
diff --git a/spec/support/matchers/match_ids.rb b/spec/support/matchers/match_ids.rb
new file mode 100644
index 00000000000..d8424405b96
--- /dev/null
+++ b/spec/support/matchers/match_ids.rb
@@ -0,0 +1,24 @@
+RSpec::Matchers.define :match_ids do |*expected|
+ match do |actual|
+ actual_ids = map_ids(actual)
+ expected_ids = map_ids(expected)
+
+ expect(actual_ids).to match_array(expected_ids)
+ end
+
+ description do
+ 'matches elements by ids'
+ end
+
+ def map_ids(elements)
+ elements = elements.flatten if elements.respond_to?(:flatten)
+
+ if elements.respond_to?(:map)
+ elements.map(&:id)
+ elsif elements.respond_to?(:id)
+ [elements.id]
+ else
+ raise ArgumentError, "could not map elements to ids: #{elements}"
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/discussions.rb b/spec/support/shared_examples/requests/api/discussions.rb
new file mode 100644
index 00000000000..b6aeb30d69c
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/discussions.rb
@@ -0,0 +1,169 @@
+shared_examples 'discussions API' do |parent_type, noteable_type, id_name|
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do
+ it "returns an array of discussions" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['id']).to eq(note.discussion_id)
+ end
+
+ it "returns a 404 error when noteable id not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/12345/discussions", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it "returns 404 when not authorized" do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", private_user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id" do
+ it "returns a discussion by id" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions/#{note.discussion_id}", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['id']).to eq(note.discussion_id)
+ expect(json_response['notes'].first['body']).to eq(note.note)
+ end
+
+ it "returns a 404 error if discussion not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do
+ it "creates a new note" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['notes'].first['body']).to eq('hi!')
+ expect(json_response['notes'].first['author']['username']).to eq(user.username)
+ end
+
+ it "returns a 400 bad request error if body not given" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it "returns a 401 unauthorized error if user not authenticated" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions"), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(401)
+ end
+
+ context 'when an admin or owner makes the request' do
+ it 'accepts the creation date to be set' do
+ creation_time = 2.weeks.ago
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user),
+ body: 'hi!', created_at: creation_time
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['notes'].first['body']).to eq('hi!')
+ expect(json_response['notes'].first['author']['username']).to eq(user.username)
+ expect(Time.parse(json_response['notes'].first['created_at'])).to be_like_time(creation_time)
+ end
+ end
+
+ context 'when user does not have access to read the discussion' do
+ before do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ it 'responds with 404' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", private_user),
+ body: 'Foo'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+
+ describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes" do
+ it 'adds a new note to the discussion' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes", user), body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('Hello!')
+ expect(json_response['type']).to eq('DiscussionNote')
+ end
+
+ it 'returns a 400 bad request error if body not given' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it "returns a 400 bad request error if discussion is individual note" do
+ note.update_attribute(:type, nil)
+
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes", user), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+
+ describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ it 'returns modified note' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user), body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['body']).to eq('Hello!')
+ end
+
+ it 'returns a 404 error when note id not found' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/12345", user),
+ body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 400 bad request error if body not given' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+
+ describe "DELETE /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ it 'deletes a note' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(204)
+ # Check if note is really deleted
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it_behaves_like '412 response' do
+ let(:request) do
+ api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/notes.rb b/spec/support/shared_examples/requests/api/notes.rb
new file mode 100644
index 00000000000..79b2196660c
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/notes.rb
@@ -0,0 +1,206 @@
+shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do
+ context 'sorting' do
+ before do
+ params = { noteable: noteable, author: user }
+ params[:project] = parent if parent.is_a?(Project)
+
+ create_list(:note, 3, params)
+ end
+
+ it 'sorts by created_at in descending order by default' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user)
+
+ response_dates = json_response.map { |note| note['created_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort.reverse)
+ end
+
+ it 'sorts by ascending order when requested' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?sort=asc", user)
+
+ response_dates = json_response.map { |note| note['created_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort)
+ end
+
+ it 'sorts by updated_at in descending order when requested' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?order_by=updated_at", user)
+
+ response_dates = json_response.map { |note| note['updated_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort.reverse)
+ end
+
+ it 'sorts by updated_at in ascending order when requested' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?order_by=updated_at&sort=asc", user)
+
+ response_dates = json_response.map { |note| note['updated_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort)
+ end
+ end
+
+ it "returns an array of notes" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['body']).to eq(note.note)
+ end
+
+ it "returns a 404 error when noteable id not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/12345/notes", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it "returns 404 when not authorized" do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do
+ it "returns a note by id" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['body']).to eq(note.note)
+ end
+
+ it "returns a 404 error if note not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do
+ it "creates a new note" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ end
+
+ it "returns a 400 bad request error if body not given" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it "returns a 401 unauthorized error if user not authenticated" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes"), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(401)
+ end
+
+ it "creates an activity event when a note is created" do
+ expect(Event).to receive(:create!)
+
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: 'hi!'
+ end
+
+ context 'when an admin or owner makes the request' do
+ it 'accepts the creation date to be set' do
+ creation_time = 2.weeks.ago
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user),
+ body: 'hi!', created_at: creation_time
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ end
+ end
+
+ context 'when the user is posting an award emoji on a noteable created by someone else' do
+ it 'creates a new note' do
+ parent.add_developer(private_user)
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user), body: ':+1:'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq(':+1:')
+ end
+ end
+
+ context 'when the user is posting an award emoji on his/her own noteable' do
+ it 'creates a new note' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: ':+1:'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq(':+1:')
+ end
+ end
+
+ context 'when user does not have access to read the noteable' do
+ before do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ it 'responds with 404' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user),
+ body: 'Foo'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+
+ describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do
+ it 'returns modified note' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user), body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['body']).to eq('Hello!')
+ end
+
+ it 'returns a 404 error when note id not found' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/12345", user),
+ body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 400 bad request error if body not given' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+
+ describe "DELETE /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do
+ it 'deletes a note' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(204)
+ # Check if note is really deleted
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user)
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it_behaves_like '412 response' do
+ let(:request) { api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user) }
+ end
+ end
+end
diff --git a/spec/tasks/gitlab/artifacts/check_rake_spec.rb b/spec/tasks/gitlab/artifacts/check_rake_spec.rb
new file mode 100644
index 00000000000..d495b08aca0
--- /dev/null
+++ b/spec/tasks/gitlab/artifacts/check_rake_spec.rb
@@ -0,0 +1,34 @@
+require 'rake_helper'
+
+describe 'gitlab:artifacts rake tasks' do
+ describe 'check' do
+ let!(:artifact) { create(:ci_job_artifact, :archive, :correct_checksum) }
+
+ before do
+ Rake.application.rake_require('tasks/gitlab/artifacts/check')
+ stub_env('VERBOSE' => 'true')
+ end
+
+ it 'outputs the integrity check for each batch' do
+ expect { run_rake_task('gitlab:artifacts:check') }.to output(/Failures: 0/).to_stdout
+ end
+
+ it 'errors out about missing files on the file system' do
+ FileUtils.rm_f(artifact.file.path)
+
+ expect { run_rake_task('gitlab:artifacts:check') }.to output(/No such file.*#{Regexp.quote(artifact.file.path)}/).to_stdout
+ end
+
+ it 'errors out about invalid checksum' do
+ artifact.update_column(:file_sha256, 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
+
+ expect { run_rake_task('gitlab:artifacts:check') }.to output(/Checksum mismatch/).to_stdout
+ end
+
+ it 'errors out about missing checksum' do
+ artifact.update_column(:file_sha256, nil)
+
+ expect { run_rake_task('gitlab:artifacts:check') }.to output(/Checksum missing/).to_stdout
+ end
+ end
+end
diff --git a/spec/views/projects/tree/show.html.haml_spec.rb b/spec/views/projects/tree/show.html.haml_spec.rb
index 44b32df0395..3b098320ad7 100644
--- a/spec/views/projects/tree/show.html.haml_spec.rb
+++ b/spec/views/projects/tree/show.html.haml_spec.rb
@@ -13,6 +13,7 @@ describe 'projects/tree/show' do
allow(view).to receive(:can?).and_return(true)
allow(view).to receive(:can_collaborate_with_project?).and_return(true)
+ allow(view).to receive_message_chain('user_access.can_push_to_branch?').and_return(true)
allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings)
end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 5d9b0679796..cd6661f09a1 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -114,6 +114,18 @@ describe PostReceive do
end
end
+ describe '#process_wiki_changes' do
+ let(:gl_repository) { "wiki-#{project.id}" }
+
+ it 'updates project activity' do
+ described_class.new.perform(gl_repository, key_id, base64_changes)
+
+ expect { project.reload }
+ .to change(project, :last_activity_at)
+ .and change(project, :last_repository_updated_at)
+ end
+ end
+
context "webhook" do
it "fetches the correct project" do
expect(Project).to receive(:find_by).with(id: project.id.to_s)
diff --git a/vendor/gitignore/Dart.gitignore b/vendor/gitignore/Dart.gitignore
index 58950beb4fa..7bf00e82cc9 100644
--- a/vendor/gitignore/Dart.gitignore
+++ b/vendor/gitignore/Dart.gitignore
@@ -1,4 +1,4 @@
-# See https://www.dartlang.org/tools/private-files.html
+# See https://www.dartlang.org/guides/libraries/private-files
# Files and directories created by pub
.dart_tool/
diff --git a/vendor/gitignore/Qt.gitignore b/vendor/gitignore/Qt.gitignore
index 037a1e75790..5291a385b25 100644
--- a/vendor/gitignore/Qt.gitignore
+++ b/vendor/gitignore/Qt.gitignore
@@ -1,5 +1,4 @@
# C++ objects and libs
-
*.slo
*.lo
*.o
@@ -11,7 +10,6 @@
*.dylib
# Qt-es
-
object_script.*.Release
object_script.*.Debug
*_plugin_import.cpp
@@ -35,13 +33,11 @@ Makefile*
target_wrapper.*
# QtCreator
-
*.autosave
-# QtCtreator Qml
+# QtCreator Qml
*.qmlproject.user
*.qmlproject.user.*
-# QtCtreator CMake
+# QtCreator CMake
CMakeLists.txt.user*
-
diff --git a/vendor/gitignore/R.gitignore b/vendor/gitignore/R.gitignore
index fcff087aebb..26fad6fadff 100644
--- a/vendor/gitignore/R.gitignore
+++ b/vendor/gitignore/R.gitignore
@@ -31,3 +31,6 @@ vignettes/*.pdf
# Temporary files created by R markdown
*.utf8.md
*.knit.md
+
+# Shiny token, see https://shiny.rstudio.com/articles/shinyapps.html
+rsconnect/
diff --git a/vendor/gitignore/TeX.gitignore b/vendor/gitignore/TeX.gitignore
index 5359e544bcf..78c1c5cd26e 100644
--- a/vendor/gitignore/TeX.gitignore
+++ b/vendor/gitignore/TeX.gitignore
@@ -110,6 +110,14 @@ acs-*.bib
*.gaux
*.gtex
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
# hyperref
*.brf
diff --git a/vendor/gitignore/VisualStudio.gitignore b/vendor/gitignore/VisualStudio.gitignore
index c49041ff7d2..8e930f59c47 100644
--- a/vendor/gitignore/VisualStudio.gitignore
+++ b/vendor/gitignore/VisualStudio.gitignore
@@ -259,9 +259,6 @@ FakesAssemblies/
.ntvs_analysis.dat
node_modules/
-# TypeScript v1 declaration files
-typings/
-
# Visual Studio 6 build log
*.plg
diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
index 0ac8885405e..c233e255fe0 100644
--- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
+++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
@@ -36,7 +36,6 @@ variables:
KUBERNETES_VERSION: 1.8.6
HELM_VERSION: 2.6.1
- CODECLIMATE_VERSION: 0.69.0
stages:
- build
@@ -286,6 +285,8 @@ production:
export CI_APPLICATION_TAG=$CI_COMMIT_SHA
export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID}
export TILLER_NAMESPACE=$KUBE_NAMESPACE
+ # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable" for Static Code Analysis
+ export SCA_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
function sast_container() {
if [[ -n "$CI_REGISTRY_USER" ]]; then
@@ -306,20 +307,16 @@ production:
}
function codeclimate() {
- cc_opts="--env CODECLIMATE_CODE="$PWD" \
- --volume "$PWD":/code \
- --volume /var/run/docker.sock:/var/run/docker.sock \
- --volume /tmp/cc:/tmp/cc"
-
- docker run ${cc_opts} "codeclimate/codeclimate:${CODECLIMATE_VERSION}" init
- docker run ${cc_opts} "codeclimate/codeclimate:${CODECLIMATE_VERSION}" analyze -f json > codeclimate.json
+ docker run --env CODECLIMATE_CODE="$PWD" \
+ --volume "$PWD":/code \
+ --volume /var/run/docker.sock:/var/run/docker.sock \
+ --volume /tmp/cc:/tmp/cc \
+ "registry.gitlab.com/gitlab-org/security-products/codequality/codeclimate:${SCA_VERSION}" analyze -f json > codeclimate.json
}
function sast() {
case "$CI_SERVER_VERSION" in
*-ee)
- # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable"
- SAST_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
# Deprecation notice for CONFIDENCE_LEVEL variable
if [ -z "$SAST_CONFIDENCE_LEVEL" -a "$CONFIDENCE_LEVEL" ]; then
@@ -331,7 +328,7 @@ production:
--env SAST_DISABLE_REMOTE_CHECKS="${SAST_DISABLE_REMOTE_CHECKS:-false}" \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
- "registry.gitlab.com/gitlab-org/security-products/sast:$SAST_VERSION" /app/bin/run /code
+ "registry.gitlab.com/gitlab-org/security-products/sast:$SCA_VERSION" /app/bin/run /code
;;
*)
echo "GitLab EE is required"
diff --git a/vendor/licenses.csv b/vendor/licenses.csv
index 8f127468e25..03115292f02 100644
--- a/vendor/licenses.csv
+++ b/vendor/licenses.csv
@@ -9,14 +9,17 @@
JSONStream,1.3.2,MIT
RedCloth,4.3.2,MIT
abbrev,1.0.9,ISC
+abbrev,1.1.1,ISC
accepts,1.3.3,MIT
+accepts,1.3.4,MIT
ace-rails-ap,4.1.2,MIT
acorn,3.3.0,MIT
acorn,4.0.13,MIT
acorn,5.1.1,MIT
-acorn,5.3.0,MIT
+acorn,5.4.1,MIT
acorn-dynamic-import,2.0.2,MIT
acorn-jsx,3.0.1,MIT
+acorn-node,1.3.0,Apache 2.0
actionmailer,4.2.10,MIT
actionpack,4.2.10,MIT
actionview,4.2.10,MIT
@@ -25,6 +28,7 @@ activemodel,4.2.10,MIT
activerecord,4.2.10,MIT
activesupport,4.2.10,MIT
acts-as-taggable-on,4.0.0,MIT
+address,1.0.3,MIT
addressable,2.5.2,Apache 2.0
addressparser,1.0.1,MIT
after,0.8.2,MIT
@@ -32,59 +36,70 @@ agent-base,2.1.1,MIT
ajv,4.11.8,MIT
ajv,5.2.2,MIT
ajv,5.5.2,MIT
+ajv,6.1.1,MIT
ajv-keywords,1.5.1,MIT
-ajv-keywords,2.1.0,MIT
+ajv-keywords,3.1.0,MIT
akismet,2.0.0,MIT
align-text,0.1.4,MIT
allocations,1.0.5,MIT
alphanum-sort,1.0.2,MIT
amdefine,1.0.1,BSD-3-Clause OR MIT
+amqplib,0.5.2,MIT
+ansi-align,2.0.0,ISC
ansi-escapes,1.4.0,MIT
-ansi-html,0.0.5,"Apache, Version 2.0"
+ansi-escapes,3.0.0,MIT
ansi-html,0.0.7,Apache 2.0
ansi-regex,2.1.1,MIT
ansi-regex,3.0.0,MIT
ansi-styles,2.2.1,MIT
ansi-styles,3.2.0,MIT
anymatch,1.3.2,ISC
+anymatch,2.0.0,ISC
append-transform,0.4.0,MIT
-aproba,1.1.2,ISC
+aproba,1.2.0,ISC
are-we-there-yet,1.1.4,ISC
arel,6.0.4,MIT
argparse,1.0.9,MIT
arr-diff,2.0.0,MIT
-arr-flatten,1.0.1,MIT
+arr-diff,4.0.0,MIT
+arr-flatten,1.1.0,MIT
+arr-union,3.1.0,MIT
array-filter,0.0.1,MIT
array-find,1.0.0,MIT
array-find-index,1.0.2,MIT
array-flatten,1.1.1,MIT
array-flatten,2.1.1,MIT
+array-includes,3.0.3,MIT
array-map,0.0.0,MIT
array-reduce,0.0.0,MIT
array-slice,0.2.3,MIT
array-union,1.0.2,MIT
array-uniq,1.0.3,MIT
array-unique,0.2.1,MIT
+array-unique,0.3.2,MIT
arraybuffer.slice,0.0.7,MIT
arrify,1.0.1,MIT
asana,0.6.0,MIT
asciidoctor,1.5.3,MIT
asciidoctor-plantuml,0.0.7,MIT
asn1,0.2.3,MIT
-asn1.js,4.9.1,MIT
+asn1.js,4.10.1,MIT
assert,1.4.1,MIT
assert-plus,0.2.0,MIT
assert-plus,1.0.0,MIT
asset_sync,2.2.0,MIT
-ast-types,0.10.1,MIT
+assign-symbols,1.0.0,MIT
+ast-types,0.11.1,MIT
astw,2.2.0,MIT
async,0.9.2,MIT
async,1.5.2,MIT
async,2.1.5,MIT
async,2.4.1,MIT
+async,2.6.0,MIT
async-each,1.0.1,MIT
async-limiter,1.0.0,MIT
asynckit,0.4.0,MIT
+atob,2.0.3,(MIT OR Apache-2.0)
atomic,1.1.99,Apache 2.0
attr_encrypted,3.0.3,MIT
attr_required,1.0.0,MIT
@@ -176,9 +191,10 @@ babylon,7.0.0-beta.32,MIT
backo2,1.0.2,MIT
balanced-match,0.4.2,MIT
balanced-match,1.0.0,MIT
+base,0.11.2,MIT
base32,0.3.2,MIT
base64-arraybuffer,0.1.5,MIT
-base64-js,1.2.0,MIT
+base64-js,1.2.3,MIT
base64id,1.0.0,MIT
batch,0.6.1,MIT
batch-loader,1.2.1,MIT
@@ -186,50 +202,57 @@ bcrypt,3.1.11,MIT
bcrypt-pbkdf,1.0.1,New BSD
bcrypt_pbkdf,1.0.0,MIT
better-assert,1.0.2,MIT
+bfj-node4,5.2.1,MIT
big.js,3.1.3,MIT
-binary-extensions,1.10.0,MIT
+binary-extensions,1.11.0,MIT
bindata,2.4.1,ruby
+bitsyntax,0.0.4,Unknown
bl,1.1.2,MIT
blackst0ne-mermaid,7.1.0-fixed,MIT
blob,0.0.4,MIT*
block-stream,0.0.9,ISC
-bluebird,2.11.0,MIT
bluebird,3.5.0,MIT
-bn.js,4.11.6,MIT
-body-parser,1.17.2,MIT
+bluebird,3.5.1,MIT
+bn.js,4.11.8,MIT
+body-parser,1.18.2,MIT
bonjour,3.5.0,MIT
boom,2.10.1,New BSD
boom,4.3.1,New BSD
boom,5.2.0,New BSD
bootstrap-sass,3.3.6,MIT
bootstrap_form,2.7.0,MIT
+boxen,1.3.0,MIT
+brace-expansion,1.1.11,MIT
brace-expansion,1.1.8,MIT
braces,0.1.5,MIT
braces,1.8.5,MIT
-brorand,1.0.7,MIT
+braces,2.3.1,MIT
+brorand,1.1.0,MIT
browser,2.2.0,MIT
-browser-pack,6.0.2,MIT
+browser-pack,6.0.4,MIT
browser-resolve,1.11.2,MIT
browserify,14.5.0,MIT
-browserify-aes,1.0.6,MIT
+browserify-aes,1.1.1,MIT
browserify-cipher,1.0.0,MIT
browserify-des,1.0.0,MIT
browserify-rsa,4.0.1,MIT
-browserify-sign,4.0.0,ISC
+browserify-sign,4.0.4,ISC
browserify-zlib,0.1.4,MIT
browserify-zlib,0.2.0,MIT
browserslist,1.7.7,MIT
buffer,4.9.1,MIT
-buffer,5.0.8,MIT
+buffer,5.1.0,MIT
buffer-indexof,1.1.0,MIT
+buffer-more-ints,0.0.2,MIT
buffer-xor,1.0.3,MIT
builder,3.2.3,MIT
buildmail,4.0.1,MIT
builtin-modules,1.1.1,MIT
builtin-status-codes,3.0.0,MIT
-bytes,2.4.0,MIT
bytes,2.5.0,MIT
bytes,3.0.0,MIT
+cacache,10.0.4,ISC
+cache-base,1.0.1,MIT
cached-path-relative,1.0.1,MIT
caller-path,0.1.0,MIT
callsite,1.0.0,MIT*
@@ -241,6 +264,7 @@ camelcase,4.1.0,MIT
camelcase-keys,2.1.0,MIT
caniuse-api,1.6.1,MIT
caniuse-db,1.0.30000649,CC-BY-4.0
+capture-stack-trace,1.0.0,MIT
carrierwave,1.2.1,MIT
caseless,0.11.0,Apache 2.0
caseless,0.12.0,Apache 2.0
@@ -248,18 +272,27 @@ cause,0.1,MIT
center-align,0.1.3,MIT
chalk,1.1.3,MIT
chalk,2.3.0,MIT
+chalk,2.3.1,MIT
+chardet,0.4.2,MIT
charlock_holmes,0.7.5,MIT
+chart.js,1.0.2,MIT
+check-types,7.3.0,MIT
chokidar,1.7.0,MIT
+chokidar,2.0.2,MIT
+chownr,1.0.1,ISC
chronic,0.10.2,MIT
chronic_duration,0.10.6,MIT
chunky_png,1.3.5,MIT
-cipher-base,1.0.3,MIT
+cipher-base,1.0.4,MIT
circular-json,0.3.3,MIT
-circular-json,0.4.0,MIT
+circular-json,0.5.1,MIT
citrus,3.0.2,MIT
clap,1.1.3,MIT
+class-utils,0.3.6,MIT
classlist-polyfill,1.2.0,Unlicense
+cli-boxes,1.0.0,MIT
cli-cursor,1.0.2,MIT
+cli-cursor,2.1.0,MIT
cli-width,2.1.0,ISC
clipboard,1.7.1,MIT
cliui,2.1.0,ISC
@@ -270,6 +303,7 @@ co,4.6.0,MIT
coa,1.0.1,MIT
code-point-at,1.1.0,MIT
coercible,1.0.0,MIT
+collection-visit,1.0.0,MIT
color,0.11.4,MIT
color-convert,1.9.1,MIT
color-name,1.1.2,MIT
@@ -278,21 +312,23 @@ colormin,1.1.2,MIT
colors,1.1.2,MIT
combine-lists,1.0.1,MIT
combine-source-map,0.7.2,MIT
-combined-stream,1.0.5,MIT
-commander,2.9.0,MIT
+combine-source-map,0.8.0,MIT
+combined-stream,1.0.6,MIT
+commander,2.14.1,MIT
commondir,1.0.1,MIT
+commonmarker,0.17.8,MIT
component-bind,1.0.0,MIT*
component-emitter,1.2.1,MIT
component-inherit,0.0.3,MIT*
compressible,2.0.11,MIT
compression,1.7.0,MIT
-compression-webpack-plugin,1.0.0,MIT
+compression-webpack-plugin,1.1.7,MIT
concat-map,0.0.1,MIT
concat-stream,1.5.2,MIT
concat-stream,1.6.0,MIT
concurrent-ruby-ext,1.0.5,MIT
-configstore,1.4.0,Simplified BSD
-connect,3.6.3,MIT
+configstore,3.1.1,Simplified BSD
+connect,3.6.6,MIT
connect-history-api-fallback,1.3.0,MIT
connection_pool,2.2.1,MIT
console-browserify,1.1.0,MIT
@@ -301,21 +337,25 @@ consolidate,0.14.5,MIT
constants-browserify,1.0.0,MIT
contains-path,0.1.0,MIT
content-disposition,0.5.2,MIT
-content-type,1.0.2,MIT
+content-type,1.0.4,MIT
convert-source-map,1.1.3,MIT
convert-source-map,1.5.0,MIT
cookie,0.3.1,MIT
cookie-signature,1.0.6,MIT
-copy-webpack-plugin,4.0.1,MIT
+copy-concurrently,1.0.5,ISC
+copy-descriptor,0.1.1,MIT
+copy-webpack-plugin,4.4.1,MIT
core-js,2.3.0,MIT
core-js,2.4.1,MIT
core-js,2.5.1,MIT
+core-js,2.5.3,MIT
core-util-is,1.0.2,MIT
cosmiconfig,2.1.1,MIT
crack,0.4.3,MIT
create-ecdh,4.0.0,MIT
-create-hash,1.1.2,MIT
-create-hmac,1.1.4,MIT
+create-error-class,3.0.2,MIT
+create-hash,1.1.3,MIT
+create-hmac,1.1.6,MIT
creole,0.5.0,ruby
cropper,2.3.0,MIT
cross-spawn,5.1.0,MIT
@@ -323,9 +363,9 @@ cryptiles,2.0.5,New BSD
cryptiles,3.1.2,New BSD
crypto-browserify,3.11.0,MIT
crypto-browserify,3.12.0,MIT
+crypto-random-string,1.0.0,MIT
css-color-names,0.0.4,MIT
-css-loader,0.28.0,MIT
-css-selector-tokenizer,0.6.0,MIT
+css-loader,0.28.9,MIT
css-selector-tokenizer,0.7.0,MIT
css_parser,1.5.0,MIT
cssesc,0.1.0,MIT
@@ -333,6 +373,7 @@ cssnano,3.10.0,MIT
csso,2.3.2,MIT
currently-unhandled,0.4.1,MIT
custom-event,1.0.1,MIT
+cyclist,0.2.2,MIT*
d,0.1.1,MIT
d,1.0.0,MIT
d3,3.5.17,New BSD
@@ -363,7 +404,6 @@ date-format,1.2.0,MIT
date-now,0.1.4,MIT
de-indent,1.0.2,MIT
debug,2.2.0,MIT
-debug,2.6.7,MIT
debug,2.6.8,MIT
debug,2.6.9,MIT
debug,3.1.0,MIT
@@ -372,6 +412,7 @@ decamelize,1.2.0,MIT
deckar01-task_list,2.0.0,MIT
declarative,0.0.10,MIT
declarative-option,0.1.0,MIT
+decode-uri-component,0.2.0,MIT
decompress-response,3.3.0,MIT
deep-equal,1.0.1,MIT
deep-extend,0.4.2,MIT
@@ -379,6 +420,9 @@ deep-is,0.1.3,MIT
default-require-extensions,1.0.0,MIT
default_value_for,3.0.2,MIT
define-properties,1.1.2,MIT
+define-property,0.2.5,MIT
+define-property,1.0.0,MIT
+define-property,2.0.2,MIT
defined,1.0.0,MIT
degenerator,1.0.4,MIT
del,2.2.2,MIT
@@ -386,14 +430,15 @@ del,3.0.0,MIT
delayed-stream,1.0.0,MIT
delegate,3.1.2,MIT
delegates,1.0.0,MIT
-depd,1.1.0,MIT
depd,1.1.1,MIT
deps-sort,2.0.0,MIT
des.js,1.0.0,MIT
descendants_tracker,0.0.4,MIT
destroy,1.0.4,MIT
detect-indent,4.0.0,MIT
+detect-libc,1.0.3,Apache 2.0
detect-node,2.0.3,ISC
+detect-port-alt,1.1.5,MIT
detective,4.7.1,MIT
devise,4.2.0,MIT
devise-two-factor,3.0.0,MIT
@@ -402,6 +447,7 @@ diff,3.4.0,New BSD
diff-lcs,1.3,"MIT,Artistic-2.0,GPL-2.0+"
diffie-hellman,5.0.2,MIT
diffy,3.1.0,MIT
+dir-glob,2.0.0,MIT
dns-equal,1.0.0,MIT
dns-packet,1.2.2,MIT
dns-txt,2.0.2,MIT
@@ -418,26 +464,28 @@ domhandler,2.4.1,Simplified BSD
domutils,1.6.2,Simplified BSD
doorkeeper,4.2.6,MIT
doorkeeper-openid_connect,1.2.0,MIT
+dot-prop,4.2.0,MIT
double-ended-queue,2.1.0-0,MIT
dropzone,4.2.0,MIT
dropzonejs-rails,0.7.2,MIT
duplexer,0.1.1,MIT
duplexer2,0.1.4,New BSD
duplexer3,0.1.4,New BSD
-duplexify,3.5.1,MIT
+duplexify,3.5.3,MIT
ecc-jsbn,0.1.1,MIT
ee-first,1.1.1,MIT
-ejs,2.5.6,Apache 2.0
+ejs,2.5.7,Apache 2.0
electron-to-chromium,1.3.3,ISC
-elliptic,6.3.3,MIT
+elliptic,6.4.0,MIT
email_reply_trimmer,0.1.6,MIT
emoji-unicode-version,0.2.1,MIT
emojis-list,2.1.0,MIT
-encodeurl,1.0.1,MIT
+encodeurl,1.0.2,MIT
encryptor,3.0.0,MIT
end-of-stream,1.4.0,MIT
-engine.io,3.1.4,MIT
-engine.io-client,3.1.4,MIT
+end-of-stream,1.4.1,MIT
+engine.io,3.1.5,MIT
+engine.io-client,3.1.5,MIT
engine.io-parser,2.1.2,MIT
enhanced-resolve,0.9.1,MIT
enhanced-resolve,3.4.1,MIT
@@ -447,7 +495,7 @@ equalizer,0.0.11,MIT
errno,0.1.4,MIT
error-ex,1.3.0,MIT
erubis,2.7.0,MIT
-es-abstract,1.8.2,MIT
+es-abstract,1.10.0,MIT
es-to-primitive,1.1.1,MIT
es5-ext,0.10.24,MIT
es6-iterator,2.0.1,MIT
@@ -487,28 +535,35 @@ estraverse,4.1.1,Simplified BSD
estraverse,4.2.0,Simplified BSD
esutils,2.0.2,Simplified BSD
et-orbi,1.0.3,MIT
-etag,1.8.0,MIT
+etag,1.8.1,MIT
eve-raphael,0.5.0,Apache 2.0
event-emitter,0.3.5,MIT
event-stream,3.3.4,MIT
eventemitter3,1.2.0,MIT
events,1.1.1,MIT
eventsource,0.1.6,MIT
-evp_bytestokey,1.0.0,MIT
+evp_bytestokey,1.0.3,MIT
excon,0.57.1,MIT
execa,0.7.0,MIT
execjs,2.6.0,MIT
exit-hook,1.1.1,MIT
expand-braces,0.1.2,MIT
expand-brackets,0.1.5,MIT
+expand-brackets,2.1.4,MIT
expand-range,0.1.1,MIT
expand-range,1.8.2,MIT
-exports-loader,0.6.4,MIT
-express,4.15.4,MIT
+expand-tilde,2.0.2,MIT
+exports-loader,0.7.0,MIT
+express,4.16.2,MIT
expression_parser,0.9.0,MIT
extend,3.0.1,MIT
+extend-shallow,2.0.1,MIT
+extend-shallow,3.0.2,MIT
+external-editor,2.1.0,MIT
extglob,0.3.2,MIT
+extglob,2.0.4,MIT
extsprintf,1.3.0,MIT
+extsprintf,1.4.0,MIT
faraday,0.12.2,MIT
faraday_middleware,0.11.0.1,MIT
faraday_middleware-multi_json,0.0.6,MIT
@@ -520,18 +575,19 @@ fast_gettext,1.4.0,"MIT,ruby"
fastparse,1.1.1,MIT
faye-websocket,0.10.0,MIT
faye-websocket,0.11.1,MIT
-faye-websocket,0.7.3,MIT
ffi,1.9.18,New BSD
figures,1.7.0,MIT
+figures,2.0.0,MIT
file-entry-cache,2.0.0,MIT
-file-loader,0.11.1,MIT
+file-loader,1.1.8,MIT
file-uri-to-path,1.0.0,MIT
-filename-regex,2.0.0,MIT
+filename-regex,2.0.1,MIT
fileset,2.0.3,MIT
-filesize,3.3.0,New BSD
-filesize,3.5.10,New BSD
+filesize,3.5.11,New BSD
+filesize,3.6.0,New BSD
fill-range,2.2.3,MIT
-finalhandler,1.0.4,MIT
+fill-range,4.0.0,MIT
+finalhandler,1.1.0,MIT
find-cache-dir,1.0.0,MIT
find-root,0.1.2,MIT
find-up,1.1.2,MIT
@@ -542,6 +598,7 @@ flipper,0.11.0,MIT
flipper-active_record,0.11.0,MIT
flipper-active_support_cache_store,0.11.0,MIT
flowdock,0.7.1,MIT
+flush-write-stream,1.0.2,MIT
fog-aliyun,0.2.0,MIT
fog-aws,1.4.0,MIT
fog-core,1.44.3,MIT
@@ -554,26 +611,26 @@ fog-xml,0.1.3,MIT
follow-redirects,1.0.0,MIT
follow-redirects,1.2.6,MIT
font-awesome-rails,4.7.0.1,"MIT,SIL Open Font License"
-for-each,0.3.2,MIT
-for-in,0.1.6,MIT
-for-own,0.1.4,MIT
+for-in,1.0.2,MIT
+for-own,0.1.5,MIT
foreach,2.0.5,MIT
forever-agent,0.6.1,Apache 2.0
form-data,2.0.0,MIT
form-data,2.1.4,MIT
-form-data,2.3.1,MIT
+form-data,2.3.2,MIT
formatador,0.2.5,MIT
-forwarded,0.1.0,MIT
-fresh,0.5.0,MIT
+forwarded,0.1.2,MIT
+fragment-cache,0.2.1,MIT
+fresh,0.5.2,MIT
from,0.1.7,MIT
+from2,2.3.0,MIT
fs-access,1.0.1,MIT
-fs-extra,0.26.7,MIT
+fs-write-stream-atomic,1.0.10,ISC
fs.realpath,1.0.0,ISC
-fsevents,1.1.2,MIT
+fsevents,1.1.3,MIT
fstream,1.0.11,ISC
fstream-ignore,1.0.5,ISC
ftp,0.3.10,MIT
-function-bind,1.1.0,MIT
function-bind,1.1.1,MIT
fuzzaldrin-plus,0.5.0,MIT
gauge,2.7.4,ISC
@@ -585,28 +642,33 @@ get-caller-file,1.0.2,ISC
get-stdin,4.0.1,MIT
get-stream,3.0.0,MIT
get-uri,2.0.1,MIT
+get-value,2.0.6,MIT
get_process_mem,0.2.0,MIT
getpass,0.1.7,MIT
gettext_i18n_rails,1.8.0,MIT
gettext_i18n_rails_js,1.2.0,MIT
-gitaly-proto,0.84.0,MIT
-github-linguist,4.7.6,MIT
+gitaly-proto,0.88.0,MIT
+github-linguist,5.3.3,MIT
github-markup,1.6.1,MIT
gitlab-flowdock-git-hook,1.0.1,MIT
gitlab-grit,2.8.2,MIT
gitlab-markup,1.6.3,MIT
gitlab_omniauth-ldap,2.0.4,MIT
glob,5.0.15,ISC
-glob,6.0.4,ISC
glob,7.1.1,ISC
glob,7.1.2,ISC
glob-base,0.3.0,MIT
glob-parent,2.0.0,ISC
+glob-parent,3.1.0,ISC
+global-dirs,0.1.1,MIT
+global-modules,1.0.0,MIT
+global-prefix,1.0.2,MIT
globalid,0.4.1,MIT
globals,10.4.0,MIT
globals,9.18.0,MIT
globby,5.0.0,MIT
globby,6.1.0,MIT
+globby,7.1.1,MIT
gollum-grit_adapter,1.0.1,MIT
gollum-lib,4.2.7,MIT
gollum-rugged_adapter,0.4.4,MIT
@@ -615,19 +677,19 @@ good-listener,1.2.2,MIT
google-api-client,0.13.6,Apache 2.0
google-protobuf,3.5.1,New BSD
googleapis-common-protos-types,1.0.1,Apache 2.0
-googleauth,0.5.3,Apache 2.0
-got,3.3.1,MIT
+googleauth,0.6.2,Apache 2.0
+got,6.7.1,MIT
got,7.1.0,MIT
gpgme,2.0.13,LGPL-2.1+
graceful-fs,4.1.11,ISC
-graceful-readlink,1.0.1,MIT
grape,1.0.0,MIT
grape-entity,0.6.0,MIT
grape-route-helpers,2.1.0,MIT
grape_logging,1.7.0,MIT
graphlib,2.1.1,MIT
-grpc,1.8.3,Apache 2.0
+grpc,1.10.0,Apache 2.0
gzip-size,3.0.0,MIT
+gzip-size,4.1.0,MIT
hamlit,2.6.1,MIT
handle-thing,1.2.5,MIT
handlebars,4.0.6,MIT
@@ -642,11 +704,18 @@ has-binary2,1.0.2,MIT
has-cors,1.1.0,MIT
has-flag,1.0.0,MIT
has-flag,2.0.0,MIT
+has-flag,3.0.0,MIT
has-symbol-support-x,1.3.0,MIT
has-to-string-tag-x,1.3.0,MIT
has-unicode,2.0.1,ISC
+has-value,0.3.1,MIT
+has-value,1.0.0,MIT
+has-values,0.1.4,MIT
+has-values,1.0.0,MIT
+hash-base,2.0.2,MIT
+hash-base,3.0.4,MIT
hash-sum,1.0.2,MIT
-hash.js,1.0.3,MIT
+hash.js,1.1.3,MIT
hashie,3.5.6,MIT
hashie-forbidden_attributes,0.1.1,MIT
hawk,3.1.3,New BSD
@@ -655,9 +724,11 @@ he,1.1.1,MIT
health_check,2.6.0,MIT
hipchat,1.5.2,MIT
hipchat-notifier,1.1.0,MIT
+hmac-drbg,1.0.1,MIT
hoek,2.16.3,New BSD
-hoek,4.2.0,New BSD
+hoek,4.2.1,New BSD
home-or-tmp,2.0.0,MIT
+homedir-polyfill,1.0.1,MIT
hosted-git-info,2.2.0,ISC
hpack.js,2.1.6,MIT
html-comment-regex,1.1.1,MIT
@@ -670,7 +741,6 @@ htmlparser2,3.9.2,MIT
http,0.9.8,MIT
http-cookie,1.0.3,MIT
http-deceiver,1.2.7,MIT
-http-errors,1.6.1,MIT
http-errors,1.6.2,MIT
http-form_data,1.0.1,MIT
http-proxy,1.16.2,MIT
@@ -690,26 +760,31 @@ i18n,0.9.1,MIT
ice_nine,0.11.2,MIT
iconv-lite,0.4.15,MIT
iconv-lite,0.4.19,MIT
-icss-replace-symbols,1.0.2,ISC
+icss-replace-symbols,1.1.0,ISC
+icss-utils,2.1.0,ISC
ieee754,1.1.8,New BSD
+iferr,0.1.5,MIT
ignore,3.3.3,MIT
+ignore,3.3.7,MIT
ignore-by-default,1.0.1,ISC
immediate,3.0.6,MIT
-imports-loader,0.7.1,MIT
+import-lazy,2.1.0,MIT
+import-local,1.0.0,MIT
+imports-loader,0.8.0,MIT
imurmurhash,0.1.4,MIT
indent-string,2.1.0,MIT
indexes-of,1.0.1,MIT
indexof,0.0.1,MIT*
-infinity-agent,2.0.3,MIT
inflection,1.10.0,MIT
inflection,1.3.8,MIT
inflight,1.0.6,ISC
influxdb,0.2.3,MIT
inherits,2.0.1,ISC
inherits,2.0.3,ISC
-ini,1.3.4,ISC
+ini,1.3.5,ISC
inline-source-map,0.6.2,MIT
inquirer,0.12.0,MIT
+inquirer,3.3.0,MIT
insert-module-globals,7.0.1,MIT
internal-ip,1.2.0,MIT
interpret,1.0.1,MIT
@@ -717,46 +792,62 @@ invariant,2.2.2,New BSD
invert-kv,1.0.0,MIT
ip,1.0.1,MIT
ip,1.1.5,MIT
-ipaddr.js,1.4.0,MIT
+ipaddr.js,1.6.0,MIT
ipaddress,0.8.3,MIT
is-absolute,0.2.6,MIT
is-absolute-url,2.1.0,MIT
+is-accessor-descriptor,0.1.6,MIT
+is-accessor-descriptor,1.0.0,MIT
is-arrayish,0.2.1,MIT
is-binary-path,1.0.1,MIT
is-buffer,1.1.5,MIT
is-buffer,1.1.6,MIT
is-builtin-module,1.0.0,MIT
is-callable,1.1.3,MIT
+is-data-descriptor,0.1.4,MIT
+is-data-descriptor,1.0.0,MIT
is-date-object,1.0.1,MIT
-is-dotfile,1.0.2,MIT
+is-descriptor,0.1.6,MIT
+is-descriptor,1.0.2,MIT
+is-dotfile,1.0.3,MIT
is-equal-shallow,0.1.3,MIT
is-extendable,0.1.1,MIT
+is-extendable,1.0.1,MIT
is-extglob,1.0.0,MIT
is-extglob,2.1.1,MIT
is-finite,1.0.2,MIT
is-fullwidth-code-point,1.0.0,MIT
is-fullwidth-code-point,2.0.0,MIT
-is-function,1.0.1,MIT
is-glob,2.0.1,MIT
is-glob,3.1.0,MIT
+is-glob,4.0.0,MIT
+is-installed-globally,0.1.0,MIT
+is-my-ip-valid,1.0.0,MIT
is-my-json-valid,2.16.0,MIT
-is-my-json-valid,2.17.1,MIT
+is-my-json-valid,2.17.2,MIT
is-npm,1.0.0,MIT
is-number,0.1.1,MIT
is-number,2.1.0,MIT
+is-number,3.0.0,MIT
+is-number,4.0.0,MIT
+is-obj,1.0.1,MIT
is-object,1.0.1,MIT
+is-odd,2.0.0,MIT
is-path-cwd,1.0.0,MIT
is-path-in-cwd,1.0.0,MIT
is-path-inside,1.0.0,MIT
is-plain-obj,1.1.0,MIT
+is-plain-object,2.0.4,MIT
is-posix-bracket,0.1.1,MIT
is-primitive,2.0.0,MIT
+is-promise,2.1.0,MIT
is-property,1.0.2,MIT
is-redirect,1.0.0,MIT
is-regex,1.0.4,MIT
is-relative,0.2.1,MIT
is-resolvable,1.0.0,MIT
is-retry-allowed,1.1.0,MIT
+is-root,1.0.0,MIT
is-stream,1.1.0,MIT
is-svg,2.1.0,MIT
is-symbol,1.0.1,MIT
@@ -764,12 +855,16 @@ is-typedarray,1.0.0,MIT
is-unc-path,0.1.2,MIT
is-utf8,0.2.1,MIT
is-windows,0.2.0,MIT
+is-windows,1.0.2,MIT
+is-wsl,1.1.0,MIT
isarray,0.0.1,MIT
isarray,1.0.0,MIT
isarray,2.0.1,MIT
isbinaryfile,3.0.2,MIT
isexe,1.1.2,ISC
+isexe,2.0.0,ISC
isobject,2.1.0,MIT
+isobject,3.0.1,MIT
isstream,0.1.2,MIT
istanbul,0.4.5,New BSD
istanbul-api,1.2.1,New BSD
@@ -784,10 +879,11 @@ jasmine-core,2.9.0,MIT
jasmine-jquery,2.1.1,MIT
jed,1.1.1,MIT
jira-ruby,1.4.1,MIT
-jquery,2.2.4,MIT
+jquery,3.3.1,MIT
jquery-atwho-rails,1.3.2,MIT
jquery-rails,4.3.1,MIT
jquery-ujs,1.2.2,MIT
+jquery.waitforimages,2.2.0,MIT
js-base64,2.1.9,New BSD
js-cookie,2.1.3,MIT
js-tokens,3.0.2,MIT
@@ -806,7 +902,6 @@ json-stable-stringify,1.0.1,MIT
json-stringify-safe,5.0.1,ISC
json3,3.3.2,MIT
json5,0.5.1,MIT
-jsonfile,2.4.0,MIT
jsonify,0.0.0,Public Domain
jsonparse,1.3.1,MIT
jsonpointer,4.0.1,MIT
@@ -820,18 +915,23 @@ kaminari-activerecord,1.0.1,MIT
kaminari-core,1.0.1,MIT
karma,2.0.0,MIT
karma-chrome-launcher,2.2.0,MIT
-karma-coverage-istanbul-reporter,1.3.3,MIT
+karma-coverage-istanbul-reporter,1.4.1,MIT
karma-jasmine,1.1.1,MIT
karma-mocha-reporter,2.2.5,MIT
karma-sourcemap-loader,0.3.7,MIT
karma-webpack,2.0.7,MIT
+katex,0.8.3,MIT
kgio,2.10.0,LGPL-2.1+
-kind-of,3.1.0,MIT
-klaw,1.3.1,MIT
+killable,1.0.0,ISC
+kind-of,3.2.2,MIT
+kind-of,4.0.0,MIT
+kind-of,5.1.0,MIT
+kind-of,6.0.2,MIT
kubeclient,2.2.0,MIT
labeled-stream-splicer,2.0.0,MIT
-latest-version,1.0.1,MIT
+latest-version,3.1.0,MIT
lazy-cache,1.0.4,MIT
+lazy-cache,2.0.2,MIT
lcid,1.0.0,MIT
levn,0.3.0,MIT
lexical-scope,1.2.0,MIT
@@ -850,37 +950,31 @@ locale,2.1.2,"ruby,LGPLv3+"
locate-path,2.0.0,MIT
lodash,3.10.1,MIT
lodash,4.17.4,MIT
-lodash._baseassign,3.2.0,MIT
-lodash._basecopy,3.0.1,MIT
+lodash,4.17.5,MIT
lodash._baseget,3.7.2,MIT
-lodash._bindcallback,3.0.1,MIT
-lodash._createassigner,3.1.1,MIT
-lodash._getnative,3.9.1,MIT
-lodash._isiterateecall,3.0.9,MIT
lodash._topath,3.8.1,MIT
-lodash.assign,3.2.0,MIT
lodash.camelcase,4.1.1,MIT
lodash.camelcase,4.3.0,MIT
lodash.capitalize,4.2.1,MIT
lodash.clonedeep,4.5.0,MIT
lodash.cond,4.5.2,MIT
lodash.deburr,4.1.0,MIT
-lodash.defaults,3.1.2,MIT
+lodash.endswith,4.2.1,MIT
lodash.escaperegexp,4.1.2,MIT
lodash.get,3.7.0,MIT
-lodash.isarguments,3.1.0,MIT
lodash.isarray,3.0.4,MIT
+lodash.isfunction,3.0.9,MIT
+lodash.isstring,4.0.1,MIT
lodash.kebabcase,4.0.1,MIT
-lodash.keys,3.1.2,MIT
lodash.memoize,3.0.4,MIT
lodash.memoize,4.1.2,MIT
lodash.mergewith,4.6.0,MIT
-lodash.restparam,3.6.1,MIT
lodash.snakecase,4.0.1,MIT
+lodash.startswith,4.2.1,MIT
lodash.uniq,4.5.0,MIT
lodash.words,4.2.0,MIT
log-symbols,2.1.0,MIT
-log4js,2.4.1,Apache 2.0
+log4js,2.5.3,Apache 2.0
logging,2.2.2,MIT
loggly,1.1.1,MIT
loglevel,1.4.1,MIT
@@ -890,7 +984,6 @@ loofah,2.0.3,MIT
loose-envify,1.3.1,MIT
loud-rejection,1.6.0,MIT
lowercase-keys,1.0.0,MIT
-lru-cache,2.2.4,MIT
lru-cache,2.6.5,ISC
lru-cache,4.1.1,ISC
macaddress,0.2.8,MIT
@@ -899,10 +992,14 @@ mail_room,0.9.1,MIT
mailcomposer,4.0.1,MIT
mailgun-js,0.7.15,MIT
make-dir,1.0.0,MIT
+map-cache,0.2.2,MIT
map-obj,1.0.1,MIT
map-stream,0.1.0,Unknown
+map-visit,1.0.0,MIT
marked,0.3.12,MIT
+match-at,0.1.1,MIT
math-expression-evaluator,1.2.16,MIT
+md5.js,1.3.4,MIT
media-typer,0.3.0,MIT
mem,1.1.0,MIT
memoist,0.16.0,MIT
@@ -913,14 +1010,13 @@ merge-descriptors,1.0.1,MIT
method_source,0.8.2,MIT
methods,1.1.2,MIT
micromatch,2.3.11,MIT
-miller-rabin,4.0.0,MIT
-mime,1.3.4,MIT
+micromatch,3.1.6,MIT
+miller-rabin,4.0.1,MIT
+mime,1.4.1,MIT
mime,1.6.0,MIT
-mime-db,1.27.0,MIT
mime-db,1.29.0,MIT
-mime-db,1.30.0,MIT
-mime-types,2.1.15,MIT
-mime-types,2.1.17,MIT
+mime-db,1.33.0,MIT
+mime-types,2.1.18,MIT
mime-types,3.1,MIT
mime-types-data,3.2016.0521,MIT
mimemagic,0.3.0,MIT
@@ -929,19 +1025,24 @@ mimic-response,1.0.0,MIT
mini_mime,0.1.4,MIT
mini_portile2,2.3.0,MIT
minimalistic-assert,1.0.0,ISC
+minimalistic-crypto-utils,1.0.1,MIT
minimatch,3.0.3,ISC
minimatch,3.0.4,ISC
+minimist,0.0.10,MIT
minimist,0.0.8,MIT
minimist,1.2.0,MIT
+mississippi,2.0.0,Simplified BSD
+mixin-deep,1.3.1,MIT
mkdirp,0.5.1,MIT
module-deps,4.1.1,MIT
moment,2.19.2,MIT
monaco-editor,0.10.0,MIT
mousetrap,1.4.6,Apache 2.0
mousetrap-rails,1.4.6,"MIT,Apache"
+move-concurrently,1.0.1,ISC
ms,0.7.1,MIT
ms,2.0.0,MIT
-multi_json,1.12.2,MIT
+multi_json,1.13.1,MIT
multi_xml,0.6.0,MIT
multicast-dns,6.1.1,MIT
multicast-dns-service-types,1.1.0,MIT
@@ -949,21 +1050,21 @@ multipart-post,2.0.0,MIT
mustermann,1.0.0,MIT
mustermann-grape,1.0.0,MIT
mute-stream,0.0.5,ISC
+mute-stream,0.0.7,ISC
mysql2,0.4.10,MIT
name-all-modules-plugin,1.0.1,MIT
-nan,2.6.2,MIT
+nan,2.8.0,MIT
+nanomatch,1.2.9,MIT
natural-compare,1.4.0,MIT
negotiator,0.6.1,MIT
-nested-error-stacks,1.0.2,MIT
net-ldap,0.16.0,MIT
net-ssh,4.1.0,MIT
netmask,1.0.6,MIT
netrc,0.11.0,MIT
-node-dir,0.1.17,MIT
node-forge,0.6.33,New BSD
node-libs-browser,1.1.1,MIT
node-libs-browser,2.0.0,MIT
-node-pre-gyp,0.6.37,New BSD
+node-pre-gyp,0.6.39,New BSD
node-uuid,1.4.8,MIT
nodemailer,2.7.2,MIT
nodemailer-direct-transport,3.3.2,MIT
@@ -972,7 +1073,7 @@ nodemailer-shared,1.1.0,MIT
nodemailer-smtp-pool,2.8.2,MIT
nodemailer-smtp-transport,2.7.2,MIT
nodemailer-wellknown,0.1.10,MIT
-nodemon,1.11.0,MIT
+nodemon,1.15.1,MIT
nokogiri,1.8.2,MIT
nopt,1.0.10,MIT
nopt,3.0.6,ISC
@@ -990,12 +1091,13 @@ numerizer,0.1.1,MIT
oauth,0.5.1,MIT
oauth-sign,0.8.2,Apache 2.0
oauth2,1.4.0,MIT
-object-assign,3.0.0,MIT
object-assign,4.1.1,MIT
object-component,0.0.3,MIT*
-object-inspect,1.3.0,MIT
+object-copy,0.1.0,MIT
object-keys,1.0.11,MIT
+object-visit,1.0.1,MIT
object.omit,2.0.1,MIT
+object.pick,1.3.0,MIT
obuf,1.1.1,MIT
octokit,4.6.2,MIT
oj,2.17.5,MIT
@@ -1021,8 +1123,9 @@ on-finished,2.3.0,MIT
on-headers,1.0.1,MIT
once,1.4.0,ISC
onetime,1.1.0,MIT
+onetime,2.0.1,MIT
opener,1.4.3,(WTFPL OR MIT)
-opn,4.0.2,MIT
+opn,5.2.0,MIT
optimist,0.6.1,MIT
optionator,0.8.2,MIT
org-ruby,0.9.12,MIT
@@ -1035,27 +1138,33 @@ os-homedir,1.0.2,MIT
os-locale,1.4.0,MIT
os-locale,2.1.0,MIT
os-tmpdir,1.0.2,MIT
-osenv,0.1.4,ISC
+osenv,0.1.5,ISC
p-cancelable,0.3.0,MIT
p-finally,1.0.0,MIT
p-limit,1.1.0,MIT
+p-limit,1.2.0,MIT
p-locate,2.0.0,MIT
p-map,1.1.1,MIT
p-timeout,1.2.0,MIT
+p-try,1.0.0,MIT
pac-proxy-agent,1.1.0,MIT
pac-resolver,2.0.0,MIT
-package-json,1.2.0,MIT
+package-json,4.0.1,MIT
pako,0.2.9,MIT
pako,1.0.5,(MIT AND Zlib)
pako,1.0.6,(MIT AND Zlib)
+parallel-transform,1.1.0,MIT
parents,1.0.1,MIT
-parse-asn1,5.0.0,ISC
+parse-asn1,5.1.0,ISC
parse-glob,3.0.4,MIT
parse-json,2.2.0,MIT
+parse-passwd,1.0.0,MIT
parseqs,0.0.5,MIT
parseuri,0.0.5,MIT
-parseurl,1.3.1,MIT
+parseurl,1.3.2,MIT
+pascalcase,0.1.1,MIT
path-browserify,0.0.0,MIT
+path-dirname,1.0.2,MIT
path-exists,2.1.0,MIT
path-exists,3.0.0,MIT
path-is-absolute,1.0.1,MIT
@@ -1067,13 +1176,14 @@ path-proxy,1.0.0,MIT
path-to-regexp,0.1.7,MIT
path-type,1.1.0,MIT
path-type,2.0.0,MIT
+path-type,3.0.0,MIT
pause-stream,0.0.11,Apache 2.0
-pbkdf2,3.0.9,MIT
+pbkdf2,3.0.14,MIT
peek,1.0.1,MIT
peek-gc,0.0.2,MIT
peek-host,1.0.0,MIT
peek-mysql2,1.1.0,MIT
-peek-performance_bar,1.3.0,MIT
+peek-performance_bar,1.3.1,MIT
peek-pg,1.3.0,MIT
peek-rblineprof,0.2.0,MIT
peek-redis,1.2.0,MIT
@@ -1092,10 +1202,12 @@ pkg-up,1.0.0,MIT
pluralize,1.2.1,MIT
po_to_json,1.0.1,MIT
portfinder,1.0.13,MIT
+posix-character-classes,0.1.1,MIT
posix-spawn,0.3.13,MIT
postcss,5.2.16,MIT
postcss,6.0.14,MIT
postcss,6.0.15,MIT
+postcss,6.0.19,MIT
postcss-calc,5.3.1,MIT
postcss-colormin,2.2.2,MIT
postcss-convert-values,2.6.1,MIT
@@ -1116,10 +1228,10 @@ postcss-minify-font-values,1.0.5,MIT
postcss-minify-gradients,1.0.5,MIT
postcss-minify-params,1.2.2,MIT
postcss-minify-selectors,2.1.1,MIT
-postcss-modules-extract-imports,1.0.1,ISC
-postcss-modules-local-by-default,1.1.1,MIT
-postcss-modules-scope,1.0.2,ISC
-postcss-modules-values,1.2.2,ISC
+postcss-modules-extract-imports,1.2.0,ISC
+postcss-modules-local-by-default,1.2.0,MIT
+postcss-modules-scope,1.1.0,ISC
+postcss-modules-values,1.3.0,ISC
postcss-normalize-charset,1.1.1,MIT
postcss-normalize-url,3.0.8,MIT
postcss-ordered-values,2.2.3,MIT
@@ -1140,26 +1252,31 @@ prettier,1.8.2,MIT
prettier,1.9.2,MIT
prismjs,1.6.0,MIT
private,0.1.8,MIT
+process,0.11.10,MIT
process,0.11.9,MIT
process-nextick-args,1.0.7,MIT
+process-nextick-args,2.0.0,MIT
progress,1.1.8,MIT
prometheus-client-mmap,0.9.1,Apache 2.0
-proxy-addr,1.1.5,MIT
+promise-inflight,1.0.1,ISC
+proxy-addr,2.0.3,MIT
proxy-agent,2.0.0,MIT
prr,0.0.0,MIT
ps-tree,1.1.0,MIT
pseudomap,1.0.2,ISC
+pstree.remy,1.1.0,MIT
public-encrypt,4.0.0,MIT
-public_suffix,3.0.0,MIT
+public_suffix,3.0.2,MIT
+pump,2.0.1,MIT
+pumpify,1.4.0,MIT
punycode,1.3.2,MIT
punycode,1.4.1,MIT
pyu-ruby-sasl,0.0.3.3,MIT
q,1.4.1,MIT
q,1.5.0,MIT
-qjobs,1.1.5,MIT
+qjobs,1.2.0,MIT
qs,6.2.3,New BSD
qs,6.4.0,New BSD
-qs,6.5.0,New BSD
qs,6.5.1,New BSD
query-string,4.3.2,MIT
querystring,0.2.0,MIT
@@ -1183,14 +1300,12 @@ railties,4.2.10,MIT
rainbow,2.2.2,MIT
raindrops,0.18.0,LGPL-2.1+
rake,12.3.0,MIT
-randomatic,1.1.6,MIT
-randombytes,2.0.3,MIT
+randomatic,1.1.7,MIT
randombytes,2.0.6,MIT
-randomfill,1.0.3,MIT
+randomfill,1.0.4,MIT
range-parser,1.2.0,MIT
raphael,2.2.7,MIT
raven-js,3.22.1,Simplified BSD
-raw-body,2.2.0,MIT
raw-body,2.3.2,MIT
raw-loader,0.5.1,MIT
rb-fsevent,0.10.2,MIT
@@ -1198,10 +1313,11 @@ rb-inotify,0.9.10,MIT
rbnacl,4.0.2,MIT
rbnacl-libsodium,1.0.11,MIT
rc,1.2.1,(BSD-2-Clause OR MIT OR Apache-2.0)
+rc,1.2.5,(BSD-2-Clause OR MIT OR Apache-2.0)
rdoc,4.2.2,ruby
re2,1.1.1,New BSD
-react-dev-utils,0.5.2,New BSD
-read-all-stream,3.1.0,MIT
+react-dev-utils,5.0.0,MIT
+react-error-overlay,4.0.0,MIT
read-only-stream,2.0.0,MIT
read-pkg,1.1.0,MIT
read-pkg,2.0.0,MIT
@@ -1210,12 +1326,13 @@ read-pkg-up,2.0.0,MIT
readable-stream,1.1.14,MIT
readable-stream,2.0.6,MIT
readable-stream,2.3.3,MIT
+readable-stream,2.3.4,MIT
readdirp,2.1.0,MIT
readline2,1.0.1,MIT
recaptcha,3.0.0,MIT
rechoir,0.6.2,MIT
recursive-open-struct,1.0.0,MIT
-recursive-readdir,2.1.1,MIT
+recursive-readdir,2.2.1,MIT
redcarpet,3.4.0,MIT
redent,1.0.0,MIT
redis,2.8.0,MIT
@@ -1233,9 +1350,11 @@ reduce-function-call,1.0.2,MIT
regenerate,1.3.2,MIT
regenerator-runtime,0.11.0,MIT
regenerator-transform,0.10.1,BSD
-regex-cache,0.4.3,MIT
+regex-cache,0.4.4,MIT
+regex-not,1.0.2,MIT
regexpu-core,1.0.0,MIT
regexpu-core,2.0.0,MIT
+registry-auth-token,3.3.2,MIT
registry-url,3.1.0,MIT
regjsgen,0.2.0,MIT
regjsparser,0.1.5,Simplified BSD
@@ -1243,14 +1362,13 @@ remove-trailing-separator,1.1.0,ISC
repeat-element,1.1.2,MIT
repeat-string,0.2.2,MIT
repeat-string,1.6.1,MIT
-repeating,1.1.3,MIT
repeating,2.0.1,MIT
representable,3.0.4,MIT
request,2.75.0,Apache 2.0
request,2.81.0,Apache 2.0
request,2.83.0,Apache 2.0
request_store,1.3.1,MIT
-requestretry,1.12.2,MIT
+requestretry,1.13.0,MIT
require-all,2.2.0,MIT
require-directory,2.1.1,MIT
require-from-string,1.2.1,MIT
@@ -1258,22 +1376,28 @@ require-main-filename,1.0.1,ISC
require-uncached,1.0.3,MIT
requires-port,1.0.0,MIT
resolve,1.1.7,MIT
-resolve,1.4.0,MIT
resolve,1.5.0,MIT
+resolve-cwd,2.0.0,MIT
+resolve-dir,1.0.1,MIT
resolve-from,1.0.1,MIT
+resolve-from,3.0.0,MIT
+resolve-url,0.2.1,MIT
responders,2.3.0,MIT
rest-client,2.0.0,MIT
restore-cursor,1.0.1,MIT
-resumer,0.0.0,MIT
+restore-cursor,2.0.0,MIT
+ret,0.1.15,MIT
retriable,3.1.1,MIT
right-align,0.1.3,MIT
rimraf,2.6.1,ISC
+rimraf,2.6.2,ISC
rinku,2.0.0,ISC
-ripemd160,1.0.1,New BSD
+ripemd160,2.0.1,MIT
rotp,2.1.2,MIT
rouge,2.2.1,MIT
rqrcode,0.7.0,MIT
rqrcode-rails3,0.1.7,MIT
+ruby-enum,0.7.2,MIT
ruby-fogbugz,0.2.1,MIT
ruby-prof,0.16.2,Simplified BSD
ruby-saml,1.4.1,MIT
@@ -1283,9 +1407,13 @@ rubypants,0.2.0,BSD
rufus-scheduler,3.4.0,MIT
rugged,0.26.0,MIT
run-async,0.1.0,MIT
+run-async,2.3.0,MIT
+run-queue,1.0.3,ISC
rx-lite,3.1.2,Apache 2.0
-safe-buffer,5.0.1,MIT
+rx-lite,4.0.8,Apache 2.0
+rx-lite-aggregates,4.0.8,Apache 2.0
safe-buffer,5.1.1,MIT
+safe-regex,1.1.0,MIT
safe_yaml,1.0.4,MIT
sanitize,2.1.0,MIT
sanitize-html,1.16.3,MIT
@@ -1295,6 +1423,7 @@ sass-rails,5.0.6,MIT
sawyer,0.8.1,MIT
sax,1.2.2,ISC
schema-utils,0.3.0,MIT
+schema-utils,0.4.5,MIT
securecompare,1.0.0,MIT
seed-fu,2.3.7,MIT
select,1.1.2,MIT
@@ -1304,19 +1433,24 @@ select2-rails,3.5.9.3,MIT
selfsigned,1.10.1,MIT
semver,5.0.3,ISC
semver,5.3.0,ISC
+semver,5.5.0,ISC
semver-diff,2.1.0,MIT
-send,0.15.4,MIT
+send,0.16.1,MIT
sentry-raven,2.5.3,Apache 2.0
+serialize-javascript,1.4.0,New BSD
serve-index,1.9.0,MIT
-serve-static,1.12.4,MIT
+serve-static,1.13.1,MIT
set-blocking,2.0.0,ISC
+set-getter,0.1.0,MIT
set-immediate-shim,1.0.1,MIT
+set-value,0.4.3,MIT
+set-value,2.0.0,MIT
setimmediate,1.0.5,MIT
setprototypeof,1.0.3,ISC
+setprototypeof,1.1.0,ISC
settingslogic,2.0.9,MIT
sexp_processor,4.9.0,MIT
-sha.js,2.4.8,MIT
-sha.js,2.4.9,MIT
+sha.js,2.4.10,MIT
shasum,1.0.2,MIT
shebang-command,1.2.0,MIT
shebang-regex,1.0.0,MIT
@@ -1326,64 +1460,72 @@ sidekiq,5.0.5,LGPL
sidekiq-cron,0.6.0,MIT
sidekiq-limit_fetch,3.4.0,MIT
signal-exit,3.0.2,ISC
-signet,0.7.3,Apache 2.0
+signet,0.8.1,Apache 2.0
slack-node,0.2.0,MIT
slack-notifier,1.5.1,MIT
slash,1.0.0,MIT
slice-ansi,0.0.4,MIT
-slide,1.1.6,ISC
smart-buffer,1.1.15,MIT
smtp-connection,2.12.0,MIT
+snapdragon,0.8.1,MIT
+snapdragon-node,2.1.1,MIT
+snapdragon-util,3.0.1,MIT
sntp,1.0.9,BSD
sntp,2.1.0,BSD
socket.io,2.0.4,MIT
socket.io-adapter,1.1.1,MIT
socket.io-client,2.0.4,MIT
socket.io-parser,3.1.2,MIT
-sockjs,0.3.18,MIT
-sockjs-client,1.0.1,MIT
+sockjs,0.3.19,MIT
sockjs-client,1.1.4,MIT
socks,1.1.10,MIT
socks,1.1.9,MIT
socks-proxy-agent,2.1.1,MIT
sort-keys,1.1.2,MIT
-source-list-map,0.1.8,MIT
source-list-map,2.0.0,MIT
source-map,0.2.0,New BSD
source-map,0.4.4,New BSD
+source-map,0.5.0,New BSD
source-map,0.5.6,New BSD
source-map,0.5.7,New BSD
source-map,0.6.1,New BSD
+source-map-resolve,0.5.1,MIT
source-map-support,0.4.18,MIT
+source-map-url,0.4.0,MIT
spdx-correct,1.0.2,Apache 2.0
spdx-expression-parse,1.0.4,(MIT AND CC-BY-3.0)
spdx-license-ids,1.2.2,Unlicense
spdy,3.4.7,MIT
spdy-transport,2.0.20,MIT
split,0.3.3,MIT
+split-string,3.1.0,MIT
sprintf-js,1.0.3,New BSD
sprockets,3.7.1,MIT
sprockets-rails,3.2.1,MIT
sql.js,0.4.0,MIT
srcset,1.0.0,MIT
+sshkey,1.9.0,MIT
sshpk,1.13.1,MIT
+ssri,5.2.4,ISC
state_machines,0.4.0,MIT
state_machines-activemodel,0.4.0,MIT
state_machines-activerecord,0.4.0,MIT
+static-extend,0.1.2,MIT
statuses,1.3.1,MIT
+statuses,1.4.0,MIT
stream-browserify,2.0.1,MIT
stream-combiner,0.0.4,MIT
stream-combiner2,1.1.1,MIT
+stream-each,1.2.2,MIT
stream-http,2.6.3,MIT
-stream-http,2.7.2,MIT
+stream-http,2.8.0,MIT
stream-shift,1.0.0,MIT
stream-splicer,2.0.0,MIT
streamroller,0.7.0,MIT
strict-uri-encode,1.1.0,MIT
-string-length,1.0.1,MIT
string-width,1.0.2,MIT
string-width,2.0.0,MIT
-string.prototype.trim,1.1.2,MIT
+string-width,2.1.1,MIT
string_decoder,0.10.31,MIT
string_decoder,1.0.3,MIT
stringex,2.7.1,MIT
@@ -1395,23 +1537,25 @@ strip-bom,3.0.0,MIT
strip-eof,1.0.0,MIT
strip-indent,1.0.1,MIT
strip-json-comments,2.0.1,MIT
+style-loader,0.20.2,MIT
subarg,1.0.0,MIT
supports-color,2.0.0,MIT
supports-color,3.2.3,MIT
supports-color,4.2.1,MIT
supports-color,4.5.0,MIT
supports-color,5.1.0,MIT
+supports-color,5.2.0,MIT
svg4everybody,2.1.9,CC0-1.0
svgo,0.7.2,MIT
-syntax-error,1.3.0,MIT
+syntax-error,1.4.0,MIT
sys-filesystem,1.1.6,Artistic 2.0
table,3.8.3,New BSD
tapable,0.1.10,MIT
tapable,0.2.8,MIT
-tape,4.8.0,MIT
tar,2.2.1,ISC
-tar-pack,3.4.0,Simplified BSD
+tar-pack,3.4.1,Simplified BSD
temple,0.7.7,MIT
+term-size,1.2.0,MIT
test-exclude,4.1.1,ISC
text,1.3.1,MIT
text-table,0.2.0,MIT
@@ -1427,35 +1571,37 @@ thunky,0.1.0,MIT*
tilt,2.0.6,MIT
time-stamp,2.0.0,MIT
timeago.js,3.0.2,MIT
-timed-out,2.0.0,MIT
timed-out,4.0.1,MIT
timers-browserify,1.4.2,MIT
timers-browserify,2.0.4,MIT
timespan,2.3.0,MIT
timfel-krb5-auth,0.8.3,LGPL
tiny-emitter,2.0.2,MIT
-tmp,0.0.31,MIT
tmp,0.0.33,MIT
to-array,0.1.4,MIT
to-arraybuffer,1.0.1,MIT
to-fast-properties,1.0.3,MIT
to-fast-properties,2.0.0,MIT
-toml-rb,0.3.15,MIT
-touch,1.0.0,ISC
-tough-cookie,2.3.2,New BSD
+to-object-path,0.3.0,MIT
+to-regex,3.0.1,MIT
+to-regex-range,2.1.1,MIT
+toml-rb,1.0.0,MIT
+touch,3.1.0,ISC
tough-cookie,2.3.3,New BSD
traverse,0.6.6,MIT
trim-newlines,1.0.0,MIT
trim-right,1.0.1,MIT
truncato,0.7.10,MIT
+tryer,1.0.0,MIT
tryit,1.0.3,MIT
tsscmp,1.0.5,MIT
tty-browserify,0.0.0,MIT
+tty-browserify,0.0.1,MIT
tunnel-agent,0.4.3,Apache 2.0
tunnel-agent,0.6.0,Apache 2.0
tweetnacl,0.14.5,Unlicense
type-check,0.3.2,MIT
-type-is,1.6.15,MIT
+type-is,1.6.16,MIT
typedarray,0.0.6,MIT
tzinfo,1.2.4,MIT
u2f,0.2.1,MIT
@@ -1465,40 +1611,48 @@ uglify-js,2.8.29,Simplified BSD
uglify-to-browserify,1.0.2,MIT
uglifyjs-webpack-plugin,0.4.6,MIT
uid-number,0.0.6,ISC
-ultron,1.1.0,MIT
+ultron,1.1.1,MIT
umd,3.0.1,MIT
unc-path-regex,0.1.2,MIT
-undefsafe,0.0.3,MIT / http://rem.mit-license.org
+undefsafe,2.0.2,MIT
underscore,1.7.0,MIT
underscore,1.8.3,MIT
unf,0.1.4,BSD
unf_ext,0.0.7.4,MIT
unicorn,5.1.0,ruby
unicorn-worker-killer,0.4.4,ruby
+union-value,1.0.0,MIT
uniq,1.0.1,MIT
uniqid,4.1.1,MIT
uniqs,2.0.0,MIT
+unique-filename,1.1.0,ISC
+unique-slug,2.0.0,ISC
+unique-string,1.0.0,MIT
unpipe,1.0.0,MIT
-update-notifier,0.5.0,Simplified BSD
+unset-value,1.0.0,MIT
+unzip-response,2.0.1,MIT
+upath,1.0.2,MIT
+update-notifier,2.3.0,Simplified BSD
+urix,0.1.0,MIT
url,0.11.0,MIT
-url-loader,0.5.8,MIT
+url-loader,0.6.2,MIT
url-parse,1.0.5,MIT
-url-parse,1.1.7,MIT
url-parse,1.1.9,MIT
url-parse-lax,1.0.0,MIT
url-to-options,1.0.1,MIT
url_safe_base64,0.2.2,MIT
+use,2.0.2,MIT
user-home,2.0.0,MIT
-useragent,2.2.1,MIT
+useragent,2.3.0,MIT
util,0.10.3,MIT
util-deprecate,1.0.2,MIT
-utils-merge,1.0.0,MIT
-uuid,2.0.3,MIT
-uuid,3.1.0,MIT
-uws,0.14.5,Zlib
+utils-merge,1.0.1,MIT
+uuid,3.2.1,MIT
+uws,9.14.0,Zlib
validate-npm-package-license,3.0.1,Apache 2.0
validates_hostname,1.0.6,MIT
vary,1.1.1,MIT
+vary,1.1.2,MIT
vendors,1.0.1,MIT
verror,1.10.0,MIT
version_sorter,2.1.0,MIT
@@ -1510,21 +1664,20 @@ void-elements,2.0.1,MIT
vue,2.5.13,MIT
vue-eslint-parser,2.0.1,MIT
vue-hot-reload-api,2.2.4,MIT
-vue-loader,13.7.0,MIT
+vue-loader,14.1.1,MIT
vue-resource,1.3.5,MIT
vue-router,3.0.1,MIT
-vue-style-loader,3.0.3,MIT
+vue-style-loader,4.0.2,MIT
vue-template-compiler,2.5.13,MIT
vue-template-es2015-compiler,1.6.0,MIT
vuex,3.0.1,MIT
warden,1.2.6,MIT
watchpack,1.4.0,MIT
wbuf,1.7.2,MIT
-webpack,3.5.5,MIT
-webpack-bundle-analyzer,2.8.2,MIT
-webpack-dev-middleware,1.11.0,MIT
+webpack,3.11.0,MIT
+webpack-bundle-analyzer,2.10.0,MIT
webpack-dev-middleware,1.12.2,MIT
-webpack-dev-server,2.7.1,MIT
+webpack-dev-server,2.11.2,MIT
webpack-rails,0.9.10,MIT
webpack-sources,1.0.1,MIT
webpack-stats-plugin,0.1.5,MIT
@@ -1533,9 +1686,11 @@ websocket-extensions,0.1.1,MIT
when,3.7.8,MIT
whet.extend,0.9.9,MIT
which,1.2.12,ISC
+which,1.3.0,ISC
which-module,1.0.0,ISC
which-module,2.0.0,ISC
wide-align,1.1.2,ISC
+widest-line,2.0.0,MIT
wikicloth,0.8.1,MIT
window-size,0.1.0,MIT
wordwrap,0.0.2,MIT
@@ -1545,15 +1700,16 @@ worker-loader,1.1.0,MIT
wrap-ansi,2.1.0,MIT
wrappy,1.0.2,ISC
write,0.2.1,MIT
-write-file-atomic,1.3.4,ISC
-ws,2.3.1,MIT
+write-file-atomic,2.3.0,ISC
ws,3.3.3,MIT
-xdg-basedir,2.0.0,MIT
+ws,4.0.0,MIT
+xdg-basedir,3.0.0,MIT
xml-simple,1.1.5,ruby
xmlhttprequest-ssl,1.5.5,MIT
xregexp,2.0.0,MIT
xtend,4.0.1,MIT
y18n,3.2.1,ISC
+y18n,4.0.0,ISC
yallist,2.1.2,ISC
yargs,3.10.0,MIT
yargs,6.6.0,MIT
diff --git a/vendor/project_templates/express.tar.gz b/vendor/project_templates/express.tar.gz
index 06093deb459..dcf5e4a0416 100644
--- a/vendor/project_templates/express.tar.gz
+++ b/vendor/project_templates/express.tar.gz
Binary files differ
diff --git a/vendor/project_templates/rails.tar.gz b/vendor/project_templates/rails.tar.gz
index 85cc1b6bb78..d4856090ed9 100644
--- a/vendor/project_templates/rails.tar.gz
+++ b/vendor/project_templates/rails.tar.gz
Binary files differ
diff --git a/vendor/project_templates/spring.tar.gz b/vendor/project_templates/spring.tar.gz
index e98d3ce7b8f..6ee7e76f676 100644
--- a/vendor/project_templates/spring.tar.gz
+++ b/vendor/project_templates/spring.tar.gz
Binary files differ
diff --git a/yarn.lock b/yarn.lock
index ab0ad265d81..a2eee3a547d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -54,9 +54,9 @@
lodash "^4.2.0"
to-fast-properties "^2.0.0"
-"@gitlab-org/gitlab-svgs@^1.8.0":
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.8.0.tgz#95d6afa94395860699ddad60a82bd1bbbc2ba89f"
+"@gitlab-org/gitlab-svgs@^1.13.0":
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.13.0.tgz#9e856ef9fa7bbe49b2dce9789187a89e11311215"
"@types/jquery@^2.0.40":
version "2.0.48"