Merge branch 'master' into 61964-unicorn-instrumentation
This commit is contained in:
commit
0393c5059d
|
|
@ -79,3 +79,4 @@ package-lock.json
|
|||
/junit_*.xml
|
||||
/coverage-frontend/
|
||||
jsdoc/
|
||||
**/tmp/rubocop_cache/**
|
||||
|
|
@ -13,10 +13,8 @@ variables:
|
|||
BUILD_ASSETS_IMAGE: "false"
|
||||
|
||||
before_script:
|
||||
- bundle --version
|
||||
- date
|
||||
- source scripts/utils.sh
|
||||
- date
|
||||
- source scripts/prepare_build.sh
|
||||
- date
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Backend Maintainers are the default for all ruby files
|
||||
*.rb @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern @mayra-cabrera
|
||||
*.rake @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern @mayra-cabrera
|
||||
*.rb @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern @mayra-cabrera @reprazent
|
||||
*.rake @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern @mayra-cabrera @reprazent
|
||||
|
||||
# Technical writing team are the default reviewers for everything in `doc/`
|
||||
/doc/ @axil @marcia
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package-and-qa:
|
||||
image: ruby:2.6-alpine
|
||||
stage: qa
|
||||
stage: review # So even if review-deploy failed we can still run this
|
||||
when: manual
|
||||
before_script: []
|
||||
dependencies: []
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@
|
|||
|
||||
.use-pg-10: &use-pg-10
|
||||
services:
|
||||
- postgres:10.7
|
||||
- redis:alpine
|
||||
- name: postgres:10.7
|
||||
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
||||
- name: redis:alpine
|
||||
|
||||
.use-mysql: &use-mysql
|
||||
services:
|
||||
|
|
@ -52,8 +53,10 @@
|
|||
script:
|
||||
- JOB_NAME=( $CI_JOB_NAME )
|
||||
- TEST_TOOL=${JOB_NAME[0]}
|
||||
- export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${TEST_TOOL}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
|
||||
- export KNAPSACK_GENERATE_REPORT=true
|
||||
- TEST_LEVEL=${JOB_NAME[1]}
|
||||
- DATABASE=${JOB_NAME[2]}
|
||||
- export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
|
||||
- export KNAPSACK_GENERATE_REPORT=true KNAPSACK_LOG_LEVEL=debug KNAPSACK_TEST_DIR=spec
|
||||
- export SUITE_FLAKY_RSPEC_REPORT_PATH=${FLAKY_RSPEC_SUITE_REPORT_PATH}
|
||||
- export FLAKY_RSPEC_REPORT_PATH=rspec_flaky/all_${TEST_TOOL}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
|
||||
- export NEW_FLAKY_RSPEC_REPORT_PATH=rspec_flaky/new_${TEST_TOOL}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
|
||||
|
|
@ -63,7 +66,10 @@
|
|||
- '[[ -f $FLAKY_RSPEC_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_REPORT_PATH}'
|
||||
- '[[ -f $NEW_FLAKY_RSPEC_REPORT_PATH ]] || echo "{}" > ${NEW_FLAKY_RSPEC_REPORT_PATH}'
|
||||
- scripts/gitaly-test-spawn
|
||||
- knapsack rspec "--color --format documentation --format RspecJunitFormatter --out junit_rspec.xml"
|
||||
- date
|
||||
- 'export KNAPSACK_TEST_FILE_PATTERN=$(ruby -r./lib/quality/test_level.rb -e "puts Quality::TestLevel.new.pattern(:${TEST_LEVEL})")'
|
||||
- knapsack rspec "--color --format documentation --format RspecJunitFormatter --out junit_rspec.xml --tag level:${TEST_LEVEL} --tag ~geo"
|
||||
- date
|
||||
artifacts:
|
||||
expire_in: 31d
|
||||
when: always
|
||||
|
|
@ -140,19 +146,68 @@ setup-test-env:
|
|||
except:
|
||||
- /(^docs[\/-].*|.*-docs$)/
|
||||
|
||||
rspec-pg:
|
||||
rspec unit pg:
|
||||
<<: *rspec-metadata-pg
|
||||
parallel: 50
|
||||
parallel: 20
|
||||
|
||||
rspec-pg-10:
|
||||
rspec integration pg:
|
||||
<<: *rspec-metadata-pg
|
||||
parallel: 6
|
||||
|
||||
rspec system pg:
|
||||
<<: *rspec-metadata-pg
|
||||
parallel: 24
|
||||
|
||||
rspec unit pg-10:
|
||||
<<: *rspec-metadata-pg-10
|
||||
<<: *only-schedules-master
|
||||
parallel: 50
|
||||
parallel: 20
|
||||
|
||||
rspec-mysql:
|
||||
rspec integration pg-10:
|
||||
<<: *rspec-metadata-pg-10
|
||||
<<: *only-schedules-master
|
||||
parallel: 6
|
||||
|
||||
rspec system pg-10:
|
||||
<<: *rspec-metadata-pg-10
|
||||
<<: *only-schedules-master
|
||||
parallel: 24
|
||||
|
||||
rspec unit mysql:
|
||||
<<: *rspec-metadata-mysql
|
||||
<<: *only-schedules-master
|
||||
parallel: 50
|
||||
parallel: 20
|
||||
|
||||
rspec integration mysql:
|
||||
<<: *rspec-metadata-mysql
|
||||
<<: *only-schedules-master
|
||||
parallel: 6
|
||||
|
||||
rspec system mysql:
|
||||
<<: *rspec-metadata-mysql
|
||||
<<: *only-schedules-master
|
||||
parallel: 24
|
||||
|
||||
.rspec-mysql-on-demand: &rspec-mysql-on-demand
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_MESSAGE =~ /\[run mysql\]/i
|
||||
- $CI_COMMIT_REF_NAME =~ /mysql/
|
||||
|
||||
rspec unit mysql on-demand:
|
||||
<<: *rspec-metadata-mysql
|
||||
<<: *rspec-mysql-on-demand
|
||||
parallel: 20
|
||||
|
||||
rspec integration mysql on-demand:
|
||||
<<: *rspec-metadata-mysql
|
||||
<<: *rspec-mysql-on-demand
|
||||
parallel: 6
|
||||
|
||||
rspec system mysql on-demand:
|
||||
<<: *rspec-metadata-mysql
|
||||
<<: *rspec-mysql-on-demand
|
||||
parallel: 24
|
||||
|
||||
rspec-fast-spec-helper:
|
||||
<<: *rspec-metadata-pg
|
||||
|
|
@ -164,16 +219,17 @@ rspec-fast-spec-helper:
|
|||
script:
|
||||
- export CACHE_CLASSES=true
|
||||
- scripts/gitaly-test-spawn
|
||||
- bin/rspec --color --format documentation --tag quarantine spec/
|
||||
- bin/rspec --color --format documentation --tag quarantine -- spec/
|
||||
|
||||
rspec-pg-quarantine:
|
||||
rspec quarantine pg:
|
||||
<<: *rspec-metadata-pg
|
||||
<<: *rspec-quarantine
|
||||
allow_failure: true
|
||||
|
||||
rspec-mysql-quarantine:
|
||||
rspec quarantine mysql:
|
||||
<<: *rspec-metadata-mysql
|
||||
<<: *rspec-quarantine
|
||||
<<: *only-schedules-master
|
||||
allow_failure: true
|
||||
|
||||
static-analysis:
|
||||
|
|
|
|||
|
|
@ -40,12 +40,12 @@ update-tests-metadata:
|
|||
policy: push
|
||||
script:
|
||||
- retry gem install fog-aws mime-types activesupport rspec_profiling postgres-copy --no-document
|
||||
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec-pg_node_*.json
|
||||
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec_*_pg_node_*.json
|
||||
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH'
|
||||
- rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json
|
||||
- scripts/merge-reports ${FLAKY_RSPEC_SUITE_REPORT_PATH} rspec_flaky/all_*_*.json
|
||||
- FLAKY_RSPEC_GENERATE_REPORT=1 scripts/prune-old-flaky-specs ${FLAKY_RSPEC_SUITE_REPORT_PATH}
|
||||
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH'
|
||||
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $FLAKY_RSPEC_SUITE_REPORT_PATH'
|
||||
- rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json
|
||||
- rm -f rspec_flaky/all_*.json rspec_flaky/new_*.json
|
||||
- scripts/insert-rspec-profiling-data
|
||||
only:
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
inherits_from:
|
||||
- .haml-lint_todo.yml
|
||||
# Whether to ignore frontmatter at the beginning of HAML documents for
|
||||
# frameworks such as Jekyll/Middleman
|
||||
skip_frontmatter: false
|
||||
exclude:
|
||||
- 'vendor/**/*'
|
||||
- 'spec/**/*'
|
||||
require:
|
||||
- './haml_lint/linter/no_plain_nodes.rb'
|
||||
|
||||
linters:
|
||||
AltText:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,523 @@
|
|||
# This configuration was generated by
|
||||
# `haml-lint --auto-gen-config`
|
||||
# on 2019-05-07 19:04:08 +0100 using Haml-Lint version 0.30.0.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the lints are removed from the code base.
|
||||
# Note that changes in the inspected code, or installation of new
|
||||
# versions of Haml-Lint, may require this file to be generated again.
|
||||
|
||||
linters:
|
||||
|
||||
# Offense count: 2075
|
||||
NoPlainNodes:
|
||||
enabled: true
|
||||
exclude:
|
||||
- "app/views/admin/abuse_reports/_abuse_report.html.haml"
|
||||
- "app/views/admin/abuse_reports/index.html.haml"
|
||||
- "app/views/admin/appearances/_form.html.haml"
|
||||
- "app/views/admin/application_settings/_abuse.html.haml"
|
||||
- "app/views/admin/application_settings/_diff_limits.html.haml"
|
||||
- "app/views/admin/application_settings/_gitaly.html.haml"
|
||||
- "app/views/admin/application_settings/_influx.html.haml"
|
||||
- "app/views/admin/application_settings/_ip_limits.html.haml"
|
||||
- "app/views/admin/application_settings/_logging.html.haml"
|
||||
- "app/views/admin/application_settings/_performance.html.haml"
|
||||
- "app/views/admin/application_settings/_plantuml.html.haml"
|
||||
- "app/views/admin/application_settings/_prometheus.html.haml"
|
||||
- "app/views/admin/application_settings/_realtime.html.haml"
|
||||
- "app/views/admin/application_settings/_repository_check.html.haml"
|
||||
- "app/views/admin/application_settings/_repository_storage.html.haml"
|
||||
- "app/views/admin/application_settings/_signin.html.haml"
|
||||
- "app/views/admin/application_settings/_signup.html.haml"
|
||||
- "app/views/admin/application_settings/_spam.html.haml"
|
||||
- "app/views/admin/application_settings/_terminal.html.haml"
|
||||
- "app/views/admin/application_settings/_usage.html.haml"
|
||||
- "app/views/admin/application_settings/_visibility_and_access.html.haml"
|
||||
- "app/views/admin/applications/_delete_form.html.haml"
|
||||
- "app/views/admin/applications/_form.html.haml"
|
||||
- "app/views/admin/applications/edit.html.haml"
|
||||
- "app/views/admin/applications/index.html.haml"
|
||||
- "app/views/admin/applications/new.html.haml"
|
||||
- "app/views/admin/applications/show.html.haml"
|
||||
- "app/views/admin/background_jobs/show.html.haml"
|
||||
- "app/views/admin/broadcast_messages/index.html.haml"
|
||||
- "app/views/admin/dashboard/index.html.haml"
|
||||
- "app/views/admin/deploy_keys/new.html.haml"
|
||||
- "app/views/admin/groups/show.html.haml"
|
||||
- "app/views/admin/health_check/show.html.haml"
|
||||
- "app/views/admin/hook_logs/_index.html.haml"
|
||||
- "app/views/admin/hook_logs/show.html.haml"
|
||||
- "app/views/admin/hooks/_form.html.haml"
|
||||
- "app/views/admin/hooks/edit.html.haml"
|
||||
- "app/views/admin/hooks/index.html.haml"
|
||||
- "app/views/admin/labels/_form.html.haml"
|
||||
- "app/views/admin/logs/show.html.haml"
|
||||
- "app/views/admin/projects/_projects.html.haml"
|
||||
- "app/views/admin/projects/show.html.haml"
|
||||
- "app/views/admin/requests_profiles/index.html.haml"
|
||||
- "app/views/admin/runners/_runner.html.haml"
|
||||
- "app/views/admin/runners/index.html.haml"
|
||||
- "app/views/admin/runners/show.html.haml"
|
||||
- "app/views/admin/services/_form.html.haml"
|
||||
- "app/views/admin/services/index.html.haml"
|
||||
- "app/views/admin/spam_logs/_spam_log.html.haml"
|
||||
- "app/views/admin/spam_logs/index.html.haml"
|
||||
- "app/views/admin/system_info/show.html.haml"
|
||||
- "app/views/admin/users/_access_levels.html.haml"
|
||||
- "app/views/admin/users/_form.html.haml"
|
||||
- "app/views/admin/users/_head.html.haml"
|
||||
- "app/views/admin/users/_profile.html.haml"
|
||||
- "app/views/admin/users/_projects.html.haml"
|
||||
- "app/views/admin/users/new.html.haml"
|
||||
- "app/views/admin/users/projects.html.haml"
|
||||
- "app/views/admin/users/show.html.haml"
|
||||
- "app/views/clusters/clusters/_cluster.html.haml"
|
||||
- "app/views/clusters/clusters/_form.html.haml"
|
||||
- "app/views/clusters/clusters/_gcp_signup_offer_banner.html.haml"
|
||||
- "app/views/clusters/clusters/gcp/_form.html.haml"
|
||||
- "app/views/clusters/clusters/new.html.haml"
|
||||
- "app/views/dashboard/milestones/index.html.haml"
|
||||
- "app/views/dashboard/projects/_blank_state_admin_welcome.html.haml"
|
||||
- "app/views/dashboard/projects/_blank_state_welcome.html.haml"
|
||||
- "app/views/dashboard/projects/_zero_authorized_projects.html.haml"
|
||||
- "app/views/dashboard/snippets/index.html.haml"
|
||||
- "app/views/dashboard/todos/_todo.html.haml"
|
||||
- "app/views/dashboard/todos/index.html.haml"
|
||||
- "app/views/devise/confirmations/almost_there.haml"
|
||||
- "app/views/devise/mailer/_confirmation_instructions_account.html.haml"
|
||||
- "app/views/devise/mailer/_confirmation_instructions_secondary.html.haml"
|
||||
- "app/views/devise/mailer/email_changed.html.haml"
|
||||
- "app/views/devise/mailer/password_change.html.haml"
|
||||
- "app/views/devise/mailer/reset_password_instructions.html.haml"
|
||||
- "app/views/devise/mailer/unlock_instructions.html.haml"
|
||||
- "app/views/devise/passwords/edit.html.haml"
|
||||
- "app/views/devise/sessions/_new_base.html.haml"
|
||||
- "app/views/devise/sessions/_new_crowd.html.haml"
|
||||
- "app/views/devise/sessions/_new_ldap.html.haml"
|
||||
- "app/views/devise/sessions/new.html.haml"
|
||||
- "app/views/devise/sessions/two_factor.html.haml"
|
||||
- "app/views/devise/shared/_omniauth_box.html.haml"
|
||||
- "app/views/devise/shared/_sign_in_link.html.haml"
|
||||
- "app/views/devise/shared/_signup_box.html.haml"
|
||||
- "app/views/devise/shared/_tabs_normal.html.haml"
|
||||
- "app/views/discussions/_discussion.html.haml"
|
||||
- "app/views/discussions/_headline.html.haml"
|
||||
- "app/views/discussions/_notes.html.haml"
|
||||
- "app/views/discussions/_resolve_all.html.haml"
|
||||
- "app/views/doorkeeper/applications/_delete_form.html.haml"
|
||||
- "app/views/doorkeeper/authorized_applications/_delete_form.html.haml"
|
||||
- "app/views/errors/encoding.html.haml"
|
||||
- "app/views/errors/git_not_found.html.haml"
|
||||
- "app/views/errors/omniauth_error.html.haml"
|
||||
- "app/views/errors/precondition_failed.html.haml"
|
||||
- "app/views/events/_commit.html.haml"
|
||||
- "app/views/events/_event_push.atom.haml"
|
||||
- "app/views/events/event/_push.html.haml"
|
||||
- "app/views/groups/_create_chat_team.html.haml"
|
||||
- "app/views/groups/_group_admin_settings.html.haml"
|
||||
- "app/views/groups/group_members/_new_group_member.html.haml"
|
||||
- "app/views/groups/group_members/index.html.haml"
|
||||
- "app/views/groups/labels/edit.html.haml"
|
||||
- "app/views/groups/labels/new.html.haml"
|
||||
- "app/views/groups/milestones/edit.html.haml"
|
||||
- "app/views/groups/milestones/index.html.haml"
|
||||
- "app/views/groups/milestones/new.html.haml"
|
||||
- "app/views/groups/projects.html.haml"
|
||||
- "app/views/groups/runners/edit.html.haml"
|
||||
- "app/views/groups/settings/_advanced.html.haml"
|
||||
- "app/views/groups/settings/_lfs.html.haml"
|
||||
- "app/views/help/_shortcuts.html.haml"
|
||||
- "app/views/help/index.html.haml"
|
||||
- "app/views/help/instance_configuration.html.haml"
|
||||
- "app/views/help/instance_configuration/_gitlab_ci.html.haml"
|
||||
- "app/views/help/instance_configuration/_gitlab_pages.html.haml"
|
||||
- "app/views/help/instance_configuration/_ssh_info.html.haml"
|
||||
- "app/views/help/ui.html.haml"
|
||||
- "app/views/import/bitbucket/status.html.haml"
|
||||
- "app/views/import/bitbucket_server/status.html.haml"
|
||||
- "app/views/instance_statistics/cohorts/_cohorts_table.html.haml"
|
||||
- "app/views/instance_statistics/cohorts/_usage_ping.html.haml"
|
||||
- "app/views/invites/show.html.haml"
|
||||
- "app/views/layouts/_mailer.html.haml"
|
||||
- "app/views/layouts/header/_default.html.haml"
|
||||
- "app/views/layouts/header/_new_dropdown.haml"
|
||||
- "app/views/layouts/mailer/devise.html.haml"
|
||||
- "app/views/layouts/nav/sidebar/_profile.html.haml"
|
||||
- "app/views/layouts/notify.html.haml"
|
||||
- "app/views/notify/_failed_builds.html.haml"
|
||||
- "app/views/notify/_reassigned_issuable_email.html.haml"
|
||||
- "app/views/notify/_removal_notification.html.haml"
|
||||
- "app/views/notify/autodevops_disabled_email.html.haml"
|
||||
- "app/views/notify/changed_milestone_email.html.haml"
|
||||
- "app/views/notify/import_issues_csv_email.html.haml"
|
||||
- "app/views/notify/issue_moved_email.html.haml"
|
||||
- "app/views/notify/member_access_denied_email.html.haml"
|
||||
- "app/views/notify/member_invite_accepted_email.html.haml"
|
||||
- "app/views/notify/member_invite_declined_email.html.haml"
|
||||
- "app/views/notify/member_invited_email.html.haml"
|
||||
- "app/views/notify/new_gpg_key_email.html.haml"
|
||||
- "app/views/notify/new_mention_in_issue_email.html.haml"
|
||||
- "app/views/notify/new_ssh_key_email.html.haml"
|
||||
- "app/views/notify/new_user_email.html.haml"
|
||||
- "app/views/notify/pages_domain_disabled_email.html.haml"
|
||||
- "app/views/notify/pages_domain_enabled_email.html.haml"
|
||||
- "app/views/notify/pages_domain_verification_failed_email.html.haml"
|
||||
- "app/views/notify/pages_domain_verification_succeeded_email.html.haml"
|
||||
- "app/views/notify/pipeline_failed_email.html.haml"
|
||||
- "app/views/notify/pipeline_success_email.html.haml"
|
||||
- "app/views/notify/project_was_exported_email.html.haml"
|
||||
- "app/views/notify/project_was_moved_email.html.haml"
|
||||
- "app/views/notify/project_was_not_exported_email.html.haml"
|
||||
- "app/views/notify/push_to_merge_request_email.html.haml"
|
||||
- "app/views/notify/remote_mirror_update_failed_email.html.haml"
|
||||
- "app/views/notify/removed_milestone_issue_email.html.haml"
|
||||
- "app/views/notify/removed_milestone_merge_request_email.html.haml"
|
||||
- "app/views/notify/repository_push_email.html.haml"
|
||||
- "app/views/peek/views/_gc.html.haml"
|
||||
- "app/views/peek/views/_redis.html.haml"
|
||||
- "app/views/peek/views/_sidekiq.html.haml"
|
||||
- "app/views/profiles/_event_table.html.haml"
|
||||
- "app/views/profiles/active_sessions/_active_session.html.haml"
|
||||
- "app/views/profiles/active_sessions/index.html.haml"
|
||||
- "app/views/profiles/audit_log.html.haml"
|
||||
- "app/views/profiles/chat_names/_chat_name.html.haml"
|
||||
- "app/views/profiles/chat_names/index.html.haml"
|
||||
- "app/views/profiles/chat_names/new.html.haml"
|
||||
- "app/views/profiles/emails/index.html.haml"
|
||||
- "app/views/profiles/gpg_keys/_key.html.haml"
|
||||
- "app/views/profiles/gpg_keys/index.html.haml"
|
||||
- "app/views/profiles/keys/_key.html.haml"
|
||||
- "app/views/profiles/keys/_key_details.html.haml"
|
||||
- "app/views/profiles/keys/index.html.haml"
|
||||
- "app/views/profiles/notifications/show.html.haml"
|
||||
- "app/views/profiles/passwords/edit.html.haml"
|
||||
- "app/views/profiles/personal_access_tokens/index.html.haml"
|
||||
- "app/views/profiles/preferences/show.html.haml"
|
||||
- "app/views/profiles/show.html.haml"
|
||||
- "app/views/profiles/two_factor_auths/_codes.html.haml"
|
||||
- "app/views/profiles/two_factor_auths/codes.html.haml"
|
||||
- "app/views/profiles/two_factor_auths/create.html.haml"
|
||||
- "app/views/profiles/two_factor_auths/show.html.haml"
|
||||
- "app/views/projects/_bitbucket_import_modal.html.haml"
|
||||
- "app/views/projects/_customize_workflow.html.haml"
|
||||
- "app/views/projects/_deletion_failed.html.haml"
|
||||
- "app/views/projects/_fork_suggestion.html.haml"
|
||||
- "app/views/projects/_gitlab_import_modal.html.haml"
|
||||
- "app/views/projects/_home_panel.html.haml"
|
||||
- "app/views/projects/_import_project_pane.html.haml"
|
||||
- "app/views/projects/_issuable_by_email.html.haml"
|
||||
- "app/views/projects/_md_preview.html.haml"
|
||||
- "app/views/projects/_new_project_fields.html.haml"
|
||||
- "app/views/projects/_readme.html.haml"
|
||||
- "app/views/projects/artifacts/_tree_file.html.haml"
|
||||
- "app/views/projects/artifacts/browse.html.haml"
|
||||
- "app/views/projects/blame/_age_map_legend.html.haml"
|
||||
- "app/views/projects/blame/show.html.haml"
|
||||
- "app/views/projects/blob/_editor.html.haml"
|
||||
- "app/views/projects/blob/_header_content.html.haml"
|
||||
- "app/views/projects/blob/_new_dir.html.haml"
|
||||
- "app/views/projects/blob/_remove.html.haml"
|
||||
- "app/views/projects/blob/_render_error.html.haml"
|
||||
- "app/views/projects/blob/_template_selectors.html.haml"
|
||||
- "app/views/projects/blob/_upload.html.haml"
|
||||
- "app/views/projects/blob/edit.html.haml"
|
||||
- "app/views/projects/blob/new.html.haml"
|
||||
- "app/views/projects/blob/preview.html.haml"
|
||||
- "app/views/projects/blob/viewers/_empty.html.haml"
|
||||
- "app/views/projects/blob/viewers/_stl.html.haml"
|
||||
- "app/views/projects/branches/_branch.html.haml"
|
||||
- "app/views/projects/branches/_commit.html.haml"
|
||||
- "app/views/projects/branches/_delete_protected_modal.html.haml"
|
||||
- "app/views/projects/branches/new.html.haml"
|
||||
- "app/views/projects/ci/builds/_build.html.haml"
|
||||
- "app/views/projects/ci/lints/_create.html.haml"
|
||||
- "app/views/projects/commit/_change.html.haml"
|
||||
- "app/views/projects/commits/_commit.html.haml"
|
||||
- "app/views/projects/commits/_inline_commit.html.haml"
|
||||
- "app/views/projects/compare/_form.html.haml"
|
||||
- "app/views/projects/compare/index.html.haml"
|
||||
- "app/views/projects/cycle_analytics/_empty_stage.html.haml"
|
||||
- "app/views/projects/cycle_analytics/_no_access.html.haml"
|
||||
- "app/views/projects/cycle_analytics/_overview.html.haml"
|
||||
- "app/views/projects/cycle_analytics/show.html.haml"
|
||||
- "app/views/projects/deploy_keys/_form.html.haml"
|
||||
- "app/views/projects/deploy_keys/_index.html.haml"
|
||||
- "app/views/projects/deploy_keys/edit.html.haml"
|
||||
- "app/views/projects/deploy_tokens/_revoke_modal.html.haml"
|
||||
- "app/views/projects/deploy_tokens/_table.html.haml"
|
||||
- "app/views/projects/deployments/_deployment.html.haml"
|
||||
- "app/views/projects/diffs/_file_header.html.haml"
|
||||
- "app/views/projects/diffs/_replaced_image_diff.html.haml"
|
||||
- "app/views/projects/diffs/_stats.html.haml"
|
||||
- "app/views/projects/empty.html.haml"
|
||||
- "app/views/projects/environments/show.html.haml"
|
||||
- "app/views/projects/forks/error.html.haml"
|
||||
- "app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml"
|
||||
- "app/views/projects/graphs/charts.html.haml"
|
||||
- "app/views/projects/hook_logs/_index.html.haml"
|
||||
- "app/views/projects/hook_logs/show.html.haml"
|
||||
- "app/views/projects/hooks/_index.html.haml"
|
||||
- "app/views/projects/hooks/edit.html.haml"
|
||||
- "app/views/projects/imports/new.html.haml"
|
||||
- "app/views/projects/imports/show.html.haml"
|
||||
- "app/views/projects/issues/_issue.html.haml"
|
||||
- "app/views/projects/issues/_new_branch.html.haml"
|
||||
- "app/views/projects/issues/import_csv/_modal.html.haml"
|
||||
- "app/views/projects/issues/show.html.haml"
|
||||
- "app/views/projects/jobs/_header.html.haml"
|
||||
- "app/views/projects/jobs/_table.html.haml"
|
||||
- "app/views/projects/jobs/index.html.haml"
|
||||
- "app/views/projects/labels/edit.html.haml"
|
||||
- "app/views/projects/labels/new.html.haml"
|
||||
- "app/views/projects/mattermosts/_no_teams.html.haml"
|
||||
- "app/views/projects/mattermosts/_team_selection.html.haml"
|
||||
- "app/views/projects/mattermosts/new.html.haml"
|
||||
- "app/views/projects/merge_requests/_commits.html.haml"
|
||||
- "app/views/projects/merge_requests/_discussion.html.haml"
|
||||
- "app/views/projects/merge_requests/_how_to_merge.html.haml"
|
||||
- "app/views/projects/merge_requests/_merge_request.html.haml"
|
||||
- "app/views/projects/merge_requests/_mr_title.html.haml"
|
||||
- "app/views/projects/merge_requests/conflicts/_commit_stats.html.haml"
|
||||
- "app/views/projects/merge_requests/conflicts/_file_actions.html.haml"
|
||||
- "app/views/projects/merge_requests/conflicts/_submit_form.html.haml"
|
||||
- "app/views/projects/merge_requests/conflicts/components/_diff_file_editor.html.haml"
|
||||
- "app/views/projects/merge_requests/conflicts/components/_inline_conflict_lines.html.haml"
|
||||
- "app/views/projects/merge_requests/conflicts/show.html.haml"
|
||||
- "app/views/projects/merge_requests/creations/_diffs.html.haml"
|
||||
- "app/views/projects/merge_requests/creations/_new_compare.html.haml"
|
||||
- "app/views/projects/merge_requests/creations/_new_submit.html.haml"
|
||||
- "app/views/projects/merge_requests/diffs/_different_base.html.haml"
|
||||
- "app/views/projects/merge_requests/diffs/_diffs.html.haml"
|
||||
- "app/views/projects/merge_requests/diffs/_version_controls.html.haml"
|
||||
- "app/views/projects/merge_requests/invalid.html.haml"
|
||||
- "app/views/projects/merge_requests/widget/open/_error.html.haml"
|
||||
- "app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml"
|
||||
- "app/views/projects/mirrors/_ssh_host_keys.html.haml"
|
||||
- "app/views/projects/new.html.haml"
|
||||
- "app/views/projects/no_repo.html.haml"
|
||||
- "app/views/projects/pages/_access.html.haml"
|
||||
- "app/views/projects/pages/_destroy.haml"
|
||||
- "app/views/projects/pages/_https_only.html.haml"
|
||||
- "app/views/projects/pages/_list.html.haml"
|
||||
- "app/views/projects/pages/_no_domains.html.haml"
|
||||
- "app/views/projects/pages/_use.html.haml"
|
||||
- "app/views/projects/pages/show.html.haml"
|
||||
- "app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml"
|
||||
- "app/views/projects/pipelines/_info.html.haml"
|
||||
- "app/views/projects/pipelines/charts/_pipelines.haml"
|
||||
- "app/views/projects/protected_branches/shared/_branches_list.html.haml"
|
||||
- "app/views/projects/protected_branches/shared/_create_protected_branch.html.haml"
|
||||
- "app/views/projects/protected_branches/shared/_dropdown.html.haml"
|
||||
- "app/views/projects/protected_branches/shared/_index.html.haml"
|
||||
- "app/views/projects/protected_branches/shared/_matching_branch.html.haml"
|
||||
- "app/views/projects/protected_branches/shared/_protected_branch.html.haml"
|
||||
- "app/views/projects/protected_branches/show.html.haml"
|
||||
- "app/views/projects/protected_tags/shared/_create_protected_tag.html.haml"
|
||||
- "app/views/projects/protected_tags/shared/_dropdown.html.haml"
|
||||
- "app/views/projects/protected_tags/shared/_index.html.haml"
|
||||
- "app/views/projects/protected_tags/shared/_matching_tag.html.haml"
|
||||
- "app/views/projects/protected_tags/shared/_protected_tag.html.haml"
|
||||
- "app/views/projects/protected_tags/shared/_tags_list.html.haml"
|
||||
- "app/views/projects/protected_tags/show.html.haml"
|
||||
- "app/views/projects/registry/repositories/_tag.html.haml"
|
||||
- "app/views/projects/repositories/_feed.html.haml"
|
||||
- "app/views/projects/runners/_shared_runners.html.haml"
|
||||
- "app/views/projects/runners/edit.html.haml"
|
||||
- "app/views/projects/services/_form.html.haml"
|
||||
- "app/views/projects/services/_index.html.haml"
|
||||
- "app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml"
|
||||
- "app/views/projects/services/mattermost_slash_commands/_help.html.haml"
|
||||
- "app/views/projects/services/prometheus/_metrics.html.haml"
|
||||
- "app/views/projects/services/slack_slash_commands/_help.html.haml"
|
||||
- "app/views/projects/settings/ci_cd/_badge.html.haml"
|
||||
- "app/views/projects/settings/ci_cd/_form.html.haml"
|
||||
- "app/views/projects/stage/_stage.html.haml"
|
||||
- "app/views/projects/tags/index.html.haml"
|
||||
- "app/views/projects/tags/new.html.haml"
|
||||
- "app/views/projects/tags/releases/edit.html.haml"
|
||||
- "app/views/projects/tree/_tree_row.html.haml"
|
||||
- "app/views/projects/tree/_truncated_notice_tree_row.html.haml"
|
||||
- "app/views/projects/triggers/_content.html.haml"
|
||||
- "app/views/projects/triggers/_form.html.haml"
|
||||
- "app/views/projects/triggers/_index.html.haml"
|
||||
- "app/views/projects/triggers/_trigger.html.haml"
|
||||
- "app/views/projects/triggers/edit.html.haml"
|
||||
- "app/views/projects/wikis/_new.html.haml"
|
||||
- "app/views/projects/wikis/_pages_wiki_page.html.haml"
|
||||
- "app/views/projects/wikis/edit.html.haml"
|
||||
- "app/views/projects/wikis/history.html.haml"
|
||||
- "app/views/repository_check_mailer/notify.html.haml"
|
||||
- "app/views/search/_form.html.haml"
|
||||
- "app/views/search/results/_issue.html.haml"
|
||||
- "app/views/search/results/_note.html.haml"
|
||||
- "app/views/search/results/_snippet_blob.html.haml"
|
||||
- "app/views/search/results/_snippet_title.html.haml"
|
||||
- "app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml"
|
||||
- "app/views/shared/_commit_message_container.html.haml"
|
||||
- "app/views/shared/_confirm_modal.html.haml"
|
||||
- "app/views/shared/_delete_label_modal.html.haml"
|
||||
- "app/views/shared/_group_form.html.haml"
|
||||
- "app/views/shared/_group_tips.html.haml"
|
||||
- "app/views/shared/_milestone_expired.html.haml"
|
||||
- "app/views/shared/_no_password.html.haml"
|
||||
- "app/views/shared/_no_ssh.html.haml"
|
||||
- "app/views/shared/_outdated_browser.html.haml"
|
||||
- "app/views/shared/_personal_access_tokens_created_container.html.haml"
|
||||
- "app/views/shared/_personal_access_tokens_table.html.haml"
|
||||
- "app/views/shared/_ping_consent.html.haml"
|
||||
- "app/views/shared/_project_limit.html.haml"
|
||||
- "app/views/shared/_service_settings.html.haml"
|
||||
- "app/views/shared/boards/components/_board.html.haml"
|
||||
- "app/views/shared/boards/components/_sidebar.html.haml"
|
||||
- "app/views/shared/boards/components/sidebar/_due_date.html.haml"
|
||||
- "app/views/shared/boards/components/sidebar/_labels.html.haml"
|
||||
- "app/views/shared/boards/components/sidebar/_milestone.html.haml"
|
||||
- "app/views/shared/empty_states/_priority_labels.html.haml"
|
||||
- "app/views/shared/hook_logs/_content.html.haml"
|
||||
- "app/views/shared/issuable/_assignees.html.haml"
|
||||
- "app/views/shared/issuable/_board_create_list_dropdown.html.haml"
|
||||
- "app/views/shared/issuable/_bulk_update_sidebar.html.haml"
|
||||
- "app/views/shared/issuable/_close_reopen_report_toggle.html.haml"
|
||||
- "app/views/shared/issuable/_form.html.haml"
|
||||
- "app/views/shared/issuable/_search_bar.html.haml"
|
||||
- "app/views/shared/issuable/_sidebar.html.haml"
|
||||
- "app/views/shared/issuable/form/_default_templates.html.haml"
|
||||
- "app/views/shared/issuable/form/_issue_assignee.html.haml"
|
||||
- "app/views/shared/issuable/form/_template_selector.html.haml"
|
||||
- "app/views/shared/issuable/form/_title.html.haml"
|
||||
- "app/views/shared/labels/_form.html.haml"
|
||||
- "app/views/shared/members/_member.html.haml"
|
||||
- "app/views/shared/milestones/_form_dates.html.haml"
|
||||
- "app/views/shared/milestones/_issuable.html.haml"
|
||||
- "app/views/shared/milestones/_milestone.html.haml"
|
||||
- "app/views/shared/milestones/_sidebar.html.haml"
|
||||
- "app/views/shared/milestones/_top.html.haml"
|
||||
- "app/views/shared/notes/_hints.html.haml"
|
||||
- "app/views/shared/notes/_note.html.haml"
|
||||
- "app/views/shared/notifications/_button.html.haml"
|
||||
- "app/views/shared/notifications/_custom_notifications.html.haml"
|
||||
- "app/views/shared/notifications/_new_button.html.haml"
|
||||
- "app/views/shared/notifications/_notification_dropdown.html.haml"
|
||||
- "app/views/shared/plugins/_index.html.haml"
|
||||
- "app/views/shared/projects/_dropdown.html.haml"
|
||||
- "app/views/shared/projects/_list.html.haml"
|
||||
- "app/views/shared/projects/_project.html.haml"
|
||||
- "app/views/shared/runners/_runner_description.html.haml"
|
||||
- "app/views/shared/runners/show.html.haml"
|
||||
- "app/views/shared/snippets/_embed.html.haml"
|
||||
- "app/views/shared/snippets/_header.html.haml"
|
||||
- "app/views/shared/snippets/_snippet.html.haml"
|
||||
- "app/views/shared/tokens/_scopes_list.html.haml"
|
||||
- "app/views/shared/web_hooks/_form.html.haml"
|
||||
- "app/views/shared/web_hooks/_test_button.html.haml"
|
||||
- "app/views/u2f/_authenticate.html.haml"
|
||||
- "app/views/u2f/_register.html.haml"
|
||||
- "app/views/users/_deletion_guidance.html.haml"
|
||||
- "ee/app/views/admin/_namespace_plan_info.html.haml"
|
||||
- "ee/app/views/admin/application_settings/_elasticsearch_form.html.haml"
|
||||
- "ee/app/views/admin/application_settings/_slack.html.haml"
|
||||
- "ee/app/views/admin/application_settings/_snowplow.html.haml"
|
||||
- "ee/app/views/admin/application_settings/_templates.html.haml"
|
||||
- "ee/app/views/admin/audit_logs/index.html.haml"
|
||||
- "ee/app/views/admin/dashboard/stats.html.haml"
|
||||
- "ee/app/views/admin/emails/show.html.haml"
|
||||
- "ee/app/views/admin/geo/nodes/edit.html.haml"
|
||||
- "ee/app/views/admin/geo/nodes/new.html.haml"
|
||||
- "ee/app/views/admin/geo/projects/_registry_failed.html.haml"
|
||||
- "ee/app/views/admin/geo/projects/_registry_never.html.haml"
|
||||
- "ee/app/views/admin/licenses/_breakdown.html.haml"
|
||||
- "ee/app/views/admin/licenses/_upload_trial_license.html.haml"
|
||||
- "ee/app/views/admin/licenses/missing.html.haml"
|
||||
- "ee/app/views/admin/licenses/new.html.haml"
|
||||
- "ee/app/views/admin/licenses/show.html.haml"
|
||||
- "ee/app/views/admin/monitoring/ee/_nav.html.haml"
|
||||
- "ee/app/views/admin/projects/_shared_runner_status.html.haml"
|
||||
- "ee/app/views/admin/push_rules/show.html.haml"
|
||||
- "ee/app/views/admin/users/_limits.html.haml"
|
||||
- "ee/app/views/admin/users/_user_detail_note.html.haml"
|
||||
- "ee/app/views/dashboard/projects/_blank_state_ee_trial.html.haml"
|
||||
- "ee/app/views/errors/kerberos_denied.html.haml"
|
||||
- "ee/app/views/groups/analytics/show.html.haml"
|
||||
- "ee/app/views/groups/audit_events/index.html.haml"
|
||||
- "ee/app/views/groups/ee/_settings_nav.html.haml"
|
||||
- "ee/app/views/groups/epics/_epic.html.haml"
|
||||
- "ee/app/views/groups/group_members/_ldap_sync.html.haml"
|
||||
- "ee/app/views/groups/group_members/_sync_button.html.haml"
|
||||
- "ee/app/views/groups/hooks/_project_hook.html.haml"
|
||||
- "ee/app/views/groups/hooks/index.html.haml"
|
||||
- "ee/app/views/groups/ldap_group_links/index.html.haml"
|
||||
- "ee/app/views/groups/pipeline_quota/index.html.haml"
|
||||
- "ee/app/views/jira_connect/subscriptions/index.html.haml"
|
||||
- "ee/app/views/layouts/jira_connect.html.haml"
|
||||
- "ee/app/views/layouts/nav/ee/_epic_link.html.haml"
|
||||
- "ee/app/views/layouts/nav/ee/admin/_new_monitoring_sidebar.html.haml"
|
||||
- "ee/app/views/layouts/service_desk.html.haml"
|
||||
- "ee/app/views/ldap_group_links/_form.html.haml"
|
||||
- "ee/app/views/ldap_group_links/_ldap_group_link.html.haml"
|
||||
- "ee/app/views/ldap_group_links/_ldap_group_links.html.haml"
|
||||
- "ee/app/views/ldap_group_links/_ldap_group_links_show.html.haml"
|
||||
- "ee/app/views/ldap_group_links/_ldap_group_links_synchronizations.html.haml"
|
||||
- "ee/app/views/namespaces/_shared_runner_status.html.haml"
|
||||
- "ee/app/views/namespaces/_shared_runners_minutes_setting.html.haml"
|
||||
- "ee/app/views/namespaces/pipelines_quota/_extra_shared_runners_minutes_quota.html.haml"
|
||||
- "ee/app/views/namespaces/pipelines_quota/_list.haml"
|
||||
- "ee/app/views/notify/approved_merge_request_email.html.haml"
|
||||
- "ee/app/views/notify/epic_status_changed_email.html.haml"
|
||||
- "ee/app/views/notify/issues_csv_email.html.haml"
|
||||
- "ee/app/views/notify/new_review_email.html.haml"
|
||||
- "ee/app/views/notify/prometheus_alert_fired_email.html.haml"
|
||||
- "ee/app/views/notify/send_admin_notification.html.haml"
|
||||
- "ee/app/views/notify/send_unsubscribed_notification.html.haml"
|
||||
- "ee/app/views/notify/unapproved_merge_request_email.html.haml"
|
||||
- "ee/app/views/oauth/geo_auth/error.html.haml"
|
||||
- "ee/app/views/profiles/pipeline_quota/index.haml"
|
||||
- "ee/app/views/projects/audit_events/index.html.haml"
|
||||
- "ee/app/views/projects/blob/_owners.html.haml"
|
||||
- "ee/app/views/projects/commits/_mirror_status.html.haml"
|
||||
- "ee/app/views/projects/feature_flags/_configure_feature_flags_modal.html.haml"
|
||||
- "ee/app/views/projects/issues/_issue_weight.html.haml"
|
||||
- "ee/app/views/projects/issues/_related_issues.html.haml"
|
||||
- "ee/app/views/projects/issues/export_csv/_modal.html.haml"
|
||||
- "ee/app/views/projects/jobs/_shared_runner_limit_warning.html.haml"
|
||||
- "ee/app/views/projects/merge_requests/_approvals_count.html.haml"
|
||||
- "ee/app/views/projects/merge_requests/widget/open/_geo.html.haml"
|
||||
- "ee/app/views/projects/mirrors/_mirrored_repositories_count.html.haml"
|
||||
- "ee/app/views/projects/protected_branches/ee/_create_protected_branch.html.haml"
|
||||
- "ee/app/views/projects/protected_branches/ee/_dropdown.html.haml"
|
||||
- "ee/app/views/projects/protected_branches/ee/_fallback_update_protected_branch.html.haml"
|
||||
- "ee/app/views/projects/protected_tags/_protected_tag_extra_create_access_levels.haml"
|
||||
- "ee/app/views/projects/protected_tags/ee/_create_protected_tag.html.haml"
|
||||
- "ee/app/views/projects/push_rules/_index.html.haml"
|
||||
- "ee/app/views/projects/services/gitlab_slack_application/_help.html.haml"
|
||||
- "ee/app/views/projects/services/gitlab_slack_application/_slack_integration_form.html.haml"
|
||||
- "ee/app/views/projects/services/prometheus/_metrics.html.haml"
|
||||
- "ee/app/views/projects/settings/slacks/edit.html.haml"
|
||||
- "ee/app/views/shared/_additional_email_text.html.haml"
|
||||
- "ee/app/views/shared/_geo_info_modal.html.haml"
|
||||
- "ee/app/views/shared/_mirror_update_button.html.haml"
|
||||
- "ee/app/views/shared/_shared_runners_minutes_limit.html.haml"
|
||||
- "ee/app/views/shared/audit_events/_event_table.html.haml"
|
||||
- "ee/app/views/shared/boards/components/_list_weight.html.haml"
|
||||
- "ee/app/views/shared/boards/components/sidebar/_epic.html.haml"
|
||||
- "ee/app/views/shared/ee/_import_form.html.haml"
|
||||
- "ee/app/views/shared/epic/_search_bar.html.haml"
|
||||
- "ee/app/views/shared/issuable/_approvals.html.haml"
|
||||
- "ee/app/views/shared/issuable/_board_create_list_dropdown.html.haml"
|
||||
- "ee/app/views/shared/issuable/_filter_weight.html.haml"
|
||||
- "ee/app/views/shared/issuable/_sidebar_item_epic.haml"
|
||||
- "ee/app/views/shared/members/ee/_ldap_tag.html.haml"
|
||||
- "ee/app/views/shared/members/ee/_override_member_buttons.html.haml"
|
||||
- "ee/app/views/shared/members/ee/_sso_badge.html.haml"
|
||||
- "ee/app/views/shared/milestones/_burndown.html.haml"
|
||||
- "ee/app/views/shared/milestones/_weight.html.haml"
|
||||
- "ee/app/views/shared/promotions/_promote_audit_events.html.haml"
|
||||
- "ee/app/views/shared/promotions/_promote_burndown_charts.html.haml"
|
||||
- "ee/app/views/shared/promotions/_promote_csv_export.html.haml"
|
||||
- "ee/app/views/shared/promotions/_promote_issue_weights.html.haml"
|
||||
- "ee/app/views/shared/promotions/_promote_repository_features.html.haml"
|
||||
- "ee/app/views/shared/promotions/_promote_servicedesk.html.haml"
|
||||
- "ee/app/views/shared/push_rules/_form.html.haml"
|
||||
- "ee/app/views/unsubscribes/show.html.haml"
|
||||
- "ee/app/views/admin/users/_auditor_access_level_radio.html.haml"
|
||||
- "ee/app/views/admin/users/_auditor_user_badge.html.haml"
|
||||
- "ee/app/views/projects/protected_branches/_update_protected_branch.html.haml"
|
||||
185
CHANGELOG.md
185
CHANGELOG.md
|
|
@ -2,6 +2,191 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 11.11.0 (2019-05-22)
|
||||
|
||||
### Security (1 change)
|
||||
|
||||
- Destroy project remote mirrors instead of disabling. !27087
|
||||
|
||||
### Fixed (74 changes, 19 of them are from the community)
|
||||
|
||||
- Don't create a temp reference for branch comparisons within project. !24038
|
||||
- Fix some label links not appearing on group labels page and label title being a link on project labels page. !24060 (Tanya Pazitny)
|
||||
- Fix extra emails for custom notifications. !25607
|
||||
- Rewind IID on Ci::Pipelines. !26490
|
||||
- Fix duplicate merge request pipelines created by Sidekiq worker retry. !26643
|
||||
- Catch and report OpenSSL exceptions while fetching external configuration files in CI::Config. !26750 (Drew Cimino)
|
||||
- stop rendering download links for expired artifacts on the project tags page. !26753 (Drew Cimino)
|
||||
- Format extra help page text like wiki. !26782 (Bastian Blank)
|
||||
- Always show instance configuration link. !26783 (Bastian Blank)
|
||||
- Display maximum artifact size from runtime config. !26784 (Bastian Blank)
|
||||
- Resolve issue where list labels did not have the correct text color on creation. !26794 (Tucker Chapman)
|
||||
- Set release name when adding release notes to an existing tag. !26807
|
||||
- Fix the bug that the project statistics is not updated. !26854 (Hiroyuki Sato)
|
||||
- Client side changes for ListLastCommitsForTree response update. !26880
|
||||
- Fix api group visibility. !26896
|
||||
- Require all templates to use default stages. !26954
|
||||
- Remove a "reopen merge request button" on a "merged" merge request. !26965 (Hiroyuki Sato)
|
||||
- Fix misaligned image diff swipe view. !26969 (ftab)
|
||||
- Add badge-pill class on group member count. !27019
|
||||
- Remove leading / trailing spaces from heading when generating header ids. !27025 (Willian Balmant)
|
||||
- Respect updated_at attribute in notes produced by API calls. !27124 (Ben Gamari)
|
||||
- Fix GitHub project import visibility. !27133 (Daniel Wyatt)
|
||||
- Fixes actions dropdowns in environments page. !27160
|
||||
- Fixes create button background for Environments form. !27161
|
||||
- Display scoped labels in Issue Boards. !27164
|
||||
- Align UrlValidator to validate_url gem implementation. !27194 (Horatiu Eugen Vlad)
|
||||
- Resolve Web IDE template dropdown showing duplicates. !27237
|
||||
- Update GitLab Workhorse to v8.6.0. !27260
|
||||
- Only show in autocomplete when author active. !27292
|
||||
- Remove deadline for Git fsck. !27299
|
||||
- Show prioritized labels to guests. !27307
|
||||
- Properly expire all pipeline caches when pipeline is deleted. !27334
|
||||
- Replaced icon for external URL with doc-text icon. !27365
|
||||
- Add auto direction for issue title. !27378 (Ahmad Haghighi)
|
||||
- fix wiki search result links in titles. !27400 (khm)
|
||||
- Fix system notes timestamp when creating issue in the past. !27406
|
||||
- Fix approvals sometimes being reset after a merge request is rebased. !27446
|
||||
- Fix empty block in MR widget when user doesn't have permission. !27462
|
||||
- Fix wrong use of ActiveRecord in PoolRepository. !27464
|
||||
- Show proper preview for uploaded images in Web IDE. !27471
|
||||
- Resolve Renaming an image via Web IDE corrupts it. !27486
|
||||
- Clean up CarrierWave's import/export files. !27487
|
||||
- Fix autocomplete dropdown for usernames starting with period. !27533 (Jan Beckmann)
|
||||
- Disable password autocomplete in mirror repository form. !27542
|
||||
- Always use internal ID tables in development and production. !27544
|
||||
- Only show the "target branch has advanced" message when the merge request is open. !27588
|
||||
- Resolve Misalignment on suggested changes diff table. !27612
|
||||
- Update Workhorse to v8.7.0. !27630
|
||||
- Fix FE API and IDE handling of '/' relative_url_root. !27635
|
||||
- Hide ScopedBadge overflow notes. !27651
|
||||
- Fix base domain help text update. !27746
|
||||
- Upgrade letter_opener_web to support Rails 5.1. !27829
|
||||
- Fix webpack assets handling when relative url root is '/'. !27909
|
||||
- Fix IDE get file data with '/' as relative root. !27911
|
||||
- Allow a member to have an access level equal to parent group. !27913
|
||||
- Fix issuables state_id nil when importing projects from GitHub. !28027
|
||||
- Fix uploading of LFS tracked file through UI. !28052
|
||||
- Render Next badge only for gitlab.com. !28056
|
||||
- Fix update head pipeline process of Pipelines for merge requests. !28057
|
||||
- Fix visual issues in set status modal. !28147
|
||||
- Use a path for the related merge requests endpoint. !28171
|
||||
- disable SSH key validation in key details view. !28180 (Roger Meier)
|
||||
- Fix MR discussion border missing in chrome sometimes. !28185
|
||||
- Fix Error 500 when inviting user already present. !28198
|
||||
- Remove non-semantic use of `.row` in member listing controls. !28204
|
||||
- Properly handle LFS Batch API response in project import. !28223
|
||||
- Fix project visibility level validation. !28305 (Peter Marko)
|
||||
- Fix incorrect prefix used in new uploads for personal snippets. !28337
|
||||
- Fix Rugged get_tree_entries recursive flag not working. !28494
|
||||
- Fixes next badge being always visible.
|
||||
- Next badge must visible when canary flag is true.
|
||||
- Adds arrow icons to select option in CI/CD settings.
|
||||
- Vertically aligns the play button for stages.
|
||||
- Allow replying to individual notes from API.
|
||||
|
||||
### Changed (19 changes, 3 of them are from the community)
|
||||
|
||||
- Sort by due date and popularity in both directions for Issues and Merge requests. !25502 (Nermin Vehabovic)
|
||||
- Improve pipelines table spacing, add triggerer column. !26136
|
||||
- Allow extra arguments in helm commands when deploying the application in Auto-DevOps.gitlab-ci.yml. !26171 (tortuetorche)
|
||||
- Switch to sassc-rails for faster stylesheet compilation. !26224
|
||||
- Reorganize project merge request settings. !26834
|
||||
- Display a toast message when the Kubernetes runner has successfully upgraded. !27206
|
||||
- Allow guests users to access project releases. !27247
|
||||
- Add help texts to K8 form fields. !27274
|
||||
- Support prometheus for group level clusters. !27280
|
||||
- Include link to raw job log in plain-text emails. !27409
|
||||
- Only escape Markdown emphasis characters in autocomplete when necessary. !27457
|
||||
- Move location of charts/auto-deploy-app -> gitlab-org/charts/auto-deploy-app. !27477
|
||||
- Make canceled jobs not retryable. !27503
|
||||
- Upgrade to Gitaly v1.36.0. !27831
|
||||
- Update deployment event chat notification message. !27972
|
||||
- Upgrade to Gitaly v1.42.0. !28135
|
||||
- Resolve discussion when apply suggestion. !28160
|
||||
- Improve expanding diff to full file performance.
|
||||
- Knative version bump 0.3 -> 0.5. (Chris Baumbauer <cab@cabnetworks.net>)
|
||||
|
||||
### Performance (5 changes)
|
||||
|
||||
- Added list_pages method to avoid loading all wiki pages content. !22801
|
||||
- Add gitaly session id & catfile-cache feature flag. !27472
|
||||
- Add improvements to global search of issues and merge requests. !27817
|
||||
- Disable method replacement in avatar loading. !27866
|
||||
- Fix Blob.lazy always loading all previously-requested blobs when a new request is made.
|
||||
|
||||
### Added (36 changes, 10 of them are from the community)
|
||||
|
||||
- Add time preferences for user. !25381
|
||||
- Added write_repository scope for personal access token. !26021 (Horatiu Eugen Vlad)
|
||||
- Mark disabled pages domains for removal, but don't remove them yet. !26212
|
||||
- Remove pages domains if they weren't verified for 1 week. !26227
|
||||
- Expose pipeline variables via API. !26501 (Agustin Henze <tin@redhat.com>)
|
||||
- Download a folder from repository. !26532 (kiameisomabes)
|
||||
- Remove cleaned up OIDs from database and cache. !26555
|
||||
- Disables kubernetes resources creation if a cluster is not managed. !26565
|
||||
- Add CI_COMMIT_REF_PROTECTED CI variable. !26716 (Jason van den Hurk)
|
||||
- Add new API endpoint to expose a single environment. !26887
|
||||
- Allow Sentry configuration to be passed on gitlab.yml. !27091 (Roger Meier)
|
||||
- CI variables of type file. !27112
|
||||
- Allow linking to a private helm repository by providing credentials, and customisation of repository name. !27123 (Stuart Moore @stjm-cc)
|
||||
- Add time tracking information to Issue Boards sidebar. !27166
|
||||
- Play all manual jobs in a stage. !27188
|
||||
- Instance level kubernetes clusters. !27196
|
||||
- Adds if InfluxDB and Prometheus metrics are enabled to usage ping data. !27238
|
||||
- Autosave description in epics. !27296
|
||||
- Add deployment events to chat notification services. !27338
|
||||
- Add packages_size to ProjectStatistics. !27373
|
||||
- Added OmniAuth OpenID Connect strategy. !27383 (Horatiu Eugen Vlad)
|
||||
- Test using Git 2.21. !27418
|
||||
- Use official Gitea logo in importer. !27424 (Matti Ranta (@techknowlogick))
|
||||
- Add option to set access_level of runners upon registration. !27490 (Zelin L)
|
||||
- Add initial GraphQL query for Groups. !27492
|
||||
- Enable Sidekiq Reliable Fetcher for background jobs by default. !27530
|
||||
- Add backend support for a External Dashboard URL setting. !27550
|
||||
- Implement UI for uninstalling Cluster’s managed apps. !27559
|
||||
- Resolve Salesforce.com omniauth support. !27834
|
||||
- Leave project/group from access granted email. !27892
|
||||
- Allow Sentry client-side DSN to be passed on gitlab.yml. !27967
|
||||
- GraphQL: improve evaluation of query complexity based on arguments and query limits. !28017
|
||||
- Adds badge for Canary environment and help link.
|
||||
- Support negative matches.
|
||||
- Show category icons in user popover.
|
||||
- Added Omniauth UltraAuth strategy to GitLab. (Kartikey Tanna)
|
||||
|
||||
### Other (29 changes, 8 of them are from the community)
|
||||
|
||||
- Validate refs used in controllers don't have spaces. !24037
|
||||
- Migrate correlation and tracing code to LabKit. !25379
|
||||
- Update node.js to 10.15.3 in CI template for Hexo. !25943 (Takuya Noguchi)
|
||||
- Improve icons and button order in project overview. !26796
|
||||
- Add instructions on how to contribute a Built-In template for project. !26976
|
||||
- Extract DiscussionNotes component from NoteableDiscussion. !27066
|
||||
- Bump gRPC to 1.19.0 and protobuf to 3.7.1. !27086
|
||||
- Extract DiscussionActions component from NoteableDiscussion. !27227
|
||||
- Show disabled project repo mirrors in settings. !27326
|
||||
- Add backtrace to Gitaly performance bar. !27345
|
||||
- Moved EE/CE differences for dropdown_value_collapsed into CE. !27367
|
||||
- Remove "You are already signed in" banner. !27377
|
||||
- Move ee-specific code from boards/components/issue_card_inner.vue. !27394 (Roman Rodionov)
|
||||
- Upgrade to Rails 5.1. !27480 (Jasper Maes)
|
||||
- Update GitLab Runner Helm Chart to 0.4.0. !27508
|
||||
- Update GitLab Runner Helm Chart to 0.4.1. !27627
|
||||
- Refactored notes tests from Karma to Jest. !27648 (Martin Hobert)
|
||||
- refactor(issue): Refactored issue tests from Karma to Jest. !27673 (Martin Hobert)
|
||||
- Refactored Karma spec files to Jest. !27688 (Martin Hobert)
|
||||
- Add CSS fix for <wbr> elements on IE11. !27846
|
||||
- Update clair-local-scan to v2.0.8 for container scanning. !27977
|
||||
- Use PostgreSQL 10.7 in tests. !28020
|
||||
- Document EE License Auto Import During Install. !28106
|
||||
- Remove the note in the docs that multi-line suggestions are not yet available. !28119 (hardysim)
|
||||
- Update gitlab-shell to v9.1.0. !28184
|
||||
- Add EE fixtures to SeedFu list. !28241
|
||||
- Replaces CSS with BS4 utility class for pipeline schedules.
|
||||
- Creates a vendors folder for external CSS.
|
||||
- Add some frozen string to spec/**/*.rb. (gfyoung)
|
||||
|
||||
|
||||
## 11.10.4 (2019-05-01)
|
||||
|
||||
### Fixed (12 changes)
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._
|
|||
## Contributing Documentation has been moved
|
||||
|
||||
As of July 2018, all the documentation for contributing to the GitLab project has been moved to a new location.
|
||||
[View the new documentation](doc/development/contributing/index.md) to find the latest information.
|
||||
[View the new documentation](https://about.gitlab.com/community/contribute/) to find the latest information.
|
||||
|
||||
## Contribute to GitLab
|
||||
|
||||
This [documentation](doc/development/contributing/index.md#contribute-to-gitlab) has been moved.
|
||||
[View the new documentation](https://about.gitlab.com/community/contribute/) to find the latest information.
|
||||
|
||||
## Security vulnerability disclosure
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ This [documentation](doc/development/contributing/index.md#helping-others) has b
|
|||
|
||||
## I want to contribute!
|
||||
|
||||
This [documentation](doc/development/contributing/index.md#i-want-to-contribute) has been moved.
|
||||
[View the new documentation](https://about.gitlab.com/community/contribute/) to find the latest information.
|
||||
|
||||
## Contribution Flow
|
||||
|
||||
|
|
|
|||
9
Gemfile
9
Gemfile
|
|
@ -23,7 +23,7 @@ gem 'grape-path-helpers', '~> 1.1'
|
|||
gem 'faraday', '~> 0.12'
|
||||
|
||||
# Authentication libraries
|
||||
gem 'devise', '~> 4.4'
|
||||
gem 'devise', '~> 4.6'
|
||||
gem 'doorkeeper', '~> 4.3'
|
||||
gem 'doorkeeper-openid_connect', '~> 1.5'
|
||||
gem 'omniauth', '~> 1.8'
|
||||
|
|
@ -361,7 +361,7 @@ group :development, :test do
|
|||
|
||||
gem 'scss_lint', '~> 0.56.0', require: false
|
||||
gem 'haml_lint', '~> 0.31.0', require: false
|
||||
gem 'simplecov', '~> 0.14.0', require: false
|
||||
gem 'simplecov', '~> 0.16.1', require: false
|
||||
gem 'bundler-audit', '~> 0.5.0', require: false
|
||||
|
||||
gem 'benchmark-ips', '~> 2.3.0', require: false
|
||||
|
|
@ -372,6 +372,7 @@ group :development, :test do
|
|||
gem 'activerecord_sane_schema_dumper', '1.0'
|
||||
|
||||
gem 'stackprof', '~> 0.2.10', require: false
|
||||
gem 'derailed_benchmarks', require: false
|
||||
|
||||
gem 'simple_po_parser', '~> 1.1.2', require: false
|
||||
|
||||
|
|
@ -379,7 +380,7 @@ group :development, :test do
|
|||
end
|
||||
|
||||
group :test do
|
||||
gem 'shoulda-matchers', '~> 3.1.2', require: false
|
||||
gem 'shoulda-matchers', '~> 4.0.1', require: false
|
||||
gem 'email_spec', '~> 2.2.0'
|
||||
gem 'json-schema', '~> 2.8.0'
|
||||
gem 'webmock', '~> 3.5.1'
|
||||
|
|
@ -399,6 +400,8 @@ gem 'html2text'
|
|||
|
||||
gem 'ruby-prof', '~> 0.17.0'
|
||||
gem 'rbtrace', '~> 0.4', require: false
|
||||
gem 'memory_profiler', '~> 0.9', require: false
|
||||
gem 'benchmark-memory', '~> 0.1', require: false
|
||||
|
||||
# OAuth
|
||||
gem 'oauth2', '~> 1.4'
|
||||
|
|
|
|||
35
Gemfile.lock
35
Gemfile.lock
|
|
@ -82,6 +82,8 @@ GEM
|
|||
bcrypt (3.1.12)
|
||||
bcrypt_pbkdf (1.0.0)
|
||||
benchmark-ips (2.3.0)
|
||||
benchmark-memory (0.1.2)
|
||||
memory_profiler (~> 0.9)
|
||||
better_errors (2.5.0)
|
||||
coderay (>= 1.0.0)
|
||||
erubi (>= 1.0.0)
|
||||
|
|
@ -155,10 +157,18 @@ GEM
|
|||
html-pipeline
|
||||
declarative (0.0.10)
|
||||
declarative-option (0.1.0)
|
||||
derailed_benchmarks (1.3.5)
|
||||
benchmark-ips (~> 2)
|
||||
get_process_mem (~> 0)
|
||||
heapy (~> 0)
|
||||
memory_profiler (~> 0)
|
||||
rack (>= 1)
|
||||
rake (> 10, < 13)
|
||||
thor (~> 0.19)
|
||||
descendants_tracker (0.0.4)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
device_detector (1.0.0)
|
||||
devise (4.4.3)
|
||||
devise (4.6.2)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 4.1.0, < 6.0)
|
||||
|
|
@ -174,7 +184,7 @@ GEM
|
|||
diffy (3.1.0)
|
||||
discordrb-webhooks-blackst0ne (3.3.0)
|
||||
rest-client (~> 2.0)
|
||||
docile (1.1.5)
|
||||
docile (1.3.1)
|
||||
domain_name (0.5.20180417)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
doorkeeper (4.3.2)
|
||||
|
|
@ -377,6 +387,7 @@ GEM
|
|||
hashie (>= 3.0)
|
||||
health_check (2.6.0)
|
||||
rails (>= 4.0)
|
||||
heapy (0.1.4)
|
||||
hipchat (1.5.2)
|
||||
httparty
|
||||
mimemagic
|
||||
|
|
@ -478,6 +489,7 @@ GEM
|
|||
memoist (0.16.0)
|
||||
memoizable (0.4.2)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
memory_profiler (0.9.13)
|
||||
method_source (0.9.2)
|
||||
mime-types (3.2.2)
|
||||
mime-types-data (~> 3.2015)
|
||||
|
|
@ -857,8 +869,8 @@ GEM
|
|||
sexp_processor (4.12.0)
|
||||
sham_rack (1.3.6)
|
||||
rack
|
||||
shoulda-matchers (3.1.2)
|
||||
activesupport (>= 4.0.0)
|
||||
shoulda-matchers (4.0.1)
|
||||
activesupport (>= 4.2.0)
|
||||
sidekiq (5.2.7)
|
||||
connection_pool (~> 2.2, >= 2.2.2)
|
||||
rack (>= 1.5.0)
|
||||
|
|
@ -873,11 +885,11 @@ GEM
|
|||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simple_po_parser (1.1.2)
|
||||
simplecov (0.14.1)
|
||||
docile (~> 1.1.0)
|
||||
simplecov (0.16.1)
|
||||
docile (~> 1.1)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.0)
|
||||
simplecov-html (0.10.2)
|
||||
slack-notifier (1.5.1)
|
||||
spring (2.0.2)
|
||||
activesupport (>= 4.2)
|
||||
|
|
@ -1014,6 +1026,7 @@ DEPENDENCIES
|
|||
batch-loader (~> 1.4.0)
|
||||
bcrypt_pbkdf (~> 1.0)
|
||||
benchmark-ips (~> 2.3.0)
|
||||
benchmark-memory (~> 0.1)
|
||||
better_errors (~> 2.5.0)
|
||||
binding_of_caller (~> 0.8.0)
|
||||
bootsnap (~> 1.4)
|
||||
|
|
@ -1034,8 +1047,9 @@ DEPENDENCIES
|
|||
creole (~> 0.5.0)
|
||||
database_cleaner (~> 1.7.0)
|
||||
deckar01-task_list (= 2.2.0)
|
||||
derailed_benchmarks
|
||||
device_detector
|
||||
devise (~> 4.4)
|
||||
devise (~> 4.6)
|
||||
devise-two-factor (~> 3.0.0)
|
||||
diffy (~> 3.1.0)
|
||||
discordrb-webhooks-blackst0ne (~> 3.3)
|
||||
|
|
@ -1111,6 +1125,7 @@ DEPENDENCIES
|
|||
lograge (~> 0.5)
|
||||
loofah (~> 2.2)
|
||||
mail_room (~> 0.9.1)
|
||||
memory_profiler (~> 0.9)
|
||||
method_source (~> 0.8)
|
||||
mimemagic (~> 0.3.2)
|
||||
mini_magick
|
||||
|
|
@ -1199,11 +1214,11 @@ DEPENDENCIES
|
|||
sentry-raven (~> 2.7)
|
||||
settingslogic (~> 2.0.9)
|
||||
sham_rack (~> 1.3.6)
|
||||
shoulda-matchers (~> 3.1.2)
|
||||
shoulda-matchers (~> 4.0.1)
|
||||
sidekiq (~> 5.2.7)
|
||||
sidekiq-cron (~> 1.0)
|
||||
simple_po_parser (~> 1.1.2)
|
||||
simplecov (~> 0.14.0)
|
||||
simplecov (~> 0.16.1)
|
||||
slack-notifier (~> 1.5.1)
|
||||
spring (~> 2.0.0)
|
||||
spring-commands-rspec (~> 1.0.4)
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.4 KiB |
|
|
@ -1,10 +1,12 @@
|
|||
import { sprintf, __ } from '~/locale';
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
resolveButtonTitle() {
|
||||
let title = 'Mark as resolved';
|
||||
let title = __('Mark comment as resolved');
|
||||
|
||||
if (this.resolvedBy) {
|
||||
title = `Resolved by ${this.resolvedBy.name}`;
|
||||
title = sprintf(__('Resolved by %{name}'), { name: this.resolvedBy.name });
|
||||
}
|
||||
|
||||
return title;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { __ } from '~/locale';
|
||||
|
||||
const notImplemented = () => {
|
||||
throw new Error('Not implemented!');
|
||||
throw new Error(__('Not implemented!'));
|
||||
};
|
||||
|
||||
export default {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import * as mutationTypes from './mutation_types';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
const notImplemented = () => {
|
||||
throw new Error('Not implemented!');
|
||||
throw new Error(__('Not implemented!'));
|
||||
};
|
||||
|
||||
export default {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import Visibility from 'visibilityjs';
|
||||
import Vue from 'vue';
|
||||
import AccessorUtilities from '~/lib/utils/accessor';
|
||||
import { GlToast } from '@gitlab/ui';
|
||||
import PersistentUserCallout from '../persistent_user_callout';
|
||||
import { s__, sprintf } from '../locale';
|
||||
|
|
@ -43,8 +44,10 @@ export default class Clusters {
|
|||
helpPath,
|
||||
ingressHelpPath,
|
||||
ingressDnsHelpPath,
|
||||
clusterId,
|
||||
} = document.querySelector('.js-edit-cluster-form').dataset;
|
||||
|
||||
this.clusterId = clusterId;
|
||||
this.store = new ClustersStore();
|
||||
this.store.setHelpPaths(helpPath, ingressHelpPath, ingressDnsHelpPath);
|
||||
this.store.setManagePrometheusPath(managePrometheusPath);
|
||||
|
|
@ -69,6 +72,10 @@ export default class Clusters {
|
|||
this.errorContainer = document.querySelector('.js-cluster-error');
|
||||
this.successContainer = document.querySelector('.js-cluster-success');
|
||||
this.creatingContainer = document.querySelector('.js-cluster-creating');
|
||||
this.unreachableContainer = document.querySelector('.js-cluster-api-unreachable');
|
||||
this.authenticationFailureContainer = document.querySelector(
|
||||
'.js-cluster-authentication-failure',
|
||||
);
|
||||
this.errorReasonContainer = this.errorContainer.querySelector('.js-error-reason');
|
||||
this.successApplicationContainer = document.querySelector('.js-cluster-application-notice');
|
||||
this.showTokenButton = document.querySelector('.js-show-cluster-token');
|
||||
|
|
@ -125,6 +132,13 @@ export default class Clusters {
|
|||
PersistentUserCallout.factory(callout);
|
||||
}
|
||||
|
||||
addBannerCloseHandler(el, status) {
|
||||
el.querySelector('.js-close-banner').addEventListener('click', () => {
|
||||
el.classList.add('hidden');
|
||||
this.setBannerDismissedState(status, true);
|
||||
});
|
||||
}
|
||||
|
||||
addListeners() {
|
||||
if (this.showTokenButton) this.showTokenButton.addEventListener('click', this.showToken);
|
||||
eventHub.$on('installApplication', this.installApplication);
|
||||
|
|
@ -133,6 +147,9 @@ export default class Clusters {
|
|||
eventHub.$on('saveKnativeDomain', data => this.saveKnativeDomain(data));
|
||||
eventHub.$on('setKnativeHostname', data => this.setKnativeHostname(data));
|
||||
eventHub.$on('uninstallApplication', data => this.uninstallApplication(data));
|
||||
// Add event listener to all the banner close buttons
|
||||
this.addBannerCloseHandler(this.unreachableContainer, 'unreachable');
|
||||
this.addBannerCloseHandler(this.authenticationFailureContainer, 'authentication_failure');
|
||||
}
|
||||
|
||||
removeListeners() {
|
||||
|
|
@ -205,6 +222,8 @@ export default class Clusters {
|
|||
this.errorContainer.classList.add('hidden');
|
||||
this.successContainer.classList.add('hidden');
|
||||
this.creatingContainer.classList.add('hidden');
|
||||
this.unreachableContainer.classList.add('hidden');
|
||||
this.authenticationFailureContainer.classList.add('hidden');
|
||||
}
|
||||
|
||||
checkForNewInstalls(prevApplicationMap, newApplicationMap) {
|
||||
|
|
@ -228,9 +247,32 @@ export default class Clusters {
|
|||
}
|
||||
}
|
||||
|
||||
setBannerDismissedState(status, isDismissed) {
|
||||
if (AccessorUtilities.isLocalStorageAccessSafe()) {
|
||||
window.localStorage.setItem(
|
||||
`cluster_${this.clusterId}_banner_dismissed`,
|
||||
`${status}_${isDismissed}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
isBannerDismissed(status) {
|
||||
let bannerState;
|
||||
if (AccessorUtilities.isLocalStorageAccessSafe()) {
|
||||
bannerState = window.localStorage.getItem(`cluster_${this.clusterId}_banner_dismissed`);
|
||||
}
|
||||
|
||||
return bannerState === `${status}_true`;
|
||||
}
|
||||
|
||||
updateContainer(prevStatus, status, error) {
|
||||
this.hideAll();
|
||||
|
||||
if (this.isBannerDismissed(status)) {
|
||||
return;
|
||||
}
|
||||
this.setBannerDismissedState(status, false);
|
||||
|
||||
// We poll all the time but only want the `created` banner to show when newly created
|
||||
if (this.store.state.status !== 'created' || prevStatus !== this.store.state.status) {
|
||||
switch (status) {
|
||||
|
|
@ -241,6 +283,12 @@ export default class Clusters {
|
|||
this.errorContainer.classList.remove('hidden');
|
||||
this.errorReasonContainer.textContent = error;
|
||||
break;
|
||||
case 'unreachable':
|
||||
this.unreachableContainer.classList.remove('hidden');
|
||||
break;
|
||||
case 'authentication_failure':
|
||||
this.authenticationFailureContainer.classList.remove('hidden');
|
||||
break;
|
||||
case 'scheduled':
|
||||
case 'creating':
|
||||
this.creatingContainer.classList.remove('hidden');
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import 'core-js/fn/array/from';
|
|||
import 'core-js/fn/array/includes';
|
||||
import 'core-js/fn/object/assign';
|
||||
import 'core-js/fn/object/values';
|
||||
import 'core-js/fn/object/entries';
|
||||
import 'core-js/fn/promise';
|
||||
import 'core-js/fn/promise/finally';
|
||||
import 'core-js/fn/string/code-point-at';
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ export default class CreateMergeRequestDropdown {
|
|||
this.branchCreated = true;
|
||||
window.location.href = data.url;
|
||||
})
|
||||
.catch(() => Flash('Failed to create a branch for this issue. Please try again.'));
|
||||
.catch(() => Flash(__('Failed to create a branch for this issue. Please try again.')));
|
||||
}
|
||||
|
||||
createMergeRequest() {
|
||||
|
|
@ -130,7 +130,7 @@ export default class CreateMergeRequestDropdown {
|
|||
this.mergeRequestCreated = true;
|
||||
window.location.href = data.url;
|
||||
})
|
||||
.catch(() => Flash('Failed to create Merge Request. Please try again.'));
|
||||
.catch(() => Flash(__('Failed to create Merge Request. Please try again.')));
|
||||
}
|
||||
|
||||
disable() {
|
||||
|
|
@ -227,7 +227,7 @@ export default class CreateMergeRequestDropdown {
|
|||
.catch(() => {
|
||||
this.unavailable();
|
||||
this.disable();
|
||||
new Flash('Failed to get ref.');
|
||||
new Flash(__('Failed to get ref.'));
|
||||
|
||||
this.isGettingRef = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,15 @@ class DirtySubmitForm {
|
|||
}
|
||||
|
||||
registerListeners() {
|
||||
const throttledUpdateDirtyInput = _.throttle(
|
||||
event => this.updateDirtyInput(event),
|
||||
DirtySubmitForm.THROTTLE_DURATION,
|
||||
const getThrottledHandlerForInput = _.memoize(() =>
|
||||
_.throttle(event => this.updateDirtyInput(event), DirtySubmitForm.THROTTLE_DURATION),
|
||||
);
|
||||
|
||||
const throttledUpdateDirtyInput = event => {
|
||||
const throttledHandler = getThrottledHandlerForInput(event.target.name);
|
||||
throttledHandler(event);
|
||||
};
|
||||
|
||||
this.form.addEventListener('input', throttledUpdateDirtyInput);
|
||||
this.form.addEventListener('change', throttledUpdateDirtyInput);
|
||||
$(this.form).on('change.select2', throttledUpdateDirtyInput);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import _ from 'underscore';
|
|||
import './behaviors/preview_markdown';
|
||||
import csrf from './lib/utils/csrf';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { n__, __ } from '~/locale';
|
||||
|
||||
Dropzone.autoDiscover = false;
|
||||
|
||||
|
|
@ -90,7 +91,7 @@ export default function dropzoneInput(form) {
|
|||
if (!processingFileCount) $attachButton.removeClass('hide');
|
||||
addFileToForm(response.link.url);
|
||||
},
|
||||
error: (file, errorMessage = 'Attaching the file failed.', xhr) => {
|
||||
error: (file, errorMessage = __('Attaching the file failed.'), xhr) => {
|
||||
// If 'error' event is fired by dropzone, the second parameter is error message.
|
||||
// If the 'errorMessage' parameter is empty, the default error message is set.
|
||||
// If the 'error' event is fired by backend (xhr) error response, the third parameter is
|
||||
|
|
@ -273,19 +274,11 @@ export default function dropzoneInput(form) {
|
|||
};
|
||||
|
||||
updateAttachingMessage = (files, messageContainer) => {
|
||||
let attachingMessage;
|
||||
const filesCount = files.filter(file => file.status === 'uploading' || file.status === 'queued')
|
||||
.length;
|
||||
const attachingMessage = n__('Attaching a file', 'Attaching %d files', filesCount);
|
||||
|
||||
// Dinamycally change uploading files text depending on files number in
|
||||
// dropzone files queue.
|
||||
if (filesCount > 1) {
|
||||
attachingMessage = `Attaching ${filesCount} files -`;
|
||||
} else {
|
||||
attachingMessage = 'Attaching a file -';
|
||||
}
|
||||
|
||||
messageContainer.text(attachingMessage);
|
||||
messageContainer.text(`${attachingMessage} -`);
|
||||
};
|
||||
|
||||
form.find('.markdown-selector').click(function onMarkdownClick(e) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import Vue from 'vue';
|
||||
import ErrorTrackingSettings from './components/app.vue';
|
||||
import createStore from './store';
|
||||
import initSettingsPanels from '~/settings_panels';
|
||||
|
||||
export default () => {
|
||||
initSettingsPanels();
|
||||
const formContainerEl = document.querySelector('.js-error-tracking-form');
|
||||
const {
|
||||
dataset: { apiHost, enabled, project, token, listProjectsEndpoint, operationsSettingsEndpoint },
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export default class DropdownUser extends DropdownAjaxFilter {
|
|||
group_id: this.getGroupId(),
|
||||
project_id: this.getProjectId(),
|
||||
current_user: true,
|
||||
...this.projectOrGroupId(),
|
||||
},
|
||||
onLoadingFinished: () => {
|
||||
this.hideCurrentUser();
|
||||
|
|
@ -36,4 +37,17 @@ export default class DropdownUser extends DropdownAjaxFilter {
|
|||
getProjectId() {
|
||||
return this.input.getAttribute('data-project-id');
|
||||
}
|
||||
|
||||
projectOrGroupId() {
|
||||
const projectId = this.getProjectId();
|
||||
const groupId = this.getGroupId();
|
||||
if (groupId) {
|
||||
return {
|
||||
group_id: groupId,
|
||||
};
|
||||
}
|
||||
return {
|
||||
project_id: projectId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -335,6 +335,10 @@ GitLabDropdown = (function() {
|
|||
_this.fullData = data;
|
||||
_this.parseData(_this.fullData);
|
||||
_this.focusTextInput();
|
||||
|
||||
// Update dropdown position since remote data may have changed dropdown size
|
||||
_this.dropdown.find('.dropdown-menu-toggle').dropdown('update');
|
||||
|
||||
if (
|
||||
_this.options.filterable &&
|
||||
_this.filter &&
|
||||
|
|
@ -702,6 +706,10 @@ GitLabDropdown = (function() {
|
|||
}
|
||||
html = document.createElement('li');
|
||||
|
||||
if (rowHidden) {
|
||||
html.style.display = 'none';
|
||||
}
|
||||
|
||||
if (data === 'divider' || data === 'separator') {
|
||||
html.className = data;
|
||||
return html;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import Vue from 'vue';
|
||||
import { mapActions, mapState, mapGetters } from 'vuex';
|
||||
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import FindFile from '~/vue_shared/components/file_finder/index.vue';
|
||||
import NewModal from './new_dropdown/modal.vue';
|
||||
|
|
@ -22,6 +23,8 @@ export default {
|
|||
FindFile,
|
||||
ErrorMessage,
|
||||
CommitEditorHeader,
|
||||
GlButton,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
props: {
|
||||
rightPaneComponent: {
|
||||
|
|
@ -47,13 +50,15 @@ export default {
|
|||
'someUncommittedChanges',
|
||||
'isCommitModeActive',
|
||||
'allBlobs',
|
||||
'emptyRepo',
|
||||
'currentTree',
|
||||
]),
|
||||
},
|
||||
mounted() {
|
||||
window.onbeforeunload = e => this.onBeforeUnload(e);
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['toggleFileFinder']),
|
||||
...mapActions(['toggleFileFinder', 'openNewEntryModal']),
|
||||
onBeforeUnload(e = {}) {
|
||||
const returnValue = __('Are you sure you want to lose unsaved changes?');
|
||||
|
||||
|
|
@ -98,17 +103,40 @@ export default {
|
|||
<repo-editor :file="activeFile" class="multi-file-edit-pane-content" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div v-once class="ide-empty-state">
|
||||
<div class="ide-empty-state">
|
||||
<div class="row js-empty-state">
|
||||
<div class="col-12">
|
||||
<div class="svg-content svg-250"><img :src="emptyStateSvgPath" /></div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="text-content text-center">
|
||||
<h4>Welcome to the GitLab IDE</h4>
|
||||
<p>
|
||||
Select a file from the left sidebar to begin editing. Afterwards, you'll be able
|
||||
to commit your changes.
|
||||
<h4>
|
||||
{{ __('Make and review changes in the browser with the Web IDE') }}
|
||||
</h4>
|
||||
<template v-if="emptyRepo">
|
||||
<p>
|
||||
{{
|
||||
__(
|
||||
"Create a new file as there are no files yet. Afterwards, you'll be able to commit your changes.",
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<gl-button
|
||||
variant="success"
|
||||
:title="__('New file')"
|
||||
:aria-label="__('New file')"
|
||||
@click="openNewEntryModal({ type: 'blob' })"
|
||||
>
|
||||
{{ __('New file') }}
|
||||
</gl-button>
|
||||
</template>
|
||||
<gl-loading-icon v-else-if="!currentTree || currentTree.loading" size="md" />
|
||||
<p v-else>
|
||||
{{
|
||||
__(
|
||||
"Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes.",
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -54,14 +54,17 @@ export default {
|
|||
<slot name="header"></slot>
|
||||
</header>
|
||||
<div class="ide-tree-body h-100">
|
||||
<file-row
|
||||
v-for="file in currentTree.tree"
|
||||
:key="file.key"
|
||||
:file="file"
|
||||
:level="0"
|
||||
:extra-component="$options.FileRowExtra"
|
||||
@toggleTreeOpen="toggleTreeOpen"
|
||||
/>
|
||||
<template v-if="currentTree.tree.length">
|
||||
<file-row
|
||||
v-for="file in currentTree.tree"
|
||||
:key="file.key"
|
||||
:file="file"
|
||||
:level="0"
|
||||
:extra-component="$options.FileRowExtra"
|
||||
@toggleTreeOpen="toggleTreeOpen"
|
||||
/>
|
||||
</template>
|
||||
<div v-else class="file-row">{{ __('No files') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
import $ from 'jquery';
|
||||
import Vue from 'vue';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import flash from '~/flash';
|
||||
import _ from 'underscore';
|
||||
import * as types from './mutation_types';
|
||||
import { decorateFiles } from '../lib/files';
|
||||
import { stageKeys } from '../constants';
|
||||
import service from '../services';
|
||||
|
||||
export const redirectToUrl = (_, url) => visitUrl(url);
|
||||
export const redirectToUrl = (self, url) => visitUrl(url);
|
||||
|
||||
export const setInitialData = ({ commit }, data) => commit(types.SET_INITIAL_DATA, data);
|
||||
|
||||
|
|
@ -239,6 +242,53 @@ export const renameEntry = (
|
|||
}
|
||||
};
|
||||
|
||||
export const getBranchData = ({ commit, state }, { projectId, branchId, force = false } = {}) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const currentProject = state.projects[projectId];
|
||||
if (!currentProject || !currentProject.branches[branchId] || force) {
|
||||
service
|
||||
.getBranchData(projectId, branchId)
|
||||
.then(({ data }) => {
|
||||
const { id } = data.commit;
|
||||
commit(types.SET_BRANCH, {
|
||||
projectPath: projectId,
|
||||
branchName: branchId,
|
||||
branch: data,
|
||||
});
|
||||
commit(types.SET_BRANCH_WORKING_REFERENCE, { projectId, branchId, reference: id });
|
||||
resolve(data);
|
||||
})
|
||||
.catch(e => {
|
||||
if (e.response.status === 404) {
|
||||
reject(e);
|
||||
} else {
|
||||
flash(
|
||||
__('Error loading branch data. Please try again.'),
|
||||
'alert',
|
||||
document,
|
||||
null,
|
||||
false,
|
||||
true,
|
||||
);
|
||||
|
||||
reject(
|
||||
new Error(
|
||||
sprintf(
|
||||
__('Branch not loaded - %{branchId}'),
|
||||
{
|
||||
branchId: `<strong>${_.escape(projectId)}/${_.escape(branchId)}</strong>`,
|
||||
},
|
||||
false,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
resolve(currentProject.branches[branchId]);
|
||||
}
|
||||
});
|
||||
|
||||
export * from './actions/tree';
|
||||
export * from './actions/file';
|
||||
export * from './actions/project';
|
||||
|
|
|
|||
|
|
@ -35,48 +35,6 @@ export const getProjectData = ({ commit, state }, { namespace, projectId, force
|
|||
}
|
||||
});
|
||||
|
||||
export const getBranchData = (
|
||||
{ commit, dispatch, state },
|
||||
{ projectId, branchId, force = false } = {},
|
||||
) =>
|
||||
new Promise((resolve, reject) => {
|
||||
if (
|
||||
typeof state.projects[`${projectId}`] === 'undefined' ||
|
||||
!state.projects[`${projectId}`].branches[branchId] ||
|
||||
force
|
||||
) {
|
||||
service
|
||||
.getBranchData(`${projectId}`, branchId)
|
||||
.then(({ data }) => {
|
||||
const { id } = data.commit;
|
||||
commit(types.SET_BRANCH, {
|
||||
projectPath: `${projectId}`,
|
||||
branchName: branchId,
|
||||
branch: data,
|
||||
});
|
||||
commit(types.SET_BRANCH_WORKING_REFERENCE, { projectId, branchId, reference: id });
|
||||
resolve(data);
|
||||
})
|
||||
.catch(e => {
|
||||
if (e.response.status === 404) {
|
||||
dispatch('showBranchNotFoundError', branchId);
|
||||
} else {
|
||||
flash(
|
||||
__('Error loading branch data. Please try again.'),
|
||||
'alert',
|
||||
document,
|
||||
null,
|
||||
false,
|
||||
true,
|
||||
);
|
||||
}
|
||||
reject(new Error(`Branch not loaded - ${projectId}/${branchId}`));
|
||||
});
|
||||
} else {
|
||||
resolve(state.projects[`${projectId}`].branches[branchId]);
|
||||
}
|
||||
});
|
||||
|
||||
export const refreshLastCommitData = ({ commit }, { projectId, branchId } = {}) =>
|
||||
service
|
||||
.getBranchData(projectId, branchId)
|
||||
|
|
@ -125,40 +83,66 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => {
|
|||
});
|
||||
};
|
||||
|
||||
export const openBranch = ({ dispatch, state }, { projectId, branchId, basePath }) => {
|
||||
export const showEmptyState = ({ commit, state }, { projectId, branchId }) => {
|
||||
const treePath = `${projectId}/${branchId}`;
|
||||
commit(types.CREATE_TREE, { treePath });
|
||||
commit(types.TOGGLE_LOADING, {
|
||||
entry: state.trees[treePath],
|
||||
forceValue: false,
|
||||
});
|
||||
};
|
||||
|
||||
export const openBranch = ({ dispatch, state, getters }, { projectId, branchId, basePath }) => {
|
||||
dispatch('setCurrentBranchId', branchId);
|
||||
|
||||
dispatch('getBranchData', {
|
||||
projectId,
|
||||
branchId,
|
||||
});
|
||||
|
||||
return dispatch('getFiles', {
|
||||
if (getters.emptyRepo) {
|
||||
return dispatch('showEmptyState', { projectId, branchId });
|
||||
}
|
||||
return dispatch('getBranchData', {
|
||||
projectId,
|
||||
branchId,
|
||||
})
|
||||
.then(() => {
|
||||
if (basePath) {
|
||||
const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath;
|
||||
const treeEntryKey = Object.keys(state.entries).find(
|
||||
key => key === path && !state.entries[key].pending,
|
||||
);
|
||||
const treeEntry = state.entries[treeEntryKey];
|
||||
|
||||
if (treeEntry) {
|
||||
dispatch('handleTreeEntryAction', treeEntry);
|
||||
} else {
|
||||
dispatch('createTempEntry', {
|
||||
name: path,
|
||||
type: 'blob',
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
dispatch('getMergeRequestsForBranch', {
|
||||
projectId,
|
||||
branchId,
|
||||
});
|
||||
dispatch('getFiles', {
|
||||
projectId,
|
||||
branchId,
|
||||
})
|
||||
.then(() => {
|
||||
if (basePath) {
|
||||
const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath;
|
||||
const treeEntryKey = Object.keys(state.entries).find(
|
||||
key => key === path && !state.entries[key].pending,
|
||||
);
|
||||
const treeEntry = state.entries[treeEntryKey];
|
||||
|
||||
if (treeEntry) {
|
||||
dispatch('handleTreeEntryAction', treeEntry);
|
||||
} else {
|
||||
dispatch('createTempEntry', {
|
||||
name: path,
|
||||
type: 'blob',
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(
|
||||
() =>
|
||||
new Error(
|
||||
sprintf(
|
||||
__('An error occurred whilst getting files for - %{branchId}'),
|
||||
{
|
||||
branchId: `<strong>${_.escape(projectId)}/${_.escape(branchId)}</strong>`,
|
||||
},
|
||||
false,
|
||||
),
|
||||
),
|
||||
);
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch('showBranchNotFoundError', branchId);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -74,17 +74,13 @@ export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } =
|
|||
resolve();
|
||||
})
|
||||
.catch(e => {
|
||||
if (e.response.status === 404) {
|
||||
dispatch('showBranchNotFoundError', branchId);
|
||||
} else {
|
||||
dispatch('setErrorMessage', {
|
||||
text: __('An error occurred whilst loading all the files.'),
|
||||
action: payload =>
|
||||
dispatch('getFiles', payload).then(() => dispatch('setErrorMessage', null)),
|
||||
actionText: __('Please try again'),
|
||||
actionPayload: { projectId, branchId },
|
||||
});
|
||||
}
|
||||
dispatch('setErrorMessage', {
|
||||
text: __('An error occurred whilst loading all the files.'),
|
||||
action: payload =>
|
||||
dispatch('getFiles', payload).then(() => dispatch('setErrorMessage', null)),
|
||||
actionText: __('Please try again'),
|
||||
actionPayload: { projectId, branchId },
|
||||
});
|
||||
reject(e);
|
||||
});
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ export const currentMergeRequest = state => {
|
|||
|
||||
export const currentProject = state => state.projects[state.currentProjectId];
|
||||
|
||||
export const emptyRepo = state =>
|
||||
state.projects[state.currentProjectId] && state.projects[state.currentProjectId].empty_repo;
|
||||
|
||||
export const currentTree = state =>
|
||||
state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,17 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
|
|||
return null;
|
||||
}
|
||||
|
||||
if (!data.parent_ids.length) {
|
||||
commit(
|
||||
rootTypes.TOGGLE_EMPTY_STATE,
|
||||
{
|
||||
projectPath: rootState.currentProjectId,
|
||||
value: false,
|
||||
},
|
||||
{ root: true },
|
||||
);
|
||||
}
|
||||
|
||||
dispatch('setLastCommitMessage', data);
|
||||
dispatch('updateCommitMessage', '');
|
||||
return dispatch('updateFilesAfterCommit', {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export const SET_LINKS = 'SET_LINKS';
|
|||
export const SET_PROJECT = 'SET_PROJECT';
|
||||
export const SET_CURRENT_PROJECT = 'SET_CURRENT_PROJECT';
|
||||
export const TOGGLE_PROJECT_OPEN = 'TOGGLE_PROJECT_OPEN';
|
||||
export const TOGGLE_EMPTY_STATE = 'TOGGLE_EMPTY_STATE';
|
||||
|
||||
// Merge Request Mutation Types
|
||||
export const SET_MERGE_REQUEST = 'SET_MERGE_REQUEST';
|
||||
|
|
|
|||
|
|
@ -19,6 +19,12 @@ export default {
|
|||
});
|
||||
},
|
||||
[types.SET_BRANCH_WORKING_REFERENCE](state, { projectId, branchId, reference }) {
|
||||
if (!state.projects[projectId].branches[branchId]) {
|
||||
Object.assign(state.projects[projectId].branches, {
|
||||
[branchId]: {},
|
||||
});
|
||||
}
|
||||
|
||||
Object.assign(state.projects[projectId].branches[branchId], {
|
||||
workingReference: reference,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,4 +21,9 @@ export default {
|
|||
}),
|
||||
});
|
||||
},
|
||||
[types.TOGGLE_EMPTY_STATE](state, { projectPath, value }) {
|
||||
Object.assign(state.projects[projectPath], {
|
||||
empty_repo: value,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { __ } from '~/locale';
|
||||
|
||||
export const namespaceSelectOptions = state => {
|
||||
const serializedNamespaces = state.namespaces.map(({ fullPath }) => ({
|
||||
id: fullPath,
|
||||
|
|
@ -5,9 +7,9 @@ export const namespaceSelectOptions = state => {
|
|||
}));
|
||||
|
||||
return [
|
||||
{ text: 'Groups', children: serializedNamespaces },
|
||||
{ text: __('Groups'), children: serializedNamespaces },
|
||||
{
|
||||
text: 'Users',
|
||||
text: __('Users'),
|
||||
children: [{ id: state.defaultTargetNamespace, text: state.defaultTargetNamespace }],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ export default {
|
|||
'isScrollTopDisabled',
|
||||
'isScrolledToBottomBeforeReceivingTrace',
|
||||
'hasError',
|
||||
'selectedStage',
|
||||
]),
|
||||
...mapGetters([
|
||||
'headerTime',
|
||||
|
|
@ -121,7 +122,13 @@ export default {
|
|||
// fetch the stages for the dropdown on the sidebar
|
||||
job(newVal, oldVal) {
|
||||
if (_.isEmpty(oldVal) && !_.isEmpty(newVal.pipeline)) {
|
||||
this.fetchStages();
|
||||
const stages = this.job.pipeline.details.stages || [];
|
||||
|
||||
const defaultStage = stages.find(stage => stage && stage.name === this.selectedStage);
|
||||
|
||||
if (defaultStage) {
|
||||
this.fetchJobsForStage(defaultStage);
|
||||
}
|
||||
}
|
||||
|
||||
if (newVal.archived) {
|
||||
|
|
@ -160,7 +167,7 @@ export default {
|
|||
'setJobEndpoint',
|
||||
'setTraceOptions',
|
||||
'fetchJob',
|
||||
'fetchStages',
|
||||
'fetchJobsForStage',
|
||||
'hideSidebar',
|
||||
'showSidebar',
|
||||
'toggleSidebar',
|
||||
|
|
@ -269,7 +276,6 @@ export default {
|
|||
:class="{ 'sticky-top border-bottom-0': hasTrace }"
|
||||
>
|
||||
<icon name="lock" class="align-text-bottom" />
|
||||
|
||||
{{ __('This job is archived. Only the complete pipeline can be retried.') }}
|
||||
</div>
|
||||
<!-- job log -->
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(['job', 'stages', 'jobs', 'selectedStage', 'isLoadingStages']),
|
||||
...mapState(['job', 'stages', 'jobs', 'selectedStage']),
|
||||
coverage() {
|
||||
return `${this.job.coverage}%`;
|
||||
},
|
||||
|
|
@ -208,7 +208,6 @@ export default {
|
|||
/>
|
||||
|
||||
<stages-dropdown
|
||||
v-if="!isLoadingStages"
|
||||
:stages="stages"
|
||||
:pipeline="job.pipeline"
|
||||
:selected-stage="selectedStage"
|
||||
|
|
|
|||
|
|
@ -178,30 +178,6 @@ export const receiveTraceError = ({ commit }) => {
|
|||
flash(__('An error occurred while fetching the job log.'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Stages dropdown on sidebar
|
||||
*/
|
||||
export const requestStages = ({ commit }) => commit(types.REQUEST_STAGES);
|
||||
export const fetchStages = ({ state, dispatch }) => {
|
||||
dispatch('requestStages');
|
||||
|
||||
axios
|
||||
.get(`${state.job.pipeline.path}.json`)
|
||||
.then(({ data }) => {
|
||||
// Set selected stage
|
||||
dispatch('receiveStagesSuccess', data.details.stages);
|
||||
const selectedStage = data.details.stages.find(stage => stage.name === state.selectedStage);
|
||||
dispatch('fetchJobsForStage', selectedStage);
|
||||
})
|
||||
.catch(() => dispatch('receiveStagesError'));
|
||||
};
|
||||
export const receiveStagesSuccess = ({ commit }, data) =>
|
||||
commit(types.RECEIVE_STAGES_SUCCESS, data);
|
||||
export const receiveStagesError = ({ commit }) => {
|
||||
commit(types.RECEIVE_STAGES_ERROR);
|
||||
flash(__('An error occurred while fetching stages.'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Jobs list on sidebar - depend on stages dropdown
|
||||
*/
|
||||
|
|
@ -209,7 +185,7 @@ export const requestJobsForStage = ({ commit }, stage) =>
|
|||
commit(types.REQUEST_JOBS_FOR_STAGE, stage);
|
||||
|
||||
// On stage click, set selected stage + fetch job
|
||||
export const fetchJobsForStage = ({ dispatch }, stage) => {
|
||||
export const fetchJobsForStage = ({ dispatch }, stage = {}) => {
|
||||
dispatch('requestJobsForStage', stage);
|
||||
|
||||
axios
|
||||
|
|
|
|||
|
|
@ -24,10 +24,6 @@ export const STOP_POLLING_TRACE = 'STOP_POLLING_TRACE';
|
|||
export const RECEIVE_TRACE_SUCCESS = 'RECEIVE_TRACE_SUCCESS';
|
||||
export const RECEIVE_TRACE_ERROR = 'RECEIVE_TRACE_ERROR';
|
||||
|
||||
export const REQUEST_STAGES = 'REQUEST_STAGES';
|
||||
export const RECEIVE_STAGES_SUCCESS = 'RECEIVE_STAGES_SUCCESS';
|
||||
export const RECEIVE_STAGES_ERROR = 'RECEIVE_STAGES_ERROR';
|
||||
|
||||
export const SET_SELECTED_STAGE = 'SET_SELECTED_STAGE';
|
||||
export const REQUEST_JOBS_FOR_STAGE = 'REQUEST_JOBS_FOR_STAGE';
|
||||
export const RECEIVE_JOBS_FOR_STAGE_SUCCESS = 'RECEIVE_JOBS_FOR_STAGE_SUCCESS';
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@ export default {
|
|||
state.isLoading = false;
|
||||
state.job = job;
|
||||
|
||||
state.stages =
|
||||
job.pipeline && job.pipeline.details && job.pipeline.details.stages
|
||||
? job.pipeline.details.stages
|
||||
: [];
|
||||
|
||||
/**
|
||||
* We only update it on the first request
|
||||
* The dropdown can be changed by the user
|
||||
|
|
@ -101,19 +106,7 @@ export default {
|
|||
state.isScrolledToBottomBeforeReceivingTrace = toggle;
|
||||
},
|
||||
|
||||
[types.REQUEST_STAGES](state) {
|
||||
state.isLoadingStages = true;
|
||||
},
|
||||
[types.RECEIVE_STAGES_SUCCESS](state, stages) {
|
||||
state.isLoadingStages = false;
|
||||
state.stages = stages;
|
||||
},
|
||||
[types.RECEIVE_STAGES_ERROR](state) {
|
||||
state.isLoadingStages = false;
|
||||
state.stages = [];
|
||||
},
|
||||
|
||||
[types.REQUEST_JOBS_FOR_STAGE](state, stage) {
|
||||
[types.REQUEST_JOBS_FOR_STAGE](state, stage = {}) {
|
||||
state.isLoadingJobs = true;
|
||||
state.selectedStage = stage.name;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ export default () => ({
|
|||
traceState: null,
|
||||
|
||||
// sidebar dropdown & list of jobs
|
||||
isLoadingStages: false,
|
||||
isLoadingJobs: false,
|
||||
selectedStage: '',
|
||||
stages: [],
|
||||
|
|
|
|||
|
|
@ -5,13 +5,14 @@ import Sortable from 'sortablejs';
|
|||
|
||||
import flash from './flash';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { __ } from './locale';
|
||||
|
||||
export default class LabelManager {
|
||||
constructor({ togglePriorityButton, prioritizedLabels, otherLabels } = {}) {
|
||||
this.togglePriorityButton = togglePriorityButton || $('.js-toggle-priority');
|
||||
this.prioritizedLabels = prioritizedLabels || $('.js-prioritized-labels');
|
||||
this.otherLabels = otherLabels || $('.js-other-labels');
|
||||
this.errorMessage = 'Unable to update label prioritization at this time';
|
||||
this.errorMessage = __('Unable to update label prioritization at this time');
|
||||
this.emptyState = document.querySelector('#js-priority-labels-empty-state');
|
||||
this.$badgeItemTemplate = $('#js-badge-item-template');
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import $ from 'jquery';
|
||||
import _ from 'underscore';
|
||||
import { sprintf, __ } from './locale';
|
||||
import { sprintf, s__, __ } from './locale';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import IssuableBulkUpdateActions from './issuable_bulk_update_actions';
|
||||
import CreateLabelDropdown from './create_label';
|
||||
|
|
@ -178,7 +178,7 @@ export default class LabelsSelect {
|
|||
});
|
||||
}
|
||||
} else {
|
||||
template = '<span class="no-value">None</span>';
|
||||
template = `<span class="no-value">${__('None')}</span>`;
|
||||
}
|
||||
$value.removeAttr('style').html(template);
|
||||
$sidebarCollapsedValue.text(labelCount);
|
||||
|
|
@ -190,7 +190,9 @@ export default class LabelsSelect {
|
|||
|
||||
if (labelTitles.length > 5) {
|
||||
labelTitles = labelTitles.slice(0, 5);
|
||||
labelTitles.push('and ' + (data.labels.length - 5) + ' more');
|
||||
labelTitles.push(
|
||||
sprintf(s__('Labels|and %{count} more'), { count: data.labels.length - 5 }),
|
||||
);
|
||||
}
|
||||
|
||||
labelTooltipTitle = labelTitles.join(', ');
|
||||
|
|
@ -219,13 +221,13 @@ export default class LabelsSelect {
|
|||
if (showNo) {
|
||||
extraData.unshift({
|
||||
id: 0,
|
||||
title: 'No Label',
|
||||
title: __('No Label'),
|
||||
});
|
||||
}
|
||||
if (showAny) {
|
||||
extraData.unshift({
|
||||
isAny: true,
|
||||
title: 'Any Label',
|
||||
title: __('Any Label'),
|
||||
});
|
||||
}
|
||||
if (extraData.length) {
|
||||
|
|
@ -341,7 +343,7 @@ export default class LabelsSelect {
|
|||
|
||||
if (selected && selected.id === 0) {
|
||||
this.selected = [];
|
||||
return 'No Label';
|
||||
return __('No Label');
|
||||
} else if (isSelected) {
|
||||
this.selected.push(title);
|
||||
} else if (!isSelected && title) {
|
||||
|
|
@ -579,7 +581,7 @@ export default class LabelsSelect {
|
|||
if ($('.selected-issuable:checked').length) {
|
||||
return;
|
||||
}
|
||||
return $('.issues-bulk-update .labels-filter .dropdown-toggle-text').text('Label');
|
||||
return $('.issues-bulk-update .labels-filter .dropdown-toggle-text').text(__('Label'));
|
||||
}
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
enableBulkLabelDropdown() {
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ import { InMemoryCache } from 'apollo-cache-inmemory';
|
|||
import { createUploadLink } from 'apollo-upload-client';
|
||||
import csrf from '~/lib/utils/csrf';
|
||||
|
||||
export default (resolvers = {}, baseUrl = '') => {
|
||||
export default (resolvers = {}, config = {}) => {
|
||||
let uri = `${gon.relative_url_root}/api/graphql`;
|
||||
|
||||
if (baseUrl) {
|
||||
if (config.baseUrl) {
|
||||
// Prepend baseUrl and ensure that `///` are replaced with `/`
|
||||
uri = `${baseUrl}${uri}`.replace(/\/{3,}/g, '/');
|
||||
uri = `${config.baseUrl}${uri}`.replace(/\/{3,}/g, '/');
|
||||
}
|
||||
|
||||
return new ApolloClient({
|
||||
|
|
@ -18,7 +18,7 @@ export default (resolvers = {}, baseUrl = '') => {
|
|||
[csrf.headerKey]: csrf.token,
|
||||
},
|
||||
}),
|
||||
cache: new InMemoryCache(),
|
||||
cache: new InMemoryCache(config.cacheConfig),
|
||||
resolvers,
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import _ from 'underscore';
|
|||
import timeago from 'timeago.js';
|
||||
import dateFormat from 'dateformat';
|
||||
import { pluralize } from './text_utility';
|
||||
import { languageCode, s__ } from '../../locale';
|
||||
import { languageCode, s__, __ } from '../../locale';
|
||||
|
||||
window.timeago = timeago;
|
||||
|
||||
|
|
@ -63,7 +63,15 @@ export const pad = (val, len = 2) => `0${val}`.slice(-len);
|
|||
* @returns {String}
|
||||
*/
|
||||
export const getDayName = date =>
|
||||
['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][date.getDay()];
|
||||
[
|
||||
__('Sunday'),
|
||||
__('Monday'),
|
||||
__('Tuesday'),
|
||||
__('Wednesday'),
|
||||
__('Thursday'),
|
||||
__('Friday'),
|
||||
__('Saturday'),
|
||||
][date.getDay()];
|
||||
|
||||
/**
|
||||
* @example
|
||||
|
|
@ -71,7 +79,12 @@ export const getDayName = date =>
|
|||
* @param {date} datetime
|
||||
* @returns {String}
|
||||
*/
|
||||
export const formatDate = datetime => dateFormat(datetime, 'mmm d, yyyy h:MMtt Z');
|
||||
export const formatDate = datetime => {
|
||||
if (_.isString(datetime) && datetime.match(/\d+-\d+\d+ /)) {
|
||||
throw new Error('Invalid date');
|
||||
}
|
||||
return dateFormat(datetime, 'mmm d, yyyy h:MMtt Z');
|
||||
};
|
||||
|
||||
/**
|
||||
* Timeago uses underscores instead of dashes to separate language from country code.
|
||||
|
|
@ -320,13 +333,13 @@ export const getSundays = date => {
|
|||
}
|
||||
|
||||
const daysToSunday = [
|
||||
'Saturday',
|
||||
'Friday',
|
||||
'Thursday',
|
||||
'Wednesday',
|
||||
'Tuesday',
|
||||
'Monday',
|
||||
'Sunday',
|
||||
__('Saturday'),
|
||||
__('Friday'),
|
||||
__('Thursday'),
|
||||
__('Wednesday'),
|
||||
__('Tuesday'),
|
||||
__('Monday'),
|
||||
__('Sunday'),
|
||||
];
|
||||
|
||||
const month = date.getMonth();
|
||||
|
|
@ -336,7 +349,7 @@ export const getSundays = date => {
|
|||
|
||||
while (dateOfMonth.getMonth() === month) {
|
||||
const dayName = getDayName(dateOfMonth);
|
||||
if (dayName === 'Sunday') {
|
||||
if (dayName === __('Sunday')) {
|
||||
sundays.push(new Date(dateOfMonth.getTime()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { BYTES_IN_KIB } from './constants';
|
||||
import { sprintf, __ } from '~/locale';
|
||||
|
||||
/**
|
||||
* Function that allows a number with an X amount of decimals
|
||||
|
|
@ -72,13 +73,13 @@ export function bytesToGiB(number) {
|
|||
*/
|
||||
export function numberToHumanSize(size) {
|
||||
if (size < BYTES_IN_KIB) {
|
||||
return `${size} bytes`;
|
||||
return sprintf(__('%{size} bytes'), { size });
|
||||
} else if (size < BYTES_IN_KIB * BYTES_IN_KIB) {
|
||||
return `${bytesToKiB(size).toFixed(2)} KiB`;
|
||||
return sprintf(__('%{size} KiB'), { size: bytesToKiB(size).toFixed(2) });
|
||||
} else if (size < BYTES_IN_KIB * BYTES_IN_KIB * BYTES_IN_KIB) {
|
||||
return `${bytesToMiB(size).toFixed(2)} MiB`;
|
||||
return sprintf(__('%{size} MiB'), { size: bytesToMiB(size).toFixed(2) });
|
||||
}
|
||||
return `${bytesToGiB(size).toFixed(2)} GiB`;
|
||||
return sprintf(__('%{size} GiB'), { size: bytesToGiB(size).toFixed(2) });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ delete window.translations;
|
|||
@param text The text to be translated
|
||||
@returns {String} The translated text
|
||||
*/
|
||||
const gettext = text => locale.gettext.bind(locale)(ensureSingleLine(text));
|
||||
const gettext = text => locale.gettext(ensureSingleLine(text));
|
||||
|
||||
/**
|
||||
Translate the text with a number
|
||||
|
|
|
|||
|
|
@ -125,17 +125,17 @@ export default {
|
|||
},
|
||||
earliestDatapoint() {
|
||||
return this.chartData.reduce((acc, series) => {
|
||||
if (!series.data.length) {
|
||||
const { data } = series;
|
||||
const { length } = data;
|
||||
if (!length) {
|
||||
return acc;
|
||||
}
|
||||
const [[timestamp]] = series.data.sort(([a], [b]) => {
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
return a > b ? 1 : 0;
|
||||
});
|
||||
|
||||
return timestamp < acc || acc === null ? timestamp : acc;
|
||||
const [first] = data[0];
|
||||
const [last] = data[length - 1];
|
||||
const seriesEarliest = first < last ? first : last;
|
||||
|
||||
return seriesEarliest < acc || acc === null ? seriesEarliest : acc;
|
||||
}, null);
|
||||
},
|
||||
isMultiSeries() {
|
||||
|
|
|
|||
|
|
@ -8,16 +8,14 @@ import {
|
|||
GlLink,
|
||||
} from '@gitlab/ui';
|
||||
import _ from 'underscore';
|
||||
import { mapActions, mapState } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
import '~/vue_shared/mixins/is_ee';
|
||||
import { getParameterValues } from '~/lib/utils/url_utility';
|
||||
import Flash from '../../flash';
|
||||
import MonitoringService from '../services/monitoring_service';
|
||||
import MonitorAreaChart from './charts/area.vue';
|
||||
import GraphGroup from './graph_group.vue';
|
||||
import EmptyState from './empty_state.vue';
|
||||
import MonitoringStore from '../stores/monitoring_store';
|
||||
import { timeWindows, timeWindowsKeyNames } from '../constants';
|
||||
import { getTimeDiff } from '../utils';
|
||||
|
||||
|
|
@ -128,9 +126,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
store: new MonitoringStore(),
|
||||
state: 'gettingStarted',
|
||||
showEmptyState: true,
|
||||
elWidth: 0,
|
||||
selectedTimeWindow: '',
|
||||
selectedTimeWindowKey: '',
|
||||
|
|
@ -141,13 +137,21 @@ export default {
|
|||
canAddMetrics() {
|
||||
return this.customMetricsAvailable && this.customMetricsPath.length;
|
||||
},
|
||||
...mapState('monitoringDashboard', [
|
||||
'groups',
|
||||
'emptyState',
|
||||
'showEmptyState',
|
||||
'environments',
|
||||
'deploymentData',
|
||||
]),
|
||||
},
|
||||
created() {
|
||||
this.service = new MonitoringService({
|
||||
this.setEndpoints({
|
||||
metricsEndpoint: this.metricsEndpoint,
|
||||
deploymentEndpoint: this.deploymentEndpoint,
|
||||
environmentsEndpoint: this.environmentsEndpoint,
|
||||
deploymentsEndpoint: this.deploymentEndpoint,
|
||||
});
|
||||
|
||||
this.timeWindows = timeWindows;
|
||||
this.selectedTimeWindowKey =
|
||||
_.escape(getParameterValues('time_window')[0]) || timeWindowsKeyNames.eightHours;
|
||||
|
|
@ -165,31 +169,11 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
const startEndWindow = getTimeDiff(this.timeWindows[this.selectedTimeWindowKey]);
|
||||
this.servicePromises = [
|
||||
this.service
|
||||
.getGraphsData(startEndWindow)
|
||||
.then(data => this.store.storeMetrics(data))
|
||||
.catch(() => Flash(s__('Metrics|There was an error while retrieving metrics'))),
|
||||
this.service
|
||||
.getDeploymentData()
|
||||
.then(data => this.store.storeDeploymentData(data))
|
||||
.catch(() => Flash(s__('Metrics|There was an error getting deployment information.'))),
|
||||
];
|
||||
if (!this.hasMetrics) {
|
||||
this.state = 'gettingStarted';
|
||||
this.setGettingStartedEmptyState();
|
||||
} else {
|
||||
if (this.environmentsEndpoint) {
|
||||
this.servicePromises.push(
|
||||
this.service
|
||||
.getEnvironmentsData()
|
||||
.then(data => this.store.storeEnvironmentsData(data))
|
||||
.catch(() =>
|
||||
Flash(s__('Metrics|There was an error getting environments information.')),
|
||||
),
|
||||
);
|
||||
}
|
||||
this.getGraphsData();
|
||||
this.fetchData(getTimeDiff(this.timeWindows.eightHours));
|
||||
|
||||
sidebarMutationObserver = new MutationObserver(this.onSidebarMutation);
|
||||
sidebarMutationObserver.observe(document.querySelector('.layout-page'), {
|
||||
attributes: true,
|
||||
|
|
@ -199,6 +183,11 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('monitoringDashboard', [
|
||||
'fetchData',
|
||||
'setGettingStartedEmptyState',
|
||||
'setEndpoints',
|
||||
]),
|
||||
getGraphAlerts(queries) {
|
||||
if (!this.allAlerts) return {};
|
||||
const metricIdsForChart = queries.map(q => q.metricId);
|
||||
|
|
@ -207,21 +196,6 @@ export default {
|
|||
getGraphAlertValues(queries) {
|
||||
return Object.values(this.getGraphAlerts(queries));
|
||||
},
|
||||
getGraphsData() {
|
||||
this.state = 'loading';
|
||||
Promise.all(this.servicePromises)
|
||||
.then(() => {
|
||||
if (this.store.groups.length < 1) {
|
||||
this.state = 'noData';
|
||||
return;
|
||||
}
|
||||
|
||||
this.showEmptyState = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.state = 'unableToConnect';
|
||||
});
|
||||
},
|
||||
hideAddMetricModal() {
|
||||
this.$refs.addMetricModal.hide();
|
||||
},
|
||||
|
|
@ -263,10 +237,10 @@ export default {
|
|||
class="prepend-left-10 js-environments-dropdown"
|
||||
toggle-class="dropdown-menu-toggle"
|
||||
:text="currentEnvironmentName"
|
||||
:disabled="store.environmentsData.length === 0"
|
||||
:disabled="environments.length === 0"
|
||||
>
|
||||
<gl-dropdown-item
|
||||
v-for="environment in store.environmentsData"
|
||||
v-for="environment in environments"
|
||||
:key="environment.id"
|
||||
:active="environment.name === currentEnvironmentName"
|
||||
active-class="is-active"
|
||||
|
|
@ -336,7 +310,7 @@ export default {
|
|||
</div>
|
||||
</div>
|
||||
<graph-group
|
||||
v-for="(groupData, index) in store.groups"
|
||||
v-for="(groupData, index) in groups"
|
||||
:key="index"
|
||||
:name="groupData.group"
|
||||
:show-panels="showPanels"
|
||||
|
|
@ -345,7 +319,7 @@ export default {
|
|||
v-for="(graphData, graphIndex) in groupData.metrics"
|
||||
:key="graphIndex"
|
||||
:graph-data="graphData"
|
||||
:deployment-data="store.deploymentData"
|
||||
:deployment-data="deploymentData"
|
||||
:thresholds="getGraphAlertValues(graphData.queries)"
|
||||
:container-width="elWidth"
|
||||
group-id="monitor-area-chart"
|
||||
|
|
@ -362,7 +336,7 @@ export default {
|
|||
</div>
|
||||
<empty-state
|
||||
v-else
|
||||
:selected-state="state"
|
||||
:selected-state="emptyState"
|
||||
:documentation-path="documentationPath"
|
||||
:settings-path="settingsPath"
|
||||
:clusters-path="clustersPath"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import Vue from 'vue';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import Dashboard from 'ee_else_ce/monitoring/components/dashboard.vue';
|
||||
import store from './stores';
|
||||
|
||||
export default (props = {}) => {
|
||||
const el = document.getElementById('prometheus-graphs');
|
||||
|
|
@ -9,6 +10,7 @@ export default (props = {}) => {
|
|||
// eslint-disable-next-line no-new
|
||||
new Vue({
|
||||
el,
|
||||
store,
|
||||
render(createElement) {
|
||||
return createElement(Dashboard, {
|
||||
props: {
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
import axios from '../../lib/utils/axios_utils';
|
||||
import statusCodes from '../../lib/utils/http_status';
|
||||
import { backOff } from '../../lib/utils/common_utils';
|
||||
import { s__, __ } from '../../locale';
|
||||
|
||||
const MAX_REQUESTS = 3;
|
||||
|
||||
function backOffRequest(makeRequestCallback) {
|
||||
let requestCounter = 0;
|
||||
return backOff((next, stop) => {
|
||||
makeRequestCallback()
|
||||
.then(resp => {
|
||||
if (resp.status === statusCodes.NO_CONTENT) {
|
||||
requestCounter += 1;
|
||||
if (requestCounter < MAX_REQUESTS) {
|
||||
next();
|
||||
} else {
|
||||
stop(new Error(__('Failed to connect to the prometheus server')));
|
||||
}
|
||||
} else {
|
||||
stop(resp);
|
||||
}
|
||||
})
|
||||
.catch(stop);
|
||||
});
|
||||
}
|
||||
|
||||
export default class MonitoringService {
|
||||
constructor({ metricsEndpoint, deploymentEndpoint, environmentsEndpoint }) {
|
||||
this.metricsEndpoint = metricsEndpoint;
|
||||
this.deploymentEndpoint = deploymentEndpoint;
|
||||
this.environmentsEndpoint = environmentsEndpoint;
|
||||
}
|
||||
|
||||
getGraphsData(params = {}) {
|
||||
return backOffRequest(() => axios.get(this.metricsEndpoint, { params }))
|
||||
.then(resp => resp.data)
|
||||
.then(response => {
|
||||
if (!response || !response.data || !response.success) {
|
||||
throw new Error(s__('Metrics|Unexpected metrics data response from prometheus endpoint'));
|
||||
}
|
||||
return response.data;
|
||||
});
|
||||
}
|
||||
|
||||
getDeploymentData() {
|
||||
if (!this.deploymentEndpoint) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return backOffRequest(() => axios.get(this.deploymentEndpoint))
|
||||
.then(resp => resp.data)
|
||||
.then(response => {
|
||||
if (!response || !response.deployments) {
|
||||
throw new Error(
|
||||
s__('Metrics|Unexpected deployment data response from prometheus endpoint'),
|
||||
);
|
||||
}
|
||||
return response.deployments;
|
||||
});
|
||||
}
|
||||
|
||||
getEnvironmentsData() {
|
||||
return axios
|
||||
.get(this.environmentsEndpoint)
|
||||
.then(resp => resp.data)
|
||||
.then(response => {
|
||||
if (!response || !response.environments) {
|
||||
throw new Error(
|
||||
s__('Metrics|There was an error fetching the environments data, please try again'),
|
||||
);
|
||||
}
|
||||
return response.environments;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
import * as types from './mutation_types';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import createFlash from '~/flash';
|
||||
import statusCodes from '../../lib/utils/http_status';
|
||||
import { backOff } from '../../lib/utils/common_utils';
|
||||
import { s__, __ } from '../../locale';
|
||||
|
||||
const MAX_REQUESTS = 3;
|
||||
|
||||
function backOffRequest(makeRequestCallback) {
|
||||
let requestCounter = 0;
|
||||
return backOff((next, stop) => {
|
||||
makeRequestCallback()
|
||||
.then(resp => {
|
||||
if (resp.status === statusCodes.NO_CONTENT) {
|
||||
requestCounter += 1;
|
||||
if (requestCounter < MAX_REQUESTS) {
|
||||
next();
|
||||
} else {
|
||||
stop(new Error(__('Failed to connect to the prometheus server')));
|
||||
}
|
||||
} else {
|
||||
stop(resp);
|
||||
}
|
||||
})
|
||||
.catch(stop);
|
||||
});
|
||||
}
|
||||
|
||||
export const setGettingStartedEmptyState = ({ commit }) => {
|
||||
commit(types.SET_GETTING_STARTED_EMPTY_STATE);
|
||||
};
|
||||
|
||||
export const setEndpoints = ({ commit }, endpoints) => {
|
||||
commit(types.SET_ENDPOINTS, endpoints);
|
||||
};
|
||||
|
||||
export const requestMetricsData = ({ commit }) => commit(types.REQUEST_METRICS_DATA);
|
||||
export const receiveMetricsDataSuccess = ({ commit }, data) =>
|
||||
commit(types.RECEIVE_METRICS_DATA_SUCCESS, data);
|
||||
export const receiveMetricsDataFailure = ({ commit }, error) =>
|
||||
commit(types.RECEIVE_METRICS_DATA_FAILURE, error);
|
||||
export const receiveDeploymentsDataSuccess = ({ commit }, data) =>
|
||||
commit(types.RECEIVE_DEPLOYMENTS_DATA_SUCCESS, data);
|
||||
export const receiveDeploymentsDataFailure = ({ commit }) =>
|
||||
commit(types.RECEIVE_DEPLOYMENTS_DATA_FAILURE);
|
||||
export const receiveEnvironmentsDataSuccess = ({ commit }, data) =>
|
||||
commit(types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS, data);
|
||||
export const receiveEnvironmentsDataFailure = ({ commit }) =>
|
||||
commit(types.RECEIVE_ENVIRONMENTS_DATA_FAILURE);
|
||||
|
||||
export const fetchData = ({ dispatch }, params) => {
|
||||
dispatch('fetchMetricsData', params);
|
||||
dispatch('fetchDeploymentsData');
|
||||
dispatch('fetchEnvironmentsData');
|
||||
};
|
||||
|
||||
export const fetchMetricsData = ({ state, dispatch }, params) => {
|
||||
dispatch('requestMetricsData');
|
||||
|
||||
return backOffRequest(() => axios.get(state.metricsEndpoint, { params }))
|
||||
.then(resp => resp.data)
|
||||
.then(response => {
|
||||
if (!response || !response.data || !response.success) {
|
||||
dispatch('receiveMetricsDataFailure', null);
|
||||
createFlash(s__('Metrics|Unexpected metrics data response from prometheus endpoint'));
|
||||
}
|
||||
dispatch('receiveMetricsDataSuccess', response.data);
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch('receiveMetricsDataFailure', error);
|
||||
createFlash(s__('Metrics|There was an error while retrieving metrics'));
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchDeploymentsData = ({ state, dispatch }) => {
|
||||
if (!state.deploymentEndpoint) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return backOffRequest(() => axios.get(state.deploymentEndpoint))
|
||||
.then(resp => resp.data)
|
||||
.then(response => {
|
||||
if (!response || !response.deployments) {
|
||||
createFlash(s__('Metrics|Unexpected deployment data response from prometheus endpoint'));
|
||||
}
|
||||
|
||||
dispatch('receiveDeploymentsDataSuccess', response.deployments);
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch('receiveDeploymentsDataFailure');
|
||||
createFlash(s__('Metrics|There was an error getting deployment information.'));
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchEnvironmentsData = ({ state, dispatch }) => {
|
||||
if (!state.environmentsEndpoint) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return axios
|
||||
.get(state.environmentsEndpoint)
|
||||
.then(resp => resp.data)
|
||||
.then(response => {
|
||||
if (!response || !response.environments) {
|
||||
createFlash(
|
||||
s__('Metrics|There was an error fetching the environments data, please try again'),
|
||||
);
|
||||
}
|
||||
dispatch('receiveEnvironmentsDataSuccess', response.environments);
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch('receiveEnvironmentsDataFailure');
|
||||
createFlash(s__('Metrics|There was an error getting environments information.'));
|
||||
});
|
||||
};
|
||||
|
||||
// prevent babel-plugin-rewire from generating an invalid default during karma tests
|
||||
export default () => {};
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import * as actions from './actions';
|
||||
import mutations from './mutations';
|
||||
import state from './state';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export const createStore = () =>
|
||||
new Vuex.Store({
|
||||
modules: {
|
||||
monitoringDashboard: {
|
||||
namespaced: true,
|
||||
actions,
|
||||
mutations,
|
||||
state,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default createStore();
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
export const REQUEST_METRICS_DATA = 'REQUEST_METRICS_DATA';
|
||||
export const RECEIVE_METRICS_DATA_SUCCESS = 'RECEIVE_METRICS_DATA_SUCCESS';
|
||||
export const RECEIVE_METRICS_DATA_FAILURE = 'RECEIVE_METRICS_DATA_FAILURE';
|
||||
export const REQUEST_DEPLOYMENTS_DATA = 'REQUEST_DEPLOYMENTS_DATA';
|
||||
export const RECEIVE_DEPLOYMENTS_DATA_SUCCESS = 'RECEIVE_DEPLOYMENTS_DATA_SUCCESS';
|
||||
export const RECEIVE_DEPLOYMENTS_DATA_FAILURE = 'RECEIVE_DEPLOYMENTS_DATA_FAILURE';
|
||||
export const REQUEST_ENVIRONMENTS_DATA = 'REQUEST_ENVIRONMENTS_DATA';
|
||||
export const RECEIVE_ENVIRONMENTS_DATA_SUCCESS = 'RECEIVE_ENVIRONMENTS_DATA_SUCCESS';
|
||||
export const RECEIVE_ENVIRONMENTS_DATA_FAILURE = 'RECEIVE_ENVIRONMENTS_DATA_FAILURE';
|
||||
export const SET_TIME_WINDOW = 'SET_TIME_WINDOW';
|
||||
export const SET_METRICS_ENDPOINT = 'SET_METRICS_ENDPOINT';
|
||||
export const SET_ENVIRONMENTS_ENDPOINT = 'SET_ENVIRONMENTS_ENDPOINT';
|
||||
export const SET_DEPLOYMENTS_ENDPOINT = 'SET_DEPLOYMENTS_ENDPOINT';
|
||||
export const SET_ENDPOINTS = 'SET_ENDPOINTS';
|
||||
export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE';
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import * as types from './mutation_types';
|
||||
import { normalizeMetrics, sortMetrics } from './utils';
|
||||
|
||||
export default {
|
||||
[types.REQUEST_METRICS_DATA](state) {
|
||||
state.emptyState = 'loading';
|
||||
state.showEmptyState = true;
|
||||
},
|
||||
[types.RECEIVE_METRICS_DATA_SUCCESS](state, groupData) {
|
||||
state.groups = groupData.map(group => ({
|
||||
...group,
|
||||
metrics: normalizeMetrics(sortMetrics(group.metrics)),
|
||||
}));
|
||||
|
||||
if (!state.groups.length) {
|
||||
state.emptyState = 'noData';
|
||||
} else {
|
||||
state.showEmptyState = false;
|
||||
}
|
||||
},
|
||||
[types.RECEIVE_METRICS_DATA_FAILURE](state, error) {
|
||||
state.emptyState = error ? 'unableToConnect' : 'noData';
|
||||
state.showEmptyState = true;
|
||||
},
|
||||
[types.RECEIVE_DEPLOYMENTS_DATA_SUCCESS](state, deployments) {
|
||||
state.deploymentData = deployments;
|
||||
},
|
||||
[types.RECEIVE_DEPLOYMENTS_DATA_FAILURE](state) {
|
||||
state.deploymentData = [];
|
||||
},
|
||||
[types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS](state, environments) {
|
||||
state.environments = environments;
|
||||
},
|
||||
[types.RECEIVE_ENVIRONMENTS_DATA_FAILURE](state) {
|
||||
state.environments = [];
|
||||
},
|
||||
[types.SET_ENDPOINTS](state, endpoints) {
|
||||
state.metricsEndpoint = endpoints.metricsEndpoint;
|
||||
state.environmentsEndpoint = endpoints.environmentsEndpoint;
|
||||
state.deploymentsEndpoint = endpoints.deploymentsEndpoint;
|
||||
},
|
||||
[types.SET_GETTING_STARTED_EMPTY_STATE](state) {
|
||||
state.emptyState = 'gettingStarted';
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
export default () => ({
|
||||
hasMetrics: false,
|
||||
showPanels: true,
|
||||
metricsEndpoint: null,
|
||||
environmentsEndpoint: null,
|
||||
deploymentsEndpoint: null,
|
||||
emptyState: 'gettingStarted',
|
||||
showEmptyState: true,
|
||||
groups: [],
|
||||
deploymentData: [],
|
||||
environments: [],
|
||||
});
|
||||
|
|
@ -1,12 +1,5 @@
|
|||
import _ from 'underscore';
|
||||
|
||||
function sortMetrics(metrics) {
|
||||
return _.chain(metrics)
|
||||
.sortBy('title')
|
||||
.sortBy('weight')
|
||||
.value();
|
||||
}
|
||||
|
||||
function checkQueryEmptyData(query) {
|
||||
return {
|
||||
...query,
|
||||
|
|
@ -59,7 +52,13 @@ function groupQueriesByChartInfo(metrics) {
|
|||
return Object.values(metricsByChart);
|
||||
}
|
||||
|
||||
function normalizeMetrics(metrics) {
|
||||
export const sortMetrics = metrics =>
|
||||
_.chain(metrics)
|
||||
.sortBy('title')
|
||||
.sortBy('weight')
|
||||
.value();
|
||||
|
||||
export const normalizeMetrics = metrics => {
|
||||
const groupedMetrics = groupQueriesByChartInfo(metrics);
|
||||
|
||||
return groupedMetrics.map(metric => {
|
||||
|
|
@ -81,31 +80,4 @@ function normalizeMetrics(metrics) {
|
|||
queries: removeTimeSeriesNoData(queries),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export default class MonitoringStore {
|
||||
constructor() {
|
||||
this.groups = [];
|
||||
this.deploymentData = [];
|
||||
this.environmentsData = [];
|
||||
}
|
||||
|
||||
storeMetrics(groups = []) {
|
||||
this.groups = groups.map(group => ({
|
||||
...group,
|
||||
metrics: normalizeMetrics(sortMetrics(group.metrics)),
|
||||
}));
|
||||
}
|
||||
|
||||
storeDeploymentData(deploymentData = []) {
|
||||
this.deploymentData = deploymentData;
|
||||
}
|
||||
|
||||
storeEnvironmentsData(environmentsData = []) {
|
||||
this.environmentsData = environmentsData.filter(environment => !!environment.last_deployment);
|
||||
}
|
||||
|
||||
getMetricsCount() {
|
||||
return this.groups.reduce((count, group) => count + group.metrics.length, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -148,12 +148,9 @@ export default {
|
|||
href="#"
|
||||
title="Add reaction"
|
||||
>
|
||||
<icon
|
||||
css-classes="link-highlight award-control-icon-neutral"
|
||||
name="emoji_slightly_smiling_face"
|
||||
/>
|
||||
<icon css-classes="link-highlight award-control-icon-positive" name="emoji_smiley" />
|
||||
<icon css-classes="link-highlight award-control-icon-super-positive" name="emoji_smiley" />
|
||||
<icon css-classes="link-highlight award-control-icon-neutral" name="slight-smile" />
|
||||
<icon css-classes="link-highlight award-control-icon-positive" name="smiley" />
|
||||
<icon css-classes="link-highlight award-control-icon-super-positive" name="smiley" />
|
||||
</a>
|
||||
</div>
|
||||
<reply-button
|
||||
|
|
|
|||
|
|
@ -189,13 +189,13 @@ export default {
|
|||
type="button"
|
||||
>
|
||||
<span class="award-control-icon award-control-icon-neutral">
|
||||
<icon name="emoji_slightly_smiling_face" />
|
||||
<icon name="slight-smile" />
|
||||
</span>
|
||||
<span class="award-control-icon award-control-icon-positive">
|
||||
<icon name="emoji_smiley" />
|
||||
<icon name="smiley" />
|
||||
</span>
|
||||
<span class="award-control-icon award-control-icon-super-positive">
|
||||
<icon name="emoji_smiley" />
|
||||
<icon name="smiley" />
|
||||
</span>
|
||||
<i
|
||||
aria-hidden="true"
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ export default {
|
|||
text() {
|
||||
return sprintf(
|
||||
s__(`Milestones|Promoting %{milestoneTitle} will make it available for all projects inside %{groupName}.
|
||||
Existing project milestones with the same title will be merged.
|
||||
This action cannot be reversed.`),
|
||||
Existing project milestones with the same title will be merged.`),
|
||||
{ milestoneTitle: this.milestoneTitle, groupName: this.groupName },
|
||||
);
|
||||
},
|
||||
|
|
@ -72,6 +71,9 @@ export default {
|
|||
<template slot="title">
|
||||
{{ title }}
|
||||
</template>
|
||||
{{ text }}
|
||||
<div>
|
||||
<p>{{ text }}</p>
|
||||
<p>{{ s__('Milestones|This action cannot be reversed.') }}</p>
|
||||
</div>
|
||||
</gl-modal>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import pdfjsLib from 'vendor/pdf';
|
||||
import workerSrc from 'vendor/pdf.worker.min';
|
||||
import pdfjsLib from 'pdfjs-dist/build/pdf';
|
||||
import workerSrc from 'pdfjs-dist/build/pdf.worker.min';
|
||||
|
||||
import page from './page/index.vue';
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,9 @@ export default {
|
|||
>
|
||||
<ci-icon :status="group.status" />
|
||||
|
||||
<span class="ci-status-text"> {{ group.name }} </span>
|
||||
<span class="ci-status-text text-truncate mw-70p gl-pl-1 d-inline-block align-bottom">
|
||||
{{ group.name }}
|
||||
</span>
|
||||
|
||||
<span class="dropdown-counter-badge"> {{ group.size }} </span>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ export default class ProjectLabelSubscription {
|
|||
let newAction;
|
||||
|
||||
if (oldStatus === 'unsubscribed') {
|
||||
[newStatus, newAction] = ['subscribed', 'Unsubscribe'];
|
||||
[newStatus, newAction] = ['subscribed', __('Unsubscribe')];
|
||||
} else {
|
||||
[newStatus, newAction] = ['unsubscribed', 'Subscribe'];
|
||||
[newStatus, newAction] = ['unsubscribed', __('Subscribe')];
|
||||
}
|
||||
|
||||
$btn.removeClass('disabled');
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import $ from 'jquery';
|
||||
import Api from './api';
|
||||
import ProjectSelectComboButton from './project_select_combo_button';
|
||||
import { s__ } from './locale';
|
||||
|
||||
export default function projectSelect() {
|
||||
import(/* webpackChunkName: 'select2' */ 'select2/select2')
|
||||
|
|
@ -21,9 +22,9 @@ export default function projectSelect() {
|
|||
this.includeProjectsInSubgroups = $(select).data('includeProjectsInSubgroups') || false;
|
||||
this.allowClear = $(select).data('allowClear') || false;
|
||||
|
||||
placeholder = 'Search for project';
|
||||
placeholder = s__('ProjectSelect|Search for project');
|
||||
if (this.includeGroups) {
|
||||
placeholder += ' or group';
|
||||
placeholder += s__('ProjectSelect| or group');
|
||||
}
|
||||
|
||||
$(select).select2({
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ export default {
|
|||
<button
|
||||
v-if="isCollapsible"
|
||||
type="button"
|
||||
class="js-collapse-btn btn float-right btn-sm"
|
||||
class="js-collapse-btn btn float-right btn-sm qa-expand-report-button"
|
||||
@click="toggleCollapsed"
|
||||
>
|
||||
{{ collapseText }}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
<script>
|
||||
import getRefMixin from '../mixins/get_ref';
|
||||
import getProjectShortPath from '../queries/getProjectShortPath.graphql';
|
||||
|
||||
export default {
|
||||
apollo: {
|
||||
projectShortPath: {
|
||||
query: getProjectShortPath,
|
||||
},
|
||||
},
|
||||
mixins: [getRefMixin],
|
||||
props: {
|
||||
currentPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '/',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
projectShortPath: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
pathLinks() {
|
||||
return this.currentPath
|
||||
.split('/')
|
||||
.filter(p => p !== '')
|
||||
.reduce(
|
||||
(acc, name, i) => {
|
||||
const path = `${i > 0 ? acc[i].path : ''}/${name}`;
|
||||
|
||||
return acc.concat({
|
||||
name,
|
||||
path,
|
||||
to: `/tree/${this.ref}${path}`,
|
||||
});
|
||||
},
|
||||
[{ name: this.projectShortPath, path: '/', to: `/tree/${this.ref}` }],
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isLast(i) {
|
||||
return i === this.pathLinks.length - 1;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav :aria-label="__('Files breadcrumb')">
|
||||
<ol class="breadcrumb repo-breadcrumb">
|
||||
<li v-for="(link, i) in pathLinks" :key="i" class="breadcrumb-item">
|
||||
<router-link :to="link.to" :aria-current="isLast(i) ? 'page' : null">
|
||||
{{ link.name }}
|
||||
</router-link>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<template>
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="name" scope="col">{{ s__('ProjectFileTree|Name') }}</th>
|
||||
<th id="last-commit" scope="col" class="d-none d-sm-table-cell">{{ __('Last commit') }}</th>
|
||||
<th id="last-update" scope="col" class="text-right">{{ __('Last update') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
<script>
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import createFlash from '~/flash';
|
||||
import { sprintf, __ } from '../../../locale';
|
||||
import getRefMixin from '../../mixins/get_ref';
|
||||
import getFiles from '../../queries/getFiles.graphql';
|
||||
import getProjectPath from '../../queries/getProjectPath.graphql';
|
||||
import TableHeader from './header.vue';
|
||||
import TableRow from './row.vue';
|
||||
import ParentRow from './parent_row.vue';
|
||||
|
||||
const PAGE_SIZE = 100;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlLoadingIcon,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
ParentRow,
|
||||
},
|
||||
mixins: [getRefMixin],
|
||||
apollo: {
|
||||
projectPath: {
|
||||
query: getProjectPath,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
path: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
projectPath: '',
|
||||
nextPageCursor: '',
|
||||
entries: {
|
||||
trees: [],
|
||||
submodules: [],
|
||||
blobs: [],
|
||||
},
|
||||
isLoadingFiles: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
tableCaption() {
|
||||
return sprintf(
|
||||
__('Files, directories, and submodules in the path %{path} for commit reference %{ref}'),
|
||||
{ path: this.path, ref: this.ref },
|
||||
);
|
||||
},
|
||||
showParentRow() {
|
||||
return !this.isLoadingFiles && ['', '/'].indexOf(this.path) === -1;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
$route: function routeChange() {
|
||||
this.entries.trees = [];
|
||||
this.entries.submodules = [];
|
||||
this.entries.blobs = [];
|
||||
this.nextPageCursor = '';
|
||||
this.fetchFiles();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// We need to wait for `ref` and `projectPath` to be set
|
||||
this.$nextTick(() => this.fetchFiles());
|
||||
},
|
||||
methods: {
|
||||
fetchFiles() {
|
||||
this.isLoadingFiles = true;
|
||||
|
||||
return this.$apollo
|
||||
.query({
|
||||
query: getFiles,
|
||||
variables: {
|
||||
projectPath: this.projectPath,
|
||||
ref: this.ref,
|
||||
path: this.path,
|
||||
nextPageCursor: this.nextPageCursor,
|
||||
pageSize: PAGE_SIZE,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => {
|
||||
if (!data) return;
|
||||
|
||||
const pageInfo = this.hasNextPage(data.project.repository.tree);
|
||||
|
||||
this.isLoadingFiles = false;
|
||||
this.entries = Object.keys(this.entries).reduce(
|
||||
(acc, key) => ({
|
||||
...acc,
|
||||
[key]: this.normalizeData(key, data.project.repository.tree[key].edges),
|
||||
}),
|
||||
{},
|
||||
);
|
||||
|
||||
if (pageInfo && pageInfo.hasNextPage) {
|
||||
this.nextPageCursor = pageInfo.endCursor;
|
||||
this.fetchFiles();
|
||||
}
|
||||
})
|
||||
.catch(() => createFlash(__('An error occurding while fetching folder content.')));
|
||||
},
|
||||
normalizeData(key, data) {
|
||||
return this.entries[key].concat(data.map(({ node }) => node));
|
||||
},
|
||||
hasNextPage(data) {
|
||||
return []
|
||||
.concat(data.trees.pageInfo, data.submodules.pageInfo, data.blobs.pageInfo)
|
||||
.find(({ hasNextPage }) => hasNextPage);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="tree-content-holder">
|
||||
<div class="table-holder bordered-box">
|
||||
<table class="table tree-table qa-file-tree" aria-live="polite">
|
||||
<caption class="sr-only">
|
||||
{{
|
||||
tableCaption
|
||||
}}
|
||||
</caption>
|
||||
<table-header v-once />
|
||||
<tbody>
|
||||
<parent-row v-show="showParentRow" :commit-ref="ref" :path="path" />
|
||||
<template v-for="val in entries">
|
||||
<table-row
|
||||
v-for="entry in val"
|
||||
:id="entry.id"
|
||||
:key="`${entry.flatPath}-${entry.id}`"
|
||||
:current-path="path"
|
||||
:path="entry.flatPath"
|
||||
:type="entry.type"
|
||||
/>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
<gl-loading-icon v-show="isLoadingFiles" class="my-3" size="md" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<script>
|
||||
export default {
|
||||
props: {
|
||||
commitRef: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
path: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
parentRoute() {
|
||||
const splitArray = this.path.split('/');
|
||||
splitArray.pop();
|
||||
|
||||
return { path: `/tree/${this.commitRef}/${splitArray.join('/')}` };
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clickRow() {
|
||||
this.$router.push(this.parentRoute);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tr v-once @click="clickRow">
|
||||
<td colspan="3" class="tree-item-file-name">
|
||||
<router-link :to="parentRoute" :aria-label="__('Go to parent')">
|
||||
..
|
||||
</router-link>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<script>
|
||||
import { getIconName } from '../../utils/icon';
|
||||
import getRefMixin from '../../mixins/get_ref';
|
||||
|
||||
export default {
|
||||
mixins: [getRefMixin],
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
currentPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
path: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
routerLinkTo() {
|
||||
return this.isFolder ? { path: `/tree/${this.ref}/${this.path}` } : null;
|
||||
},
|
||||
iconName() {
|
||||
return `fa-${getIconName(this.type, this.path)}`;
|
||||
},
|
||||
isFolder() {
|
||||
return this.type === 'tree';
|
||||
},
|
||||
isSubmodule() {
|
||||
return this.type === 'commit';
|
||||
},
|
||||
linkComponent() {
|
||||
return this.isFolder ? 'router-link' : 'a';
|
||||
},
|
||||
fullPath() {
|
||||
return this.path.replace(new RegExp(`^${this.currentPath}/`), '');
|
||||
},
|
||||
shortSha() {
|
||||
return this.id.slice(0, 8);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openRow() {
|
||||
if (this.isFolder) {
|
||||
this.$router.push(this.routerLinkTo);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tr v-once :class="`file_${id}`" class="tree-item" @click="openRow">
|
||||
<td class="tree-item-file-name">
|
||||
<i :aria-label="type" role="img" :class="iconName" class="fa fa-fw"></i>
|
||||
<component :is="linkComponent" :to="routerLinkTo" class="str-truncated">
|
||||
{{ fullPath }}
|
||||
</component>
|
||||
<template v-if="isSubmodule">
|
||||
@ <a href="#" class="commit-sha">{{ shortSha }}</a>
|
||||
</template>
|
||||
</td>
|
||||
<td class="d-none d-sm-table-cell tree-commit"></td>
|
||||
<td class="tree-time-ago text-right"></td>
|
||||
</tr>
|
||||
</template>
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"__schema":{"types":[{"kind":"INTERFACE","name":"Entry","possibleTypes":[{"name":"Blob"},{"name":"Submodule"},{"name":"TreeEntry"}]}]}}
|
||||
|
|
@ -1,10 +1,42 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
import introspectionQueryResultData from './fragmentTypes.json';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
const defaultClient = createDefaultClient({});
|
||||
// We create a fragment matcher so that we can create a fragment from an interface
|
||||
// Without this, Apollo throws a heuristic fragment matcher warning
|
||||
const fragmentMatcher = new IntrospectionFragmentMatcher({
|
||||
introspectionQueryResultData,
|
||||
});
|
||||
|
||||
const defaultClient = createDefaultClient(
|
||||
{},
|
||||
{
|
||||
cacheConfig: {
|
||||
fragmentMatcher,
|
||||
dataIdFromObject: obj => {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
switch (obj.__typename) {
|
||||
// We need to create a dynamic ID for each entry
|
||||
// Each entry can have the same ID as the ID is a commit ID
|
||||
// So we create a unique cache ID with the path and the ID
|
||||
case 'TreeEntry':
|
||||
case 'Submodule':
|
||||
case 'Blob':
|
||||
return `${obj.flatPath}-${obj.id}`;
|
||||
default:
|
||||
// If the type doesn't match any of the above we fallback
|
||||
// to using the default Apollo ID
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
return obj.id || obj._id;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export default new VueApollo({
|
||||
defaultClient,
|
||||
|
|
|
|||
|
|
@ -1,22 +1,56 @@
|
|||
import Vue from 'vue';
|
||||
import createRouter from './router';
|
||||
import App from './components/app.vue';
|
||||
import Breadcrumbs from './components/breadcrumbs.vue';
|
||||
import apolloProvider from './graphql';
|
||||
import { setTitle } from './utils/title';
|
||||
|
||||
export default function setupVueRepositoryList() {
|
||||
const el = document.getElementById('js-tree-list');
|
||||
const { projectPath, ref } = el.dataset;
|
||||
const { projectPath, projectShortPath, ref, fullName } = el.dataset;
|
||||
const router = createRouter(projectPath, ref);
|
||||
|
||||
apolloProvider.clients.defaultClient.cache.writeData({
|
||||
data: {
|
||||
projectPath,
|
||||
projectShortPath,
|
||||
ref,
|
||||
},
|
||||
});
|
||||
|
||||
router.afterEach(({ params: { pathMatch } }) => {
|
||||
const isRoot = pathMatch === undefined || pathMatch === '/';
|
||||
|
||||
setTitle(pathMatch, ref, fullName);
|
||||
|
||||
if (!isRoot) {
|
||||
document
|
||||
.querySelectorAll('.js-keep-hidden-on-navigation')
|
||||
.forEach(elem => elem.classList.add('hidden'));
|
||||
}
|
||||
|
||||
document
|
||||
.querySelectorAll('.js-hide-on-navigation')
|
||||
.forEach(elem => elem.classList.toggle('hidden', !isRoot));
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new Vue({
|
||||
el: document.getElementById('js-repo-breadcrumb'),
|
||||
router,
|
||||
apolloProvider,
|
||||
render(h) {
|
||||
return h(Breadcrumbs, {
|
||||
props: {
|
||||
currentPath: this.$route.params.pathMatch,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
router: createRouter(projectPath, ref),
|
||||
router,
|
||||
apolloProvider,
|
||||
render(h) {
|
||||
return h(App);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
import getRef from '../queries/getRef.graphql';
|
||||
|
||||
export default {
|
||||
apollo: {
|
||||
ref: {
|
||||
query: getRef,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ref: '',
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
<script>
|
||||
import getRef from '../queries/getRef.graphql';
|
||||
import FileTable from '../components/table/index.vue';
|
||||
|
||||
export default {
|
||||
apollo: {
|
||||
ref: {
|
||||
query: getRef,
|
||||
},
|
||||
components: {
|
||||
FileTable,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -16,9 +14,5 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<router-link :to="{ path: `/tree/${ref}/app` }">
|
||||
Go to tree
|
||||
</router-link>
|
||||
</div>
|
||||
<file-table path="/" />
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
<script>
|
||||
import FileTable from '../components/table/index.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FileTable,
|
||||
},
|
||||
props: {
|
||||
path: {
|
||||
type: String,
|
||||
|
|
@ -11,5 +16,5 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div>{{ path }}</div>
|
||||
<file-table :path="path" />
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
fragment TreeEntry on Entry {
|
||||
id
|
||||
flatPath
|
||||
type
|
||||
}
|
||||
|
||||
fragment PageInfo on PageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
|
||||
query getFiles(
|
||||
$projectPath: ID!
|
||||
$path: String
|
||||
$ref: String!
|
||||
$pageSize: Int!
|
||||
$nextPageCursor: String
|
||||
) {
|
||||
project(fullPath: $projectPath) {
|
||||
repository {
|
||||
tree(path: $path, ref: $ref) {
|
||||
trees(first: $pageSize, after: $nextPageCursor) {
|
||||
edges {
|
||||
node {
|
||||
...TreeEntry
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
...PageInfo
|
||||
}
|
||||
}
|
||||
submodules(first: $pageSize, after: $nextPageCursor) {
|
||||
edges {
|
||||
node {
|
||||
...TreeEntry
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
...PageInfo
|
||||
}
|
||||
}
|
||||
blobs(first: $pageSize, after: $nextPageCursor) {
|
||||
edges {
|
||||
node {
|
||||
...TreeEntry
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
...PageInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
query getProjectPath {
|
||||
projectPath
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
query getProjectShortPath {
|
||||
projectShortPath @client
|
||||
}
|
||||
|
|
@ -11,25 +11,18 @@ export default function createRouter(base, baseRef) {
|
|||
mode: 'history',
|
||||
base: joinPaths(gon.relative_url_root || '', base),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'projectRoot',
|
||||
component: IndexPage,
|
||||
},
|
||||
{
|
||||
path: `/tree/${baseRef}(/.*)?`,
|
||||
name: 'treePath',
|
||||
component: TreePage,
|
||||
props: route => ({
|
||||
path: route.params.pathMatch,
|
||||
path: route.params.pathMatch && route.params.pathMatch.replace(/^\//, ''),
|
||||
}),
|
||||
beforeEnter(to, from, next) {
|
||||
document
|
||||
.querySelectorAll('.js-hide-on-navigation')
|
||||
.forEach(el => el.classList.add('hidden'));
|
||||
|
||||
next();
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: 'projectRoot',
|
||||
component: IndexPage,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
const entryTypeIcons = {
|
||||
tree: 'folder',
|
||||
commit: 'archive',
|
||||
};
|
||||
|
||||
const fileTypeIcons = [
|
||||
{ extensions: ['pdf'], name: 'file-pdf-o' },
|
||||
{
|
||||
extensions: [
|
||||
'jpg',
|
||||
'jpeg',
|
||||
'jif',
|
||||
'jfif',
|
||||
'jp2',
|
||||
'jpx',
|
||||
'j2k',
|
||||
'j2c',
|
||||
'png',
|
||||
'gif',
|
||||
'tif',
|
||||
'tiff',
|
||||
'svg',
|
||||
'ico',
|
||||
'bmp',
|
||||
],
|
||||
name: 'file-image-o',
|
||||
},
|
||||
{
|
||||
extensions: ['zip', 'zipx', 'tar', 'gz', 'bz', 'bzip', 'xz', 'rar', '7z'],
|
||||
name: 'file-archive-o',
|
||||
},
|
||||
{ extensions: ['mp3', 'wma', 'ogg', 'oga', 'wav', 'flac', 'aac'], name: 'file-audio-o' },
|
||||
{
|
||||
extensions: [
|
||||
'mp4',
|
||||
'm4p',
|
||||
'm4v',
|
||||
'mpg',
|
||||
'mp2',
|
||||
'mpeg',
|
||||
'mpe',
|
||||
'mpv',
|
||||
'm2v',
|
||||
'avi',
|
||||
'mkv',
|
||||
'flv',
|
||||
'ogv',
|
||||
'mov',
|
||||
'3gp',
|
||||
'3g2',
|
||||
],
|
||||
name: 'file-video-o',
|
||||
},
|
||||
{ extensions: ['doc', 'dot', 'docx', 'docm', 'dotx', 'dotm', 'docb'], name: 'file-word-o' },
|
||||
{
|
||||
extensions: [
|
||||
'xls',
|
||||
'xlt',
|
||||
'xlm',
|
||||
'xlsx',
|
||||
'xlsm',
|
||||
'xltx',
|
||||
'xltm',
|
||||
'xlsb',
|
||||
'xla',
|
||||
'xlam',
|
||||
'xll',
|
||||
'xlw',
|
||||
],
|
||||
name: 'file-excel-o',
|
||||
},
|
||||
{
|
||||
extensions: [
|
||||
'ppt',
|
||||
'pot',
|
||||
'pps',
|
||||
'pptx',
|
||||
'pptm',
|
||||
'potx',
|
||||
'potm',
|
||||
'ppam',
|
||||
'ppsx',
|
||||
'ppsm',
|
||||
'sldx',
|
||||
'sldm',
|
||||
],
|
||||
name: 'file-powerpoint-o',
|
||||
},
|
||||
];
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const getIconName = (type, path) => {
|
||||
if (entryTypeIcons[type]) return entryTypeIcons[type];
|
||||
|
||||
const extension = path.split('.').pop();
|
||||
const file = fileTypeIcons.find(t => t.extensions.some(ext => ext === extension));
|
||||
|
||||
return file ? file.name : 'file-text-o';
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const setTitle = (pathMatch, ref, project) => {
|
||||
if (!pathMatch) return;
|
||||
|
||||
const path = pathMatch.replace(/^\//, '');
|
||||
const isEmpty = path === '';
|
||||
|
||||
document.title = `${isEmpty ? 'Files' : path} · ${ref} · ${project}`;
|
||||
};
|
||||
|
|
@ -5,7 +5,7 @@ import _ from 'underscore';
|
|||
import Cookies from 'js-cookie';
|
||||
import flash from './flash';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { __ } from './locale';
|
||||
import { sprintf, s__, __ } from './locale';
|
||||
|
||||
function Sidebar(currentUser) {
|
||||
this.toggleTodo = this.toggleTodo.bind(this);
|
||||
|
|
@ -101,7 +101,10 @@ Sidebar.prototype.toggleTodo = function(e) {
|
|||
this.todoUpdateDone(data);
|
||||
})
|
||||
.catch(() =>
|
||||
flash(`There was an error ${ajaxType === 'post' ? 'adding a' : 'deleting the'} todo.`),
|
||||
flash(sprintf(__('There was an error %{message} todo.')), {
|
||||
message:
|
||||
ajaxType === 'post' ? s__('RightSidebar|adding a') : s__('RightSidebar|deleting the'),
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import $ from 'jquery';
|
||||
import { escape, throttle } from 'underscore';
|
||||
import { s__, sprintf } from '~/locale';
|
||||
import { s__, __, sprintf } from '~/locale';
|
||||
import { getIdenticonBackgroundClass, getIdenticonTitle } from '~/helpers/avatar_helper';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import DropdownUtils from './filtered_search/dropdown_utils';
|
||||
|
|
@ -407,6 +407,7 @@ export class SearchAutocomplete {
|
|||
if (this.searchInput.val() === '') {
|
||||
return this.restoreOriginalState();
|
||||
}
|
||||
this.dropdownMenu.removeClass('show');
|
||||
}
|
||||
|
||||
restoreOriginalState() {
|
||||
|
|
@ -439,7 +440,7 @@ export class SearchAutocomplete {
|
|||
|
||||
restoreMenu() {
|
||||
var html;
|
||||
html = '<ul><li class="dropdown-menu-empty-item"><a>Loading...</a></li></ul>';
|
||||
html = `<ul><li class="dropdown-menu-empty-item"><a>${__('Loading...')}</a></li></ul>`;
|
||||
return this.dropdownContent.html(html);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,9 +194,9 @@ export default {
|
|||
v-show="noEmoji"
|
||||
class="js-no-emoji-placeholder no-emoji-placeholder position-relative"
|
||||
>
|
||||
<icon name="emoji_slightly_smiling_face" css-classes="award-control-icon-neutral" />
|
||||
<icon name="emoji_smiley" css-classes="award-control-icon-positive" />
|
||||
<icon name="emoji_smile" css-classes="award-control-icon-super-positive" />
|
||||
<icon name="slight-smile" css-classes="award-control-icon-neutral" />
|
||||
<icon name="smiley" css-classes="award-control-icon-positive" />
|
||||
<icon name="smile" css-classes="award-control-icon-super-positive" />
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export default class Star {
|
|||
$this.prepend(spriteIcon('star', iconClasses));
|
||||
}
|
||||
})
|
||||
.catch(() => Flash('Star toggle failed. Try again later.'));
|
||||
.catch(() => Flash(__('Star toggle failed. Try again later.')));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import $ from 'jquery';
|
||||
import { __ } from './locale';
|
||||
|
||||
export default function subscriptionSelect() {
|
||||
$('.js-subscription-event').each((i, element) => {
|
||||
|
|
@ -8,7 +9,7 @@ export default function subscriptionSelect() {
|
|||
selectable: true,
|
||||
fieldName,
|
||||
toggleLabel(selected, el, instance) {
|
||||
let label = 'Subscription';
|
||||
let label = __('Subscription');
|
||||
const $item = instance.dropdown.find('.is-active');
|
||||
if ($item.length) {
|
||||
label = $item.text();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import $ from 'jquery';
|
|||
import axios from './lib/utils/axios_utils';
|
||||
import Flash, { hideFlash } from './flash';
|
||||
import { parseBoolean } from './lib/utils/common_utils';
|
||||
import { __ } from './locale';
|
||||
|
||||
export default () => {
|
||||
$('body').on('click', '.js-usage-consent-action', e => {
|
||||
|
|
@ -25,7 +26,7 @@ export default () => {
|
|||
})
|
||||
.catch(() => {
|
||||
hideConsentMessage();
|
||||
Flash('Something went wrong. Try again later.');
|
||||
Flash(__('Something went wrong. Try again later.'));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import $ from 'jquery';
|
||||
import _ from 'underscore';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { __ } from './locale';
|
||||
import { s__, __, sprintf } from './locale';
|
||||
import ModalStore from './boards/stores/modal_store';
|
||||
|
||||
// TODO: remove eventHub hack after code splitting refactor
|
||||
|
|
@ -157,14 +157,20 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
.get(0);
|
||||
|
||||
if (selectedUsers.length === 0) {
|
||||
return 'Unassigned';
|
||||
return s__('UsersSelect|Unassigned');
|
||||
} else if (selectedUsers.length === 1) {
|
||||
return firstUser.name;
|
||||
} else if (isSelected) {
|
||||
const otherSelected = selectedUsers.filter(s => s !== selectedUser.id);
|
||||
return `${selectedUser.name} + ${otherSelected.length} more`;
|
||||
return sprintf(s__('UsersSelect|%{name} + %{length} more'), {
|
||||
name: selectedUser.name,
|
||||
length: otherSelected.length,
|
||||
});
|
||||
} else {
|
||||
return `${firstUser.name} + ${selectedUsers.length - 1} more`;
|
||||
return sprintf(s__('UsersSelect|%{name} + %{length} more'), {
|
||||
name: firstUser.name,
|
||||
length: selectedUsers.length - 1,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -218,11 +224,11 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
tooltipTitle = _.escape(user.name);
|
||||
} else {
|
||||
user = {
|
||||
name: 'Unassigned',
|
||||
name: s__('UsersSelect|Unassigned'),
|
||||
username: '',
|
||||
avatar: '',
|
||||
};
|
||||
tooltipTitle = __('Assignee');
|
||||
tooltipTitle = s__('UsersSelect|Assignee');
|
||||
}
|
||||
$value.html(assigneeTemplate(user));
|
||||
$collapsedSidebar.attr('title', tooltipTitle).tooltip('_fixTitle');
|
||||
|
|
@ -233,7 +239,11 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
'<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>',
|
||||
);
|
||||
assigneeTemplate = _.template(
|
||||
'<% if (username) { %> <a class="author-link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself"> No assignee - <a href="#" class="js-assign-yourself"> assign yourself </a> </span> <% } %>',
|
||||
`<% if (username) { %> <a class="author-link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself">
|
||||
${sprintf(s__('UsersSelect|No assignee - %{openingTag} assign yourself %{closingTag}'), {
|
||||
openingTag: '<a href="#" class="js-assign-yourself">',
|
||||
closingTag: '</a>',
|
||||
})}</span> <% } %>`,
|
||||
);
|
||||
return $dropdown.glDropdown({
|
||||
showMenuAbove: showMenuAbove,
|
||||
|
|
@ -302,7 +312,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
showDivider += 1;
|
||||
users.unshift({
|
||||
beforeDivider: true,
|
||||
name: 'Unassigned',
|
||||
name: s__('UsersSelect|Unassigned'),
|
||||
id: 0,
|
||||
});
|
||||
}
|
||||
|
|
@ -310,7 +320,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
showDivider += 1;
|
||||
name = showAnyUser;
|
||||
if (name === true) {
|
||||
name = 'Any User';
|
||||
name = s__('UsersSelect|Any User');
|
||||
}
|
||||
anyUser = {
|
||||
beforeDivider: true,
|
||||
|
|
@ -596,7 +606,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
showEmailUser = $(select).data('emailUser');
|
||||
firstUser = $(select).data('firstUser');
|
||||
return $(select).select2({
|
||||
placeholder: 'Search for a user',
|
||||
placeholder: __('Search for a user'),
|
||||
multiple: $(select).hasClass('multiselect'),
|
||||
minimumInputLength: 0,
|
||||
query: function(query) {
|
||||
|
|
@ -621,7 +631,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
}
|
||||
if (showNullUser) {
|
||||
nullUser = {
|
||||
name: 'Unassigned',
|
||||
name: s__('UsersSelect|Unassigned'),
|
||||
id: 0,
|
||||
};
|
||||
data.results.unshift(nullUser);
|
||||
|
|
@ -629,7 +639,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
if (showAnyUser) {
|
||||
name = showAnyUser;
|
||||
if (name === true) {
|
||||
name = 'Any User';
|
||||
name = s__('UsersSelect|Any User');
|
||||
}
|
||||
anyUser = {
|
||||
name: name,
|
||||
|
|
@ -645,7 +655,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
) {
|
||||
var trimmed = query.term.trim();
|
||||
emailUser = {
|
||||
name: 'Invite "' + trimmed + '" by email',
|
||||
name: sprintf(__('Invite "%{trimmed}" by email'), { trimmed }),
|
||||
username: trimmed,
|
||||
id: trimmed,
|
||||
invite: true,
|
||||
|
|
@ -688,7 +698,7 @@ UsersSelect.prototype.initSelection = function(element, callback) {
|
|||
id = $(element).val();
|
||||
if (id === '0') {
|
||||
nullUser = {
|
||||
name: 'Unassigned',
|
||||
name: s__('UsersSelect|Unassigned'),
|
||||
};
|
||||
return callback(nullUser);
|
||||
} else if (id !== '') {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export default {
|
|||
required: false,
|
||||
default: () => ({
|
||||
sourceProjectId: '',
|
||||
issueId: '',
|
||||
mergeRequestId: '',
|
||||
appUrl: '',
|
||||
}),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export default {
|
|||
visualReviewAppMeta() {
|
||||
return {
|
||||
appUrl: this.mr.appUrl,
|
||||
issueId: this.mr.iid,
|
||||
mergeRequestId: this.mr.iid,
|
||||
sourceProjectId: this.mr.sourceProjectId,
|
||||
};
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<p v-once class="mr-info-list mr-links source-branch-removal-status append-bottom-0">
|
||||
<p v-once class="mr-info-list mr-links append-bottom-0">
|
||||
<span class="status-text" v-html="removesBranchText"> </span>
|
||||
<i v-tooltip :title="tooltipTitle" :aria-label="tooltipTitle" class="fa fa-question-circle">
|
||||
</i>
|
||||
|
|
|
|||
|
|
@ -333,41 +333,45 @@ export default {
|
|||
<div class="mr-widget-section">
|
||||
<component :is="componentName" :mr="mr" :service="service" />
|
||||
|
||||
<section v-if="shouldRenderCollaborationStatus" class="mr-info-list mr-links">
|
||||
{{ s__('mrWidget|Allows commits from members who can merge to the target branch') }}
|
||||
</section>
|
||||
<div class="mr-widget-info">
|
||||
<section v-if="shouldRenderCollaborationStatus" class="mr-info-list mr-links">
|
||||
<p>
|
||||
{{ s__('mrWidget|Allows commits from members who can merge to the target branch') }}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<mr-widget-related-links
|
||||
v-if="shouldRenderRelatedLinks"
|
||||
:state="mr.state"
|
||||
:related-links="mr.relatedLinks"
|
||||
/>
|
||||
<mr-widget-related-links
|
||||
v-if="shouldRenderRelatedLinks"
|
||||
:state="mr.state"
|
||||
:related-links="mr.relatedLinks"
|
||||
/>
|
||||
|
||||
<mr-widget-alert-message
|
||||
v-if="showMergePipelineForkWarning"
|
||||
type="warning"
|
||||
:help-path="mr.mergeRequestPipelinesHelpPath"
|
||||
>
|
||||
{{
|
||||
s__(
|
||||
'mrWidget|Fork merge requests do not create merge request pipelines which validate a post merge result',
|
||||
)
|
||||
}}
|
||||
</mr-widget-alert-message>
|
||||
<mr-widget-alert-message
|
||||
v-if="showMergePipelineForkWarning"
|
||||
type="warning"
|
||||
:help-path="mr.mergeRequestPipelinesHelpPath"
|
||||
>
|
||||
{{
|
||||
s__(
|
||||
'mrWidget|Fork merge requests do not create merge request pipelines which validate a post merge result',
|
||||
)
|
||||
}}
|
||||
</mr-widget-alert-message>
|
||||
|
||||
<mr-widget-alert-message
|
||||
v-if="showTargetBranchAdvancedError"
|
||||
type="danger"
|
||||
:help-path="mr.mergeRequestPipelinesHelpPath"
|
||||
>
|
||||
{{
|
||||
s__(
|
||||
'mrWidget|The target branch has advanced, which invalidates the merge request pipeline. Please update the source branch and retry merging',
|
||||
)
|
||||
}}
|
||||
</mr-widget-alert-message>
|
||||
<mr-widget-alert-message
|
||||
v-if="showTargetBranchAdvancedError"
|
||||
type="danger"
|
||||
:help-path="mr.mergeRequestPipelinesHelpPath"
|
||||
>
|
||||
{{
|
||||
s__(
|
||||
'mrWidget|The target branch has advanced, which invalidates the merge request pipeline. Please update the source branch and retry merging',
|
||||
)
|
||||
}}
|
||||
</mr-widget-alert-message>
|
||||
|
||||
<source-branch-removal-status v-if="shouldRenderSourceBranchRemovalStatus" />
|
||||
<source-branch-removal-status v-if="shouldRenderSourceBranchRemovalStatus" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="shouldRenderMergeHelp" class="mr-widget-footer"><mr-widget-merge-help /></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -71,11 +71,15 @@ export default {
|
|||
</div>
|
||||
<div class="text-secondary">
|
||||
<div v-if="user.bio" class="js-bio d-flex mb-1">
|
||||
<icon name="profile" css-classes="category-icon" />
|
||||
<icon name="profile" css-classes="category-icon flex-shrink-0" />
|
||||
<span class="ml-1">{{ user.bio }}</span>
|
||||
</div>
|
||||
<div v-if="user.organization" class="js-organization d-flex mb-1">
|
||||
<icon v-show="!jobInfoIsLoading" name="work" css-classes="category-icon" />
|
||||
<icon
|
||||
v-show="!jobInfoIsLoading"
|
||||
name="work"
|
||||
css-classes="category-icon flex-shrink-0"
|
||||
/>
|
||||
<span class="ml-1">{{ user.organization }}</span>
|
||||
</div>
|
||||
<gl-skeleton-loading
|
||||
|
|
@ -88,7 +92,7 @@ export default {
|
|||
<icon
|
||||
v-show="!locationIsLoading && user.location"
|
||||
name="location"
|
||||
css-classes="category-icon"
|
||||
css-classes="category-icon flex-shrink-0"
|
||||
/>
|
||||
<span class="ml-1">{{ user.location }}</span>
|
||||
<gl-skeleton-loading
|
||||
|
|
|
|||
|
|
@ -0,0 +1,232 @@
|
|||
$avatar-sizes: (
|
||||
16: (
|
||||
font-size: 10px,
|
||||
line-height: 16px,
|
||||
border-radius: $border-radius-small
|
||||
),
|
||||
18: (
|
||||
border-radius: $border-radius-small
|
||||
),
|
||||
19: (
|
||||
border-radius: $border-radius-small
|
||||
),
|
||||
20: (
|
||||
border-radius: $border-radius-small
|
||||
),
|
||||
24: (
|
||||
font-size: 12px,
|
||||
line-height: 24px,
|
||||
border-radius: $border-radius-default
|
||||
),
|
||||
26: (
|
||||
font-size: 20px,
|
||||
line-height: 1.33,
|
||||
border-radius: $border-radius-default
|
||||
),
|
||||
32: (
|
||||
font-size: 14px,
|
||||
line-height: 32px,
|
||||
border-radius: $border-radius-default
|
||||
),
|
||||
36: (
|
||||
border-radius: $border-radius-default
|
||||
),
|
||||
40: (
|
||||
font-size: 16px,
|
||||
line-height: 38px,
|
||||
border-radius: $border-radius-default
|
||||
),
|
||||
46: (
|
||||
border-radius: $border-radius-default
|
||||
),
|
||||
48: (
|
||||
font-size: 20px,
|
||||
line-height: 48px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
60: (
|
||||
font-size: 32px,
|
||||
line-height: 58px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
64: (
|
||||
font-size: 28px,
|
||||
line-height: 64px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
70: (
|
||||
font-size: 34px,
|
||||
line-height: 70px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
90: (
|
||||
font-size: 36px,
|
||||
line-height: 88px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
96: (
|
||||
font-size: 48px,
|
||||
line-height: 96px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
100: (
|
||||
font-size: 36px,
|
||||
line-height: 98px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
110: (
|
||||
font-size: 40px,
|
||||
line-height: 108px,
|
||||
font-weight: $gl-font-weight-normal,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
140: (
|
||||
font-size: 72px,
|
||||
line-height: 138px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
160: (
|
||||
font-size: 96px,
|
||||
line-height: 158px,
|
||||
border-radius: $border-radius-large
|
||||
)
|
||||
);
|
||||
|
||||
$identicon-backgrounds: $identicon-red, $identicon-purple, $identicon-indigo, $identicon-blue, $identicon-teal,
|
||||
$identicon-orange, $gray-darker;
|
||||
|
||||
.avatar-circle {
|
||||
float: left;
|
||||
margin-right: 15px;
|
||||
border-radius: $avatar-radius;
|
||||
border: 1px solid $gray-normal;
|
||||
|
||||
@each $size, $size-config in $avatar-sizes {
|
||||
&.s#{$size} {
|
||||
@include avatar-size(#{$size}px, if($size < 36, 8px, 16px));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
@extend .avatar-circle;
|
||||
transition-property: none;
|
||||
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
background: $gray-lightest;
|
||||
overflow: hidden;
|
||||
border-color: rgba($black, $gl-avatar-border-opacity);
|
||||
|
||||
&.avatar-inline {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
margin-left: 2px;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.s16 {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&.s24 {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&.center {
|
||||
font-size: 14px;
|
||||
line-height: 1.8em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&.avatar-tile {
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
&.avatar-placeholder {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.identicon {
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
color: $gray-800;
|
||||
background-color: $gray-darker;
|
||||
|
||||
// Sizes
|
||||
@each $size, $size-config in $avatar-sizes {
|
||||
$keys: map-keys($size-config);
|
||||
|
||||
&.s#{$size} {
|
||||
@each $key in $keys {
|
||||
// We don't want `border-radius` to be included here.
|
||||
@if ($key != 'border-radius') {
|
||||
#{$key}: map-get($size-config, #{$key});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Background colors
|
||||
@for $i from 1 through length($identicon-backgrounds) {
|
||||
&.bg#{$i} {
|
||||
background-color: nth($identicon-backgrounds, $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
@extend .avatar-circle;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
|
||||
a {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
&.s40 {
|
||||
min-width: 40px;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
&.s64 {
|
||||
min-width: 64px;
|
||||
min-height: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.rect-avatar {
|
||||
border-radius: $border-radius-small;
|
||||
|
||||
@each $size, $size-config in $avatar-sizes {
|
||||
&.s#{$size} {
|
||||
border-radius: map-get($size-config, 'border-radius');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-counter {
|
||||
background-color: $gray-darkest;
|
||||
color: $white-light;
|
||||
border: 1px solid $gray-normal;
|
||||
border-radius: 1em;
|
||||
font-family: $regular-font;
|
||||
font-size: 9px;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
@import 'framework/animations';
|
||||
@import 'framework/vue_transitions';
|
||||
@import 'framework/avatar';
|
||||
@import 'framework/asciidoctor';
|
||||
@import 'framework/banner';
|
||||
@import 'framework/blocks';
|
||||
|
|
|
|||
|
|
@ -1,194 +0,0 @@
|
|||
@mixin avatar-size($size, $margin-right) {
|
||||
width: $size;
|
||||
height: $size;
|
||||
margin-right: $margin-right;
|
||||
}
|
||||
|
||||
.avatar-circle {
|
||||
float: left;
|
||||
margin-right: 15px;
|
||||
border-radius: $avatar-radius;
|
||||
border: 1px solid $gray-normal;
|
||||
&.s16 { @include avatar-size(16px, 6px); }
|
||||
&.s18 { @include avatar-size(18px, 6px); }
|
||||
&.s19 { @include avatar-size(19px, 6px); }
|
||||
&.s20 { @include avatar-size(20px, 7px); }
|
||||
&.s24 { @include avatar-size(24px, 8px); }
|
||||
&.s26 { @include avatar-size(26px, 8px); }
|
||||
&.s32 { @include avatar-size(32px, 10px); }
|
||||
&.s36 { @include avatar-size(36px, 10px); }
|
||||
&.s40 { @include avatar-size(40px, 10px); }
|
||||
&.s46 { @include avatar-size(46px, 15px); }
|
||||
&.s48 { @include avatar-size(48px, 10px); }
|
||||
&.s60 { @include avatar-size(60px, 12px); }
|
||||
&.s64 { @include avatar-size(64px, 14px); }
|
||||
&.s70 { @include avatar-size(70px, 14px); }
|
||||
&.s90 { @include avatar-size(90px, 15px); }
|
||||
&.s100 { @include avatar-size(100px, 15px); }
|
||||
&.s110 { @include avatar-size(110px, 15px); }
|
||||
&.s140 { @include avatar-size(140px, 15px); }
|
||||
&.s160 { @include avatar-size(160px, 20px); }
|
||||
}
|
||||
|
||||
.avatar {
|
||||
@extend .avatar-circle;
|
||||
transition-property: none;
|
||||
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
background: $gray-lightest;
|
||||
overflow: hidden;
|
||||
|
||||
&.avatar-inline {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
margin-left: 2px;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.s16 { margin-right: 4px; }
|
||||
&.s24 { margin-right: 4px; }
|
||||
}
|
||||
|
||||
&.center {
|
||||
font-size: 14px;
|
||||
line-height: 1.8em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&.avatar-tile {
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
&.avatar-placeholder {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
&:not([href]):hover {
|
||||
border-color: darken($gray-normal, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.identicon {
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
color: $gl-gray-700;
|
||||
background-color: $gray-darker;
|
||||
|
||||
// Sizes
|
||||
&.s16 { font-size: 12px;
|
||||
line-height: 1.33; }
|
||||
|
||||
&.s24 { font-size: 13px;
|
||||
line-height: 1.8; }
|
||||
|
||||
&.s26 { font-size: 20px;
|
||||
line-height: 1.33; }
|
||||
|
||||
&.s32 { font-size: 20px;
|
||||
line-height: 30px; }
|
||||
|
||||
&.s40 { font-size: 16px;
|
||||
line-height: 38px; }
|
||||
|
||||
&.s48 { font-size: 20px;
|
||||
line-height: 46px; }
|
||||
|
||||
&.s60 { font-size: 32px;
|
||||
line-height: 58px; }
|
||||
|
||||
&.s64 { font-size: 32px;
|
||||
line-height: 64px; }
|
||||
|
||||
&.s70 { font-size: 34px;
|
||||
line-height: 70px; }
|
||||
|
||||
&.s90 { font-size: 36px;
|
||||
line-height: 88px; }
|
||||
|
||||
&.s100 { font-size: 36px;
|
||||
line-height: 98px; }
|
||||
|
||||
&.s110 { font-size: 40px;
|
||||
line-height: 108px;
|
||||
font-weight: $gl-font-weight-normal; }
|
||||
|
||||
&.s140 { font-size: 72px;
|
||||
line-height: 138px; }
|
||||
|
||||
&.s160 { font-size: 96px;
|
||||
line-height: 158px; }
|
||||
|
||||
// Background colors
|
||||
&.bg1 { background-color: $identicon-red; }
|
||||
&.bg2 { background-color: $identicon-purple; }
|
||||
&.bg3 { background-color: $identicon-indigo; }
|
||||
&.bg4 { background-color: $identicon-blue; }
|
||||
&.bg5 { background-color: $identicon-teal; }
|
||||
&.bg6 { background-color: $identicon-orange; }
|
||||
&.bg7 { background-color: $gray-darker; }
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
@extend .avatar-circle;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
|
||||
a {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
&.s40 { min-width: 40px;
|
||||
min-height: 40px; }
|
||||
|
||||
&.s64 { min-width: 64px;
|
||||
min-height: 64px; }
|
||||
}
|
||||
|
||||
.rect-avatar {
|
||||
border-radius: $border-radius-small;
|
||||
&.s16 { border-radius: $border-radius-small; }
|
||||
&.s18 { border-radius: $border-radius-small; }
|
||||
&.s19 { border-radius: $border-radius-small; }
|
||||
&.s20 { border-radius: $border-radius-small; }
|
||||
&.s24 { border-radius: $border-radius-default; }
|
||||
&.s26 { border-radius: $border-radius-default; }
|
||||
&.s32 { border-radius: $border-radius-default; }
|
||||
&.s36 { border-radius: $border-radius-default; }
|
||||
&.s40 { border-radius: $border-radius-default; }
|
||||
&.s46 { border-radius: $border-radius-default; }
|
||||
&.s48 { border-radius: $border-radius-large; }
|
||||
&.s60 { border-radius: $border-radius-large; }
|
||||
&.s64 { border-radius: $border-radius-large; }
|
||||
&.s70 { border-radius: $border-radius-large; }
|
||||
&.s90 { border-radius: $border-radius-large; }
|
||||
&.s96 { border-radius: $border-radius-large; }
|
||||
&.s100 { border-radius: $border-radius-large; }
|
||||
&.s110 { border-radius: $border-radius-large; }
|
||||
&.s140 { border-radius: $border-radius-large; }
|
||||
&.s160 { border-radius: $border-radius-large; }
|
||||
}
|
||||
|
||||
.avatar-counter {
|
||||
background-color: $gray-darkest;
|
||||
color: $white-light;
|
||||
border: 1px solid $gray-normal;
|
||||
border-radius: 1em;
|
||||
font-family: $regular-font;
|
||||
font-size: 9px;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -151,8 +151,7 @@
|
|||
outline: 0;
|
||||
|
||||
.award-control-icon svg {
|
||||
background: $award-emoji-positive-add-bg;
|
||||
fill: $award-emoji-positive-add-lines;
|
||||
fill: $blue-500;
|
||||
}
|
||||
|
||||
.award-control-icon-neutral {
|
||||
|
|
@ -236,7 +235,7 @@
|
|||
}
|
||||
|
||||
path {
|
||||
fill: $border-gray-normal;
|
||||
fill: $gray-700;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
}
|
||||
|
||||
@mixin btn-default {
|
||||
border-radius: 3px;
|
||||
border-radius: $border-radius-default;
|
||||
font-size: $gl-font-size;
|
||||
font-weight: $gl-font-weight-normal;
|
||||
padding: $gl-vert-padding $gl-btn-padding;
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
@include btn-default;
|
||||
}
|
||||
|
||||
@mixin btn-outline($background, $text, $border, $hover-background, $hover-text, $hover-border, $active-background, $active-border) {
|
||||
@mixin btn-outline($background, $text, $border, $hover-background, $hover-text, $hover-border, $active-background, $active-border, $active-text) {
|
||||
background-color: $background;
|
||||
color: $text;
|
||||
border-color: $border;
|
||||
|
|
@ -61,13 +61,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 4px 1px $blue-300;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: $active-background;
|
||||
border-color: $active-border;
|
||||
color: $hover-text;
|
||||
box-shadow: inset 0 2px 4px 0 rgba($black, 0.2);
|
||||
color: $active-text;
|
||||
|
||||
> .icon {
|
||||
color: $hover-text;
|
||||
color: $active-text;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: inset 0 2px 4px 0 rgba($black, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -164,21 +173,21 @@
|
|||
|
||||
&.btn-inverted {
|
||||
&.btn-success {
|
||||
@include btn-outline($white-light, $green-600, $green-500, $green-500, $white-light, $green-600, $green-600, $green-700);
|
||||
@include btn-outline($white-light, $green-600, $green-500, $green-100, $green-700, $green-500, $green-200, $green-600, $green-800);
|
||||
}
|
||||
|
||||
&.btn-remove,
|
||||
&.btn-danger {
|
||||
@include btn-outline($white-light, $red-500, $red-500, $red-500, $white-light, $red-600, $red-600, $red-700);
|
||||
@include btn-outline($white-light, $red-500, $red-500, $red-100, $red-700, $red-500, $red-200, $red-600, $red-800);
|
||||
}
|
||||
|
||||
&.btn-warning {
|
||||
@include btn-outline($white-light, $orange-500, $orange-500, $orange-500, $white-light, $orange-600, $orange-600, $orange-700);
|
||||
@include btn-outline($white-light, $orange-500, $orange-500, $orange-100, $orange-700, $orange-500, $orange-200, $orange-600, $orange-800);
|
||||
}
|
||||
|
||||
&.btn-primary,
|
||||
&.btn-info {
|
||||
@include btn-outline($white-light, $blue-500, $blue-500, $blue-500, $white-light, $blue-600, $blue-600, $blue-700);
|
||||
@include btn-outline($white-light, $blue-500, $blue-500, $blue-100, $blue-700, $blue-500, $blue-200, $blue-600, $blue-800);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -193,11 +202,11 @@
|
|||
|
||||
&.btn-close,
|
||||
&.btn-close-color {
|
||||
@include btn-outline($white-light, $orange-600, $orange-500, $orange-500, $white-light, $orange-600, $orange-600, $orange-700);
|
||||
@include btn-outline($white-light, $orange-600, $orange-500, $orange-100, $orange-700, $orange-500, $orange-200, $orange-600, $orange-800);
|
||||
}
|
||||
|
||||
&.btn-spam {
|
||||
@include btn-outline($white-light, $red-500, $red-500, $red-500, $white-light, $red-600, $red-600, $red-700);
|
||||
@include btn-outline($white-light, $red-500, $red-500, $red-100, $red-700, $red-500, $red-200, $red-600, $red-800);
|
||||
}
|
||||
|
||||
&.btn-danger,
|
||||
|
|
@ -402,7 +411,7 @@
|
|||
|
||||
.btn-inverted {
|
||||
&-secondary {
|
||||
@include btn-outline($white-light, $blue-500, $blue-500, $blue-500, $white-light, $blue-600, $blue-600, $blue-700);
|
||||
@include btn-outline($white-light, $blue-500, $blue-500, $blue-100, $blue-700, $blue-500, $blue-200, $blue-600, $blue-800);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue