Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-06-15 12:10:11 +00:00
parent a149886179
commit 96acc69fae
208 changed files with 1106 additions and 3650 deletions

View File

@ -181,6 +181,15 @@
- *node-modules-cache-push
- *assets-cache-push
.use-pg11:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2.patched-golang-1.16-git-2.31-lfs-2.9-chrome-89-node-14.15-yarn-1.22-postgresql-11-graphicsmagick-1.3.36"
services:
- name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:5.0-alpine
variables:
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg12:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2.patched-golang-1.16-git-2.31-lfs-2.9-chrome-89-node-14.15-yarn-1.22-postgresql-12-graphicsmagick-1.3.36"
services:
@ -190,6 +199,17 @@
variables:
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg11-ee:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2.patched-golang-1.16-git-2.31-lfs-2.9-chrome-89-node-14.15-yarn-1.22-postgresql-11-graphicsmagick-1.3.36"
services:
- name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:5.0-alpine
- name: elasticsearch:7.11.1
command: ["elasticsearch", "-E", "discovery.type=single-node"]
variables:
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg12-ee:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2.patched-golang-1.16-git-2.31-lfs-2.9-chrome-89-node-14.15-yarn-1.22-postgresql-12-graphicsmagick-1.3.36"
services:

View File

@ -58,6 +58,11 @@
- !reference [.base-script, script]
- rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag level:migration"
.rspec-base-pg11:
extends:
- .rspec-base
- .use-pg11
.rspec-base-pg12:
extends:
- .rspec-base
@ -70,6 +75,11 @@
- .use-pg12
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets as-if-foss", "detect-tests"]
.rspec-ee-base-pg11:
extends:
- .rspec-base
- .use-pg11-ee
.rspec-ee-base-pg12:
extends:
- .rspec-base
@ -81,6 +91,11 @@
- !reference [.base-script, script]
- rspec_paralellized_job "--tag ~quarantine --tag geo"
.rspec-ee-base-geo-pg11:
extends:
- .rspec-ee-base-geo
- .use-pg11-ee
.rspec-ee-base-geo-pg12:
extends:
- .rspec-ee-base-geo
@ -277,6 +292,16 @@ rspec system pg12 minimal:
- .minimal-rspec-tests
- .rails:rules:ee-and-foss-system:minimal
# Dedicated job to test DB library code against PG11.
# Note that these are already tested against PG12 in the `rspec unit pg12` / `rspec-ee unit pg12` jobs.
rspec db-library-code pg11:
extends:
- .rspec-base-pg11
- .rails:rules:ee-and-foss-db-library-code
script:
- !reference [.base-script, script]
- rspec_db_library_code
rspec fast_spec_helper:
extends:
- .rspec-base-pg12
@ -637,6 +662,80 @@ db:rollback geo:
# EE: default refs (MRs, default branch, schedules) jobs #
##################################################
##########################################
# EE/FOSS: default branch nightly scheduled jobs #
rspec migration pg11:
extends:
- .rspec-base-pg11
- .rspec-base-migration
- .rails:rules:default-branch-schedule-nightly--code-backstage
- .rspec-migration-parallel
rspec unit pg11:
extends:
- .rspec-base-pg11
- .rails:rules:default-branch-schedule-nightly--code-backstage
- .rspec-unit-parallel
rspec integration pg11:
extends:
- .rspec-base-pg11
- .rails:rules:default-branch-schedule-nightly--code-backstage
- .rspec-integration-parallel
rspec system pg11:
extends:
- .rspec-base-pg11
- .rails:rules:default-branch-schedule-nightly--code-backstage
- .rspec-system-parallel
# EE/FOSS: default branch nightly scheduled jobs #
##########################################
#####################################
# EE: default branch nightly scheduled jobs #
rspec-ee migration pg11:
extends:
- .rspec-ee-base-pg11
- .rspec-base-migration
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-migration-parallel
rspec-ee unit pg11:
extends:
- .rspec-ee-base-pg11
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-unit-parallel
rspec-ee integration pg11:
extends:
- .rspec-ee-base-pg11
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-integration-parallel
rspec-ee system pg11:
extends:
- .rspec-ee-base-pg11
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-system-parallel
rspec-ee unit pg11 geo:
extends:
- .rspec-ee-base-geo-pg11
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-unit-geo-parallel
rspec-ee integration pg11 geo:
extends:
- .rspec-ee-base-geo-pg11
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee system pg11 geo:
extends:
- .rspec-ee-base-geo-pg11
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
# EE: default branch nightly scheduled jobs #
#####################################
##################################################
# EE: Canonical MR pipelines
rspec fail-fast:

View File

@ -1 +1 @@
c50b0080e9996e5db5eb4d75dfc3811618812798
56aaf62b7d7045b9f6bdcd25566c005e5eca72fd

View File

@ -402,7 +402,7 @@ group :development, :test do
end
group :development, :test, :danger do
gem 'gitlab-dangerfiles', '~> 2.0.0', require: false
gem 'gitlab-dangerfiles', '~> 2.1.2', require: false
end
group :development, :test, :coverage do

View File

@ -451,7 +451,7 @@ GEM
terminal-table (~> 1.5, >= 1.5.1)
gitlab-chronic (0.10.5)
numerizer (~> 0.2)
gitlab-dangerfiles (2.0.0)
gitlab-dangerfiles (2.1.2)
danger-gitlab
gitlab-experiment (0.5.4)
activesupport (>= 3.0)
@ -1474,7 +1474,7 @@ DEPENDENCIES
gitaly (~> 13.12.0.pre.rc1)
github-markup (~> 1.7.0)
gitlab-chronic (~> 0.10.5)
gitlab-dangerfiles (~> 2.0.0)
gitlab-dangerfiles (~> 2.1.2)
gitlab-experiment (~> 0.5.4)
gitlab-fog-azure-rm (~> 1.1.1)
gitlab-fog-google (~> 1.13)

View File

