Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
7d175806de
commit
f44809bf96
|
@ -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}"
|
||||
|
|
|
@ -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
|
||||
|
|
68
.rubocop.yml
68
.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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
};
|
|
@ -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"
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const DropdownVariant = {
|
||||
Sidebar: 'sidebar',
|
||||
Standalone: 'standalone',
|
||||
};
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 () => {};
|
||||
|
|
|
@ -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;
|
||||
}, []);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -187,7 +187,6 @@
|
|||
|
||||
.stage-events {
|
||||
width: 60%;
|
||||
overflow: scroll;
|
||||
min-height: 467px;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 } }
|
|
@ -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"
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add severity icons for alert management
|
||||
merge_request: 30472
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: None syntax highlighting theme for Web IDE
|
||||
merge_request: 31056
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'CI / CD Analytics: Add title to page'
|
||||
merge_request: 30891
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'Issues Analytics: Add title to group-level page'
|
||||
merge_request: 31057
|
||||
author:
|
||||
type: added
|
|
@ -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!
|
||||
startDate: Time
|
||||
|
||||
"""
|
||||
List time-logs within a time range where the logged time is equal to or after startTime
|
||||
"""
|
||||
startTime: Time
|
||||
): TimelogConnection!
|
||||
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
},
|
||||
|
|
|
@ -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,99 +18248,6 @@ msgstr ""
|
|||
msgid "Security Dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Dashboard|Error fetching the vulnerability counts. Please check your network connection and try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Dashboard|Error fetching the vulnerability list. Please check your network connection and try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Dashboard|Issue Created"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Comment added to '%{vulnerabilityName}'"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Comment deleted on '%{vulnerabilityName}'"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Comment edited on '%{vulnerabilityName}'"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Create issue"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Dismiss Selected"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Dismiss vulnerability"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Dismissed '%{vulnerabilityName}'"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismissed toggle to view."
|
||||
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."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|False positive"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Learn more about setting up your dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|More info"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Oops, something doesn't seem right."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Security reports can only be accessed by authorized users."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Select a reason"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|There was an error adding the comment."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|There was an error creating the issue."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|There was an error creating the merge request."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|There was an error deleting the comment."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|There was an error dismissing the vulnerabilities."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|There was an error dismissing the vulnerability."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|There was an error reverting the dismissal."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|There was an error reverting this dismissal."
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Undo dismiss"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|Won't fix / Accept risk"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|You do not have sufficient permissions to access this report"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|You must sign in as an authorized user to see this report"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security Reports|[No reason]"
|
||||
msgstr ""
|
||||
|
||||
msgid "Security configuration help link"
|
||||
msgstr ""
|
||||
|
||||
|
@ -18371,85 +18278,202 @@ msgstr ""
|
|||
msgid "SecurityConfiguration|Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|%{firstProject} and %{secondProject}"
|
||||
msgid "SecurityReports|%{firstProject} and %{secondProject}"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|%{firstProject}, %{secondProject}, and %{rest}"
|
||||
msgid "SecurityReports|%{firstProject}, %{secondProject}, and %{rest}"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Add a project to your dashboard"
|
||||
msgid "SecurityReports|Add a project to your dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Add or remove projects from your dashboard"
|
||||
msgid "SecurityReports|Add or remove projects from your dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Add projects"
|
||||
msgid "SecurityReports|Add projects"
|
||||
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|Comment added to '%{vulnerabilityName}'"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Edit dashboard"
|
||||
msgid "SecurityReports|Comment deleted on '%{vulnerabilityName}'"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Hide dismissed"
|
||||
msgid "SecurityReports|Comment edited on '%{vulnerabilityName}'"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Introducing standalone vulnerabilities"
|
||||
msgid "SecurityReports|Create issue"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Learn More"
|
||||
msgid "SecurityReports|Dismiss Selected"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Monitor vulnerabilities in your code"
|
||||
msgid "SecurityReports|Dismiss vulnerability"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|More information"
|
||||
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|No vulnerabilities found for dashboard"
|
||||
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismissed toggle to view."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Pipeline %{pipelineLink} triggered %{timeago} by %{user}"
|
||||
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 "SecurityDashboard|Project"
|
||||
msgid "SecurityReports|Edit dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Projects added"
|
||||
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 "SecurityDashboard|Remove project from dashboard"
|
||||
msgid "SecurityReports|Error fetching the vulnerability counts. Please check your network connection and try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Report type"
|
||||
msgid "SecurityReports|Error fetching the vulnerability list. Please check your network connection and try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Return to dashboard"
|
||||
msgid "SecurityReports|False positive"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Security Dashboard"
|
||||
msgid "SecurityReports|Hide dismissed"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Select a project to add by using the project search field above."
|
||||
msgid "SecurityReports|Introducing standalone vulnerabilities"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Severity"
|
||||
msgid "SecurityReports|Issue Created"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Status"
|
||||
msgid "SecurityReports|Learn More"
|
||||
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|Learn more about setting up your dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|The security dashboard displays the latest security report. Use it to find and fix vulnerabilities."
|
||||
msgid "SecurityReports|Load more vulnerabilities"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|There was an error while generating the report."
|
||||
msgid "SecurityReports|Monitor vulnerabilities in your code"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityDashboard|Unable to add %{invalidProjects}"
|
||||
msgid "SecurityReports|More info"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|More information"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|No vulnerabilities found for dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|No vulnerabilities found for this group"
|
||||
msgstr ""
|
||||
|
||||
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 "SecurityReports|Projects added"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Remove project from dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Report type"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Return to dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Security Dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Security reports can only be accessed by authorized users."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Select a project to add by using the project search field above."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Select a reason"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Severity"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Status"
|
||||
msgstr ""
|
||||
|
||||
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 "SecurityReports|The security dashboard displays the latest security report. Use it to find and fix vulnerabilities."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|There was an error adding the comment."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|There was an error creating the issue."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|There was an error creating the merge request."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|There was an error deleting the comment."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|There was an error dismissing the vulnerabilities."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|There was an error dismissing the vulnerability."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|There was an error reverting the dismissal."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|There was an error reverting this dismissal."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|There was an error while generating the report."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Unable to add %{invalidProjects}"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Undo dismiss"
|
||||
msgstr ""
|
||||
|
||||
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 "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 "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 "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 ""
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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¬eable=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¬eable=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
|
||||
|
|
|
@ -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) }
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -45,6 +45,3 @@ describe('Clusters store actions', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
// prevent babel-plugin-rewire from generating an invalid default during karma tests
|
||||
export default () => {};
|
||||
|
|
|
@ -55,6 +55,3 @@ describe('Contributors store actions', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
// prevent babel-plugin-rewire from generating an invalid default during karma tests
|
||||
export default () => {};
|
||||
|
|
|
@ -74,6 +74,3 @@ describe('Contributors Store Getters', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
// prevent babel-plugin-rewire from generating an invalid default during karma tests
|
||||
export default () => {};
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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()', () => {
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
const createLabelLink = wrapper
|
||||
.find('.dropdown-footer')
|
||||
.findAll(GlLink)
|
||||
.at(0);
|
||||
const manageLabelsLink = wrapper
|
||||
.find('.dropdown-footer')
|
||||
.findAll(GlLink)
|
||||
.at(1);
|
||||
|
||||
expect(createLabelBtn.exists()).toBe(true);
|
||||
expect(createLabelBtn.text()).toBe('Create label');
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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`', () => {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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 });
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue