summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/review.gitlab-ci.yml7
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml12
-rw-r--r--.rubocop.yml68
-rw-r--r--CHANGELOG-EE.md8
-rw-r--r--app/assets/javascripts/alert_management/components/alert_management_list.vue14
-rw-r--r--app/assets/javascripts/ide/lib/themes/index.js5
-rw-r--r--app/assets/javascripts/ide/lib/themes/none.js17
-rw-r--r--app/assets/javascripts/monitoring/components/charts/anomaly.vue2
-rw-r--r--app/assets/javascripts/projects/pipelines/charts/components/app.vue3
-rw-r--r--app/assets/javascripts/releases/components/asset_links_form.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/constants.js5
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_button.vue28
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view.vue44
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue30
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue63
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/getters.js22
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js14
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/state.js3
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss10
-rw-r--r--app/assets/stylesheets/page_bundles/_ide_monaco_overrides.scss8
-rw-r--r--app/assets/stylesheets/pages/alerts_list.scss24
-rw-r--r--app/assets/stylesheets/pages/cycle_analytics.scss1
-rw-r--r--app/models/timelog.rb4
-rw-r--r--app/presenters/projects/settings/deploy_keys_presenter.rb4
-rw-r--r--app/views/projects/cycle_analytics/show.html.haml2
-rw-r--r--app/views/shared/deploy_keys/_index.html.haml (renamed from app/views/projects/deploy_keys/_index.html.haml)7
-rw-r--r--app/views/shared/deploy_keys/_project_group_form.html.haml (renamed from app/views/projects/deploy_keys/_form.html.haml)6
-rw-r--r--changelogs/unreleased/214528.yml5
-rw-r--r--changelogs/unreleased/216543-none-syntax-highlighting-theme-for-web-ide.yml5
-rw-r--r--changelogs/unreleased/mw-cicd-analytics-add-title.yml5
-rw-r--r--changelogs/unreleased/mw-ia-group-level-add-title.yml5
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql18
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json44
-rw-r--r--locale/gitlab.pot193
-rw-r--r--qa/qa/page/project/settings/deploy_keys.rb2
-rw-r--r--qa/qa/page/project/settings/repository.rb2
-rwxr-xr-xscripts/review_apps/review-apps.sh11
-rw-r--r--spec/config/application_spec.rb12
-rw-r--r--spec/features/merge_request/user_resolves_conflicts_spec.rb4
-rw-r--r--spec/features/milestones/user_creates_milestone_spec.rb6
-rw-r--r--spec/features/milestones/user_views_milestone_spec.rb6
-rw-r--r--spec/features/projects/branches/user_creates_branch_spec.rb10
-rw-r--r--spec/features/projects/commit/comments/user_edits_comments_spec.rb6
-rw-r--r--spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb10
-rw-r--r--spec/frontend/alert_management/components/alert_management_list_spec.js19
-rw-r--r--spec/frontend/clusters_list/store/actions_spec.js3
-rw-r--r--spec/frontend/contributors/store/actions_spec.js3
-rw-r--r--spec/frontend/contributors/store/getters_spec.js3
-rw-r--r--spec/frontend/create_cluster/eks_cluster/services/aws_services_facade_spec.js14
-rw-r--r--spec/frontend/mocks_spec.js13
-rw-r--r--spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js26
-rw-r--r--spec/frontend/notes/old_notes_spec.js49
-rw-r--r--spec/frontend/releases/stores/modules/detail/actions_spec.js2
-rw-r--r--spec/frontend/releases/stores/modules/detail/mutations_spec.js19
-rw-r--r--spec/frontend/static_site_editor/services/submit_content_changes_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_button_spec.js25
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js14
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js63
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/labels_select_root_spec.js24
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js2
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js24
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js20
-rw-r--r--spec/models/timelog_spec.rb6
65 files changed, 732 insertions, 364 deletions
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index 99cd85bdc00..b259588ae5e 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -6,8 +6,7 @@ build-qa-image:
stage: build-images
needs: []
script:
- - '[[ -d "ee/" ]] || export GITLAB_EDITION="ce"'
- - export QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-${GITLAB_EDITION:-ee}-qa:${CI_COMMIT_REF_SLUG}"
+ - export QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_REF_SLUG}"
- /kaniko/executor --context=${CI_PROJECT_DIR} --dockerfile=${CI_PROJECT_DIR}/qa/Dockerfile --destination=${QA_IMAGE} --cache=true
review-cleanup:
@@ -71,7 +70,6 @@ review-deploy:
resource_group: "review/${CI_COMMIT_REF_NAME}"
allow_failure: true
before_script:
- - '[[ -d "ee/" ]] || export GITLAB_EDITION="ce"'
- export GITLAB_SHELL_VERSION=$(<GITLAB_SHELL_VERSION)
- export GITALY_VERSION=$(<GITALY_SERVER_VERSION)
- export GITLAB_WORKHORSE_VERSION=$(<GITLAB_WORKHORSE_VERSION)
@@ -148,8 +146,7 @@ review-stop:
GITHUB_ACCESS_TOKEN: "${REVIEW_APPS_QA_GITHUB_ACCESS_TOKEN}"
EE_LICENSE: "${REVIEW_APPS_EE_LICENSE}"
before_script:
- - '[[ -d "ee/" ]] || export GITLAB_EDITION="ce"'
- - export QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-${GITLAB_EDITION:-ee}-qa:${CI_COMMIT_REF_SLUG}"
+ - export QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_REF_SLUG}"
- export CI_ENVIRONMENT_URL="$(cat environment_url.txt)"
- echo "${CI_ENVIRONMENT_URL}"
- echo "${QA_IMAGE}"
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 3e4f5da007b..044136fb564 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -472,6 +472,8 @@
################
.review:rules:mr-and-schedule-auto:
rules:
+ - <<: *if-not-ee
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *code-qa-patterns
when: on_success
@@ -480,6 +482,8 @@
.review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise:
rules:
+ - <<: *if-not-ee
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *frontend-patterns
when: on_success
@@ -492,12 +496,16 @@
.review:rules:mr-only-auto:
rules:
+ - <<: *if-not-ee
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *code-qa-patterns
when: on_success
.review:rules:mr-only-auto-if-frontend-manual-otherwise:
rules:
+ - <<: *if-not-ee
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *frontend-patterns
when: on_success
@@ -507,12 +515,16 @@
.review:rules:mr-only-manual:
rules:
+ - <<: *if-not-ee
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *code-qa-patterns
when: manual
.review:rules:review-cleanup:
rules:
+ - <<: *if-not-ee
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *code-qa-patterns
when: manual
diff --git a/.rubocop.yml b/.rubocop.yml
index 300cfe3d74c..fbcad46a0c7 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -335,10 +335,76 @@ RSpec/AnyInstanceOf:
RSpec/ImplicitSubject:
Enabled: false
+# WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/211580
RSpec/LeakyConstantDeclaration:
Enabled: true
Exclude:
- - 'spec/**/*.rb'
+ - 'spec/db/schema_spec.rb'
+ - 'spec/graphql/gitlab_schema_spec.rb'
+ - 'spec/helpers/visibility_level_helper_spec.rb'
+ - 'spec/initializers/secret_token_spec.rb'
+ - 'spec/lib/declarative_policy_spec.rb'
+ - 'spec/lib/feature_spec.rb'
+ - 'spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb'
+ - 'spec/lib/gitlab/ci/build/credentials/factory_spec.rb'
+ - 'spec/lib/gitlab/ci/config/entry/retry_spec.rb'
+ - 'spec/lib/gitlab/cluster/mixins/puma_cluster_spec.rb'
+ - 'spec/lib/gitlab/cluster/mixins/unicorn_http_server_spec.rb'
+ - 'spec/lib/gitlab/config/entry/factory_spec.rb'
+ - 'spec/lib/gitlab/config/entry/simplifiable_spec.rb'
+ - 'spec/lib/gitlab/database/migration_helpers_spec.rb'
+ - 'spec/lib/gitlab/database/obsolete_ignored_columns_spec.rb'
+ - 'spec/lib/gitlab/database/with_lock_retries_spec.rb'
+ - 'spec/lib/gitlab/git/diff_collection_spec.rb'
+ - 'spec/lib/gitlab/graphql/pagination/keyset/connection_spec.rb'
+ - 'spec/lib/gitlab/health_checks/master_check_spec.rb'
+ - 'spec/lib/gitlab/import_export/attribute_configuration_spec.rb'
+ - 'spec/lib/gitlab/import_export/import_test_coverage_spec.rb'
+ - 'spec/lib/gitlab/import_export/project/relation_factory_spec.rb'
+ - 'spec/lib/gitlab/jira_import/issues_importer_spec.rb'
+ - 'spec/lib/gitlab/no_cache_headers_spec.rb'
+ - 'spec/lib/gitlab/path_regex_spec.rb'
+ - 'spec/lib/gitlab/quick_actions/dsl_spec.rb'
+ - 'spec/lib/gitlab/sidekiq_middleware/client_metrics_spec.rb'
+ - 'spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb'
+ - 'spec/lib/gitlab/sidekiq_middleware_spec.rb'
+ - 'spec/lib/gitlab/view/presenter/factory_spec.rb'
+ - 'spec/lib/marginalia_spec.rb'
+ - 'spec/lib/omni_auth/strategies/jwt_spec.rb'
+ - 'spec/lib/system_check/simple_executor_spec.rb'
+ - 'spec/lib/system_check_spec.rb'
+ - 'spec/mailers/notify_spec.rb'
+ - 'spec/migrations/20191125114345_add_admin_mode_protected_path_spec.rb'
+ - 'spec/migrations/encrypt_plaintext_attributes_on_application_settings_spec.rb'
+ - 'spec/migrations/cleanup_optimistic_locking_nulls_pt2_fixed_spec.rb'
+ - 'spec/models/clusters/cluster_spec.rb'
+ - 'spec/models/concerns/batch_destroy_dependent_associations_spec.rb'
+ - 'spec/models/concerns/blocks_json_serialization_spec.rb'
+ - 'spec/models/concerns/bulk_insert_safe_spec.rb'
+ - 'spec/models/concerns/bulk_insertable_associations_spec.rb'
+ - 'spec/models/concerns/mentionable_spec.rb'
+ - 'spec/models/concerns/reactive_caching_spec.rb'
+ - 'spec/models/concerns/triggerable_hooks_spec.rb'
+ - 'spec/models/repository_spec.rb'
+ - 'spec/models/tree_spec.rb'
+ - 'spec/policies/merge_request_policy_spec.rb'
+ - 'spec/requests/api/graphql/tasks/task_completion_status_spec.rb'
+ - 'spec/requests/api/statistics_spec.rb'
+ - 'spec/rubocop/cop/rspec/env_assignment_spec.rb'
+ - 'spec/serializers/commit_entity_spec.rb'
+ - 'spec/services/ci/retry_build_service_spec.rb'
+ - 'spec/services/clusters/applications/check_installation_progress_service_spec.rb'
+ - 'spec/services/clusters/applications/check_uninstall_progress_service_spec.rb'
+ - 'spec/services/clusters/applications/check_upgrade_progress_service_spec.rb'
+ - 'spec/services/clusters/applications/ingress_modsecurity_usage_service_spec.rb'
+ - 'spec/services/issues/resolve_discussions_spec.rb'
+ - 'spec/services/metrics/dashboard/clone_dashboard_service_spec.rb'
+ - 'spec/support/shared_contexts/spam_constants.rb'
+ - 'spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb'
+ - 'spec/support_specs/helpers/active_record/query_recorder_spec.rb'
+ - 'spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb'
+ - 'spec/uploaders/content_type_whitelist_spec.rb'
+ - 'spec/uploaders/records_uploads_spec.rb'
RSpec/EmptyLineAfterHook:
Enabled: false
diff --git a/CHANGELOG-EE.md b/CHANGELOG-EE.md
index 4d98d9a56e6..6ed305c1a28 100644
--- a/CHANGELOG-EE.md
+++ b/CHANGELOG-EE.md
@@ -1,5 +1,9 @@
Please view this file on the master branch, on stable branches it's out of date.
+## 12.10.4 (2020-05-05)
+
+- No changes.
+
## 12.10.2 (2020-04-30)
### Security (3 changes)
@@ -59,6 +63,10 @@ Please view this file on the master branch, on stable branches it's out of date.
- Add health status counts to usage data. !28964
+## 12.9.6 (2020-05-05)
+
+- No changes.
+
## 12.9.5 (2020-04-30)
### Security (3 changes)
diff --git a/app/assets/javascripts/alert_management/components/alert_management_list.vue b/app/assets/javascripts/alert_management/components/alert_management_list.vue
index 1e0cbfbf125..2c3674b9b96 100644
--- a/app/assets/javascripts/alert_management/components/alert_management_list.vue
+++ b/app/assets/javascripts/alert_management/components/alert_management_list.vue
@@ -5,6 +5,7 @@ import {
GlLoadingIcon,
GlTable,
GlAlert,
+ GlIcon,
GlNewDropdown,
GlNewDropdownItem,
} from '@gitlab/ui';
@@ -64,6 +65,7 @@ export default {
TimeAgo,
GlNewDropdown,
GlNewDropdownItem,
+ GlIcon,
},
props: {
projectPath: {
@@ -144,6 +146,18 @@ export default {
fixed
stacked="md"
>
+ <template #cell(severity)="{ item }">
+ <div class="d-inline-flex align-items-center justify-content-between">
+ <gl-icon
+ class="mr-2"
+ :size="12"
+ :name="`severity-${item.severity.toLowerCase()}`"
+ :class="`icon-${item.severity.toLowerCase()}`"
+ />
+ {{ item.severity }}
+ </div>
+ </template>
+
<template #cell(startedAt)="{ item }">
<time-ago :time="item.startedAt" />
</template>
diff --git a/app/assets/javascripts/ide/lib/themes/index.js b/app/assets/javascripts/ide/lib/themes/index.js
index 5e75538b664..bb5be50576c 100644
--- a/app/assets/javascripts/ide/lib/themes/index.js
+++ b/app/assets/javascripts/ide/lib/themes/index.js
@@ -3,6 +3,7 @@ import dark from './dark';
import monokai from './monokai';
import solarizedLight from './solarized_light';
import solarizedDark from './solarized_dark';
+import none from './none';
export const themes = [
{
@@ -25,6 +26,10 @@ export const themes = [
name: 'monokai',
data: monokai,
},
+ {
+ name: 'none',
+ data: none,
+ },
];
export const DEFAULT_THEME = 'white';
diff --git a/app/assets/javascripts/ide/lib/themes/none.js b/app/assets/javascripts/ide/lib/themes/none.js
new file mode 100644
index 00000000000..8e722c4ff88
--- /dev/null
+++ b/app/assets/javascripts/ide/lib/themes/none.js
@@ -0,0 +1,17 @@
+export default {
+ base: 'vs',
+ inherit: false,
+ rules: [],
+ colors: {
+ 'editor.foreground': '#2e2e2e',
+ 'editor.selectionBackground': '#aad6f8',
+ 'editor.lineHighlightBackground': '#fffeeb',
+ 'editorCursor.foreground': '#666666',
+ 'editorWhitespace.foreground': '#bbbbbb',
+
+ 'editorLineNumber.foreground': '#cccccc',
+ 'diffEditor.insertedTextBackground': '#a0f5b420',
+ 'diffEditor.removedTextBackground': '#f9d7dc20',
+ 'editorIndentGuide.activeBackground': '#cccccc',
+ },
+};
diff --git a/app/assets/javascripts/monitoring/components/charts/anomaly.vue b/app/assets/javascripts/monitoring/components/charts/anomaly.vue
index b3b6f9e7b55..34da5885c97 100644
--- a/app/assets/javascripts/monitoring/components/charts/anomaly.vue
+++ b/app/assets/javascripts/monitoring/components/charts/anomaly.vue
@@ -209,7 +209,7 @@ export default {
:series-config="metricSeriesConfig"
>
<slot></slot>
- <template v-slot:tooltipContent="slotProps">
+ <template #tooltip-content="slotProps">
<div
v-for="(content, seriesIndex) in slotProps.tooltip.content"
:key="seriesIndex"
diff --git a/app/assets/javascripts/projects/pipelines/charts/components/app.vue b/app/assets/javascripts/projects/pipelines/charts/components/app.vue
index 4dc1c512689..cdf03a5013f 100644
--- a/app/assets/javascripts/projects/pipelines/charts/components/app.vue
+++ b/app/assets/javascripts/projects/pipelines/charts/components/app.vue
@@ -113,6 +113,9 @@ export default {
</script>
<template>
<div>
+ <div class="mb-3">
+ <h3>{{ s__('PipelineCharts|CI / CD Analytics') }}</h3>
+ </div>
<h4 class="my-4">{{ s__('PipelineCharts|Overall statistics') }}</h4>
<div class="row">
<div class="col-md-6">
diff --git a/app/assets/javascripts/releases/components/asset_links_form.vue b/app/assets/javascripts/releases/components/asset_links_form.vue
index 4bdc88f01dd..0698ca5e31f 100644
--- a/app/assets/javascripts/releases/components/asset_links_form.vue
+++ b/app/assets/javascripts/releases/components/asset_links_form.vue
@@ -162,7 +162,7 @@ export default {
:state="isNameValid(link)"
@change="onLinkTitleInput(link.id, $event)"
/>
- <template v-slot:invalid-feedback>
+ <template #invalid-feedback>
<span v-if="hasEmptyName(link)" class="invalid-feedback d-inline">
{{ __('Link title is required') }}
</span>
diff --git a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
index 3d112bba668..fed9e5886c0 100644
--- a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
@@ -66,7 +66,7 @@ export default {
<template>
<assignee-avatar-link
v-if="hasOneUser"
- v-slot="{ user }"
+ #default="{ user }"
tooltip-placement="left"
:tooltip-has-name="false"
:user="firstUser"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
index d81e99d3c09..46210d810bc 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
@@ -83,7 +83,7 @@ export default {
:source-branch-link="branchLink"
:troubleshooting-docs-path="mr.troubleshootingDocsPath"
/>
- <template v-slot:footer>
+ <template #footer>
<div v-if="mr.exposedArtifactsPath" class="js-exposed-artifacts">
<artifacts-app :endpoint="mr.exposedArtifactsPath" />
</div>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/constants.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/constants.js
new file mode 100644
index 00000000000..ab652c9356a
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/constants.js
@@ -0,0 +1,5 @@
+// eslint-disable-next-line import/prefer-default-export
+export const DropdownVariant = {
+ Sidebar: 'sidebar',
+ Standalone: 'standalone',
+};
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_button.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_button.vue
index 55fa1e4ef9c..2730e8ee1da 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_button.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_button.vue
@@ -1,21 +1,35 @@
<script>
-import { mapGetters } from 'vuex';
-import { GlDeprecatedButton, GlIcon } from '@gitlab/ui';
+import { mapActions, mapGetters } from 'vuex';
+import { GlButton, GlIcon } from '@gitlab/ui';
export default {
components: {
- GlDeprecatedButton,
+ GlButton,
GlIcon,
},
computed: {
- ...mapGetters(['dropdownButtonText']),
+ ...mapGetters(['dropdownButtonText', 'isDropdownVariantStandalone']),
+ },
+ methods: {
+ ...mapActions(['toggleDropdownContents']),
+ handleButtonClick(e) {
+ if (this.isDropdownVariantStandalone) {
+ this.toggleDropdownContents();
+ e.stopPropagation();
+ }
+ },
},
};
</script>
<template>
- <gl-deprecated-button class="labels-select-dropdown-button w-100 text-left">
- <span class="dropdown-toggle-text">{{ dropdownButtonText }}</span>
+ <gl-button
+ class="labels-select-dropdown-button js-dropdown-button w-100 text-left"
+ @click="handleButtonClick"
+ >
+ <span class="dropdown-toggle-text" :class="{ 'flex-fill': isDropdownVariantStandalone }">{{
+ dropdownButtonText
+ }}</span>
<gl-icon name="chevron-down" class="pull-right" />
- </gl-deprecated-button>
+ </gl-button>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view.vue
index 6bb77f6b6f3..ba8d8391952 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view.vue
@@ -1,18 +1,10 @@
<script>
import { mapState, mapActions } from 'vuex';
-import {
- GlTooltipDirective,
- GlDeprecatedButton,
- GlIcon,
- GlFormInput,
- GlLink,
- GlLoadingIcon,
-} from '@gitlab/ui';
+import { GlTooltipDirective, GlButton, GlFormInput, GlLink, GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
- GlDeprecatedButton,
- GlIcon,
+ GlButton,
GlFormInput,
GlLink,
GlLoadingIcon,
@@ -60,25 +52,23 @@ export default {
<template>
<div class="labels-select-contents-create js-labels-create">
<div class="dropdown-title d-flex align-items-center pt-0 pb-2">
- <gl-deprecated-button
+ <gl-button
:aria-label="__('Go back')"
variant="link"
- size="sm"
+ size="small"
class="js-btn-back dropdown-header-button p-0"
+ icon="arrow-left"
@click="toggleDropdownContentsCreateView"
- >
- <gl-icon name="arrow-left" />
- </gl-deprecated-button>
+ />
<span class="flex-grow-1">{{ labelsCreateTitle }}</span>
- <gl-deprecated-button
+ <gl-button
:aria-label="__('Close')"
variant="link"
- size="sm"
+ size="small"
class="dropdown-header-button p-0"
+ icon="close"
@click="toggleDropdownContents"
- >
- <gl-icon name="close" />
- </gl-deprecated-button>
+ />
</div>
<div class="dropdown-input">
<gl-form-input
@@ -107,21 +97,19 @@ export default {
</div>
</div>
<div class="dropdown-actions clearfix pt-2 px-2">
- <gl-deprecated-button
+ <gl-button
:disabled="disableCreate"
- variant="primary"
+ category="primary"
+ variant="success"
class="pull-left d-flex align-items-center"
@click="handleCreateClick"
>
<gl-loading-icon v-show="labelCreateInProgress" :inline="true" class="mr-1" />
{{ __('Create') }}
- </gl-deprecated-button>
- <gl-deprecated-button
- class="pull-right js-btn-cancel-create"
- @click="toggleDropdownContentsCreateView"
- >
+ </gl-button>
+ <gl-button class="pull-right js-btn-cancel-create" @click="toggleDropdownContentsCreateView">
{{ __('Cancel') }}
- </gl-deprecated-button>
+ </gl-button>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue
index a8e48bfe1a1..a548ef4ac86 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue
@@ -1,13 +1,13 @@
<script>
import { mapState, mapGetters, mapActions } from 'vuex';
-import { GlLoadingIcon, GlDeprecatedButton, GlIcon, GlSearchBoxByType, GlLink } from '@gitlab/ui';
+import { GlLoadingIcon, GlButton, GlIcon, GlSearchBoxByType, GlLink } from '@gitlab/ui';
import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes';
export default {
components: {
GlLoadingIcon,
- GlDeprecatedButton,
+ GlButton,
GlIcon,
GlSearchBoxByType,
GlLink,
@@ -20,6 +20,8 @@ export default {
},
computed: {
...mapState([
+ 'allowLabelCreate',
+ 'allowMultiselect',
'labelsManagePath',
'labels',
'labelsFetchInProgress',
@@ -27,7 +29,7 @@ export default {
'footerCreateLabelTitle',
'footerManageLabelTitle',
]),
- ...mapGetters(['selectedLabelsList']),
+ ...mapGetters(['selectedLabelsList', 'isDropdownVariantSidebar']),
visibleLabels() {
if (this.searchKey) {
return this.labels.filter(label =>
@@ -56,6 +58,7 @@ export default {
'toggleDropdownContentsCreateView',
'fetchLabels',
'updateSelectedLabels',
+ 'toggleDropdownContents',
]),
getDropdownLabelBoxStyle(label) {
return {
@@ -111,6 +114,7 @@ export default {
},
handleLabelClick(label) {
this.updateSelectedLabels([label]);
+ if (!this.allowMultiselect) this.toggleDropdownContents();
},
},
};
@@ -123,17 +127,16 @@ export default {
class="labels-fetch-loading position-absolute d-flex align-items-center w-100 h-100"
size="md"
/>
- <div class="dropdown-title d-flex align-items-center pt-0 pb-2">
+ <div v-if="isDropdownVariantSidebar" class="dropdown-title d-flex align-items-center pt-0 pb-2">
<span class="flex-grow-1">{{ labelsListTitle }}</span>
- <gl-deprecated-button
+ <gl-button
:aria-label="__('Close')"
variant="link"
- size="sm"
+ size="small"
class="dropdown-header-button p-0"
+ icon="close"
@click="toggleDropdownContents"
- >
- <gl-icon name="close" />
- </gl-deprecated-button>
+ />
</div>
<div class="dropdown-input">
<gl-search-box-by-type v-model="searchKey" :autofocus="true" />
@@ -157,14 +160,13 @@ export default {
</li>
</ul>
</div>
- <div class="dropdown-footer">
+ <div v-if="isDropdownVariantSidebar" class="dropdown-footer">
<ul class="list-unstyled">
- <li>
- <gl-deprecated-button
- variant="link"
+ <li v-if="allowLabelCreate">
+ <gl-link
class="d-flex w-100 flex-row text-break-word label-item"
@click="toggleDropdownContentsCreateView"
- >{{ footerCreateLabelTitle }}</gl-deprecated-button
+ >{{ footerCreateLabelTitle }}</gl-link
>
</li>
<li>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
index 0ab45e3308c..a95a5a50a8b 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
@@ -1,7 +1,7 @@
<script>
import $ from 'jquery';
import Vue from 'vue';
-import Vuex, { mapState, mapActions } from 'vuex';
+import Vuex, { mapState, mapActions, mapGetters } from 'vuex';
import { __ } from '~/locale';
import DropdownValueCollapsed from '~/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue';
@@ -13,6 +13,8 @@ import DropdownValue from './dropdown_value.vue';
import DropdownButton from './dropdown_button.vue';
import DropdownContents from './dropdown_contents.vue';
+import { DropdownVariant } from './constants';
+
Vue.use(Vuex);
export default {
@@ -33,14 +35,19 @@ export default {
type: Boolean,
required: true,
},
+ allowMultiselect: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
allowScopedLabels: {
type: Boolean,
required: true,
},
- dropdownOnly: {
- type: Boolean,
+ variant: {
+ type: String,
required: false,
- default: false,
+ default: DropdownVariant.Sidebar,
},
selectedLabels: {
type: Array,
@@ -90,6 +97,10 @@ export default {
},
computed: {
...mapState(['showDropdownButton', 'showDropdownContents']),
+ ...mapGetters(['isDropdownVariantSidebar', 'isDropdownVariantStandalone']),
+ dropdownButtonVisible() {
+ return this.isDropdownVariantSidebar ? this.showDropdownButton : true;
+ },
},
watch: {
selectedLabels(selectedLabels) {
@@ -100,9 +111,10 @@ export default {
},
mounted() {
this.setInitialState({
- dropdownOnly: this.dropdownOnly,
+ variant: this.variant,
allowLabelEdit: this.allowLabelEdit,
allowLabelCreate: this.allowLabelCreate,
+ allowMultiselect: this.allowMultiselect,
allowScopedLabels: this.allowScopedLabels,
selectedLabels: this.selectedLabels,
labelsFetchPath: this.labelsFetchPath,
@@ -148,13 +160,20 @@ export default {
// as the dropdown wrapper is not using `GlDropdown` as
// it will also require us to use `BDropdownForm`
// which is yet to be implemented in GitLab UI.
+ const hasExceptionClass = [
+ 'js-dropdown-button',
+ 'js-btn-cancel-create',
+ 'js-sidebar-dropdown-toggle',
+ ].some(className => target?.classList.contains(className));
+
+ const hadExceptionParent = ['.js-btn-back', '.js-labels-list'].some(
+ className => $(target).parents(className).length,
+ );
+
if (
- this.showDropdownButton &&
this.showDropdownContents &&
- !$(target).parents('.js-btn-back').length &&
- !$(target).parents('.js-labels-list').length &&
- !target?.classList.contains('js-btn-cancel-create') &&
- !target?.classList.contains('js-sidebar-dropdown-toggle') &&
+ !hadExceptionParent &&
+ !hasExceptionClass &&
!this.$refs.dropdownButtonCollapsed?.$el.contains(target) &&
!this.$refs.dropdownContents?.$el.contains(target)
) {
@@ -175,10 +194,12 @@ export default {
</script>
<template>
- <div class="labels-select-wrapper position-relative">
- <div v-if="!dropdownOnly">
+ <div
+ class="labels-select-wrapper position-relative"
+ :class="{ 'is-standalone': isDropdownVariantStandalone }"
+ >
+ <template v-if="isDropdownVariantSidebar">
<dropdown-value-collapsed
- v-if="allowLabelCreate"
ref="dropdownButtonCollapsed"
:labels="selectedLabels"
@onValueClick="handleCollapsedValueClick"
@@ -190,8 +211,18 @@ export default {
<dropdown-value v-show="!showDropdownButton">
<slot></slot>
</dropdown-value>
- <dropdown-button v-show="showDropdownButton" />
- <dropdown-contents v-if="showDropdownButton && showDropdownContents" ref="dropdownContents" />
- </div>
+ <dropdown-button v-show="dropdownButtonVisible" />
+ <dropdown-contents
+ v-if="dropdownButtonVisible && showDropdownContents"
+ ref="dropdownContents"
+ />
+ </template>
+ <template v-if="isDropdownVariantStandalone">
+ <dropdown-button v-show="dropdownButtonVisible" />
+ <dropdown-contents
+ v-if="dropdownButtonVisible && showDropdownContents"
+ ref="dropdownContents"
+ />
+ </template>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/getters.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/getters.js
index c08a8a8ea58..c39222959a9 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/getters.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/getters.js
@@ -1,4 +1,5 @@
import { __, s__, sprintf } from '~/locale';
+import { DropdownVariant } from '../constants';
/**
* Returns string representing current labels
@@ -6,8 +7,11 @@ import { __, s__, sprintf } from '~/locale';
*
* @param {object} state
*/
-export const dropdownButtonText = state => {
- const selectedLabels = state.labels.filter(label => label.set);
+export const dropdownButtonText = (state, getters) => {
+ const selectedLabels = getters.isDropdownVariantSidebar
+ ? state.labels.filter(label => label.set)
+ : state.selectedLabels;
+
if (!selectedLabels.length) {
return __('Label');
} else if (selectedLabels.length > 1) {
@@ -26,5 +30,19 @@ export const dropdownButtonText = state => {
*/
export const selectedLabelsList = state => state.selectedLabels.map(label => label.id);
+/**
+ * Returns boolean representing whether dropdown variant
+ * is `sidebar`
+ * @param {object} state
+ */
+export const isDropdownVariantSidebar = state => state.variant === DropdownVariant.Sidebar;
+
+/**
+ * Returns boolean representing whether dropdown variant
+ * is `standalone`
+ * @param {object} state
+ */
+export const isDropdownVariantStandalone = state => state.variant === DropdownVariant.Standalone;
+
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js
index 32a78507e88..b55a58850a1 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js
@@ -1,4 +1,5 @@
import * as types from './mutation_types';
+import { DropdownVariant } from '../constants';
export default {
[types.SET_INITIAL_STATE](state, props) {
@@ -10,7 +11,7 @@ export default {
},
[types.TOGGLE_DROPDOWN_CONTENTS](state) {
- if (!state.dropdownOnly) {
+ if (state.variant === DropdownVariant.Sidebar) {
state.showDropdownButton = !state.showDropdownButton;
}
state.showDropdownContents = !state.showDropdownContents;
@@ -68,7 +69,16 @@ export default {
set: !label.set,
});
} else {
- allLabels.push(label);
+ // In case multiselect is not allowed
+ // we unselect any existing selected label
+ const unchangedLabel = state.allowMultiselect
+ ? label
+ : {
+ ...label,
+ touched: true,
+ set: false,
+ };
+ allLabels.push(unchangedLabel);
}
return allLabels;
}, []);
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/state.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/state.js
index c83bf9e47ec..6a6c0b4c0ee 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/state.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/state.js
@@ -13,10 +13,11 @@ export default () => ({
labelsFilterBasePath: '',
// UI Flags
+ variant: '',
allowLabelCreate: false,
allowLabelEdit: false,
allowScopedLabels: false,
- dropdownOnly: false,
+ allowMultiselect: false,
showDropdownButton: false,
showDropdownContents: false,
showDropdownContentsCreateView: false,
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index f746d7e6f69..c2898aad512 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -1032,6 +1032,16 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu {
}
.labels-select-wrapper {
+ &.is-standalone {
+ .labels-select-dropdown-contents {
+ max-height: 350px;
+
+ .dropdown-content {
+ height: 250px;
+ }
+ }
+ }
+
.labels-select-dropdown-contents {
min-height: $dropdown-min-height;
max-height: 330px;
diff --git a/app/assets/stylesheets/page_bundles/_ide_monaco_overrides.scss b/app/assets/stylesheets/page_bundles/_ide_monaco_overrides.scss
index 95e39d275f2..49175a244de 100644
--- a/app/assets/stylesheets/page_bundles/_ide_monaco_overrides.scss
+++ b/app/assets/stylesheets/page_bundles/_ide_monaco_overrides.scss
@@ -76,8 +76,9 @@
min-height: 0; // firefox fix
}
-// Apply theme related overrides only to the white theme
-.theme-white .blob-editor-container {
+// Apply theme related overrides only to the white theme and none theme
+.theme-white .blob-editor-container,
+.theme-none .blob-editor-container {
.monaco-diff-editor {
.editor.modified {
box-shadow: none;
@@ -139,7 +140,8 @@
}
}
-.theme-white .multi-file-editor-holder {
+.theme-white .multi-file-editor-holder,
+.theme-none .multi-file-editor-holder {
&.is-readonly,
.editor.original {
.monaco-editor,
diff --git a/app/assets/stylesheets/pages/alerts_list.scss b/app/assets/stylesheets/pages/alerts_list.scss
index 8546049168f..7c27237a52a 100644
--- a/app/assets/stylesheets/pages/alerts_list.scss
+++ b/app/assets/stylesheets/pages/alerts_list.scss
@@ -1,4 +1,28 @@
.alert-management-list {
+ .icon-critical {
+ color: $red-800;
+ }
+
+ .icon-high {
+ color: $red-600;
+ }
+
+ .icon-medium {
+ color: $orange-400;
+ }
+
+ .icon-low {
+ color: $orange-300;
+ }
+
+ .icon-info {
+ color: $blue-400;
+ }
+
+ .icon-unknown {
+ color: $gray-400;
+ }
+
// these styles need to be deleted once GlTable component looks in GitLab same as in @gitlab/ui
table {
color: $gray-700;
diff --git a/app/assets/stylesheets/pages/cycle_analytics.scss b/app/assets/stylesheets/pages/cycle_analytics.scss
index 0292919ea50..b97709e140f 100644
--- a/app/assets/stylesheets/pages/cycle_analytics.scss
+++ b/app/assets/stylesheets/pages/cycle_analytics.scss
@@ -187,7 +187,6 @@
.stage-events {
width: 60%;
- overflow: scroll;
min-height: 467px;
}
diff --git a/app/models/timelog.rb b/app/models/timelog.rb
index f52dd74d4c9..c0aac6f27aa 100644
--- a/app/models/timelog.rb
+++ b/app/models/timelog.rb
@@ -16,8 +16,8 @@ class Timelog < ApplicationRecord
)
end
- scope :between_dates, -> (start_date, end_date) do
- where('spent_at BETWEEN ? AND ?', start_date, end_date)
+ scope :between_times, -> (start_time, end_time) do
+ where('spent_at BETWEEN ? AND ?', start_time, end_time)
end
def issuable
diff --git a/app/presenters/projects/settings/deploy_keys_presenter.rb b/app/presenters/projects/settings/deploy_keys_presenter.rb
index 66211d02696..103c26289bf 100644
--- a/app/presenters/projects/settings/deploy_keys_presenter.rb
+++ b/app/presenters/projects/settings/deploy_keys_presenter.rb
@@ -60,11 +60,11 @@ module Projects
end
def to_partial_path
- 'projects/deploy_keys/index'
+ '../../shared/deploy_keys/index'
end
def form_partial_path
- 'projects/deploy_keys/form'
+ 'shared/deploy_keys/project_group_form'
end
private
diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml
index e912198be3f..b6c30c680e4 100644
--- a/app/views/projects/cycle_analytics/show.html.haml
+++ b/app/views/projects/cycle_analytics/show.html.haml
@@ -57,7 +57,7 @@
%nav.stage-nav
%ul
%stage-nav-item{ "v-for" => "stage in state.stages", ":key" => '`ca-stage-title-${stage.title}`', '@select' => 'selectStage(stage)', ":title" => "stage.title", ":is-user-allowed" => "stage.isUserAllowed", ":value" => "stage.value", ":is-active" => "stage.active" }
- .section.stage-events
+ .section.stage-events.overflow-auto
%gl-loading-icon{ "v-show" => "isLoadingStage", "size" => "lg" }
%template{ "v-if" => "currentStage && !currentStage.isUserAllowed" }
= render partial: "no_access"
diff --git a/app/views/projects/deploy_keys/_index.html.haml b/app/views/shared/deploy_keys/_index.html.haml
index 6b3b824f72f..f28e745f4c5 100644
--- a/app/views/projects/deploy_keys/_index.html.haml
+++ b/app/views/shared/deploy_keys/_index.html.haml
@@ -1,15 +1,14 @@
- expanded = expanded_by_default?
%section.qa-deploy-keys-settings.settings.no-animate#js-deploy-keys-settings{ class: ('expanded' if expanded), data: { qa_selector: 'deploy_keys_settings' } }
.settings-header
- %h4
- Deploy Keys
+ %h4= _('Deploy Keys')
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? 'Collapse' : 'Expand'
%p
- Deploy keys allow read-only or read-write (if enabled) access to your repository. Deploy keys can be used for CI, staging or production servers. You can create a deploy key or add an existing one.
+ = _('Deploy keys allow read-only or read-write (if enabled) access to your repository. Deploy keys can be used for CI, staging or production servers. You can create a deploy key or add an existing one.')
.settings-content
%h5.prepend-top-0
- Create a new deploy key for this project
+ = _('Create a new deploy key for this project')
= render @deploy_keys.form_partial_path
%hr
#js-deploy-keys{ data: { endpoint: project_deploy_keys_path(@project), project_id: @project.id } }
diff --git a/app/views/projects/deploy_keys/_form.html.haml b/app/views/shared/deploy_keys/_project_group_form.html.haml
index 568930595a2..8edd1d9deb8 100644
--- a/app/views/projects/deploy_keys/_form.html.haml
+++ b/app/views/shared/deploy_keys/_project_group_form.html.haml
@@ -8,17 +8,17 @@
= f.text_area :key, class: "form-control", rows: 5, required: true
.form-group.row
%p.light.append-bottom-0
- Paste a machine public key here. Read more about how to generate it
+ = _('Paste a machine public key here. Read more about how to generate it')
= link_to "here", help_page_path("ssh/README")
= f.fields_for :deploy_keys_projects do |deploy_keys_project_form|
.form-group.row
= deploy_keys_project_form.label :can_push do
= deploy_keys_project_form.check_box :can_push
- %strong Write access allowed
+ %strong= _('Write access allowed')
.form-group.row
%p.light.append-bottom-0
- Allow this key to push to repository as well? (Default only allows pull access.)
+ = _('Allow this key to push to repository as well? (Default only allows pull access.)')
.form-group.row
= f.submit "Add key", class: "btn-success btn"
diff --git a/changelogs/unreleased/214528.yml b/changelogs/unreleased/214528.yml
new file mode 100644
index 00000000000..3b85bf73552
--- /dev/null
+++ b/changelogs/unreleased/214528.yml
@@ -0,0 +1,5 @@
+---
+title: Add severity icons for alert management
+merge_request: 30472
+author:
+type: changed
diff --git a/changelogs/unreleased/216543-none-syntax-highlighting-theme-for-web-ide.yml b/changelogs/unreleased/216543-none-syntax-highlighting-theme-for-web-ide.yml
new file mode 100644
index 00000000000..c669952d4d6
--- /dev/null
+++ b/changelogs/unreleased/216543-none-syntax-highlighting-theme-for-web-ide.yml
@@ -0,0 +1,5 @@
+---
+title: None syntax highlighting theme for Web IDE
+merge_request: 31056
+author:
+type: added
diff --git a/changelogs/unreleased/mw-cicd-analytics-add-title.yml b/changelogs/unreleased/mw-cicd-analytics-add-title.yml
new file mode 100644
index 00000000000..e435452b1e4
--- /dev/null
+++ b/changelogs/unreleased/mw-cicd-analytics-add-title.yml
@@ -0,0 +1,5 @@
+---
+title: 'CI / CD Analytics: Add title to page'
+merge_request: 30891
+author:
+type: added
diff --git a/changelogs/unreleased/mw-ia-group-level-add-title.yml b/changelogs/unreleased/mw-ia-group-level-add-title.yml
new file mode 100644
index 00000000000..e24923d0350
--- /dev/null
+++ b/changelogs/unreleased/mw-ia-group-level-add-title.yml
@@ -0,0 +1,5 @@
+---
+title: 'Issues Analytics: Add title to group-level page'
+merge_request: 31057
+author:
+type: added
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 5d769d5210a..f9868ccb5b2 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -4097,9 +4097,14 @@ type Group {
before: String
"""
- List time logs within a time range where the logged date is before end_date parameter.
+ List time logs within a date range where the logged date is equal to or before endDate
"""
- endDate: Time!
+ endDate: Time
+
+ """
+ List time-logs within a time range where the logged time is equal to or before endTime
+ """
+ endTime: Time
"""
Returns the first _n_ elements from the list.
@@ -4112,9 +4117,14 @@ type Group {
last: Int
"""
- List time logs within a time range where the logged date is after start_date parameter.
+ List time logs within a date range where the logged date is equal to or after startDate
+ """
+ startDate: Time
+
+ """
+ List time-logs within a time range where the logged time is equal to or after startTime
"""
- startDate: Time!
+ startTime: Time
): TimelogConnection!
"""
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index ad66edf36d0..e5bb8d94eeb 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -11530,29 +11530,41 @@
"args": [
{
"name": "startDate",
- "description": "List time logs within a time range where the logged date is after start_date parameter.",
+ "description": "List time logs within a date range where the logged date is equal to or after startDate",
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "Time",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
},
"defaultValue": null
},
{
"name": "endDate",
- "description": "List time logs within a time range where the logged date is before end_date parameter.",
+ "description": "List time logs within a date range where the logged date is equal to or before endDate",
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "Time",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "startTime",
+ "description": "List time-logs within a time range where the logged time is equal to or after startTime",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "endTime",
+ "description": "List time-logs within a time range where the logged time is equal to or before endTime",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
},
"defaultValue": null
},
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 41b33b3aceb..f42f139b30d 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -6129,6 +6129,9 @@ msgstr ""
msgid "Create a new branch"
msgstr ""
+msgid "Create a new deploy key for this project"
+msgstr ""
+
msgid "Create a new file as there are no files yet. Afterwards, you'll be able to commit your changes."
msgstr ""
@@ -6983,6 +6986,9 @@ msgstr ""
msgid "Deploy key was successfully updated."
msgstr ""
+msgid "Deploy keys allow read-only or read-write (if enabled) access to your repository. Deploy keys can be used for CI, staging or production servers. You can create a deploy key or add an existing one."
+msgstr ""
+
msgid "Deploy progress not found. To see pods, ensure your environment matches %{linkStart}deploy board criteria%{linkEnd}."
msgstr ""
@@ -12487,9 +12493,6 @@ msgstr ""
msgid "Live preview"
msgstr ""
-msgid "Load more vulnerabilities"
-msgstr ""
-
msgid "Loading"
msgstr ""
@@ -13975,15 +13978,6 @@ msgstr ""
msgid "No thanks, don't show this again"
msgstr ""
-msgid "No vulnerabilities found for this group"
-msgstr ""
-
-msgid "No vulnerabilities found for this pipeline"
-msgstr ""
-
-msgid "No vulnerabilities found for this project"
-msgstr ""
-
msgid "No vulnerabilities present"
msgstr ""
@@ -14799,6 +14793,9 @@ msgstr ""
msgid "Past due"
msgstr ""
+msgid "Paste a machine public key here. Read more about how to generate it"
+msgstr ""
+
msgid "Paste a machine public key here. Read more about how to generate it %{link_start}here%{link_end}"
msgstr ""
@@ -14934,6 +14931,9 @@ msgstr ""
msgid "Pipeline: %{status}"
msgstr ""
+msgid "PipelineCharts|CI / CD Analytics"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr ""
@@ -18248,208 +18248,232 @@ msgstr ""
msgid "Security Dashboard"
msgstr ""
-msgid "Security Dashboard|Error fetching the vulnerability counts. Please check your network connection and try again."
+msgid "Security configuration help link"
msgstr ""
-msgid "Security Dashboard|Error fetching the vulnerability list. Please check your network connection and try again."
+msgid "Security dashboard"
msgstr ""
-msgid "Security Dashboard|Issue Created"
+msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
-msgid "Security Reports|Comment added to '%{vulnerabilityName}'"
+msgid "Security report is out of date. Run %{newPipelineLinkStart}a new pipeline%{newPipelineLinkEnd} for the target branch (%{targetBranchName})"
msgstr ""
-msgid "Security Reports|Comment deleted on '%{vulnerabilityName}'"
+msgid "SecurityConfiguration|Configured"
msgstr ""
-msgid "Security Reports|Comment edited on '%{vulnerabilityName}'"
+msgid "SecurityConfiguration|Feature"
msgstr ""
-msgid "Security Reports|Create issue"
+msgid "SecurityConfiguration|Feature documentation for %{featureName}"
msgstr ""
-msgid "Security Reports|Dismiss Selected"
+msgid "SecurityConfiguration|Not yet configured"
msgstr ""
-msgid "Security Reports|Dismiss vulnerability"
+msgid "SecurityConfiguration|Secure features"
msgstr ""
-msgid "Security Reports|Dismissed '%{vulnerabilityName}'"
+msgid "SecurityConfiguration|Status"
msgstr ""
-msgid "Security Reports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismissed toggle to view."
+msgid "SecurityReports|%{firstProject} and %{secondProject}"
msgstr ""
-msgid "Security Reports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
+msgid "SecurityReports|%{firstProject}, %{secondProject}, and %{rest}"
msgstr ""
-msgid "Security Reports|False positive"
+msgid "SecurityReports|Add a project to your dashboard"
msgstr ""
-msgid "Security Reports|Learn more about setting up your dashboard"
+msgid "SecurityReports|Add or remove projects from your dashboard"
msgstr ""
-msgid "Security Reports|More info"
+msgid "SecurityReports|Add projects"
msgstr ""
-msgid "Security Reports|Oops, something doesn't seem right."
+msgid "SecurityReports|Comment added to '%{vulnerabilityName}'"
msgstr ""
-msgid "Security Reports|Security reports can only be accessed by authorized users."
+msgid "SecurityReports|Comment deleted on '%{vulnerabilityName}'"
msgstr ""
-msgid "Security Reports|Select a reason"
+msgid "SecurityReports|Comment edited on '%{vulnerabilityName}'"
msgstr ""
-msgid "Security Reports|There was an error adding the comment."
+msgid "SecurityReports|Create issue"
msgstr ""
-msgid "Security Reports|There was an error creating the issue."
+msgid "SecurityReports|Dismiss Selected"
msgstr ""
-msgid "Security Reports|There was an error creating the merge request."
+msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
-msgid "Security Reports|There was an error deleting the comment."
+msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
-msgid "Security Reports|There was an error dismissing the vulnerabilities."
+msgid "SecurityReports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismissed toggle to view."
msgstr ""
-msgid "Security Reports|There was an error dismissing the vulnerability."
+msgid "SecurityReports|Each vulnerability now has a unique page that can be directly linked to, shared, referenced, and tracked as the single source of truth. Vulnerability occurrences also persist across scanner runs, which improves tracking and visibility and reduces duplicates between scans."
msgstr ""
-msgid "Security Reports|There was an error reverting the dismissal."
+msgid "SecurityReports|Edit dashboard"
msgstr ""
-msgid "Security Reports|There was an error reverting this dismissal."
+msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
-msgid "Security Reports|Undo dismiss"
+msgid "SecurityReports|Error fetching the vulnerability counts. Please check your network connection and try again."
msgstr ""
-msgid "Security Reports|Won't fix / Accept risk"
+msgid "SecurityReports|Error fetching the vulnerability list. Please check your network connection and try again."
msgstr ""
-msgid "Security Reports|You do not have sufficient permissions to access this report"
+msgid "SecurityReports|False positive"
msgstr ""
-msgid "Security Reports|You must sign in as an authorized user to see this report"
+msgid "SecurityReports|Hide dismissed"
msgstr ""
-msgid "Security Reports|[No reason]"
+msgid "SecurityReports|Introducing standalone vulnerabilities"
msgstr ""
-msgid "Security configuration help link"
+msgid "SecurityReports|Issue Created"
msgstr ""
-msgid "Security dashboard"
+msgid "SecurityReports|Learn More"
msgstr ""
-msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
+msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "Security report is out of date. Run %{newPipelineLinkStart}a new pipeline%{newPipelineLinkEnd} for the target branch (%{targetBranchName})"
+msgid "SecurityReports|Load more vulnerabilities"
msgstr ""
-msgid "SecurityConfiguration|Configured"
+msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
-msgid "SecurityConfiguration|Feature"
+msgid "SecurityReports|More info"
msgstr ""
-msgid "SecurityConfiguration|Feature documentation for %{featureName}"
+msgid "SecurityReports|More information"
msgstr ""
-msgid "SecurityConfiguration|Not yet configured"
+msgid "SecurityReports|No vulnerabilities found for dashboard"
msgstr ""
-msgid "SecurityConfiguration|Secure features"
+msgid "SecurityReports|No vulnerabilities found for this group"
msgstr ""
-msgid "SecurityConfiguration|Status"
+msgid "SecurityReports|No vulnerabilities found for this pipeline"
+msgstr ""
+
+msgid "SecurityReports|No vulnerabilities found for this project"
+msgstr ""
+
+msgid "SecurityReports|Oops, something doesn't seem right."
+msgstr ""
+
+msgid "SecurityReports|Pipeline %{pipelineLink} triggered %{timeago} by %{user}"
+msgstr ""
+
+msgid "SecurityReports|Project"
msgstr ""
-msgid "SecurityDashboard|%{firstProject} and %{secondProject}"
+msgid "SecurityReports|Projects added"
msgstr ""
-msgid "SecurityDashboard|%{firstProject}, %{secondProject}, and %{rest}"
+msgid "SecurityReports|Remove project from dashboard"
msgstr ""
-msgid "SecurityDashboard|Add a project to your dashboard"
+msgid "SecurityReports|Report type"
msgstr ""
-msgid "SecurityDashboard|Add or remove projects from your dashboard"
+msgid "SecurityReports|Return to dashboard"
msgstr ""
-msgid "SecurityDashboard|Add projects"
+msgid "SecurityReports|Security Dashboard"
msgstr ""
-msgid "SecurityDashboard|Each vulnerability now has a unique page that can be directly linked to, shared, referenced, and tracked as the single source of truth. Vulnerability occurrences also persist across scanner runs, which improves tracking and visibility and reduces duplicates between scans."
+msgid "SecurityReports|Security reports can only be accessed by authorized users."
msgstr ""
-msgid "SecurityDashboard|Edit dashboard"
+msgid "SecurityReports|Select a project to add by using the project search field above."
msgstr ""
-msgid "SecurityDashboard|Hide dismissed"
+msgid "SecurityReports|Select a reason"
msgstr ""
-msgid "SecurityDashboard|Introducing standalone vulnerabilities"
+msgid "SecurityReports|Severity"
msgstr ""
-msgid "SecurityDashboard|Learn More"
+msgid "SecurityReports|Status"
msgstr ""
-msgid "SecurityDashboard|Monitor vulnerabilities in your code"
+msgid "SecurityReports|The security dashboard displays the latest security findings for projects you wish to monitor. Select \"Edit dashboard\" to add and remove projects."
msgstr ""
-msgid "SecurityDashboard|More information"
+msgid "SecurityReports|The security dashboard displays the latest security report. Use it to find and fix vulnerabilities."
msgstr ""
-msgid "SecurityDashboard|No vulnerabilities found for dashboard"
+msgid "SecurityReports|There was an error adding the comment."
msgstr ""
-msgid "SecurityDashboard|Pipeline %{pipelineLink} triggered %{timeago} by %{user}"
+msgid "SecurityReports|There was an error creating the issue."
msgstr ""
-msgid "SecurityDashboard|Project"
+msgid "SecurityReports|There was an error creating the merge request."
msgstr ""
-msgid "SecurityDashboard|Projects added"
+msgid "SecurityReports|There was an error deleting the comment."
msgstr ""
-msgid "SecurityDashboard|Remove project from dashboard"
+msgid "SecurityReports|There was an error dismissing the vulnerabilities."
msgstr ""
-msgid "SecurityDashboard|Report type"
+msgid "SecurityReports|There was an error dismissing the vulnerability."
msgstr ""
-msgid "SecurityDashboard|Return to dashboard"
+msgid "SecurityReports|There was an error reverting the dismissal."
msgstr ""
-msgid "SecurityDashboard|Security Dashboard"
+msgid "SecurityReports|There was an error reverting this dismissal."
msgstr ""
-msgid "SecurityDashboard|Select a project to add by using the project search field above."
+msgid "SecurityReports|There was an error while generating the report."
msgstr ""
-msgid "SecurityDashboard|Severity"
+msgid "SecurityReports|Unable to add %{invalidProjects}"
msgstr ""
-msgid "SecurityDashboard|Status"
+msgid "SecurityReports|Undo dismiss"
msgstr ""
-msgid "SecurityDashboard|The security dashboard displays the latest security findings for projects you wish to monitor. Select \"Edit dashboard\" to add and remove projects."
+msgid "SecurityReports|While it's rare to have no vulnerabilities for your group, it can happen. In any event, we ask that you double check your settings to make sure you've set up your dashboard correctly."
msgstr ""
-msgid "SecurityDashboard|The security dashboard displays the latest security report. Use it to find and fix vulnerabilities."
+msgid "SecurityReports|While it's rare to have no vulnerabilities for your pipeline, it can happen. In any event, we ask that you double check your settings to make sure all security scanning jobs have passed successfully."
msgstr ""
-msgid "SecurityDashboard|There was an error while generating the report."
+msgid "SecurityReports|While it's rare to have no vulnerabilities for your project, it can happen. In any event, we ask that you double check your settings to make sure you've set up your dashboard correctly."
msgstr ""
-msgid "SecurityDashboard|Unable to add %{invalidProjects}"
+msgid "SecurityReports|While it's rare to have no vulnerabilities, it can happen. In any event, we ask that you please double check your settings to make sure you've set up your dashboard correctly."
+msgstr ""
+
+msgid "SecurityReports|Won't fix / Accept risk"
+msgstr ""
+
+msgid "SecurityReports|You do not have sufficient permissions to access this report"
+msgstr ""
+
+msgid "SecurityReports|You must sign in as an authorized user to see this report"
+msgstr ""
+
+msgid "SecurityReports|[No reason]"
msgstr ""
msgid "See GitLab's %{password_policy_guidelines}"
@@ -23696,15 +23720,6 @@ msgstr ""
msgid "When:"
msgstr ""
-msgid "While it's rare to have no vulnerabilities for your group, it can happen. In any event, we ask that you double check your settings to make sure you've set up your dashboard correctly."
-msgstr ""
-
-msgid "While it's rare to have no vulnerabilities for your pipeline, it can happen. In any event, we ask that you double check your settings to make sure all security scanning jobs have passed successfully."
-msgstr ""
-
-msgid "While it's rare to have no vulnerabilities for your project, it can happen. In any event, we ask that you double check your settings to make sure you've set up your dashboard correctly."
-msgstr ""
-
msgid "While it's rare to have no vulnerabilities, it can happen. In any event, we ask that you please double check your settings to make sure you've set up your dashboard correctly."
msgstr ""
diff --git a/qa/qa/page/project/settings/deploy_keys.rb b/qa/qa/page/project/settings/deploy_keys.rb
index c330d090ce6..8d655b0684e 100644
--- a/qa/qa/page/project/settings/deploy_keys.rb
+++ b/qa/qa/page/project/settings/deploy_keys.rb
@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class DeployKeys < Page::Base
- view 'app/views/projects/deploy_keys/_form.html.haml' do
+ view 'app/views/shared/deploy_keys/_form.html.haml' do
element :deploy_key_title, 'text_field :title' # rubocop:disable QA/ElementWithPattern
element :deploy_key_key, 'text_area :key' # rubocop:disable QA/ElementWithPattern
end
diff --git a/qa/qa/page/project/settings/repository.rb b/qa/qa/page/project/settings/repository.rb
index 8810b971fda..e208fb308ee 100644
--- a/qa/qa/page/project/settings/repository.rb
+++ b/qa/qa/page/project/settings/repository.rb
@@ -19,7 +19,7 @@ module QA
element :deploy_tokens_settings
end
- view 'app/views/projects/deploy_keys/_index.html.haml' do
+ view 'app/views/shared/deploy_keys/_index.html.haml' do
element :deploy_keys_settings
end
diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh
index 38c6a77b9b1..3b53ae0c44d 100755
--- a/scripts/review_apps/review-apps.sh
+++ b/scripts/review_apps/review-apps.sh
@@ -236,7 +236,6 @@ function base_config_changed() {
function deploy() {
local namespace="${KUBE_NAMESPACE}"
local release="${CI_ENVIRONMENT_SLUG}"
- local edition="${GITLAB_EDITION:-ee}"
local base_config_file_ref="master"
if [[ "$(base_config_changed)" == "true" ]]; then base_config_file_ref="${CI_COMMIT_SHA}"; fi
local base_config_file="https://gitlab.com/gitlab-org/gitlab/raw/${base_config_file_ref}/scripts/review_apps/base-config.yaml"
@@ -244,13 +243,13 @@ function deploy() {
echoinfo "Deploying ${release}..." true
IMAGE_REPOSITORY="registry.gitlab.com/gitlab-org/build/cng-mirror"
- gitlab_migrations_image_repository="${IMAGE_REPOSITORY}/gitlab-rails-${edition}"
- gitlab_sidekiq_image_repository="${IMAGE_REPOSITORY}/gitlab-sidekiq-${edition}"
- gitlab_unicorn_image_repository="${IMAGE_REPOSITORY}/gitlab-webservice-${edition}"
- gitlab_task_runner_image_repository="${IMAGE_REPOSITORY}/gitlab-task-runner-${edition}"
+ gitlab_migrations_image_repository="${IMAGE_REPOSITORY}/gitlab-rails-ee"
+ gitlab_sidekiq_image_repository="${IMAGE_REPOSITORY}/gitlab-sidekiq-ee"
+ gitlab_unicorn_image_repository="${IMAGE_REPOSITORY}/gitlab-webservice-ee"
+ gitlab_task_runner_image_repository="${IMAGE_REPOSITORY}/gitlab-task-runner-ee"
gitlab_gitaly_image_repository="${IMAGE_REPOSITORY}/gitaly"
gitlab_shell_image_repository="${IMAGE_REPOSITORY}/gitlab-shell"
- gitlab_workhorse_image_repository="${IMAGE_REPOSITORY}/gitlab-workhorse-${edition}"
+ gitlab_workhorse_image_repository="${IMAGE_REPOSITORY}/gitlab-workhorse-ee"
create_application_secret
diff --git a/spec/config/application_spec.rb b/spec/config/application_spec.rb
index 994cea4c84f..e6b8da690a2 100644
--- a/spec/config/application_spec.rb
+++ b/spec/config/application_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
describe Gitlab::Application do # rubocop:disable RSpec/FilePath
using RSpec::Parameterized::TableSyntax
- FILTERED_PARAM = ActiveSupport::ParameterFilter::FILTERED
+ filtered_param = ActiveSupport::ParameterFilter::FILTERED
context 'when parameters are logged' do
describe 'rails does not leak confidential parameters' do
@@ -19,11 +19,11 @@ describe Gitlab::Application do # rubocop:disable RSpec/FilePath
where(:input_url, :output_query) do
'/' | {}
'/?safe=1' | { 'safe' => '1' }
- '/?private_token=secret' | { 'private_token' => FILTERED_PARAM }
- '/?mixed=1&private_token=secret' | { 'mixed' => '1', 'private_token' => FILTERED_PARAM }
- '/?note=secret&noteable=1&prefix_note=2' | { 'note' => FILTERED_PARAM, 'noteable' => '1', 'prefix_note' => '2' }
- '/?note[note]=secret&target_type=1' | { 'note' => FILTERED_PARAM, 'target_type' => '1' }
- '/?safe[note]=secret&target_type=1' | { 'safe' => { 'note' => FILTERED_PARAM }, 'target_type' => '1' }
+ '/?private_token=secret' | { 'private_token' => filtered_param }
+ '/?mixed=1&private_token=secret' | { 'mixed' => '1', 'private_token' => filtered_param }
+ '/?note=secret&noteable=1&prefix_note=2' | { 'note' => filtered_param, 'noteable' => '1', 'prefix_note' => '2' }
+ '/?note[note]=secret&target_type=1' | { 'note' => filtered_param, 'target_type' => '1' }
+ '/?safe[note]=secret&target_type=1' | { 'safe' => { 'note' => filtered_param }, 'target_type' => '1' }
end
with_them do
diff --git a/spec/features/merge_request/user_resolves_conflicts_spec.rb b/spec/features/merge_request/user_resolves_conflicts_spec.rb
index 5fc65f020d3..41a7456aed5 100644
--- a/spec/features/merge_request/user_resolves_conflicts_spec.rb
+++ b/spec/features/merge_request/user_resolves_conflicts_spec.rb
@@ -183,14 +183,14 @@ describe 'Merge request > User resolves conflicts', :js do
end
end
- UNRESOLVABLE_CONFLICTS = {
+ unresolvable_conflicts = {
'conflict-too-large' => 'when the conflicts contain a large file',
'conflict-binary-file' => 'when the conflicts contain a binary file',
'conflict-missing-side' => 'when the conflicts contain a file edited in one branch and deleted in another',
'conflict-non-utf8' => 'when the conflicts contain a non-UTF-8 file'
}.freeze
- UNRESOLVABLE_CONFLICTS.each do |source_branch, description|
+ unresolvable_conflicts.each do |source_branch, description|
context description do
let(:merge_request) { create_merge_request(source_branch) }
diff --git a/spec/features/milestones/user_creates_milestone_spec.rb b/spec/features/milestones/user_creates_milestone_spec.rb
index 368a2ddecdf..12cb27b0062 100644
--- a/spec/features/milestones/user_creates_milestone_spec.rb
+++ b/spec/features/milestones/user_creates_milestone_spec.rb
@@ -14,13 +14,13 @@ describe "User creates milestone", :js do
end
it "creates milestone" do
- TITLE = "v2.3".freeze
+ title = "v2.3".freeze
- fill_in("Title", with: TITLE)
+ fill_in("Title", with: title)
fill_in("Description", with: "# Description header")
click_button("Create milestone")
- expect(page).to have_content(TITLE)
+ expect(page).to have_content(title)
.and have_content("Issues")
.and have_header_with_correct_id_and_link(1, "Description header", "description-header")
diff --git a/spec/features/milestones/user_views_milestone_spec.rb b/spec/features/milestones/user_views_milestone_spec.rb
index d8bb4902087..ca13e226432 100644
--- a/spec/features/milestones/user_views_milestone_spec.rb
+++ b/spec/features/milestones/user_views_milestone_spec.rb
@@ -14,13 +14,13 @@ describe "User views milestone" do
end
it "avoids N+1 database queries" do
- ISSUE_PARAMS = { project: project, assignees: [user], author: user, milestone: milestone, labels: labels }.freeze
+ issue_params = { project: project, assignees: [user], author: user, milestone: milestone, labels: labels }.freeze
- create(:labeled_issue, ISSUE_PARAMS)
+ create(:labeled_issue, issue_params)
control = ActiveRecord::QueryRecorder.new { visit_milestone }
- create(:labeled_issue, ISSUE_PARAMS)
+ create(:labeled_issue, issue_params)
expect { visit_milestone }.not_to exceed_query_limit(control)
end
diff --git a/spec/features/projects/branches/user_creates_branch_spec.rb b/spec/features/projects/branches/user_creates_branch_spec.rb
index 156edb973cd..8aac188160b 100644
--- a/spec/features/projects/branches/user_creates_branch_spec.rb
+++ b/spec/features/projects/branches/user_creates_branch_spec.rb
@@ -16,18 +16,18 @@ describe "User creates branch", :js do
end
it "creates new branch" do
- BRANCH_NAME = "deploy_keys".freeze
+ branch_name = "deploy_keys".freeze
- create_branch(BRANCH_NAME)
+ create_branch(branch_name)
- expect(page).to have_content(BRANCH_NAME)
+ expect(page).to have_content(branch_name)
end
context "when branch name is invalid" do
it "does not create new branch" do
- INVALID_BRANCH_NAME = "1.0 stable".freeze
+ invalid_branch_name = "1.0 stable".freeze
- fill_in("branch_name", with: INVALID_BRANCH_NAME)
+ fill_in("branch_name", with: invalid_branch_name)
page.find("body").click # defocus the branch_name input
select_branch("master")
diff --git a/spec/features/projects/commit/comments/user_edits_comments_spec.rb b/spec/features/projects/commit/comments/user_edits_comments_spec.rb
index 0fa2b2ff232..29132173674 100644
--- a/spec/features/projects/commit/comments/user_edits_comments_spec.rb
+++ b/spec/features/projects/commit/comments/user_edits_comments_spec.rb
@@ -19,7 +19,7 @@ describe "User edits a comment on a commit", :js do
end
it "edits comment" do
- NEW_COMMENT_TEXT = "+1 Awesome!".freeze
+ new_comment_text = "+1 Awesome!".freeze
page.within(".main-notes-list") do
note = find(".note")
@@ -31,14 +31,14 @@ describe "User edits a comment on a commit", :js do
page.find(".current-note-edit-form textarea")
page.within(".current-note-edit-form") do
- fill_in("note[note]", with: NEW_COMMENT_TEXT)
+ fill_in("note[note]", with: new_comment_text)
click_button("Save comment")
end
wait_for_requests
page.within(".note") do
- expect(page).to have_content(NEW_COMMENT_TEXT)
+ expect(page).to have_content(new_comment_text)
end
end
end
diff --git a/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb b/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb
index cd9299150b2..45a16fda2cb 100644
--- a/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb
+++ b/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb
@@ -88,18 +88,18 @@ describe "User interacts with deploy keys", :js do
end
it "adds new key" do
- DEPLOY_KEY_TITLE = attributes_for(:key)[:title]
- DEPLOY_KEY_BODY = attributes_for(:key)[:key]
+ deploy_key_title = attributes_for(:key)[:title]
+ deploy_key_body = attributes_for(:key)[:key]
- fill_in("deploy_key_title", with: DEPLOY_KEY_TITLE)
- fill_in("deploy_key_key", with: DEPLOY_KEY_BODY)
+ fill_in("deploy_key_title", with: deploy_key_title)
+ fill_in("deploy_key_key", with: deploy_key_body)
click_button("Add key")
expect(current_path).to eq(project_settings_repository_path(project))
page.within(".deploy-keys") do
- expect(page).to have_content(DEPLOY_KEY_TITLE)
+ expect(page).to have_content(deploy_key_title)
end
end
end
diff --git a/spec/frontend/alert_management/components/alert_management_list_spec.js b/spec/frontend/alert_management/components/alert_management_list_spec.js
index e45a9042f71..c0494d736a6 100644
--- a/spec/frontend/alert_management/components/alert_management_list_spec.js
+++ b/spec/frontend/alert_management/components/alert_management_list_spec.js
@@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils';
-import { GlEmptyState, GlTable, GlAlert, GlLoadingIcon, GlNewDropdown } from '@gitlab/ui';
+import { GlEmptyState, GlTable, GlAlert, GlLoadingIcon, GlNewDropdown, GlIcon } from '@gitlab/ui';
import AlertManagementList from '~/alert_management/components/alert_management_list.vue';
import mockAlerts from '../mocks/alerts.json';
@@ -113,5 +113,22 @@ describe('AlertManagementList', () => {
});
expect(findStatusDropdown().exists()).toBe(true);
});
+
+ it('shows correct severity icons', () => {
+ mountComponent({
+ props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
+ data: { alerts: mockAlerts, errored: false },
+ loading: false,
+ });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.find(GlTable).exists()).toBe(true);
+ expect(
+ findAlertsTable()
+ .find(GlIcon)
+ .classes('icon-critical'),
+ ).toBe(true);
+ });
+ });
});
});
diff --git a/spec/frontend/clusters_list/store/actions_spec.js b/spec/frontend/clusters_list/store/actions_spec.js
index e903200bf1d..46132f701be 100644
--- a/spec/frontend/clusters_list/store/actions_spec.js
+++ b/spec/frontend/clusters_list/store/actions_spec.js
@@ -45,6 +45,3 @@ describe('Clusters store actions', () => {
});
});
});
-
-// prevent babel-plugin-rewire from generating an invalid default during karma tests
-export default () => {};
diff --git a/spec/frontend/contributors/store/actions_spec.js b/spec/frontend/contributors/store/actions_spec.js
index fe3e2132d9d..55437da837c 100644
--- a/spec/frontend/contributors/store/actions_spec.js
+++ b/spec/frontend/contributors/store/actions_spec.js
@@ -55,6 +55,3 @@ describe('Contributors store actions', () => {
});
});
});
-
-// prevent babel-plugin-rewire from generating an invalid default during karma tests
-export default () => {};
diff --git a/spec/frontend/contributors/store/getters_spec.js b/spec/frontend/contributors/store/getters_spec.js
index e6342a669b7..a4202e0ef4b 100644
--- a/spec/frontend/contributors/store/getters_spec.js
+++ b/spec/frontend/contributors/store/getters_spec.js
@@ -74,6 +74,3 @@ describe('Contributors Store Getters', () => {
});
});
});
-
-// prevent babel-plugin-rewire from generating an invalid default during karma tests
-export default () => {};
diff --git a/spec/frontend/create_cluster/eks_cluster/services/aws_services_facade_spec.js b/spec/frontend/create_cluster/eks_cluster/services/aws_services_facade_spec.js
index 490a2775b67..0ef09b4b87e 100644
--- a/spec/frontend/create_cluster/eks_cluster/services/aws_services_facade_spec.js
+++ b/spec/frontend/create_cluster/eks_cluster/services/aws_services_facade_spec.js
@@ -75,7 +75,7 @@ describe('awsServicesFacade', () => {
});
it('return list of regions where each item has a name and value', () => {
- expect(fetchRoles()).resolves.toEqual(rolesOutput);
+ return expect(fetchRoles()).resolves.toEqual(rolesOutput);
});
});
@@ -91,7 +91,7 @@ describe('awsServicesFacade', () => {
});
it('return list of roles where each item has a name and value', () => {
- expect(fetchRegions()).resolves.toEqual(regionsOutput);
+ return expect(fetchRegions()).resolves.toEqual(regionsOutput);
});
});
@@ -112,7 +112,7 @@ describe('awsServicesFacade', () => {
});
it('return list of key pairs where each item has a name and value', () => {
- expect(fetchKeyPairs({ region })).resolves.toEqual(keyPairsOutput);
+ return expect(fetchKeyPairs({ region })).resolves.toEqual(keyPairsOutput);
});
});
@@ -133,7 +133,7 @@ describe('awsServicesFacade', () => {
});
it('return list of vpcs where each item has a name and value', () => {
- expect(fetchVpcs({ region })).resolves.toEqual(vpcsOutput);
+ return expect(fetchVpcs({ region })).resolves.toEqual(vpcsOutput);
});
});
@@ -151,7 +151,7 @@ describe('awsServicesFacade', () => {
});
it('uses name tag value as the vpc name', () => {
- expect(fetchVpcs({ region })).resolves.toEqual(vpcsOutput);
+ return expect(fetchVpcs({ region })).resolves.toEqual(vpcsOutput);
});
});
@@ -167,7 +167,7 @@ describe('awsServicesFacade', () => {
});
it('return list of subnets where each item has a name and value', () => {
- expect(fetchSubnets({ region, vpc })).resolves.toEqual(subnetsOutput);
+ return expect(fetchSubnets({ region, vpc })).resolves.toEqual(subnetsOutput);
});
});
@@ -189,7 +189,7 @@ describe('awsServicesFacade', () => {
});
it('return list of security groups where each item has a name and value', () => {
- expect(fetchSecurityGroups({ region, vpc })).resolves.toEqual(securityGroupsOutput);
+ return expect(fetchSecurityGroups({ region, vpc })).resolves.toEqual(securityGroupsOutput);
});
});
});
diff --git a/spec/frontend/mocks_spec.js b/spec/frontend/mocks_spec.js
index a4a1fdea396..110c418e579 100644
--- a/spec/frontend/mocks_spec.js
+++ b/spec/frontend/mocks_spec.js
@@ -8,12 +8,13 @@ describe('Mock auto-injection', () => {
failMock = jest.spyOn(global, 'fail').mockImplementation();
});
- it('~/lib/utils/axios_utils', done => {
- expect(axios.get('http://gitlab.com')).rejects.toThrow('Unexpected unmocked request');
- setImmediate(() => {
- expect(failMock).toHaveBeenCalledTimes(1);
- done();
- });
+ it('~/lib/utils/axios_utils', () => {
+ return Promise.all([
+ expect(axios.get('http://gitlab.com')).rejects.toThrow('Unexpected unmocked request'),
+ setImmediate(() => {
+ expect(failMock).toHaveBeenCalledTimes(1);
+ }),
+ ]);
});
it('jQuery.ajax()', () => {
diff --git a/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js b/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js
index 10fd58f749d..216ec345552 100644
--- a/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js
+++ b/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js
@@ -81,7 +81,8 @@ describe('DuplicateDashboardForm', () => {
it('with the inital form values', () => {
expect(wrapper.emitted().change).toHaveLength(1);
- expect(lastChange()).resolves.toEqual({
+
+ return expect(lastChange()).resolves.toEqual({
branch: '',
commitMessage: expect.any(String),
dashboard: dashboardGitResponse[0].path,
@@ -92,7 +93,7 @@ describe('DuplicateDashboardForm', () => {
it('containing an inputted file name', () => {
setValue('fileName', 'my_dashboard.yml');
- expect(lastChange()).resolves.toMatchObject({
+ return expect(lastChange()).resolves.toMatchObject({
fileName: 'my_dashboard.yml',
});
});
@@ -100,7 +101,7 @@ describe('DuplicateDashboardForm', () => {
it('containing a default commit message when no message is set', () => {
setValue('commitMessage', '');
- expect(lastChange()).resolves.toMatchObject({
+ return expect(lastChange()).resolves.toMatchObject({
commitMessage: expect.stringContaining('Create custom dashboard'),
});
});
@@ -108,7 +109,7 @@ describe('DuplicateDashboardForm', () => {
it('containing an inputted commit message', () => {
setValue('commitMessage', 'My commit message');
- expect(lastChange()).resolves.toMatchObject({
+ return expect(lastChange()).resolves.toMatchObject({
commitMessage: expect.stringContaining('My commit message'),
});
});
@@ -116,7 +117,7 @@ describe('DuplicateDashboardForm', () => {
it('containing an inputted branch name', () => {
setValue('branchName', 'a-new-branch');
- expect(lastChange()).resolves.toMatchObject({
+ return expect(lastChange()).resolves.toMatchObject({
branch: 'a-new-branch',
});
});
@@ -125,13 +126,14 @@ describe('DuplicateDashboardForm', () => {
setChecked(wrapper.vm.$options.radioVals.DEFAULT);
setValue('branchName', 'a-new-branch');
- expect(lastChange()).resolves.toMatchObject({
- branch: defaultBranch,
- });
-
- return wrapper.vm.$nextTick(() => {
- expect(findByRef('branchName').isVisible()).toBe(false);
- });
+ return Promise.all([
+ expect(lastChange()).resolves.toMatchObject({
+ branch: defaultBranch,
+ }),
+ wrapper.vm.$nextTick(() => {
+ expect(findByRef('branchName').isVisible()).toBe(false);
+ }),
+ ]);
});
it('when `new` branch option is chosen, focuses on the branch name input', () => {
diff --git a/spec/frontend/notes/old_notes_spec.js b/spec/frontend/notes/old_notes_spec.js
index 3f7c94c3a2b..9f3ab4185c4 100644
--- a/spec/frontend/notes/old_notes_spec.js
+++ b/spec/frontend/notes/old_notes_spec.js
@@ -212,13 +212,6 @@ describe.skip('Old Notes (~/notes.js)', () => {
jest.spyOn($note, 'toggleClass');
});
- afterEach(() => {
- expect(typeof urlUtility.getLocationHash.mock).toBe('object');
- urlUtility.getLocationHash.mockRestore();
- expect(urlUtility.getLocationHash.mock).toBeUndefined();
- expect(urlUtility.getLocationHash()).toBeNull();
- });
-
// urlUtility is a dependency of the notes module. Its getLocatinHash() method should be called internally.
it('sets target when hash matches', () => {
@@ -629,48 +622,6 @@ describe.skip('Old Notes (~/notes.js)', () => {
done();
});
});
-
- // This is a bad test carried over from the Karma -> Jest migration.
- // The corresponding test in the Karma suite tests for
- // elements and methods that don't actually exist, and gives a false
- // positive pass.
- /*
- it('should show flash error message when comment failed to be updated', done => {
- mockNotesPost();
- jest.spyOn(notes, 'addFlash').mockName('addFlash');
-
- $('.js-comment-button').click();
-
- deferredPromise()
- .then(() => {
- const $noteEl = $notesContainer.find(`#note_${note.id}`);
- $noteEl.find('.js-note-edit').click();
- $noteEl.find('textarea.js-note-text').val(updatedComment);
-
- mockNotesPostError();
-
- $noteEl.find('.js-comment-save-button').click();
- notes.updateComment({preventDefault: () => {}});
- })
- .then(() => deferredPromise())
- .then(() => {
- const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`);
-
- expect($updatedNoteEl.hasClass('.being-posted')).toEqual(false); // Remove being-posted visuals
- expect(
- $updatedNoteEl
- .find('.note-text')
- .text()
- .trim(),
- ).toEqual(sampleComment); // See if comment reverted back to original
-
- expect(notes.addFlash).toHaveBeenCalled();
- expect(notes.flashContainer.style.display).not.toBe('none');
- done();
- })
- .catch(done.fail);
- }, 5000);
- */
});
describe('postComment with Slash commands', () => {
diff --git a/spec/frontend/releases/stores/modules/detail/actions_spec.js b/spec/frontend/releases/stores/modules/detail/actions_spec.js
index 4a1790adb09..231d877a25d 100644
--- a/spec/frontend/releases/stores/modules/detail/actions_spec.js
+++ b/spec/frontend/releases/stores/modules/detail/actions_spec.js
@@ -143,7 +143,7 @@ describe('Release detail actions', () => {
{ type: types.RECEIVE_UPDATE_RELEASE_SUCCESS },
]));
- describe('when the releaseShowPage feature flag is enabled', () => {
+ it('redirects to the releases page if releaseShowPage feature flag is enabled', () => {
const rootState = { featureFlags: { releaseShowPage: true } };
const updatedState = merge({}, state, {
releasesPagePath: 'path/to/releases/page',
diff --git a/spec/frontend/releases/stores/modules/detail/mutations_spec.js b/spec/frontend/releases/stores/modules/detail/mutations_spec.js
index cb5a1880b0c..9d4f78be327 100644
--- a/spec/frontend/releases/stores/modules/detail/mutations_spec.js
+++ b/spec/frontend/releases/stores/modules/detail/mutations_spec.js
@@ -1,10 +1,3 @@
-/* eslint-disable jest/valid-describe */
-/*
- * ESLint disable directive ↑ can be removed once
- * https://github.com/jest-community/eslint-plugin-jest/issues/203
- * is resolved
- */
-
import createState from '~/releases/stores/modules/detail/state';
import mutations from '~/releases/stores/modules/detail/mutations';
import * as types from '~/releases/stores/modules/detail/mutation_types';
@@ -27,6 +20,7 @@ describe('Release detail mutations', () => {
release = convertObjectPropsToCamelCase(originalRelease);
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.REQUEST_RELEASE, () => {
it('set state.isFetchingRelease to true', () => {
mutations[types.REQUEST_RELEASE](state);
@@ -35,6 +29,7 @@ describe('Release detail mutations', () => {
});
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.RECEIVE_RELEASE_SUCCESS, () => {
it('handles a successful response from the server', () => {
mutations[types.RECEIVE_RELEASE_SUCCESS](state, release);
@@ -49,6 +44,7 @@ describe('Release detail mutations', () => {
});
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.RECEIVE_RELEASE_ERROR, () => {
it('handles an unsuccessful response from the server', () => {
const error = { message: 'An error occurred!' };
@@ -62,6 +58,7 @@ describe('Release detail mutations', () => {
});
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.UPDATE_RELEASE_TITLE, () => {
it("updates the release's title", () => {
state.release = release;
@@ -72,6 +69,7 @@ describe('Release detail mutations', () => {
});
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.UPDATE_RELEASE_NOTES, () => {
it("updates the release's notes", () => {
state.release = release;
@@ -82,6 +80,7 @@ describe('Release detail mutations', () => {
});
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.REQUEST_UPDATE_RELEASE, () => {
it('set state.isUpdatingRelease to true', () => {
mutations[types.REQUEST_UPDATE_RELEASE](state);
@@ -90,6 +89,7 @@ describe('Release detail mutations', () => {
});
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.RECEIVE_UPDATE_RELEASE_SUCCESS, () => {
it('handles a successful response from the server', () => {
mutations[types.RECEIVE_UPDATE_RELEASE_SUCCESS](state, release);
@@ -100,6 +100,7 @@ describe('Release detail mutations', () => {
});
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.RECEIVE_UPDATE_RELEASE_ERROR, () => {
it('handles an unsuccessful response from the server', () => {
const error = { message: 'An error occurred!' };
@@ -111,6 +112,7 @@ describe('Release detail mutations', () => {
});
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.ADD_EMPTY_ASSET_LINK, () => {
it('adds a new, empty link object to the release', () => {
state.release = release;
@@ -130,6 +132,7 @@ describe('Release detail mutations', () => {
});
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.UPDATE_ASSET_LINK_URL, () => {
it('updates an asset link with a new URL', () => {
state.release = release;
@@ -145,6 +148,7 @@ describe('Release detail mutations', () => {
});
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.UPDATE_ASSET_LINK_NAME, () => {
it('updates an asset link with a new name', () => {
state.release = release;
@@ -160,6 +164,7 @@ describe('Release detail mutations', () => {
});
});
+ // eslint-disable-next-line jest/valid-describe
describe(types.REMOVE_ASSET_LINK, () => {
it('removes an asset link from the release', () => {
state.release = release;
diff --git a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js
index 962950ec96c..5dd9ea86221 100644
--- a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js
+++ b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js
@@ -48,7 +48,7 @@ describe('submitContentChanges', () => {
it('notifies error when branch could not be created', () => {
Api.createBranch.mockRejectedValueOnce();
- expect(submitContentChanges({ username, projectId })).rejects.toThrow(
+ return expect(submitContentChanges({ username, projectId })).rejects.toThrow(
SUBMIT_CHANGES_BRANCH_ERROR,
);
});
@@ -72,7 +72,7 @@ describe('submitContentChanges', () => {
it('notifies error when content could not be committed', () => {
Api.commitMultiple.mockRejectedValueOnce();
- expect(submitContentChanges({ username, projectId })).rejects.toThrow(
+ return expect(submitContentChanges({ username, projectId })).rejects.toThrow(
SUBMIT_CHANGES_COMMIT_ERROR,
);
});
@@ -93,7 +93,7 @@ describe('submitContentChanges', () => {
it('notifies error when merge request could not be created', () => {
Api.createProjectMergeRequest.mockRejectedValueOnce();
- expect(submitContentChanges({ username, projectId })).rejects.toThrow(
+ return expect(submitContentChanges({ username, projectId })).rejects.toThrow(
SUBMIT_CHANGES_MERGE_REQUEST_ERROR,
);
});
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_button_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_button_spec.js
index e2d31a41e82..214eb239432 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_button_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_button_spec.js
@@ -33,9 +33,32 @@ describe('DropdownButton', () => {
wrapper.destroy();
});
+ describe('methods', () => {
+ describe('handleButtonClick', () => {
+ it('calls action `toggleDropdownContents` and stops event propagation when `state.variant` is "standalone"', () => {
+ const event = {
+ stopPropagation: jest.fn(),
+ };
+ wrapper = createComponent({
+ ...mockConfig,
+ variant: 'standalone',
+ });
+
+ jest.spyOn(wrapper.vm, 'toggleDropdownContents');
+
+ wrapper.vm.handleButtonClick(event);
+
+ expect(wrapper.vm.toggleDropdownContents).toHaveBeenCalled();
+ expect(event.stopPropagation).toHaveBeenCalled();
+
+ wrapper.destroy();
+ });
+ });
+ });
+
describe('template', () => {
it('renders component container element', () => {
- expect(wrapper.is('gl-deprecated-button-stub')).toBe(true);
+ expect(wrapper.is('gl-button-stub')).toBe(true);
});
it('renders button text element', () => {
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js
index d7ca7ce30a9..04320a72be6 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js
@@ -1,7 +1,7 @@
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
-import { GlDeprecatedButton, GlIcon, GlFormInput, GlLink, GlLoadingIcon } from '@gitlab/ui';
+import { GlButton, GlFormInput, GlLink, GlLoadingIcon } from '@gitlab/ui';
import DropdownContentsCreateView from '~/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view.vue';
import labelSelectModule from '~/vue_shared/components/sidebar/labels_select_vue/store';
@@ -127,12 +127,12 @@ describe('DropdownContentsCreateView', () => {
it('renders dropdown back button element', () => {
const backBtnEl = wrapper
.find('.dropdown-title')
- .findAll(GlDeprecatedButton)
+ .findAll(GlButton)
.at(0);
expect(backBtnEl.exists()).toBe(true);
expect(backBtnEl.attributes('aria-label')).toBe('Go back');
- expect(backBtnEl.find(GlIcon).props('name')).toBe('arrow-left');
+ expect(backBtnEl.props('icon')).toBe('arrow-left');
});
it('renders dropdown title element', () => {
@@ -145,12 +145,12 @@ describe('DropdownContentsCreateView', () => {
it('renders dropdown close button element', () => {
const closeBtnEl = wrapper
.find('.dropdown-title')
- .findAll(GlDeprecatedButton)
+ .findAll(GlButton)
.at(1);
expect(closeBtnEl.exists()).toBe(true);
expect(closeBtnEl.attributes('aria-label')).toBe('Close');
- expect(closeBtnEl.find(GlIcon).props('name')).toBe('close');
+ expect(closeBtnEl.props('icon')).toBe('close');
});
it('renders label title input element', () => {
@@ -192,7 +192,7 @@ describe('DropdownContentsCreateView', () => {
it('renders create button element', () => {
const createBtnEl = wrapper
.find('.dropdown-actions')
- .findAll(GlDeprecatedButton)
+ .findAll(GlButton)
.at(0);
expect(createBtnEl.exists()).toBe(true);
@@ -213,7 +213,7 @@ describe('DropdownContentsCreateView', () => {
it('renders cancel button element', () => {
const cancelBtnEl = wrapper
.find('.dropdown-actions')
- .findAll(GlDeprecatedButton)
+ .findAll(GlButton)
.at(1);
expect(cancelBtnEl.exists()).toBe(true);
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js
index 3e6dbdb7ecb..951ee3c9b3d 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js
@@ -1,7 +1,7 @@
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
-import { GlDeprecatedButton, GlLoadingIcon, GlIcon, GlSearchBoxByType, GlLink } from '@gitlab/ui';
+import { GlButton, GlLoadingIcon, GlIcon, GlSearchBoxByType, GlLink } from '@gitlab/ui';
import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes';
import DropdownContentsLabelsView from '~/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue';
@@ -41,13 +41,19 @@ const createComponent = (initialState = mockConfig) => {
describe('DropdownContentsLabelsView', () => {
let wrapper;
+ let wrapperStandalone;
beforeEach(() => {
wrapper = createComponent();
+ wrapperStandalone = createComponent({
+ ...mockConfig,
+ variant: 'standalone',
+ });
});
afterEach(() => {
wrapper.destroy();
+ wrapperStandalone.destroy();
});
describe('computed', () => {
@@ -165,13 +171,24 @@ describe('DropdownContentsLabelsView', () => {
});
describe('handleLabelClick', () => {
- it('calls action `updateSelectedLabels` with provided `label` param', () => {
+ beforeEach(() => {
jest.spyOn(wrapper.vm, 'updateSelectedLabels').mockImplementation();
+ });
+ it('calls action `updateSelectedLabels` with provided `label` param', () => {
wrapper.vm.handleLabelClick(mockRegularLabel);
expect(wrapper.vm.updateSelectedLabels).toHaveBeenCalledWith([mockRegularLabel]);
});
+
+ it('calls action `toggleDropdownContents` when `state.allowMultiselect` is false', () => {
+ jest.spyOn(wrapper.vm, 'toggleDropdownContents');
+ wrapper.vm.$store.state.allowMultiselect = false;
+
+ wrapper.vm.handleLabelClick(mockRegularLabel);
+
+ expect(wrapper.vm.toggleDropdownContents).toHaveBeenCalled();
+ });
});
});
@@ -198,12 +215,15 @@ describe('DropdownContentsLabelsView', () => {
expect(titleEl.text()).toBe('Assign labels');
});
+ it('does not render dropdown title element when `state.variant` is "standalone"', () => {
+ expect(wrapperStandalone.find('.dropdown-title').exists()).toBe(false);
+ });
+
it('renders dropdown close button element', () => {
- const closeButtonEl = wrapper.find('.dropdown-title').find(GlDeprecatedButton);
+ const closeButtonEl = wrapper.find('.dropdown-title').find(GlButton);
expect(closeButtonEl.exists()).toBe(true);
- expect(closeButtonEl.find(GlIcon).exists()).toBe(true);
- expect(closeButtonEl.find(GlIcon).props('name')).toBe('close');
+ expect(closeButtonEl.props('icon')).toBe('close');
});
it('renders label search input element', () => {
@@ -253,13 +273,36 @@ describe('DropdownContentsLabelsView', () => {
});
it('renders footer list items', () => {
- const createLabelBtn = wrapper.find('.dropdown-footer').find(GlDeprecatedButton);
- const manageLabelsLink = wrapper.find('.dropdown-footer').find(GlLink);
-
- expect(createLabelBtn.exists()).toBe(true);
- expect(createLabelBtn.text()).toBe('Create label');
+ const createLabelLink = wrapper
+ .find('.dropdown-footer')
+ .findAll(GlLink)
+ .at(0);
+ const manageLabelsLink = wrapper
+ .find('.dropdown-footer')
+ .findAll(GlLink)
+ .at(1);
+
+ expect(createLabelLink.exists()).toBe(true);
+ expect(createLabelLink.text()).toBe('Create label');
expect(manageLabelsLink.exists()).toBe(true);
expect(manageLabelsLink.text()).toBe('Manage labels');
});
+
+ it('does not render "Create label" footer link when `state.allowLabelCreate` is `false`', () => {
+ wrapper.vm.$store.state.allowLabelCreate = false;
+
+ return wrapper.vm.$nextTick(() => {
+ const createLabelLink = wrapper
+ .find('.dropdown-footer')
+ .findAll(GlLink)
+ .at(0);
+
+ expect(createLabelLink.text()).not.toBe('Create label');
+ });
+ });
+
+ it('does not render footer list items when `state.variant` is "standalone"', () => {
+ expect(wrapperStandalone.find('.dropdown-footer').exists()).toBe(false);
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/labels_select_root_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/labels_select_root_spec.js
index 126fd5438c4..ee4e9090e5d 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/labels_select_root_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/labels_select_root_spec.js
@@ -89,6 +89,19 @@ describe('LabelsSelectRoot', () => {
expect(wrapper.attributes('class')).toContain('labels-select-wrapper position-relative');
});
+ it('renders component root element with CSS class `is-standalone` when `state.variant` is "standalone"', () => {
+ const wrapperStandalone = createComponent({
+ ...mockConfig,
+ variant: 'standalone',
+ });
+
+ return wrapperStandalone.vm.$nextTick(() => {
+ expect(wrapperStandalone.classes()).toContain('is-standalone');
+
+ wrapperStandalone.destroy();
+ });
+ });
+
it('renders `dropdown-value-collapsed` component when `allowLabelCreate` prop is `true`', () => {
expect(wrapper.find(DropdownValueCollapsed).exists()).toBe(true);
});
@@ -101,13 +114,16 @@ describe('LabelsSelectRoot', () => {
const wrapperDropdownValue = createComponent(mockConfig, {
default: 'None',
});
+ wrapperDropdownValue.vm.$store.state.showDropdownButton = false;
- const valueComp = wrapperDropdownValue.find(DropdownValue);
+ return wrapperDropdownValue.vm.$nextTick(() => {
+ const valueComp = wrapperDropdownValue.find(DropdownValue);
- expect(valueComp.exists()).toBe(true);
- expect(valueComp.text()).toBe('None');
+ expect(valueComp.exists()).toBe(true);
+ expect(valueComp.text()).toBe('None');
- wrapperDropdownValue.destroy();
+ wrapperDropdownValue.destroy();
+ });
});
it('renders `dropdown-button` component when `showDropdownButton` prop is `true`', () => {
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js
index e50771385dc..e1008d13fc2 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js
@@ -30,8 +30,10 @@ export const mockConfig = {
allowLabelEdit: true,
allowLabelCreate: true,
allowScopedLabels: true,
+ allowMultiselect: true,
labelsListTitle: 'Assign labels',
labelsCreateTitle: 'Create label',
+ variant: 'sidebar',
dropdownOnly: false,
selectedLabels: [mockRegularLabel, mockScopedLabel],
labelsSelectInProgress: false,
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js
index bfceaa0828b..b866117efcf 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js
@@ -5,19 +5,25 @@ describe('LabelsSelect Getters', () => {
it('returns string "Label" when state.labels has no selected labels', () => {
const labels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }];
- expect(getters.dropdownButtonText({ labels })).toBe('Label');
+ expect(getters.dropdownButtonText({ labels }, { isDropdownVariantSidebar: true })).toBe(
+ 'Label',
+ );
});
it('returns label title when state.labels has only 1 label', () => {
const labels = [{ id: 1, title: 'Foobar', set: true }];
- expect(getters.dropdownButtonText({ labels })).toBe('Foobar');
+ expect(getters.dropdownButtonText({ labels }, { isDropdownVariantSidebar: true })).toBe(
+ 'Foobar',
+ );
});
it('returns first label title and remaining labels count when state.labels has more than 1 label', () => {
const labels = [{ id: 1, title: 'Foo', set: true }, { id: 2, title: 'Bar', set: true }];
- expect(getters.dropdownButtonText({ labels })).toBe('Foo +1 more');
+ expect(getters.dropdownButtonText({ labels }, { isDropdownVariantSidebar: true })).toBe(
+ 'Foo +1 more',
+ );
});
});
@@ -28,4 +34,16 @@ describe('LabelsSelect Getters', () => {
expect(getters.selectedLabelsList({ selectedLabels })).toEqual([1, 2, 3, 4]);
});
});
+
+ describe('isDropdownVariantSidebar', () => {
+ it('returns `true` when `state.variant` is "sidebar"', () => {
+ expect(getters.isDropdownVariantSidebar({ variant: 'sidebar' })).toBe(true);
+ });
+ });
+
+ describe('isDropdownVariantStandalone', () => {
+ it('returns `true` when `state.variant` is "standalone"', () => {
+ expect(getters.isDropdownVariantStandalone({ variant: 'standalone' })).toBe(true);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js
index f6ca98fcc71..3031df3362f 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js
@@ -29,6 +29,7 @@ describe('LabelsSelect Mutations', () => {
const state = {
dropdownOnly: false,
showDropdownButton: false,
+ variant: 'sidebar',
};
mutations[types.TOGGLE_DROPDOWN_CONTENTS](state);
@@ -154,10 +155,27 @@ describe('LabelsSelect Mutations', () => {
describe(`${types.UPDATE_SELECTED_LABELS}`, () => {
const labels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }];
- it('updates `state.labels` to include `touched` and `set` props based on provided `labels` param', () => {
+ it('updates `state.labels` to include `touched` and `set` props based on provided `labels` param when `state.allowMultiselect` is `true`', () => {
const updatedLabelIds = [2, 4];
const state = {
labels,
+ allowMultiselect: true,
+ };
+ mutations[types.UPDATE_SELECTED_LABELS](state, { labels });
+
+ state.labels.forEach(label => {
+ if (updatedLabelIds.includes(label.id)) {
+ expect(label.touched).toBe(true);
+ expect(label.set).toBe(true);
+ }
+ });
+ });
+
+ it('updates `state.labels` to include `touched` and `set` props based on provided `labels` param when `state.allowMultiselect` is `false`', () => {
+ const updatedLabelIds = [2];
+ const state = {
+ labels,
+ allowMultiselect: false,
};
mutations[types.UPDATE_SELECTED_LABELS](state, { labels });
diff --git a/spec/models/timelog_spec.rb b/spec/models/timelog_spec.rb
index 33c1afad59f..ae1697fb7e6 100644
--- a/spec/models/timelog_spec.rb
+++ b/spec/models/timelog_spec.rb
@@ -56,12 +56,12 @@ RSpec.describe Timelog do
end
end
- describe 'between_dates' do
- it 'returns collection of timelogs within given dates' do
+ describe 'between_times' do
+ it 'returns collection of timelogs within given times' do
create(:timelog, spent_at: 65.days.ago)
timelog1 = create(:timelog, spent_at: 15.days.ago)
timelog2 = create(:timelog, spent_at: 5.days.ago)
- timelogs = described_class.between_dates(20.days.ago, 1.day.ago)
+ timelogs = described_class.between_times(20.days.ago, 1.day.ago)
expect(timelogs).to contain_exactly(timelog1, timelog2)
end