Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									5b0916450c
								
							
						
					
					
						commit
						d6849cd8ae
					
				|  | @ -4,8 +4,8 @@ import $ from 'jquery'; | |||
| import IssuableForm from 'ee_else_ce/issuable_form'; | ||||
| import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; | ||||
| import GLForm from '~/gl_form'; | ||||
| import initSuggestions from '~/issuable_suggestions'; | ||||
| import initIssuableTypeSelector from '~/issuable_type_selector'; | ||||
| import initSuggestions from '~/issues/suggestions'; | ||||
| import initIssuableTypeSelector from '~/issues/type_selector'; | ||||
| import LabelsSelect from '~/labels_select'; | ||||
| import MilestoneSelect from '~/milestones/milestone_select'; | ||||
| import IssuableTemplateSelectors from '~/templates/issuable_template_selectors'; | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ import { | |||
|   GlSafeHtmlDirective, | ||||
|   GlAvatarLink, | ||||
|   GlAvatarLabeled, | ||||
|   GlTooltip, | ||||
| } from '@gitlab/ui'; | ||||
| import { isGid, getIdFromGraphQLId } from '~/graphql_shared/utils'; | ||||
| import { glEmojiTag } from '../../emoji'; | ||||
|  | @ -26,6 +27,7 @@ export default { | |||
|     GlButton, | ||||
|     GlAvatarLink, | ||||
|     GlAvatarLabeled, | ||||
|     GlTooltip, | ||||
|   }, | ||||
|   directives: { | ||||
|     GlTooltip: GlTooltipDirective, | ||||
|  |  | |||
|  | @ -1,38 +0,0 @@ | |||
| /* eslint-disable @gitlab/require-i18n-strings */ | ||||
| import '@gitlab/ui/dist/utility_classes.css'; | ||||
| import UsageGraph from './usage_graph.vue'; | ||||
| 
 | ||||
| export default { | ||||
|   component: UsageGraph, | ||||
|   title: 'vue_shared/components/storage_counter/usage_graph', | ||||
| }; | ||||
| 
 | ||||
| const Template = (args, { argTypes }) => ({ | ||||
|   components: { UsageGraph }, | ||||
|   props: Object.keys(argTypes), | ||||
|   template: '<usage-graph v-bind="$props" />', | ||||
| }); | ||||
| 
 | ||||
| export const Default = Template.bind({}); | ||||
| Default.argTypes = { | ||||
|   rootStorageStatistics: { | ||||
|     description: 'The statistics object with all its fields', | ||||
|     type: { name: 'object', required: true }, | ||||
|     defaultValue: { | ||||
|       buildArtifactsSize: 400000, | ||||
|       pipelineArtifactsSize: 38000, | ||||
|       lfsObjectsSize: 4800000, | ||||
|       packagesSize: 3800000, | ||||
|       repositorySize: 39000000, | ||||
|       snippetsSize: 2000112, | ||||
|       storageSize: 39930000, | ||||
|       uploadsSize: 7000, | ||||
|       wikiSize: 300000, | ||||
|     }, | ||||
|   }, | ||||
|   limit: { | ||||
|     description: | ||||
|       'When a limit is set, users will see how much of their storage usage (limit) is used. In case the limit is 0 or the current usage exceeds the limit, it just renders the distribution', | ||||
|     defaultValue: 0, | ||||
|   }, | ||||
| }; | ||||
|  | @ -1,148 +0,0 @@ | |||
| <script> | ||||
| import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; | ||||
| import { numberToHumanSize } from '~/lib/utils/number_utils'; | ||||
| import { s__ } from '~/locale'; | ||||
| 
 | ||||
| export default { | ||||
|   components: { | ||||
|     GlIcon, | ||||
|   }, | ||||
|   directives: { | ||||
|     GlTooltip: GlTooltipDirective, | ||||
|   }, | ||||
|   props: { | ||||
|     rootStorageStatistics: { | ||||
|       required: true, | ||||
|       type: Object, | ||||
|     }, | ||||
|     limit: { | ||||
|       required: true, | ||||
|       type: Number, | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     storageTypes() { | ||||
|       const { | ||||
|         buildArtifactsSize, | ||||
|         pipelineArtifactsSize, | ||||
|         lfsObjectsSize, | ||||
|         packagesSize, | ||||
|         repositorySize, | ||||
|         storageSize, | ||||
|         wikiSize, | ||||
|         snippetsSize, | ||||
|         uploadsSize, | ||||
|       } = this.rootStorageStatistics; | ||||
|       const artifactsSize = buildArtifactsSize + pipelineArtifactsSize; | ||||
| 
 | ||||
|       if (storageSize === 0) { | ||||
|         return null; | ||||
|       } | ||||
| 
 | ||||
|       return [ | ||||
|         { | ||||
|           name: s__('UsageQuota|Repositories'), | ||||
|           style: this.usageStyle(this.barRatio(repositorySize)), | ||||
|           class: 'gl-bg-data-viz-blue-500', | ||||
|           size: repositorySize, | ||||
|         }, | ||||
|         { | ||||
|           name: s__('UsageQuota|LFS Objects'), | ||||
|           style: this.usageStyle(this.barRatio(lfsObjectsSize)), | ||||
|           class: 'gl-bg-data-viz-orange-600', | ||||
|           size: lfsObjectsSize, | ||||
|         }, | ||||
|         { | ||||
|           name: s__('UsageQuota|Packages'), | ||||
|           style: this.usageStyle(this.barRatio(packagesSize)), | ||||
|           class: 'gl-bg-data-viz-aqua-500', | ||||
|           size: packagesSize, | ||||
|         }, | ||||
|         { | ||||
|           name: s__('UsageQuota|Artifacts'), | ||||
|           style: this.usageStyle(this.barRatio(artifactsSize)), | ||||
|           class: 'gl-bg-data-viz-green-600', | ||||
|           size: artifactsSize, | ||||
|           tooltip: s__('UsageQuota|Artifacts is a sum of build and pipeline artifacts.'), | ||||
|         }, | ||||
|         { | ||||
|           name: s__('UsageQuota|Wikis'), | ||||
|           style: this.usageStyle(this.barRatio(wikiSize)), | ||||
|           class: 'gl-bg-data-viz-magenta-500', | ||||
|           size: wikiSize, | ||||
|         }, | ||||
|         { | ||||
|           name: s__('UsageQuota|Snippets'), | ||||
|           style: this.usageStyle(this.barRatio(snippetsSize)), | ||||
|           class: 'gl-bg-data-viz-orange-800', | ||||
|           size: snippetsSize, | ||||
|         }, | ||||
|         { | ||||
|           name: s__('UsageQuota|Uploads'), | ||||
|           style: this.usageStyle(this.barRatio(uploadsSize)), | ||||
|           class: 'gl-bg-data-viz-aqua-700', | ||||
|           size: uploadsSize, | ||||
|         }, | ||||
|       ] | ||||
|         .filter((data) => data.size !== 0) | ||||
|         .sort((a, b) => b.size - a.size); | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     formatSize(size) { | ||||
|       return numberToHumanSize(size); | ||||
|     }, | ||||
|     usageStyle(ratio) { | ||||
|       return { flex: ratio }; | ||||
|     }, | ||||
|     barRatio(size) { | ||||
|       let max = this.rootStorageStatistics.storageSize; | ||||
| 
 | ||||
|       if (this.limit !== 0 && max <= this.limit) { | ||||
|         max = this.limit; | ||||
|       } | ||||
| 
 | ||||
|       return size / max; | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
| <template> | ||||
|   <div v-if="storageTypes" class="gl-display-flex gl-flex-direction-column w-100"> | ||||
|     <div class="gl-h-6 gl-my-5 gl-bg-gray-50 gl-rounded-base gl-display-flex"> | ||||
|       <div | ||||
|         v-for="storageType in storageTypes" | ||||
|         :key="storageType.name" | ||||
|         class="storage-type-usage gl-h-full gl-display-inline-block" | ||||
|         :class="storageType.class" | ||||
|         :style="storageType.style" | ||||
|         data-testid="storage-type-usage" | ||||
|       ></div> | ||||
|     </div> | ||||
|     <div class="row py-0"> | ||||
|       <div | ||||
|         v-for="storageType in storageTypes" | ||||
|         :key="storageType.name" | ||||
|         class="col-md-auto gl-display-flex gl-align-items-center" | ||||
|         data-testid="storage-type-legend" | ||||
|       > | ||||
|         <div class="gl-h-2 gl-w-5 gl-mr-2 gl-display-inline-block" :class="storageType.class"></div> | ||||
|         <span class="gl-mr-2 gl-font-weight-bold gl-font-sm"> | ||||
|           {{ storageType.name }} | ||||
|         </span> | ||||
|         <span class="gl-text-gray-500 gl-font-sm"> | ||||
|           {{ formatSize(storageType.size) }} | ||||
|         </span> | ||||
|         <span | ||||
|           v-if="storageType.tooltip" | ||||
|           v-gl-tooltip | ||||
|           :title="storageType.tooltip" | ||||
|           :aria-label="storageType.tooltip" | ||||
|           class="gl-ml-2" | ||||
|         > | ||||
|           <gl-icon name="question" :size="12" /> | ||||
|         </span> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | @ -163,7 +163,7 @@ module TabHelper | |||
|     action = options.delete(:action) | ||||
| 
 | ||||
|     route_matches_paths?(options.delete(:path)) || | ||||
|       route_matches_pages?(options.delete(:page)) || | ||||
|       route_matches_page_without_exclusion?(options.delete(:page), options.delete(:exclude_page)) || | ||||
|       route_matches_controllers_and_or_actions?(controller, action) | ||||
|   end | ||||
| 
 | ||||
|  | @ -188,6 +188,13 @@ module TabHelper | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def route_matches_page_without_exclusion?(pages, exclude_page) | ||||
|     return false unless route_matches_pages?(pages) | ||||
|     return true unless exclude_page.present? | ||||
| 
 | ||||
|     !route_matches_pages?(exclude_page) | ||||
|   end | ||||
| 
 | ||||
|   def route_matches_pages?(pages) | ||||
|     Array(pages).compact.any? do |single_page| | ||||
|       # We need to distinguish between Hash argument and other types of | ||||
|  |  | |||
|  | @ -37,7 +37,8 @@ class UserCallout < ApplicationRecord | |||
|     security_configuration_devops_alert: 36,   # EE-only | ||||
|     profile_personal_access_token_expiry: 37,  # EE-only | ||||
|     terraform_notification_dismissed: 38, | ||||
|     security_newsletter_callout: 39 | ||||
|     security_newsletter_callout: 39, | ||||
|     verification_reminder: 40                  # EE-only | ||||
|   } | ||||
| 
 | ||||
|   validates :feature_name, | ||||
|  |  | |||
|  | @ -1,3 +0,0 @@ | |||
| :plain | ||||
|   job = $("tr#repo_#{@repo_id}") | ||||
|   job.find(".import-actions").html("<p class='alert alert-danger'>#{_('Access denied! Please verify you can add deploy keys to this repository.')}</p>") | ||||
|  | @ -3,6 +3,7 @@ | |||
|     = render "layouts/nav/sidebar/#{nav}" | ||||
|   .content-wrapper.content-wrapper-margin{ class: "#{@content_wrapper_class}" } | ||||
|     .mobile-overlay | ||||
|     = render_if_exists 'layouts/header/verification_reminder' | ||||
|     = yield :group_invite_members_banner | ||||
|     .alert-wrapper.gl-force-block-formatting-context | ||||
|       = render 'shared/outdated_browser' | ||||
|  |  | |||
|  | @ -16,13 +16,14 @@ | |||
|     = f.check_box :confidential, class: 'form-check-input' | ||||
|     = f.label :confidential, class: 'label-bold form-check-label' | ||||
|     %span.form-text.text-muted | ||||
|       = _('The application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential.') | ||||
|       = _('Enable only for confidential applications exclusively used by a trusted backend server that can securely store the client secret. Do not enable for native-mobile, single-page, or other JavaScript applications because they cannot keep the client secret confidential.') | ||||
| 
 | ||||
|   .form-group.form-check | ||||
|     = f.check_box :expire_access_tokens, class: 'form-check-input' | ||||
|     = f.label :expire_access_tokens, class: 'label-bold form-check-label' | ||||
|     %span.form-text.text-muted | ||||
|       = _('Access tokens expire after 2 hours. A refresh token may be used at any time to generate a new access token. Non-expiring access tokens are deprecated. Clear this setting to enable backward compatibility.') | ||||
|       = _('Enable access tokens to expire after 2 hours. If disabled, tokens do not expire.') | ||||
|       = link_to _('Learn more.'), help_page_path('integration/oauth_provider.md', anchor: 'expiring-access-tokens'), target: '_blank', rel: 'noopener noreferrer' | ||||
| 
 | ||||
|   .form-group | ||||
|     = f.label :scopes, class: 'label-bold' | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ | |||
|         - if oauth_authorized_applications_enabled | ||||
|           = _("Manage applications that can use GitLab as an OAuth provider, and applications that you've authorized to use your account.") | ||||
|         - else | ||||
|           = _("Manage applications that can use GitLab as an OAuth provider.") | ||||
|           = _("Manage applications that use GitLab as an OAuth provider.") | ||||
|       - else | ||||
|         = _("Manage applications that you've authorized to use your account.") | ||||
|   .col-lg-8 | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
|   announcement_date: "2021-11-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post. | ||||
|   removal_milestone: "15.0" # The milestone when this feature is planned to be removed | ||||
|   body: | # Do not modify this line, instead modify the lines below. | ||||
|     We are changing how the date filter works in Value Stream Analytics. Instead of filtering by the time that the issue or merge request was created, the date filter will filter by the end event time of the given stage. This will result in completely different figures after this change has rolled out.  | ||||
|     We are changing how the date filter works in Value Stream Analytics. Instead of filtering by the time that the issue or merge request was created, the date filter will filter by the end event time of the given stage. This will result in completely different figures after this change has rolled out. | ||||
|      | ||||
|     If you monitor Value Stream Analytics metrics and rely on the date filter, to avoid losing data, you must save the data prior to this change. | ||||
|   stage: manage # (optional - may be required in the future) String value of the stage that the feature was created in. e.g., Growth | ||||
|  |  | |||
|  | @ -17119,6 +17119,7 @@ Name of the feature that the callout is for. | |||
| | <a id="usercalloutfeaturenameenumtwo_factor_auth_recovery_settings_check"></a>`TWO_FACTOR_AUTH_RECOVERY_SETTINGS_CHECK` | Callout feature name for two_factor_auth_recovery_settings_check. | | ||||
| | <a id="usercalloutfeaturenameenumultimate_trial"></a>`ULTIMATE_TRIAL` | Callout feature name for ultimate_trial. | | ||||
| | <a id="usercalloutfeaturenameenumunfinished_tag_cleanup_callout"></a>`UNFINISHED_TAG_CLEANUP_CALLOUT` | Callout feature name for unfinished_tag_cleanup_callout. | | ||||
| | <a id="usercalloutfeaturenameenumverification_reminder"></a>`VERIFICATION_REMINDER` | Callout feature name for verification_reminder. | | ||||
| | <a id="usercalloutfeaturenameenumweb_ide_alert_dismissed"></a>`WEB_IDE_ALERT_DISMISSED` | Callout feature name for web_ide_alert_dismissed. | | ||||
| | <a id="usercalloutfeaturenameenumweb_ide_ci_environments_guidance"></a>`WEB_IDE_CI_ENVIRONMENTS_GUIDANCE` | Callout feature name for web_ide_ci_environments_guidance. | | ||||
| 
 | ||||
|  |  | |||
|  | @ -243,9 +243,9 @@ Only project Owners have the [permissions](../../permissions.md#project-members- | |||
| to select Security Policy Project. | ||||
| 
 | ||||
| Once your policy is complete, save it by selecting **Create merge request** | ||||
| at the bottom of the editor. You will be redirected to the merge request on the project's | ||||
| at the bottom of the editor. You are redirected to the merge request on the project's | ||||
| configured security policy project. If one does not link to your project, a security | ||||
| policy project will be automatically created. Existing policies can also be | ||||
| policy project is automatically created. Existing policies can also be | ||||
| removed from the editor interface by selecting **Delete policy** | ||||
| at the bottom of the editor. | ||||
| 
 | ||||
|  | @ -293,7 +293,7 @@ This rule enforces the defined actions and schedules a scan on the provided date | |||
| | `type`     | `string` | `schedule` | The rule's type. | | ||||
| | `branches` | `array` of `string` | `*` or the branch's name | The branch the given policy applies to (supports wildcard). | | ||||
| | `cadence`  | `string` | CRON expression (for example, `0 0 * * *`) | A whitespace-separated string containing five fields that represents the scheduled time. | | ||||
| | `clusters` | `object` | | The cluster where the given policy will enforce running selected scans (only for `container_scanning`/`cluster_image_scanning` scans). The key of the object is the name of the Kubernetes cluster configured for your project in GitLab. In the optionally provided value of the object, you can precisely select Kubernetes resources that will be scanned. | | ||||
| | `clusters` | `object` | | The cluster where the given policy enforces running selected scans (only for `container_scanning`/`cluster_image_scanning` scans). The key of the object is the name of the Kubernetes cluster configured for your project in GitLab. In the optionally provided value of the object, you can precisely select Kubernetes resources that are scanned. | | ||||
| 
 | ||||
| #### `cluster` schema | ||||
| 
 | ||||
|  | @ -301,10 +301,10 @@ Use this schema to define `clusters` objects in the [`schedule` rule type](#sche | |||
| 
 | ||||
| | Field        | Type                | Possible values          | Description | | ||||
| |--------------|---------------------|--------------------------|-------------| | ||||
| | `containers` | `array` of `string` | | The container name that will be scanned (only the first value is currently supported). | | ||||
| | `resources`  | `array` of `string` | | The resource name that will be scanned (only the first value is currently supported). | | ||||
| | `namespaces` | `array` of `string` | | The namespace that will be scanned (only the first value is currently supported). | | ||||
| | `kinds`      | `array` of `string` | `deployment`/`daemonset` | The resource kind that should be scanned (only the first value is currently supported). | | ||||
| | `containers` | `array` of `string` | | The container name to be scanned (only the first value is currently supported). | | ||||
| | `resources`  | `array` of `string` | | The resource name to be scanned (only the first value is currently supported). | | ||||
| | `namespaces` | `array` of `string` | | The namespace to be scanned (only the first value is currently supported). | | ||||
| | `kinds`      | `array` of `string` | `deployment`/`daemonset` | The resource kind to be scanned (only the first value is currently supported). | | ||||
| 
 | ||||
| ### `scan` action type | ||||
| 
 | ||||
|  | @ -333,8 +333,8 @@ Note the following: | |||
| - A secret detection scan runs in `normal` mode when executed as part of a pipeline, and in | ||||
|   [`historic`](../secret_detection/index.md#full-history-secret-detection) | ||||
|   mode when executed as part of a scheduled scan. | ||||
| - A container scanning and cluster image scanning scans configured for the `pipeline` rule type will ignore the cluster defined in the `clusters` object. | ||||
|   They will use predefined CI/CD variables defined for your project. Cluster selection with the `clusters` object is supported for the `schedule` rule type. | ||||
| - A container scanning and cluster image scanning scans configured for the `pipeline` rule type ignores the cluster defined in the `clusters` object. | ||||
|   They use predefined CI/CD variables defined for your project. Cluster selection with the `clusters` object is supported for the `schedule` rule type. | ||||
|   Cluster with name provided in `clusters` object must be created and configured for the project. To be able to successfully perform the `container_scanning`/`cluster_image_scanning` scans for the cluster you must follow instructions for the [Cluster Image Scanning feature](../cluster_image_scanning/index.md#prerequisites). | ||||
| - The SAST scan uses the default template and runs in a [child pipeline](../../../ci/pipelines/parent_child_pipelines.md). | ||||
| 
 | ||||
|  |  | |||
|  | @ -49,7 +49,7 @@ namespace :gitlab do | |||
| 
 | ||||
|       # Drop all extra schema objects GitLab owns | ||||
|       Gitlab::Database::EXTRA_SCHEMAS.each do |schema| | ||||
|         connection.execute("DROP SCHEMA IF EXISTS #{connection.quote_table_name(schema)}") | ||||
|         connection.execute("DROP SCHEMA IF EXISTS #{connection.quote_table_name(schema)} CASCADE") | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|  |  | |||
|  | @ -1736,9 +1736,6 @@ msgstr "" | |||
| msgid "Access denied for your LDAP account." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Access denied! Please verify you can add deploy keys to this repository." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Access denied: %{error}" | ||||
| msgstr "" | ||||
| 
 | ||||
|  | @ -12941,6 +12938,9 @@ msgstr "" | |||
| msgid "Enable access to the performance bar for non-administrators in a given group." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Enable access tokens to expire after 2 hours. If disabled, tokens do not expire." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Enable admin mode" | ||||
| msgstr "" | ||||
| 
 | ||||
|  | @ -13013,6 +13013,9 @@ msgstr "" | |||
| msgid "Enable multipart emails" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Enable only for confidential applications exclusively used by a trusted backend server that can securely store the client secret. Do not enable for native-mobile, single-page, or other JavaScript applications because they cannot keep the client secret confidential." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Enable or disable the Pseudonymizer data collection." | ||||
| msgstr "" | ||||
| 
 | ||||
|  | @ -21259,7 +21262,7 @@ msgstr "" | |||
| msgid "Manage applications that can use GitLab as an OAuth provider, and applications that you've authorized to use your account." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Manage applications that can use GitLab as an OAuth provider." | ||||
| msgid "Manage applications that use GitLab as an OAuth provider." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Manage applications that you've authorized to use your account." | ||||
|  | @ -37553,9 +37556,6 @@ msgstr "" | |||
| msgid "UsageQuota|Increase storage temporarily" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "UsageQuota|LFS Objects" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "UsageQuota|LFS storage" | ||||
| msgstr "" | ||||
| 
 | ||||
|  | @ -37586,9 +37586,6 @@ msgstr "" | |||
| msgid "UsageQuota|Purchased storage available" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "UsageQuota|Repositories" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "UsageQuota|Repository" | ||||
| msgstr "" | ||||
| 
 | ||||
|  | @ -37667,9 +37664,6 @@ msgstr "" | |||
| msgid "UsageQuota|Wiki content." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "UsageQuota|Wikis" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "UsageQuota|You have consumed all of your additional storage, please purchase more to unlock your projects over the free %{actualRepositorySizeLimit} limit." | ||||
| msgstr "" | ||||
| 
 | ||||
|  | @ -38390,6 +38384,18 @@ msgstr "" | |||
| msgid "Verification status" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "VerificationReminder|Pipeline failing? To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "VerificationReminder|Until then, free pipeline minutes on shared runners are unavailable. %{validateLinkStart}Validate your account%{validateLinkEnd} or %{docsLinkStart}use your own runners%{docsLinkEnd}." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "VerificationReminder|Your account has been validated." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "VerificationReminder|You’ll now be able to take advantage of free pipeline minutes on shared runners." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Verified" | ||||
| msgstr "" | ||||
| 
 | ||||
|  |  | |||
|  | @ -55,9 +55,9 @@ | |||
|     "@babel/preset-env": "^7.10.1", | ||||
|     "@gitlab/at.js": "1.5.7", | ||||
|     "@gitlab/favicon-overlay": "2.0.0", | ||||
|     "@gitlab/svgs": "1.221.0", | ||||
|     "@gitlab/svgs": "1.223.0", | ||||
|     "@gitlab/tributejs": "1.0.0", | ||||
|     "@gitlab/ui": "32.40.0", | ||||
|     "@gitlab/ui": "32.41.0", | ||||
|     "@gitlab/visual-review-tools": "1.6.1", | ||||
|     "@rails/actioncable": "6.1.4-1", | ||||
|     "@rails/ujs": "6.1.4-1", | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import { shallowMount } from '@vue/test-utils'; | ||||
| import App from '~/issuable_suggestions/components/app.vue'; | ||||
| import Suggestion from '~/issuable_suggestions/components/item.vue'; | ||||
| import App from '~/issues/suggestions/components/app.vue'; | ||||
| import Suggestion from '~/issues/suggestions/components/item.vue'; | ||||
| 
 | ||||
| describe('Issuable suggestions app component', () => { | ||||
|   let wrapper; | ||||
|  | @ -1,7 +1,7 @@ | |||
| import { GlTooltip, GlLink, GlIcon } from '@gitlab/ui'; | ||||
| import { shallowMount } from '@vue/test-utils'; | ||||
| import { TEST_HOST } from 'helpers/test_constants'; | ||||
| import Suggestion from '~/issuable_suggestions/components/item.vue'; | ||||
| import Suggestion from '~/issues/suggestions/components/item.vue'; | ||||
| import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; | ||||
| import mockData from '../mock_data'; | ||||
| 
 | ||||
|  | @ -1,5 +1,5 @@ | |||
| import { shallowMount } from '@vue/test-utils'; | ||||
| import InfoPopover from '~/issuable_type_selector/components/info_popover.vue'; | ||||
| import InfoPopover from '~/issues/type_selector/components/info_popover.vue'; | ||||
| 
 | ||||
| describe('Issuable type info popover', () => { | ||||
|   let wrapper; | ||||
|  | @ -152,7 +152,7 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] = | |||
|                     aria-label="Search" | ||||
|                     class="gl-form-input gl-search-box-by-type-input form-control" | ||||
|                     placeholder="Search" | ||||
|                     type="text" | ||||
|                     type="search" | ||||
|                   /> | ||||
|                     | ||||
|                   <div | ||||
|  | @ -283,7 +283,7 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] = | |||
|                     aria-label="Search" | ||||
|                     class="gl-form-input gl-search-box-by-type-input form-control" | ||||
|                     placeholder="Search" | ||||
|                     type="text" | ||||
|                     type="search" | ||||
|                   /> | ||||
|                     | ||||
|                   <div | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import { GlButton, GlAvatarLink } from '@gitlab/ui'; | ||||
| import { GlButton, GlAvatarLink, GlTooltip } from '@gitlab/ui'; | ||||
| import { shallowMount } from '@vue/test-utils'; | ||||
| import { extendedWrapper } from 'helpers/vue_test_utils_helper'; | ||||
| import CiIconBadge from '~/vue_shared/components/ci_badge_link.vue'; | ||||
|  | @ -32,6 +32,7 @@ describe('Header CI Component', () => { | |||
|   const findTimeAgo = () => wrapper.findComponent(TimeagoTooltip); | ||||
|   const findUserLink = () => wrapper.findComponent(GlAvatarLink); | ||||
|   const findSidebarToggleBtn = () => wrapper.findComponent(GlButton); | ||||
|   const findStatusTooltip = () => wrapper.findComponent(GlTooltip); | ||||
|   const findActionButtons = () => wrapper.findByTestId('ci-header-action-buttons'); | ||||
|   const findHeaderItemText = () => wrapper.findByTestId('ci-header-item-text'); | ||||
| 
 | ||||
|  | @ -91,6 +92,21 @@ describe('Header CI Component', () => { | |||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     describe('when the user has a status', () => { | ||||
|       const STATUS_MESSAGE = 'Working on exciting features...'; | ||||
| 
 | ||||
|       beforeEach(() => { | ||||
|         createComponent({ | ||||
|           itemName: 'Pipeline', | ||||
|           user: { ...defaultProps.user, status: { message: STATUS_MESSAGE } }, | ||||
|         }); | ||||
|       }); | ||||
| 
 | ||||
|       it('renders a tooltip', () => { | ||||
|         expect(findStatusTooltip().text()).toBe(STATUS_MESSAGE); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     describe('with data from GraphQL', () => { | ||||
|       const userId = 1; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,137 +0,0 @@ | |||
| import { shallowMount } from '@vue/test-utils'; | ||||
| import { numberToHumanSize } from '~/lib/utils/number_utils'; | ||||
| import UsageGraph from '~/vue_shared/components/storage_counter/usage_graph.vue'; | ||||
| 
 | ||||
| let data; | ||||
| let wrapper; | ||||
| 
 | ||||
| function mountComponent({ rootStorageStatistics, limit }) { | ||||
|   wrapper = shallowMount(UsageGraph, { | ||||
|     propsData: { | ||||
|       rootStorageStatistics, | ||||
|       limit, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| function findStorageTypeUsagesSerialized() { | ||||
|   return wrapper | ||||
|     .findAll('[data-testid="storage-type-usage"]') | ||||
|     .wrappers.map((wp) => wp.element.style.flex); | ||||
| } | ||||
| 
 | ||||
| describe('Storage Counter usage graph component', () => { | ||||
|   beforeEach(() => { | ||||
|     data = { | ||||
|       rootStorageStatistics: { | ||||
|         wikiSize: 5000, | ||||
|         repositorySize: 4000, | ||||
|         packagesSize: 3000, | ||||
|         lfsObjectsSize: 2000, | ||||
|         buildArtifactsSize: 500, | ||||
|         pipelineArtifactsSize: 500, | ||||
|         snippetsSize: 2000, | ||||
|         storageSize: 17000, | ||||
|         uploadsSize: 1000, | ||||
|       }, | ||||
|       limit: 2000, | ||||
|     }; | ||||
|     mountComponent(data); | ||||
|   }); | ||||
| 
 | ||||
|   afterEach(() => { | ||||
|     wrapper.destroy(); | ||||
|   }); | ||||
| 
 | ||||
|   it('renders the legend in order', () => { | ||||
|     const types = wrapper.findAll('[data-testid="storage-type-legend"]'); | ||||
| 
 | ||||
|     const { | ||||
|       buildArtifactsSize, | ||||
|       pipelineArtifactsSize, | ||||
|       lfsObjectsSize, | ||||
|       packagesSize, | ||||
|       repositorySize, | ||||
|       wikiSize, | ||||
|       snippetsSize, | ||||
|       uploadsSize, | ||||
|     } = data.rootStorageStatistics; | ||||
| 
 | ||||
|     expect(types.at(0).text()).toMatchInterpolatedText(`Wikis ${numberToHumanSize(wikiSize)}`); | ||||
|     expect(types.at(1).text()).toMatchInterpolatedText( | ||||
|       `Repositories ${numberToHumanSize(repositorySize)}`, | ||||
|     ); | ||||
|     expect(types.at(2).text()).toMatchInterpolatedText( | ||||
|       `Packages ${numberToHumanSize(packagesSize)}`, | ||||
|     ); | ||||
|     expect(types.at(3).text()).toMatchInterpolatedText( | ||||
|       `LFS Objects ${numberToHumanSize(lfsObjectsSize)}`, | ||||
|     ); | ||||
|     expect(types.at(4).text()).toMatchInterpolatedText( | ||||
|       `Snippets ${numberToHumanSize(snippetsSize)}`, | ||||
|     ); | ||||
|     expect(types.at(5).text()).toMatchInterpolatedText( | ||||
|       `Artifacts ${numberToHumanSize(buildArtifactsSize + pipelineArtifactsSize)}`, | ||||
|     ); | ||||
|     expect(types.at(6).text()).toMatchInterpolatedText(`Uploads ${numberToHumanSize(uploadsSize)}`); | ||||
|   }); | ||||
| 
 | ||||
|   describe('when storage type is not used', () => { | ||||
|     beforeEach(() => { | ||||
|       data.rootStorageStatistics.wikiSize = 0; | ||||
|       mountComponent(data); | ||||
|     }); | ||||
| 
 | ||||
|     it('filters the storage type', () => { | ||||
|       expect(wrapper.text()).not.toContain('Wikis'); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('when there is no storage usage', () => { | ||||
|     beforeEach(() => { | ||||
|       data.rootStorageStatistics.storageSize = 0; | ||||
|       mountComponent(data); | ||||
|     }); | ||||
| 
 | ||||
|     it('it does not render', () => { | ||||
|       expect(wrapper.html()).toEqual(''); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('when limit is 0', () => { | ||||
|     beforeEach(() => { | ||||
|       data.limit = 0; | ||||
|       mountComponent(data); | ||||
|     }); | ||||
| 
 | ||||
|     it('sets correct flex values', () => { | ||||
|       expect(findStorageTypeUsagesSerialized()).toStrictEqual([ | ||||
|         '0.29411764705882354', | ||||
|         '0.23529411764705882', | ||||
|         '0.17647058823529413', | ||||
|         '0.11764705882352941', | ||||
|         '0.11764705882352941', | ||||
|         '0.058823529411764705', | ||||
|         '0.058823529411764705', | ||||
|       ]); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('when storage exceeds limit', () => { | ||||
|     beforeEach(() => { | ||||
|       data.limit = data.rootStorageStatistics.storageSize - 1; | ||||
|       mountComponent(data); | ||||
|     }); | ||||
| 
 | ||||
|     it('it does render correclty', () => { | ||||
|       expect(findStorageTypeUsagesSerialized()).toStrictEqual([ | ||||
|         '0.29411764705882354', | ||||
|         '0.23529411764705882', | ||||
|         '0.17647058823529413', | ||||
|         '0.11764705882352941', | ||||
|         '0.11764705882352941', | ||||
|         '0.058823529411764705', | ||||
|         '0.058823529411764705', | ||||
|       ]); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  | @ -122,11 +122,24 @@ RSpec.describe TabHelper do | |||
|       specify do | ||||
|         result = helper.nav_link(controller: controller_param, action: action_param, path: path_param) | ||||
| 
 | ||||
|         if active | ||||
|           expect(result).to match(/active/) | ||||
|         else | ||||
|           expect(result).not_to match(/active/) | ||||
|         end | ||||
|         expect(result.include?('active')).to eq(active) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     where(:page, :excluded_page, :active) do | ||||
|       nil           | nil               | false | ||||
|       '_some_page_' | nil               | true | ||||
|       '_some_page_' | '_excluded_page_' | true | ||||
|       '_some_page_' | '_some_page_'     | false | ||||
|     end | ||||
| 
 | ||||
|     with_them do | ||||
|       specify do | ||||
|         allow(helper).to receive(:route_matches_pages?).and_return(page.present?, page == excluded_page) | ||||
| 
 | ||||
|         result = helper.nav_link(page: page, exclude_page: excluded_page) | ||||
| 
 | ||||
|         expect(result.include?('active')).to eq(active) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|  | @ -149,11 +162,7 @@ RSpec.describe TabHelper do | |||
|         specify do | ||||
|           result = helper.nav_link(controller: controller_param, action: action_param, path: path_param) | ||||
| 
 | ||||
|           if active | ||||
|             expect(result).to match(/active/) | ||||
|           else | ||||
|             expect(result).not_to match(/active/) | ||||
|           end | ||||
|           expect(result.include?('active')).to eq(active) | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|  |  | |||
|  | @ -191,7 +191,7 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout do | |||
| 
 | ||||
|     it 'drops extra schemas' do | ||||
|       Gitlab::Database::EXTRA_SCHEMAS.each do |schema| | ||||
|         expect(connection).to receive(:execute).with("DROP SCHEMA IF EXISTS \"#{schema}\"") | ||||
|         expect(connection).to receive(:execute).with("DROP SCHEMA IF EXISTS \"#{schema}\" CASCADE") | ||||
|       end | ||||
| 
 | ||||
|       subject | ||||
|  |  | |||
							
								
								
									
										16
									
								
								yarn.lock
								
								
								
								
							
							
						
						
									
										16
									
								
								yarn.lock
								
								
								
								
							|  | @ -914,20 +914,20 @@ | |||
|     stylelint-declaration-strict-value "1.7.7" | ||||
|     stylelint-scss "3.18.0" | ||||
| 
 | ||||
| "@gitlab/svgs@1.221.0": | ||||
|   version "1.221.0" | ||||
|   resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.221.0.tgz#1804d181b09672d13005d49818eb2da040d67488" | ||||
|   integrity sha512-Xn29eer39uVqeuefL/3hVuxo2tazHoEFIXC0F7DnESmBggrcjueNM2tuBUk40oaX6kCzM2Bn4Qn9ESIR+V0PgQ== | ||||
| "@gitlab/svgs@1.223.0": | ||||
|   version "1.223.0" | ||||
|   resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.223.0.tgz#658e2ec0fc1e34abd1a2a1d946ac2863aa408160" | ||||
|   integrity sha512-buIXhQ24UVAs6aVqqXhVy4V9dXGIVOOBnh3+4JNoqp+5xPBff/1L6WalJuyANvRgHdkeBTuP9EPyYh11urSMgg== | ||||
| 
 | ||||
| "@gitlab/tributejs@1.0.0": | ||||
|   version "1.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8" | ||||
|   integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw== | ||||
| 
 | ||||
| "@gitlab/ui@32.40.0": | ||||
|   version "32.40.0" | ||||
|   resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.40.0.tgz#48bb27c3b9ee4658b35e4f04d3b5e172b84f589f" | ||||
|   integrity sha512-MC4FaNUd6O5T5uhzrkgRCut5LxQLabSlXA1xyvrPhorsLgE0irCb4CxtFlTUNRl1zJz5YxvJqFrGRq7RGVJXdg== | ||||
| "@gitlab/ui@32.41.0": | ||||
|   version "32.41.0" | ||||
|   resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.41.0.tgz#d88f34c8ccf120d4834ab5eac8196469cabfbd34" | ||||
|   integrity sha512-WKLYLDwOj36nOpzFtFWN/ScTZfh9qX3on3qo1hEqakBHgUhZPCkUi/W2vp9S89RrBV9qSxgGzvj+d0iw50XXgQ== | ||||
|   dependencies: | ||||
|     "@babel/standalone" "^7.0.0" | ||||
|     bootstrap-vue "2.20.1" | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue