diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-19 03:08:49 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-19 03:08:49 +0300 |
commit | af5bf83315cddeb562d2429ae88b09a95b647472 (patch) | |
tree | 350b6526fe6abfcce2ecae22760caeee19b6921b /app | |
parent | af7558b036a53ebb0484e7978694a0b419c38c70 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
10 files changed, 241 insertions, 17 deletions
diff --git a/app/assets/javascripts/analytics/shared/components/date_ranges_dropdown.vue b/app/assets/javascripts/analytics/shared/components/date_ranges_dropdown.vue index 7ea7aba6f44..8b42d671149 100644 --- a/app/assets/javascripts/analytics/shared/components/date_ranges_dropdown.vue +++ b/app/assets/javascripts/analytics/shared/components/date_ranges_dropdown.vue @@ -55,6 +55,11 @@ export default { required: false, default: false, }, + disableSelectedDayCount: { + type: Boolean, + required: false, + default: false, + }, }, data() { return { @@ -85,7 +90,9 @@ export default { return this.groupedDateRangeOptionsByValue[this.selectedValue]; }, showDaysSelectedCount() { - return !this.isCustomDateRangeSelected && this.daysSelectedCount; + return ( + !this.disableSelectedDayCount && !this.isCustomDateRangeSelected && this.daysSelectedCount + ); }, daysSelectedCount() { const { selectedDateRange } = this; diff --git a/app/assets/javascripts/observability/constants.js b/app/assets/javascripts/observability/constants.js index 34c43a10fc0..dbbec3678e8 100644 --- a/app/assets/javascripts/observability/constants.js +++ b/app/assets/javascripts/observability/constants.js @@ -1,7 +1,33 @@ +import { s__ } from '~/locale'; + export const SORTING_OPTIONS = { TIMESTAMP_DESC: 'timestamp_desc', TIMESTAMP_ASC: 'timestamp_asc', DURATION_DESC: 'duration_desc', DURATION_ASC: 'duration_asc', }; +Object.freeze(SORTING_OPTIONS); export const DEFAULT_SORTING_OPTION = SORTING_OPTIONS.TIMESTAMP_DESC; + +export const TIME_RANGE_OPTIONS = [ + { value: '5m', title: s__('Observability|Last 5 minutes') }, + { value: '15m', title: s__('Observability|Last 15 minutes') }, + { value: '30m', title: s__('Observability|Last 30 minutes') }, + { value: '1h', title: s__('Observability|Last 1 hour') }, + { value: '4h', title: s__('Observability|Last 4 hours') }, + { value: '12h', title: s__('Observability|Last 12 hours') }, + { value: '24h', title: s__('Observability|Last 24 hours') }, + { value: '7d', title: s__('Observability|Last 7 days') }, + { value: '14d', title: s__('Observability|Last 14 days') }, + { value: '30d', title: s__('Observability|Last 30 days') }, +]; +Object.freeze(TIME_RANGE_OPTIONS); + +const OPERERATOR_LIKE = '=~'; +const OPERERATOR_LIKE_TEXT = s__('ObservabilityMetrics|is like'); +const OPERERATOR_NOT_LIKE = '!~'; +const OPERERATOR_NOT_LIKE_TEXT = s__('ObservabilityMetrics|is not like'); + +const OPERATORS_LIKE = [{ value: OPERERATOR_LIKE, description: OPERERATOR_LIKE_TEXT }]; +const OPERATORS_NOT_LIKE = [{ value: OPERERATOR_NOT_LIKE, description: OPERERATOR_NOT_LIKE_TEXT }]; +export const OPERATORS_LIKE_NOT = [...OPERATORS_LIKE, ...OPERATORS_NOT_LIKE]; diff --git a/app/assets/javascripts/observability/utils.js b/app/assets/javascripts/observability/utils.js new file mode 100644 index 00000000000..bce82c58996 --- /dev/null +++ b/app/assets/javascripts/observability/utils.js @@ -0,0 +1,33 @@ +/** + * Return the data range for the given time period + * Accepted values are numbers followed by the unit 'm', 'h', 'd', e.g. '5m', '3h', '7d' + * + * e.g. timePerdio: '5m' + * returns: { min: Date(_now - 5min_), max: Date(_now_) } + * + * @param {String} timePeriod The 'period' string + * @returns {{max: Date, min: Date}|{}} where max, min are Date objects representing the period range + * It returns {} if the period filter does not represent any range (invalid range, etc) + */ +export const periodToDate = (timePeriod) => { + const maxMs = Date.now(); + let minMs; + const periodValue = parseInt(timePeriod.slice(0, -1), 10); + if (Number.isNaN(periodValue) || periodValue <= 0) return {}; + + const unit = timePeriod[timePeriod.length - 1]; + switch (unit) { + case 'm': + minMs = periodValue * 60 * 1000; + break; + case 'h': + minMs = periodValue * 60 * 1000 * 60; + break; + case 'd': + minMs = periodValue * 60 * 1000 * 60 * 24; + break; + default: + return {}; + } + return { min: new Date(maxMs - minMs), max: new Date(maxMs) }; +}; diff --git a/app/assets/javascripts/usage_quotas/components/search_and_sort_bar/search_and_sort_bar.stories.js b/app/assets/javascripts/usage_quotas/components/search_and_sort_bar/search_and_sort_bar.stories.js new file mode 100644 index 00000000000..3d0d2afbcf2 --- /dev/null +++ b/app/assets/javascripts/usage_quotas/components/search_and_sort_bar/search_and_sort_bar.stories.js @@ -0,0 +1,18 @@ +import SearchAndSortBar from './search_and_sort_bar.vue'; + +export default { + component: SearchAndSortBar, + title: 'usage_quotas/components/search_bar', +}; + +const Template = (_, { argTypes }) => ({ + components: { SearchAndSortBar }, + props: Object.keys(argTypes), + template: `<search-and-sort-bar v-bind="$props" />`, +}); +export const Default = Template.bind({}); + +Default.args = { + namespace: '42', + searchInputPlaceholder: 'search', +}; diff --git a/app/assets/javascripts/usage_quotas/components/search_and_sort_bar/search_and_sort_bar.vue b/app/assets/javascripts/usage_quotas/components/search_and_sort_bar/search_and_sort_bar.vue new file mode 100644 index 00000000000..db4c448dec4 --- /dev/null +++ b/app/assets/javascripts/usage_quotas/components/search_and_sort_bar/search_and_sort_bar.vue @@ -0,0 +1,74 @@ +<script> +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; +import FilteredSortContainerRoot from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; + +export default { + name: 'SearchAndSortBar', + components: { + FilteredSortContainerRoot, + }, + props: { + // Search + namespace: { + type: String, + required: true, + }, + searchInputPlaceholder: { + type: String, + required: true, + }, + recentSearchesStorageKey: { + type: String, + required: false, + default: '', + }, + initialFilterValue: { + type: Array, + required: false, + default: () => [], + }, + // Sort + initialSortBy: { + type: String, + required: false, + default: '', + validator: (value) => value === '' || /(_desc)|(_asc)/gi.test(value), + }, + sortOptions: { + type: Array, + default: () => [], + required: false, + }, + }, + emits: ['onFilter', 'onSort'], + methods: { + onFilter(searchTerms) { + const searchQuery = searchTerms.reduce((terms, searchTerm) => { + if (searchTerm.type !== FILTERED_SEARCH_TERM) { + return ''; + } + + return `${terms} ${searchTerm.value.data}`; + }, ''); + + this.$emit('onFilter', searchQuery.trim() || null); + }, + onSort(value) { + this.$emit('onSort', value); + }, + }, +}; +</script> + +<template> + <filtered-sort-container-root + :namespace="namespace" + :tokens="[] /* eslint-disable-line @gitlab/vue-no-new-non-primitive-in-template */" + :search-input-placeholder="searchInputPlaceholder" + :sort-options="sortOptions" + :initial-sort-by="initialSortBy" + class="gl-flex-grow-1" + @onFilter="onFilter" + @onSort="onSort" + /> +</template> diff --git a/app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue b/app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue index efdb1b185d4..a812b90e378 100644 --- a/app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue +++ b/app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue @@ -1,6 +1,7 @@ <script> import { GlAlert } from '@gitlab/ui'; import StorageUsageStatistics from 'ee_else_ce/usage_quotas/storage/components/storage_usage_statistics.vue'; +import SearchAndSortBar from '~/usage_quotas/components/search_and_sort_bar/search_and_sort_bar.vue'; import DependencyProxyUsage from './dependency_proxy_usage.vue'; import ContainerRegistryUsage from './container_registry_usage.vue'; @@ -11,8 +12,9 @@ export default { StorageUsageStatistics, DependencyProxyUsage, ContainerRegistryUsage, + SearchAndSortBar, }, - inject: ['userNamespace'], + inject: ['userNamespace', 'namespaceId'], props: { namespaceLoadingError: { type: Boolean, @@ -89,6 +91,19 @@ export default { :loading="isNamespaceStorageStatisticsLoading" /> - <slot name="ee-storage-app"></slot> + <section class="gl-mt-5"> + <div class="gl-bg-gray-10 gl-p-5 gl-display-flex"> + <search-and-sort-bar + :namespace="namespaceId" + :search-input-placeholder="__('Search')" + @onFilter=" + (searchTerm) => { + $emit('search', searchTerm); + } + " + /> + </div> + <slot name="ee-storage-app"></slot> + </section> </div> </template> diff --git a/app/assets/javascripts/usage_quotas/storage/queries/namespace_storage.query.graphql b/app/assets/javascripts/usage_quotas/storage/queries/namespace_storage.query.graphql new file mode 100644 index 00000000000..d3b34f00db0 --- /dev/null +++ b/app/assets/javascripts/usage_quotas/storage/queries/namespace_storage.query.graphql @@ -0,0 +1,17 @@ +query getNamespaceStorageStatistics($fullPath: ID!) { + namespace(fullPath: $fullPath) { + id + rootStorageStatistics { + storageSize + repositorySize + lfsObjectsSize + containerRegistrySize + containerRegistrySizeIsEstimated + dependencyProxySize + buildArtifactsSize + packagesSize + wikiSize + snippetsSize + } + } +} diff --git a/app/assets/javascripts/usage_quotas/storage/queries/project_list_storage.query.graphql b/app/assets/javascripts/usage_quotas/storage/queries/project_list_storage.query.graphql new file mode 100644 index 00000000000..fd5b681ba81 --- /dev/null +++ b/app/assets/javascripts/usage_quotas/storage/queries/project_list_storage.query.graphql @@ -0,0 +1,47 @@ +#import "~/graphql_shared/fragments/page_info.fragment.graphql" + +query getProjectListStorageStatistics( + $fullPath: ID! + $searchTerm: String = "" + $first: Int + $last: Int + $after: String + $before: String + $sortKey: NamespaceProjectSort +) { + namespace(fullPath: $fullPath) { + id + projects( + includeSubgroups: true + notAimedForDeletion: true + search: $searchTerm + first: $first + last: $last + after: $after + before: $before + sort: $sortKey + ) { + nodes { + id + fullPath + nameWithNamespace + avatarUrl + webUrl + name + statistics { + storageSize + repositorySize + lfsObjectsSize + containerRegistrySize + buildArtifactsSize + packagesSize + wikiSize + snippetsSize + } + } + pageInfo { + ...PageInfo + } + } + } +} diff --git a/app/assets/stylesheets/page_bundles/login.scss b/app/assets/stylesheets/page_bundles/login.scss index 11582ff72f0..f4313518427 100644 --- a/app/assets/stylesheets/page_bundles/login.scss +++ b/app/assets/stylesheets/page_bundles/login.scss @@ -6,10 +6,6 @@ max-width: 960px; } - .navbar-gitlab .container { - max-width: none; - } - .flash-container { margin-bottom: $gl-padding; position: relative; @@ -95,15 +91,6 @@ } } -@include media-breakpoint-down(xs) { - .login-page { - .col-md-5.float-right { - float: none !important; - margin-bottom: 45px; - } - } -} - .html-devise-layout { margin: 0; padding: 0; diff --git a/app/views/layouts/_snowplow.html.haml b/app/views/layouts/_snowplow.html.haml index 503b38496f7..616fc59d2e8 100644 --- a/app/views/layouts/_snowplow.html.haml +++ b/app/views/layouts/_snowplow.html.haml @@ -2,7 +2,7 @@ - namespace = @group || @project&.namespace || @namespace = webpack_bundle_tag 'tracker' -- if Gitlab.com? && Feature.enabled?(:gl_analytics_tracking, Feature.current_request) +- if Gitlab.com? = webpack_bundle_tag 'analytics' = javascript_tag do :plain |