@ -93,7 +93,7 @@ export default {
placement="top"
class="trigger-description gl-display-flex"
>
<div class="gl-flex-fill-1 gl-text-truncate">{{ item.description }}</div>
<div class="gl-flex-grow-1 gl-text-truncate">{{ item.description }}</div>
</tooltip-on-truncate>
</template>
<template #cell(owner)="{ item }">

View File

@ -111,7 +111,7 @@ export default {
'gl-text-body! emoji-picker-category-active': index === currentCategory,
}"
type="button"
class="gl-border-0 gl-border-b-2 gl-border-b-solid gl-flex-fill-1 gl-text-gray-300 gl-pt-3 gl-pb-3 gl-bg-transparent emoji-picker-category-tab"
class="gl-border-0 gl-border-b-2 gl-border-b-solid gl-flex-grow-1 gl-text-gray-300 gl-pt-3 gl-pb-3 gl-bg-transparent emoji-picker-category-tab"
:aria-label="category.name"
@click="scrollToCategory(category.name)"
>

View File

@ -89,7 +89,7 @@ export default {
data-testid="manual-action-link"
@click="onClickAction(action)"
>
<span class="gl-flex-fill-1">{{ action.name }}</span>
<span class="gl-flex-grow-1">{{ action.name }}</span>
<span v-if="action.scheduledAt" class="gl-text-gray-500 float-right">
<gl-icon name="clock" />
{{ remainingTime(action) }}

View File

@ -121,7 +121,7 @@ export default {
variant="info"
category="secondary"
type="button"
class="gl-mb-3 gl-flex-fill-1"
class="gl-mb-3 gl-flex-grow-1"
>{{ $options.i18n.reviewAppButtonLabel }}</gl-button
>
<gl-button

View File

@ -58,7 +58,7 @@ export default {
<span
v-gl-tooltip
:title="environment.name"
class="gl-text-truncate gl-ml-2 gl-mr-2 gl-flex-fill"
class="gl-text-truncate gl-ml-2 gl-mr-2 gl-flex-grow-1"
>
{{ environment.name }}?
</span>

View File

@ -260,7 +260,7 @@ export default {
</template>
<div v-else class="px-3">{{ __("You don't have any recent searches") }}</div>
</gl-dropdown>
<div class="filtered-search-input-container gl-flex-fill-1">
<div class="filtered-search-input-container gl-flex-grow-1">
<gl-form-input
v-model="errorSearchQuery"
class="pl-2 filtered-search"

View File

@ -157,7 +157,7 @@ export default {
:text="importTarget.target_namespace"
:disabled="isAlreadyImported"
toggle-class="gl-rounded-top-right-none! gl-rounded-bottom-right-none!"
class="import-entities-namespace-dropdown gl-h-7 gl-flex-fill-1"
class="import-entities-namespace-dropdown gl-h-7 gl-flex-grow-1"
data-qa-selector="target_namespace_selector_dropdown"
>
<gl-dropdown-item @click="$emit('update-target-namespace', '')">{{
@ -184,7 +184,7 @@ export default {
>
/
</div>
<div class="gl-flex-fill-1">
<div class="gl-flex-grow-1">
<gl-form-input
class="gl-rounded-top-left-none gl-rounded-bottom-left-none"
:class="{ 'is-invalid': isInvalid && !isAlreadyImported }"

View File

@ -36,7 +36,7 @@ export default {
<template>
<div class="top-area">
<gl-tabs
class="gl-display-flex gl-flex-fill-1 gl-p-0 gl-m-0 mobile-separator issuable-state-filters"
class="gl-display-flex gl-flex-grow-1 gl-p-0 gl-m-0 mobile-separator issuable-state-filters"
nav-class="gl-border-b-0"
>
<gl-tab

View File

@ -148,7 +148,7 @@ export default {
<template #row-details="{ item }">
<div
class="gl-display-flex gl-flex-direction-column gl-flex-fill-1 gl-bg-gray-10 gl-rounded-base gl-inset-border-1-gray-100"
class="gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-bg-gray-10 gl-rounded-base gl-inset-border-1-gray-100"
>
<file-sha
v-if="item.file_sha256"

View File

@ -91,7 +91,7 @@ export default {
label-position="hidden"
@change="toggleFeature"
/>
<div class="select-wrapper gl-flex-fill-1">
<div class="select-wrapper gl-flex-grow-1">
<select
:disabled="displaySelectInput"
class="form-control project-repo-select select-control"

View File

@ -381,7 +381,7 @@ export default {
:label="s__('ProjectSettings|Project visibility')"
>
<div class="project-feature-controls gl-display-flex gl-align-items-center gl-my-3 gl-mx-0">
<div class="select-wrapper gl-flex-fill-1">
<div class="select-wrapper gl-flex-grow-1">
<select
v-model="visibilityLevel"
:disabled="!canChangeVisibilityLevel"

View File

@ -61,7 +61,7 @@ export default {
<span :class="severityClass" class="gl-mr-5" data-testid="codequality-severity-icon">
<gl-icon v-tooltip="severityLabel" :name="severityIcon" :size="12" />
</span>
<div class="gl-flex-fill-1">
<div class="gl-flex-grow-1">
<div>
<strong v-if="isStatusSuccess">{{ s__('ciReport|Fixed:') }}</strong>
{{ issueName }}

View File

@ -10,6 +10,7 @@ export const RUNNER_ENTITY_TYPE = 'Ci::Runner';
// - Used for URL params names
// - GlFilteredSearch tokens type
export const PARAM_KEY_SEARCH = 'search';
export const PARAM_KEY_STATUS = 'status';
export const PARAM_KEY_RUNNER_TYPE = 'runner_type';
export const PARAM_KEY_SORT = 'sort';

View File

@ -6,6 +6,7 @@ query getRunners(
$after: String
$first: Int
$last: Int
$search: String
$status: CiRunnerStatus
$type: CiRunnerType
$sort: CiRunnerSort
@ -15,6 +16,7 @@ query getRunners(
after: $after
first: $first
last: $last
search: $search
status: $status
type: $type
sort: $sort

View File

@ -12,7 +12,7 @@ import {
fromUrlQueryToSearch,
fromSearchToUrl,
fromSearchToVariables,
} from './filtered_search_utils';
} from './runner_search_utils';
export default {
components: {

View File

@ -1,5 +1,12 @@
import { queryToObject, setUrlParams } from '~/lib/utils/url_utility';
import {
filterToQueryObject,
processFilters,
urlQueryToFilter,
prepareTokens,
} from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import {
PARAM_KEY_SEARCH,
PARAM_KEY_STATUS,
PARAM_KEY_RUNNER_TYPE,
PARAM_KEY_SORT,
@ -10,30 +17,6 @@ import {
RUNNER_PAGE_SIZE,
} from '../constants';
const getValuesFromFilters = (paramKey, filters) => {
return filters
.filter(({ type, value }) => type === paramKey && value.operator === '=')
.map(({ value }) => value.data);
};
const getFilterFromParams = (paramKey, params) => {
const value = params[paramKey];
if (!value) {
return [];
}
const values = Array.isArray(value) ? value : [value];
return values.map((data) => {
return {
type: paramKey,
value: {
data,
operator: '=',
},
};
});
};
const getPaginationFromParams = (params) => {
const page = parseInt(params[PARAM_KEY_PAGE], 10);
const after = params[PARAM_KEY_AFTER];
@ -55,10 +38,13 @@ export const fromUrlQueryToSearch = (query = window.location.search) => {
const params = queryToObject(query, { gatherArrays: true });
return {
filters: [
...getFilterFromParams(PARAM_KEY_STATUS, params),
...getFilterFromParams(PARAM_KEY_RUNNER_TYPE, params),
],
filters: prepareTokens(
urlQueryToFilter(query, {
filterNamesAllowList: [PARAM_KEY_STATUS, PARAM_KEY_RUNNER_TYPE],
filteredSearchTermKey: PARAM_KEY_SEARCH,
legacySpacesDecode: false,
}),
),
sort: params[PARAM_KEY_SORT] || DEFAULT_SORT,
pagination: getPaginationFromParams(params),
};
@ -68,37 +54,44 @@ export const fromSearchToUrl = (
{ filters = [], sort = null, pagination = {} },
url = window.location.href,
) => {
const urlParams = {
[PARAM_KEY_STATUS]: getValuesFromFilters(PARAM_KEY_STATUS, filters),
[PARAM_KEY_RUNNER_TYPE]: getValuesFromFilters(PARAM_KEY_RUNNER_TYPE, filters),
const filterParams = {
// Defaults
[PARAM_KEY_SEARCH]: null,
[PARAM_KEY_STATUS]: [],
[PARAM_KEY_RUNNER_TYPE]: [],
// Current filters
...filterToQueryObject(processFilters(filters), {
filteredSearchTermKey: PARAM_KEY_SEARCH,
}),
};
if (sort && sort !== DEFAULT_SORT) {
urlParams[PARAM_KEY_SORT] = sort;
}
const isDefaultSort = sort !== DEFAULT_SORT;
const isFirstPage = pagination?.page === 1;
const otherParams = {
// Sorting & Pagination
[PARAM_KEY_SORT]: isDefaultSort ? sort : null,
[PARAM_KEY_PAGE]: isFirstPage ? null : pagination.page,
[PARAM_KEY_BEFORE]: isFirstPage ? null : pagination.before,
[PARAM_KEY_AFTER]: isFirstPage ? null : pagination.after,
};
// Remove pagination params for first page
if (pagination?.page === 1) {
urlParams[PARAM_KEY_PAGE] = null;
urlParams[PARAM_KEY_BEFORE] = null;
urlParams[PARAM_KEY_AFTER] = null;
} else {
urlParams[PARAM_KEY_PAGE] = pagination.page;
urlParams[PARAM_KEY_BEFORE] = pagination.before;
urlParams[PARAM_KEY_AFTER] = pagination.after;
}
return setUrlParams(urlParams, url, false, true, true);
return setUrlParams({ ...filterParams, ...otherParams }, url, false, true, true);
};
export const fromSearchToVariables = ({ filters = [], sort = null, pagination = {} } = {}) => {
const variables = {};
const queryObj = filterToQueryObject(processFilters(filters), {
filteredSearchTermKey: PARAM_KEY_SEARCH,
});
variables.search = queryObj[PARAM_KEY_SEARCH];
// TODO Get more than one value when GraphQL API supports OR for "status"
[variables.status] = getValuesFromFilters(PARAM_KEY_STATUS, filters);
[variables.status] = queryObj[PARAM_KEY_STATUS] || [];
// TODO Get more than one value when GraphQL API supports OR for "runner type"
[variables.type] = getValuesFromFilters(PARAM_KEY_RUNNER_TYPE, filters);
[variables.type] = queryObj[PARAM_KEY_RUNNER_TYPE] || [];
if (sort) {
variables.sort = sort;

View File

@ -48,7 +48,7 @@ export default {
<template>
<gl-form class="search-page-form" @submit.prevent="applyQuery">
<section class="gl-lg-display-flex gl-align-items-flex-end">
<div class="gl-flex-fill-1 gl-mb-4 gl-lg-mb-0 gl-lg-mr-2">
<div class="gl-flex-grow-1 gl-mb-4 gl-lg-mb-0 gl-lg-mr-2">
<label>{{ __('What are you searching for?') }}</label>
<gl-search-box-by-type
id="dashboard_search"

View File

@ -148,7 +148,9 @@ export default {
</div>
<div class="hide-collapsed">
<p class="title gl-display-flex gl-justify-content-space-between">
<p
class="gl-line-height-20 gl-mb-0 gl-text-gray-900 gl-display-flex gl-justify-content-space-between"
>
{{ $options.i18n.SEVERITY }}
<gl-link
data-testid="editButton"

View File

@ -75,7 +75,7 @@ export default {
</template>
</gl-sprintf>
</div>
<div class="gl-flex-fill-1 gl-ml-7">
<div class="gl-flex-grow-1 gl-ml-7">
<gl-form-group
label-for="user-list-name"
:label="$options.translations.nameLabel"

View File

@ -51,7 +51,7 @@ export default {
<gl-icon :name="iconName" :size="24" />
</span>
<div class="gl-display-flex gl-flex-fill-1 gl-flex-direction-column gl-md-flex-direction-row">
<div class="gl-display-flex gl-flex-grow-1 gl-flex-direction-column gl-md-flex-direction-row">
<slot name="header"></slot>
<div>

View File

@ -160,7 +160,7 @@ export default {
<div class="ci-widget media">
<template v-if="hasCIError">
<gl-icon name="status_failed" class="gl-text-red-500" :size="24" />
<p class="gl-flex-fill-1 gl-ml-5 gl-mb-0" data-testid="ci-error-message">
<p class="gl-flex-grow-1 gl-ml-5 gl-mb-0" data-testid="ci-error-message">
<gl-sprintf :message="$options.errorText">
<template #link="{ content }">
<gl-link :href="mrTroubleshootingDocsPath">{{ content }}</gl-link>
@ -171,7 +171,7 @@ export default {
<template v-else-if="!hasPipeline">
<gl-loading-icon size="md" />
<p
class="gl-flex-fill-1 gl-display-flex gl-ml-5 gl-mb-0"
class="gl-flex-grow-1 gl-display-flex gl-ml-5 gl-mb-0"
data-testid="monitoring-pipeline-message"
>
{{ $options.monitoringPipelineText }}

View File

@ -107,7 +107,7 @@ export default {
<template #header>
<div
data-testid="terraform-header-text"
class="gl-flex-fill-1 gl-display-flex gl-flex-direction-column"
class="gl-flex-grow-1 gl-display-flex gl-flex-direction-column"
>
<p v-if="validPlanCountText" class="gl-m-0">
<gl-sprintf :message="validPlanCountText">

View File

@ -71,8 +71,8 @@ export default {
<gl-icon :name="iconType" :size="16" data-testid="change-type-icon" />
</span>
<div class="gl-display-flex gl-flex-fill-1 gl-flex-direction-column flex-md-row gl-pl-3">
<div class="gl-flex-fill-1 gl-display-flex gl-flex-direction-column gl-pr-3">
<div class="gl-display-flex gl-flex-grow-1 gl-flex-direction-column flex-md-row gl-pl-3">
<div class="gl-flex-grow-1 gl-display-flex gl-flex-direction-column gl-pr-3">
<p class="gl-mb-3 gl-line-height-normal">
<gl-sprintf :message="reportHeaderText">
<template #name>

View File

@ -2,7 +2,7 @@ import { isEmpty, uniqWith, isEqual } from 'lodash';
import AccessorUtilities from '~/lib/utils/accessor';
import { queryToObject } from '~/lib/utils/url_utility';
import { MAX_RECENT_TOKENS_SIZE } from './constants';
import { MAX_RECENT_TOKENS_SIZE, FILTERED_SEARCH_TERM } from './constants';
/**
* Strips enclosing quotations from a string if it has one.
@ -23,7 +23,7 @@ export const stripQuotes = (value) => value.replace(/^('|")(.*)('|")$/, '$2');
export const uniqueTokens = (tokens) => {
const knownTokens = [];
return tokens.reduce((uniques, token) => {
if (typeof token === 'object' && token.type !== 'filtered-search-term') {
if (typeof token === 'object' && token.type !== FILTERED_SEARCH_TERM) {
const tokenString = `${token.type}${token.value.operator}${token.value.data}`;
if (!knownTokens.includes(tokenString)) {
uniques.push(token);
@ -86,21 +86,37 @@ export function processFilters(filters) {
}, {});
}
function filteredSearchQueryParam(filter) {
return filter
.map(({ value }) => value)
.join(' ')
.trim();
}
/**
* This function takes a filter object and maps it into a query object. Example filter:
* { myFilterName: { value: 'foo', operator: '=' } }
* { myFilterName: { value: 'foo', operator: '=' }, search: [{ value: 'my' }, { value: 'search' }] }
* gets translated into:
* { myFilterName: 'foo', 'not[myFilterName]': null }
* { myFilterName: 'foo', 'not[myFilterName]': null, search: 'my search' }
* @param {Object} filters
* @param {Object.myFilterName} a single filter value or an array of filters
* @param {Object} filters.myFilterName a single filter value or an array of filters
* @param {Object} options
* @param {Object} [options.filteredSearchTermKey] if set, 'filtered-search-term' filters are assigned to this key, 'search' is suggested
* @return {Object} query object with both filter name and not-name with values
*/
export function filterToQueryObject(filters = {}) {
export function filterToQueryObject(filters = {}, options = {}) {
const { filteredSearchTermKey } = options;
return Object.keys(filters).reduce((memo, key) => {
const filter = filters[key];
if (typeof filteredSearchTermKey === 'string' && key === FILTERED_SEARCH_TERM) {
return { ...memo, [filteredSearchTermKey]: filteredSearchQueryParam(filter) };
}
let selected;
let unselected;
if (Array.isArray(filter)) {
selected = filter.filter((item) => item.operator === '=').map((item) => item.value);
unselected = filter.filter((item) => item.operator === '!=').map((item) => item.value);
@ -125,7 +141,7 @@ export function filterToQueryObject(filters = {}) {
* and returns the operator with it depending on the filter name
* @param {String} filterName from url
* @return {Object}
* @return {Object.filterName} extracted filtern ame
* @return {Object.filterName} extracted filter name
* @return {Object.operator} `=` or `!=`
*/
function extractNameAndOperator(filterName) {
@ -137,22 +153,53 @@ function extractNameAndOperator(filterName) {
return { filterName, operator: '=' };
}
/**
* Gathers search term as values
* @param {String|Array} value
* @returns {Array} List of search terms split by word
*/
function filteredSearchTermValue(value) {
const values = Array.isArray(value) ? value : [value];
return values
.filter((term) => term)
.join(' ')
.split(' ')
.map((term) => ({ value: term }));
}
/**
* This function takes a URL query string and maps it into a filter object. Example query string:
* '?myFilterName=foo'
* gets translated into:
* { myFilterName: { value: 'foo', operator: '=' } }
* @param {String} query URL query string, e.g. from `window.location.search`
* @param {Object} options
* @param {Object} options
* @param {String} [options.filteredSearchTermKey] if set, a FILTERED_SEARCH_TERM filter is created to this parameter. `'search'` is suggested
* @param {String[]} [options.filterNamesAllowList] if set, only this list of filters names is mapped
* @param {Boolean} [options.legacySpacesDecode] if set, plus symbols (+) are not encoded as spaces. `false` is suggested
* @return {Object} filter object with filter names and their values
*/
export function urlQueryToFilter(query = '') {
const filters = queryToObject(query, { gatherArrays: true, legacySpacesDecode: true });
export function urlQueryToFilter(query = '', options = {}) {
const { filteredSearchTermKey, filterNamesAllowList, legacySpacesDecode = true } = options;
const filters = queryToObject(query, { gatherArrays: true, legacySpacesDecode });
return Object.keys(filters).reduce((memo, key) => {
const value = filters[key];
if (!value) {
return memo;
}
if (key === filteredSearchTermKey) {
return {
...memo,
[FILTERED_SEARCH_TERM]: filteredSearchTermValue(value),
};
}
const { filterName, operator } = extractNameAndOperator(key);
if (filterNamesAllowList && !filterNamesAllowList.includes(filterName)) {
return memo;
}
let previousValues = [];
if (Array.isArray(memo[filterName])) {
previousValues = memo[filterName];

View File

@ -62,7 +62,7 @@ export default {
<slot name="left-action"></slot>
</div>
<div
class="gl-display-flex gl-xs-flex-direction-column gl-justify-content-space-between gl-align-items-stretch gl-flex-fill-1"
class="gl-display-flex gl-xs-flex-direction-column gl-justify-content-space-between gl-align-items-stretch gl-flex-grow-1"
>
<div class="gl-display-flex gl-flex-direction-column gl-xs-mb-3 gl-min-w-0 gl-flex-grow-1">
<div
@ -81,7 +81,7 @@ export default {
</div>
<div
v-if="$slots['left-secondary']"
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-min-h-6 gl-min-w-0 gl-flex-fill-1"
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-min-h-6 gl-min-w-0 gl-flex-grow-1"
>
<slot name="left-secondary"></slot>
</div>
@ -114,7 +114,7 @@ export default {
<div class="gl-w-7"></div>
<div
v-if="isDetailsShown"
class="gl-display-flex gl-flex-direction-column gl-flex-fill-1 gl-bg-gray-10 gl-rounded-base gl-inset-border-1-gray-100 gl-mb-3"
class="gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-bg-gray-10 gl-rounded-base gl-inset-border-1-gray-100 gl-mb-3"
>
<div
v-for="(row, detailIndex) in detailsSlots"

View File

@ -109,7 +109,7 @@ export default {
<div class="gl-display-flex gl-p-5 gl-bg-gray-10 gl-border-solid gl-border-1 gl-border-gray-100">
<gl-filtered-search
v-model="internalFilter"
class="gl-mr-4 gl-flex-fill-1"
class="gl-mr-4 gl-flex-grow-1"
:placeholder="__('Filter results')"
:available-tokens="tokens"
@submit="submitSearch"

View File

@ -225,7 +225,7 @@ export default {
<template v-if="!instructionsEmpty">
<div class="gl-display-flex">
<pre
class="gl-bg-gray gl-flex-fill-1 gl-white-space-pre-line"
class="gl-bg-gray gl-flex-grow-1 gl-white-space-pre-line"
data-testid="binary-instructions"
>{{ instructions.installInstructions }}</pre
>
@ -241,7 +241,7 @@ export default {
<h5 class="gl-mb-3">{{ $options.i18n.registerRunnerCommand }}</h5>
<div class="gl-display-flex">
<pre
class="gl-bg-gray gl-flex-fill-1 gl-white-space-pre-line"
class="gl-bg-gray gl-flex-grow-1 gl-white-space-pre-line"
data-testid="register-command"
>{{ instructions.registerInstructions }}</pre
>

View File

@ -47,6 +47,7 @@
@import 'framework/toggle';
@import 'framework/typography';
@import 'framework/zen';
@import 'framework/blank';
@import 'framework/wells';
@import 'framework/page_header';
@import 'framework/page_title';

View File

@ -0,0 +1,118 @@
.blank-state-parent-container {
.section-container {
padding: 10px;
}
.section-body {
width: 100%;
height: 100%;
padding-bottom: 25px;
border-radius: $border-radius-default;
}
}
.blank-state-row {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.blank-state-welcome {
text-align: center;
padding: $gl-padding 0 ($gl-padding * 2);
.blank-state-welcome-title {
font-size: 24px;
}
.blank-state-text {
margin-bottom: 0;
}
}
.blank-state-link {
color: $gl-text-color;
margin-bottom: 15px;
&:hover {
background-color: $gray-light;
text-decoration: none;
color: $gl-text-color;
}
}
.blank-state-center {
padding-top: 20px;
padding-bottom: 20px;
text-align: center;
}
.blank-state {
display: flex;
align-items: center;
padding: 20px 50px;
border: 1px solid $border-color;
border-radius: $border-radius-default;
min-height: 240px;
margin-bottom: $gl-padding;
width: calc(50% - #{$gl-padding-8});
@include media-breakpoint-down(sm) {
width: 100%;
flex-direction: column;
justify-content: center;
padding: 50px 20px;
.column-small & {
width: 100%;
}
}
}
.blank-state,
.blank-state-center {
.blank-state-icon {
svg {
display: block;
margin: auto;
}
}
.blank-state-title {
margin-top: 0;
font-size: 18px;
}
.blank-state-body {
@include media-breakpoint-down(sm) {
text-align: center;
margin-top: 20px;
}
@include media-breakpoint-up(sm) {
padding-left: 20px;
}
}
}
@include media-breakpoint-up(lg) {
.column-large {
flex: 2;
}
.column-small {
flex: 1;
margin-bottom: 15px;
.blank-state {
max-width: 400px;
flex-wrap: wrap;
margin-left: 15px;
}
.blank-state-icon {
margin-bottom: 30px;
}
}
}

View File

@ -47,7 +47,7 @@ class Clusters::ApplicationsController < Clusters::BaseController
end
def cluster_application_params
params.permit(:application, :hostname, :pages_domain_id, :email, :stack, :host, :port, :protocol, :cilium_log_enabled)
params.permit(:application, :hostname, :pages_domain_id, :email, :stack, :host, :port, :protocol)
end
def cluster_application_destroy_params

View File

@ -140,39 +140,15 @@ module MembershipActions
end
def root_params_key
case membershipable
when Namespace
:group_member
when Project
:project_member
else
raise "Unknown membershipable type: #{membershipable}!"
end
raise NotImplementedError
end
def members_page_url
case membershipable
when Namespace
polymorphic_url([membershipable, :members])
when Project
project_project_members_path(membershipable)
else
raise "Unknown membershipable type: #{membershipable}!"
end
raise NotImplementedError
end
def source_type
@source_type ||=
begin
case membershipable
when Namespace
_("group")
when Project
_("project")
else
raise "Unknown membershipable type: #{membershipable}!"
end
end
raise NotImplementedError
end
def plain_source_type

View File

@ -82,6 +82,18 @@ class Groups::GroupMembersController < Groups::ApplicationController
def plain_source_type
'group'
end
def source_type
_("group")
end
def members_page_url
polymorphic_url([group, :members])
end
def root_params_key
:group_member
end
end
Groups::GroupMembersController.prepend_mod_with('Groups::GroupMembersController')

View File

@ -11,6 +11,7 @@ class Projects::FeatureFlagsController < Projects::ApplicationController
before_action :feature_flag, only: [:edit, :update, :destroy]
before_action :ensure_flag_writable!, only: [:update]
before_action :exclude_legacy_flags_check, only: [:edit]
before_action do
push_frontend_feature_flag(:feature_flag_permissions)
@ -63,7 +64,6 @@ class Projects::FeatureFlagsController < Projects::ApplicationController
end
def edit
exclude_legacy_flags_check
end
def update
@ -108,6 +108,12 @@ class Projects::FeatureFlagsController < Projects::ApplicationController
end
end
def exclude_legacy_flags_check
if feature_flag.legacy_flag?
not_found
end
end
def create_params
params.require(:operations_feature_flag)
.permit(:name, :description, :active, :version,
@ -159,12 +165,4 @@ class Projects::FeatureFlagsController < Projects::ApplicationController
render json: { message: messages },
status: status
end
def exclude_legacy_flags_check
if Feature.enabled?(:remove_legacy_flags, project, default_enabled: :yaml) &&
Feature.disabled?(:remove_legacy_flags_override, project, default_enabled: :yaml) &&
feature_flag.legacy_flag?
not_found
end
end
end

View File

@ -66,6 +66,18 @@ class Projects::ProjectMembersController < Projects::ApplicationController
def plain_source_type
'project'
end
def source_type
_("project")
end
def members_page_url
project_project_members_path(project)
end
def root_params_key
:project_member
end
end
Projects::ProjectMembersController.prepend_mod_with('Projects::ProjectMembersController')

View File

@ -24,11 +24,7 @@ class FeatureFlagsFinder
private
def feature_flags
if exclude_legacy_flags?
project.operations_feature_flags.new_version_only
else
project.operations_feature_flags
end
project.operations_feature_flags.new_version_only
end
def by_scope(items)
@ -41,9 +37,4 @@ class FeatureFlagsFinder
items
end
end
def exclude_legacy_flags?
Feature.enabled?(:remove_legacy_flags, project, default_enabled: :yaml) &&
Feature.disabled?(:remove_legacy_flags_override, project, default_enabled: :yaml)
end
end

View File

@ -9,7 +9,8 @@ module SearchHelper
:repository_ref,
:snippets,
:sort,
:force_search_results
:force_search_results,
:project_ids
].freeze
def search_autocomplete_opts(term)

View File

@ -43,7 +43,7 @@ module Ci
dotenv: '.env',
cobertura: 'cobertura-coverage.xml',
terraform: 'tfplan.json',
cluster_applications: 'gl-cluster-applications.json',
cluster_applications: 'gl-cluster-applications.json', # DEPRECATED: https://gitlab.com/gitlab-org/gitlab/-/issues/333441
requirements: 'requirements.json',
coverage_fuzzing: 'gl-coverage-fuzzing.json',
api_fuzzing: 'gl-api-fuzzing-report.json'

View File

@ -1,121 +0,0 @@
# frozen_string_literal: true
module Clusters
module Applications
class Fluentd < ApplicationRecord
VERSION = '2.4.0'
CILIUM_CONTAINER_NAME = 'cilium-monitor'
self.table_name = 'clusters_applications_fluentd'
include ::Clusters::Concerns::ApplicationCore
include ::Clusters::Concerns::ApplicationStatus
include ::Clusters::Concerns::ApplicationVersion
include ::Clusters::Concerns::ApplicationData
include IgnorableColumns
default_value_for :version, VERSION
default_value_for :port, 514
default_value_for :protocol, :tcp
ignore_column :waf_log_enabled, remove_with: '14.2', remove_after: '2021-07-22'
enum protocol: { tcp: 0, udp: 1 }
validate :has_at_least_one_log_enabled?
def chart
'fluentd/fluentd'
end
def repository
'https://gitlab-org.gitlab.io/cluster-integration/helm-stable-archive'
end
def install_command
helm_command_module::InstallCommand.new(
name: 'fluentd',
repository: repository,
version: VERSION,
rbac: cluster.platform_kubernetes_rbac?,
chart: chart,
files: files
)
end
def values
content_values.to_yaml
end
private
def has_at_least_one_log_enabled?
errors.add(:base, _("At least one logging option is required to be enabled")) unless cilium_log_enabled
end
def content_values
YAML.load_file(chart_values_file).deep_merge!(specification)
end
def specification
{
"configMaps" => {
"output.conf" => output_configuration_content,
"general.conf" => general_configuration_content
}
}
end
def output_configuration_content
<<~EOF
<match kubernetes.**>
@type remote_syslog
@id out_kube_remote_syslog
host #{host}
port #{port}
program fluentd
hostname ${kubernetes_host}
protocol #{protocol}
packet_size 131072
<buffer kubernetes_host>
</buffer>
<format>
@type ltsv
</format>
</match>
EOF
end
def general_configuration_content
<<~EOF
<match fluent.**>
@type null
</match>
<source>
@type http
port 9880
bind 0.0.0.0
</source>
<source>
@type tail
@id in_tail_container_logs
path #{path_to_logs}
pos_file /var/log/fluentd-containers.log.pos
tag kubernetes.*
read_from_head true
<parse>
@type json
time_format %Y-%m-%dT%H:%M:%S.%NZ
</parse>
</source>
EOF
end
def path_to_logs
path = []
path << "/var/log/containers/*#{CILIUM_CONTAINER_NAME}*.log" if cilium_log_enabled
path.join(',')
end
end
end
end

View File

@ -21,7 +21,6 @@ module Clusters
Clusters::Applications::Jupyter.application_name => Clusters::Applications::Jupyter,
Clusters::Applications::Knative.application_name => Clusters::Applications::Knative,
Clusters::Applications::ElasticStack.application_name => Clusters::Applications::ElasticStack,
Clusters::Applications::Fluentd.application_name => Clusters::Applications::Fluentd,
Clusters::Applications::Cilium.application_name => Clusters::Applications::Cilium
}.freeze
DEFAULT_ENVIRONMENT = '*'
@ -68,7 +67,6 @@ module Clusters
has_one_cluster_application :jupyter
has_one_cluster_application :knative
has_one_cluster_application :elastic_stack
has_one_cluster_application :fluentd
has_one_cluster_application :cilium
has_many :kubernetes_namespaces

View File

@ -17,5 +17,4 @@ class ClusterApplicationEntity < Grape::Entity
expose :host, if: -> (e, _) { e.respond_to?(:host) }
expose :port, if: -> (e, _) { e.respond_to?(:port) }
expose :protocol, if: -> (e, _) { e.respond_to?(:protocol) }
expose :cilium_log_enabled, if: -> (e, _) { e.respond_to?(:cilium_log_enabled) }
end

View File

@ -115,7 +115,6 @@ module Ci
case artifact.file_type
when 'dotenv' then parse_dotenv_artifact(artifact)
when 'cluster_applications' then parse_cluster_applications_artifact(artifact)
else success
end
end
@ -165,10 +164,6 @@ module Ci
def parse_dotenv_artifact(artifact)
Ci::ParseDotenvArtifactService.new(project, current_user).execute(artifact)
end
def parse_cluster_applications_artifact(artifact)
Clusters::ParseClusterApplicationsArtifactService.new(job, job.user).execute(artifact)
end
end
end
end

View File

@ -5,8 +5,6 @@ module Clusters
class BaseService
InvalidApplicationError = Class.new(StandardError)
FLUENTD_KNOWN_ATTRS = %i[host protocol port cilium_log_enabled].freeze
attr_reader :cluster, :current_user, :params
def initialize(cluster, user, params = {})
@ -29,8 +27,6 @@ module Clusters
application.stack = params[:stack]
end
apply_fluentd_related_attributes(application)
if application.respond_to?(:oauth_application)
application.oauth_application = create_oauth_application(application, request)
end
@ -95,12 +91,6 @@ module Clusters
::Applications::CreateService.new(current_user, oauth_application_params).execute(request)
end
def apply_fluentd_related_attributes(application)
FLUENTD_KNOWN_ATTRS.each do |attr|
application[attr] = params[attr] if application.has_attribute?(attr)
end
end
end
end
end

View File

@ -1,94 +0,0 @@
# frozen_string_literal: true
module Clusters
class ParseClusterApplicationsArtifactService < ::BaseService
include Gitlab::Utils::StrongMemoize
MAX_ACCEPTABLE_ARTIFACT_SIZE = 5.kilobytes
RELEASE_NAMES = %w[cilium].freeze
def initialize(job, current_user)
@job = job
super(job.project, current_user)
end
def execute(artifact)
raise ArgumentError, 'Artifact is not cluster_applications file type' unless artifact&.cluster_applications?
return error(too_big_error_message, :bad_request) unless artifact.file.size < MAX_ACCEPTABLE_ARTIFACT_SIZE
return error(no_deployment_message, :bad_request) unless job.deployment
return error(no_deployment_cluster_message, :bad_request) unless cluster
parse!(artifact)
success
rescue Gitlab::Kubernetes::Helm::Parsers::ListV2::ParserError, ActiveRecord::RecordInvalid => error
Gitlab::ErrorTracking.track_exception(error, job_id: artifact.job_id)
error(error.message, :bad_request)
end
private
attr_reader :job
def cluster
strong_memoize(:cluster) do
deployment_cluster = job.deployment&.cluster
deployment_cluster if Ability.allowed?(current_user, :admin_cluster, deployment_cluster)
end
end
def parse!(artifact)
releases = []
artifact.each_blob do |blob|
next if blob.empty?
releases.concat(Gitlab::Kubernetes::Helm::Parsers::ListV2.new(blob).releases)
end
update_cluster_application_statuses!(releases)
end
def update_cluster_application_statuses!(releases)
release_by_name = releases.index_by { |release| release['Name'] }
Clusters::Cluster.transaction do
RELEASE_NAMES.each do |release_name|
application_class = Clusters::Cluster::APPLICATIONS[release_name]
application = cluster.find_or_build_application(application_class)
release = release_by_name[release_name]
if release
case release['Status']
when 'DEPLOYED'
application.make_externally_installed!
when 'FAILED'
application.make_errored!(s_('ClusterIntegration|Helm release failed to install'))
end
else
# missing, so by definition, we consider this uninstalled
application.make_externally_uninstalled! if application.persisted?
end
end
end
end
def too_big_error_message
human_size = ActiveSupport::NumberHelper.number_to_human_size(MAX_ACCEPTABLE_ARTIFACT_SIZE)
s_('ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}') % { human_size: human_size }
end
def no_deployment_message
s_('ClusterIntegration|No deployment found for this job')
end
def no_deployment_cluster_message
s_('ClusterIntegration|No deployment cluster found for this job')
end
end
end

View File

@ -1,46 +0,0 @@
# frozen_string_literal: true
module FeatureFlags
class DisableService < BaseService
def execute
return error('Feature Flag not found', 404) unless feature_flag_by_name
return error('Feature Flag Scope not found', 404) unless feature_flag_scope_by_environment_scope
return error('Strategy not found', 404) unless strategy_exist_in_persisted_data?
::FeatureFlags::UpdateService
.new(project, current_user, update_params)
.execute(feature_flag_by_name)
end
private
def update_params
if remaining_strategies.empty?
params_to_destroy_scope
else
params_to_update_scope
end
end
def remaining_strategies
strong_memoize(:remaining_strategies) do
feature_flag_scope_by_environment_scope.strategies.reject do |strategy|
strategy['name'] == params[:strategy]['name'] &&
strategy['parameters'] == params[:strategy]['parameters']
end
end
end
def strategy_exist_in_persisted_data?
feature_flag_scope_by_environment_scope.strategies != remaining_strategies
end
def params_to_destroy_scope
{ scopes_attributes: [{ id: feature_flag_scope_by_environment_scope.id, _destroy: true }] }
end
def params_to_update_scope
{ scopes_attributes: [{ id: feature_flag_scope_by_environment_scope.id, strategies: remaining_strategies }] }
end
end
end

View File

@ -1,93 +0,0 @@
# frozen_string_literal: true
module FeatureFlags
class EnableService < BaseService
def execute
if feature_flag_by_name
update_feature_flag
else
create_feature_flag
end
end
private
def create_feature_flag
::FeatureFlags::CreateService
.new(project, current_user, create_params)
.execute
end
def update_feature_flag
::FeatureFlags::UpdateService
.new(project, current_user, update_params)
.execute(feature_flag_by_name)
end
def create_params
if params[:environment_scope] == '*'
params_to_create_flag_with_default_scope
else
params_to_create_flag_with_additional_scope
end
end
def update_params
if feature_flag_scope_by_environment_scope
params_to_update_scope
else
params_to_create_scope
end
end
def params_to_create_flag_with_default_scope
{
name: params[:name],
scopes_attributes: [
{
active: true,
environment_scope: '*',
strategies: [params[:strategy]]
}
]
}
end
def params_to_create_flag_with_additional_scope
{
name: params[:name],
scopes_attributes: [
{
active: false,
environment_scope: '*'
},
{
active: true,
environment_scope: params[:environment_scope],
strategies: [params[:strategy]]
}
]
}
end
def params_to_create_scope
{
scopes_attributes: [{
active: true,
environment_scope: params[:environment_scope],
strategies: [params[:strategy]]
}]
}
end
def params_to_update_scope
{
scopes_attributes: [{
id: feature_flag_scope_by_environment_scope.id,
active: true,
strategies: feature_flag_scope_by_environment_scope.strategies | [params[:strategy]]
}]
}
end
end
end

View File

@ -8,8 +8,8 @@ module Search
attr_accessor :project, :current_user, :params
def initialize(project, user, params)
@project = project
def initialize(project_or_projects, user, params)
@project = project_or_projects
@current_user = user
@params = params.dup
end

View File

@ -41,6 +41,10 @@ class SearchService
end
# rubocop: enable CodeReuse/ActiveRecord
def projects
# overridden in EE
end
def show_snippets?
return @show_snippets if defined?(@show_snippets)

View File

@ -37,7 +37,7 @@
.todos-filters
.issues-details-filters.row-content-block.second-block
= form_tag todos_filter_path(without: [:project_id, :author_id, :type, :action_id]), method: :get, class: 'filter-form gl-display-flex gl-flex-direction-column gl-sm-flex-direction-row' do
.filter-categories.gl-display-flex.gl-flex-direction-column.gl-md-flex-direction-row.gl-flex-fill-1.gl-flex-wrap.gl-mx-n2
.filter-categories.gl-display-flex.gl-flex-direction-column.gl-md-flex-direction-row.gl-flex-grow-1.gl-flex-wrap.gl-mx-n2
.filter-item.gl-m-2
- if params[:group_id].present?
= hidden_field_tag(:group_id, params[:group_id])

View File

@ -13,5 +13,5 @@
= render "layouts/flash"
.content-wrapper.hide-when-top-nav-responsive-open{ id: "content-body", class: "d-flex flex-column align-items-stretch" }
= yield
= render "layouts/nav/top_nav_responsive", class: "gl-flex-fill-1 gl-overflow-y-auto"
= render "layouts/nav/top_nav_responsive", class: "gl-flex-grow-1 gl-overflow-y-auto"
= footer_message

View File

@ -44,6 +44,7 @@
:preserve
git clone #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
cd #{h @project.path}
git switch -c #{default_branch_name}
touch README.md
git add README.md
git commit -m "add README"
@ -56,7 +57,7 @@
%pre.bg-light
:preserve
cd existing_folder
git init
git init --initial-branch=#{default_branch_name}
git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
git add .
git commit -m "Initial commit"

View File

@ -4,7 +4,7 @@
.gl-md-display-flex
- if %w(issues merge_requests).include?(@scope)
#js-search-sidebar{ class: search_bar_classes }
.gl-w-full.gl-flex-fill-1.gl-overflow-x-hidden
.gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden
= render partial: "search/results/empty"
= render_if_exists 'shared/promotions/promote_advanced_search'
- else
@ -14,7 +14,7 @@
.results.gl-md-display-flex.gl-mt-3
- if %w(issues merge_requests).include?(@scope)
#js-search-sidebar{ class: search_bar_classes }
.gl-w-full.gl-flex-fill-1.gl-overflow-x-hidden
.gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden
- if @scope == 'commits'
%ul.content-list.commit-list
= render partial: "search/results/commit", collection: @search_objects

View File

@ -5,7 +5,7 @@
.wiki-page-header.top-area.has-sidebar-toggle.flex-column.flex-lg-row
= wiki_sidebar_toggle_button
%h3.page-title.gl-flex-fill-1
%h3.page-title.gl-flex-grow-1
= link_to_wiki_page @page
%span.light
&middot;

View File

@ -7,7 +7,7 @@
.wiki-page-header.top-area.has-sidebar-toggle.flex-column.flex-lg-row
= wiki_sidebar_toggle_button
%h3.page-title.gl-flex-fill-1
%h3.page-title.gl-flex-grow-1
- if @page.persisted?
= link_to_wiki_page @page
%span.light

View File

@ -5,7 +5,7 @@
- add_page_specific_style 'page_bundles/wiki'
.wiki-page-header.top-area.flex-column.flex-lg-row
%h3.page-title.gl-flex-fill-1
%h3.page-title.gl-flex-grow-1
= s_("Wiki|Wiki Pages")
.nav-controls.pb-md-3.pb-lg-0

View File

@ -1,8 +1,8 @@
---
name: remove_legacy_flags
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62484
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/332243
name: advanced_search_multi_project_select
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62606
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/333011
milestone: '14.0'
type: development
group: group::release
group: group::global search
default_enabled: false

View File

@ -1,8 +0,0 @@
---
name: feature_flag_api
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18198
rollout_issue_url:
milestone: '12.4'
type: development
group: group::release
default_enabled: false

View File

@ -1,8 +0,0 @@
---
name: remove_legacy_flags_override
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62484
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/332243
milestone: '14.0'
type: development
group: group::release
default_enabled: false

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -7,7 +7,7 @@ product_stage:
product_group:
product_category:
value_type: number
status: implemented
status: data_available
milestone: "13.12"
introduced_by_url:
time_frame: 28d

View File

@ -7,7 +7,7 @@ product_stage:
product_group:
product_category:
value_type: number
status: implemented
status: data_available
milestone: "13.12"
introduced_by_url:
time_frame: 28d

View File

@ -7,7 +7,7 @@ product_stage:
product_group:
product_category:
value_type: number
status: implemented
status: data_available
milestone: "13.12"
introduced_by_url:
time_frame: 28d

View File

@ -7,7 +7,7 @@ product_stage:
product_group:
product_category:
value_type: number
status: implemented
status: data_available
milestone: "13.12"
introduced_by_url:
time_frame: 28d

View File

@ -7,7 +7,7 @@ product_stage:
product_group:
product_category:
value_type: number
status: implemented
status: data_available
milestone: "13.12"
introduced_by_url:
time_frame: 28d

View File

@ -7,7 +7,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: "13.12"
time_frame: 28d
data_source: redis_hll

View File

@ -7,7 +7,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: "13.12"
time_frame: 28d
data_source: redis_hll

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 28d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -7,7 +7,7 @@ product_stage:
product_group:
product_category:
value_type: number
status: implemented
status: data_available
milestone: "13.12"
introduced_by_url:
time_frame: 7d

View File

@ -7,7 +7,7 @@ product_stage:
product_group:
product_category:
value_type: number
status: implemented
status: data_available
milestone: "13.12"
introduced_by_url:
time_frame: 7d

View File

@ -7,7 +7,7 @@ product_stage:
product_group:
product_category:
value_type: number
status: implemented
status: data_available
milestone: "13.12"
introduced_by_url:
time_frame: 7d

View File

@ -7,7 +7,7 @@ product_stage:
product_group:
product_category:
value_type: number
status: implemented
status: data_available
milestone: "13.12"
introduced_by_url:
time_frame: 7d

View File

@ -7,7 +7,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: "13.12"
time_frame: 7d
data_source: redis_hll

View File

@ -7,7 +7,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: "13.12"
time_frame: 28d
data_source: redis_hll

View File

@ -6,7 +6,7 @@ product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
status: data_available
milestone: '13.12'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59979
time_frame: 7d

View File

@ -7,7 +7,7 @@ product_stage:
product_group:
product_category:
value_type: number
status: implemented
status: data_available
milestone: "13.11"
introduced_by_url:
time_frame: all

Some files were not shown because too many files have changed in this diff Show More