提交 03a52173 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 e28b754d
/* eslint-disable @gitlab/require-i18n-strings */ /* eslint-disable @gitlab/require-i18n-strings */
import { __ } from '~/locale'; import { __ } from '~/locale';
export const ANY_AUTHOR = 'Any';
const DEFAULT_LABEL_NO_LABEL = { value: 'No label', text: __('No label') }; const DEFAULT_LABEL_NO_LABEL = { value: 'No label', text: __('No label') };
export const DEFAULT_LABEL_NONE = { value: 'None', text: __('None') }; export const DEFAULT_LABEL_NONE = { value: 'None', text: __('None') };
export const DEFAULT_LABEL_ANY = { value: 'Any', text: __('Any') }; export const DEFAULT_LABEL_ANY = { value: 'Any', text: __('Any') };
......
...@@ -11,10 +11,9 @@ import { debounce } from 'lodash'; ...@@ -11,10 +11,9 @@ import { debounce } from 'lodash';
import { deprecatedCreateFlash as createFlash } from '~/flash'; import { deprecatedCreateFlash as createFlash } from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { ANY_AUTHOR, DEBOUNCE_DELAY } from '../constants'; import { DEFAULT_LABEL_ANY, DEBOUNCE_DELAY } from '../constants';
export default { export default {
anyAuthor: ANY_AUTHOR,
components: { components: {
GlFilteredSearchToken, GlFilteredSearchToken,
GlAvatar, GlAvatar,
...@@ -35,6 +34,7 @@ export default { ...@@ -35,6 +34,7 @@ export default {
data() { data() {
return { return {
authors: this.config.initialAuthors || [], authors: this.config.initialAuthors || [],
defaultAuthors: this.config.defaultAuthors || [DEFAULT_LABEL_ANY],
loading: true, loading: true,
}; };
}, },
...@@ -99,10 +99,14 @@ export default { ...@@ -99,10 +99,14 @@ export default {
<span>{{ activeAuthor ? activeAuthor.name : inputValue }}</span> <span>{{ activeAuthor ? activeAuthor.name : inputValue }}</span>
</template> </template>
<template #suggestions> <template #suggestions>
<gl-filtered-search-suggestion :value="$options.anyAuthor"> <gl-filtered-search-suggestion
{{ __('Any') }} v-for="author in defaultAuthors"
:key="author.value"
:value="author.value"
>
{{ author.text }}
</gl-filtered-search-suggestion> </gl-filtered-search-suggestion>
<gl-deprecated-dropdown-divider /> <gl-deprecated-dropdown-divider v-if="defaultAuthors.length" />
<gl-loading-icon v-if="loading" /> <gl-loading-icon v-if="loading" />
<template v-else> <template v-else>
<gl-filtered-search-suggestion <gl-filtered-search-suggestion
......
...@@ -112,7 +112,7 @@ export default { ...@@ -112,7 +112,7 @@ export default {
> >
{{ label.text }} {{ label.text }}
</gl-filtered-search-suggestion> </gl-filtered-search-suggestion>
<gl-dropdown-divider /> <gl-dropdown-divider v-if="defaultLabels.length" />
<gl-loading-icon v-if="loading" /> <gl-loading-icon v-if="loading" />
<template v-else> <template v-else>
<gl-filtered-search-suggestion v-for="label in labels" :key="label.id" :value="label.title"> <gl-filtered-search-suggestion v-for="label in labels" :key="label.id" :value="label.title">
......
...@@ -95,7 +95,7 @@ export default { ...@@ -95,7 +95,7 @@ export default {
> >
{{ milestone.text }} {{ milestone.text }}
</gl-filtered-search-suggestion> </gl-filtered-search-suggestion>
<gl-dropdown-divider /> <gl-dropdown-divider v-if="defaultMilestones.length" />
<gl-loading-icon v-if="loading" /> <gl-loading-icon v-if="loading" />
<template v-else> <template v-else>
<gl-filtered-search-suggestion <gl-filtered-search-suggestion
......
...@@ -36,8 +36,8 @@ class Iteration < ApplicationRecord ...@@ -36,8 +36,8 @@ class Iteration < ApplicationRecord
.where('due_date is NULL or due_date >= ?', start_date) .where('due_date is NULL or due_date >= ?', start_date)
end end
scope :start_date_passed, -> { where('start_date <= ?', Date.current).where('due_date > ?', Date.current) } scope :start_date_passed, -> { where('start_date <= ?', Date.current).where('due_date >= ?', Date.current) }
scope :due_date_passed, -> { where('due_date <= ?', Date.current) } scope :due_date_passed, -> { where('due_date < ?', Date.current) }
state_machine :state_enum, initial: :upcoming do state_machine :state_enum, initial: :upcoming do
event :start do event :start do
......
- page_description brand_title unless page_description - page_description brand_title unless page_description
-# Needs a redirect on the client side since it's using an anchor to distuingish -# Needs a redirect on the client side since it's using an anchor to distinguish
-# between sign in and registration. We need to inline the JS to not render -# between sign in and registration. We need to inline the JS to not render
-# anything from this page beforehand. -# anything from this page beforehand.
-# Part of an experiment to build a new sign up flow. Will be removed again with -# Part of an experiment to build a new sign up flow. Will be removed again with
......
---
title: Update lodash to 4.17.20
merge_request: 41036
author: Takuya Noguchi
type: security
...@@ -720,6 +720,24 @@ sudo cp /opt/gitlab/embedded/ssl/certs/cacert.pem /var/opt/gitlab/gitlab-rails/s ...@@ -720,6 +720,24 @@ sudo cp /opt/gitlab/embedded/ssl/certs/cacert.pem /var/opt/gitlab/gitlab-rails/s
sudo cp /opt/gitlab/embedded/ssl/certs/cacert.pem /var/opt/gitlab/gitlab-rails/shared/pages/etc/ssl/ca-bundle.pem sudo cp /opt/gitlab/embedded/ssl/certs/cacert.pem /var/opt/gitlab/gitlab-rails/shared/pages/etc/ssl/ca-bundle.pem
``` ```
### 502 error when connecting to GitLab Pages proxy when server does not listen over IPv6
In some cases, NGINX might default to using IPv6 to connect to the GitLab Pages
service even when the server does not listen over IPv6. You can identify when
this is happening if you see something similar to the log entry below in the
`gitlab_pages_error.log`:
```plaintext
2020/02/24 16:32:05 [error] 112654#0: *4982804 connect() failed (111: Connection refused) while connecting to upstream, client: 123.123.123.123, server: ~^(?<group>.*)\.pages\.example\.com$, request: "GET /-/group/project/-/jobs/1234/artifacts/artifact.txt HTTP/1.1", upstream: "http://[::1]:8090//-/group/project/-/jobs/1234/artifacts/artifact.txt", host: "group.example.com"
```
To resolve this, set an explicit IP and port for the GitLab Pages `listen_proxy` setting
to define the explicit address that the GitLab Pages daemon should listen on:
```ruby
gitlab_pages['listen_proxy'] = '127.0.0.1:8090'
```
### 404 error after transferring project to a different group or user ### 404 error after transferring project to a different group or user
If you encounter a `404 Not Found` error a Pages site after transferring a project to If you encounter a `404 Not Found` error a Pages site after transferring a project to
......
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
"jszip": "^3.1.3", "jszip": "^3.1.3",
"jszip-utils": "^0.0.2", "jszip-utils": "^0.0.2",
"katex": "^0.10.0", "katex": "^0.10.0",
"lodash": "^4.17.15", "lodash": "^4.17.20",
"marked": "^0.3.12", "marked": "^0.3.12",
"mermaid": "^8.5.2", "mermaid": "^8.5.2",
"mersenne-twister": "1.1.0", "mersenne-twister": "1.1.0",
......
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { GlFilteredSearchToken, GlFilteredSearchTokenSegment } from '@gitlab/ui'; import {
GlFilteredSearchToken,
GlFilteredSearchTokenSegment,
GlFilteredSearchSuggestion,
GlNewDropdownDivider as GlDropdownDivider,
} from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { deprecatedCreateFlash as createFlash } from '~/flash'; import { deprecatedCreateFlash as createFlash } from '~/flash';
import {
DEFAULT_LABEL_NONE,
DEFAULT_LABEL_ANY,
} from '~/vue_shared/components/filtered_search_bar/constants';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import { mockAuthorToken, mockAuthors } from '../mock_data'; import { mockAuthorToken, mockAuthors } from '../mock_data';
jest.mock('~/flash'); jest.mock('~/flash');
const defaultStubs = {
const createComponent = ({ config = mockAuthorToken, value = { data: '' }, active = false } = {}) => Portal: true,
mount(AuthorToken, { GlFilteredSearchSuggestionList: {
template: '<div></div>',
methods: {
getValue: () => '=',
},
},
};
function createComponent(options = {}) {
const {
config = mockAuthorToken,
value = { data: '' },
active = false,
stubs = defaultStubs,
} = options;
return mount(AuthorToken, {
propsData: { propsData: {
config, config,
value, value,
...@@ -22,16 +46,9 @@ const createComponent = ({ config = mockAuthorToken, value = { data: '' }, activ ...@@ -22,16 +46,9 @@ const createComponent = ({ config = mockAuthorToken, value = { data: '' }, activ
portalName: 'fake target', portalName: 'fake target',
alignSuggestions: function fakeAlignSuggestions() {}, alignSuggestions: function fakeAlignSuggestions() {},
}, },
stubs: { stubs,
Portal: true,
GlFilteredSearchSuggestionList: {
template: '<div></div>',
methods: {
getValue: () => '=',
},
},
},
}); });
}
describe('AuthorToken', () => { describe('AuthorToken', () => {
let mock; let mock;
...@@ -139,5 +156,57 @@ describe('AuthorToken', () => { ...@@ -139,5 +156,57 @@ describe('AuthorToken', () => {
expect(tokenSegments.at(2).text()).toBe(mockAuthors[0].name); // "Administrator" expect(tokenSegments.at(2).text()).toBe(mockAuthors[0].name); // "Administrator"
}); });
}); });
it('renders provided defaultAuthors as suggestions', async () => {
const defaultAuthors = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY];
wrapper = createComponent({
active: true,
config: { ...mockAuthorToken, defaultAuthors },
stubs: { Portal: true },
});
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
const suggestionsSegment = tokenSegments.at(2);
suggestionsSegment.vm.$emit('activate');
await wrapper.vm.$nextTick();
const suggestions = wrapper.findAll(GlFilteredSearchSuggestion);
expect(suggestions).toHaveLength(defaultAuthors.length);
defaultAuthors.forEach((label, index) => {
expect(suggestions.at(index).text()).toBe(label.text);
});
});
it('does not render divider when no defaultAuthors', async () => {
wrapper = createComponent({
active: true,
config: { ...mockAuthorToken, defaultAuthors: [] },
stubs: { Portal: true },
});
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
const suggestionsSegment = tokenSegments.at(2);
suggestionsSegment.vm.$emit('activate');
await wrapper.vm.$nextTick();
expect(wrapper.contains(GlFilteredSearchSuggestion)).toBe(false);
expect(wrapper.contains(GlDropdownDivider)).toBe(false);
});
it('renders `DEFAULT_LABEL_ANY` as default suggestions', async () => {
wrapper = createComponent({
active: true,
config: { ...mockAuthorToken },
stubs: { Portal: true },
});
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
const suggestionsSegment = tokenSegments.at(2);
suggestionsSegment.vm.$emit('activate');
await wrapper.vm.$nextTick();
const suggestions = wrapper.findAll(GlFilteredSearchSuggestion);
expect(suggestions).toHaveLength(1);
expect(suggestions.at(0).text()).toBe(DEFAULT_LABEL_ANY.text);
});
}); });
}); });
...@@ -3,6 +3,7 @@ import { ...@@ -3,6 +3,7 @@ import {
GlFilteredSearchToken, GlFilteredSearchToken,
GlFilteredSearchSuggestion, GlFilteredSearchSuggestion,
GlFilteredSearchTokenSegment, GlFilteredSearchTokenSegment,
GlNewDropdownDivider as GlDropdownDivider,
} from '@gitlab/ui'; } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
...@@ -33,13 +34,14 @@ const defaultStubs = { ...@@ -33,13 +34,14 @@ const defaultStubs = {
}, },
}; };
const createComponent = ({ function createComponent(options = {}) {
config = mockLabelToken, const {
value = { data: '' }, config = mockLabelToken,
active = false, value = { data: '' },
stubs = defaultStubs, active = false,
} = {}) => stubs = defaultStubs,
mount(LabelToken, { } = options;
return mount(LabelToken, {
propsData: { propsData: {
config, config,
value, value,
...@@ -51,6 +53,7 @@ const createComponent = ({ ...@@ -51,6 +53,7 @@ const createComponent = ({
}, },
stubs, stubs,
}); });
}
describe('LabelToken', () => { describe('LabelToken', () => {
let mock; let mock;
...@@ -204,6 +207,21 @@ describe('LabelToken', () => { ...@@ -204,6 +207,21 @@ describe('LabelToken', () => {
}); });
}); });
it('does not render divider when no defaultLabels', async () => {
wrapper = createComponent({
active: true,
config: { ...mockLabelToken, defaultLabels: [] },
stubs: { Portal: true },
});
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
const suggestionsSegment = tokenSegments.at(2);
suggestionsSegment.vm.$emit('activate');
await wrapper.vm.$nextTick();
expect(wrapper.contains(GlFilteredSearchSuggestion)).toBe(false);
expect(wrapper.contains(GlDropdownDivider)).toBe(false);
});
it('renders `DEFAULT_LABELS` as default suggestions', async () => { it('renders `DEFAULT_LABELS` as default suggestions', async () => {
wrapper = createComponent({ wrapper = createComponent({
active: true, active: true,
......
...@@ -3,6 +3,7 @@ import { ...@@ -3,6 +3,7 @@ import {
GlFilteredSearchToken, GlFilteredSearchToken,
GlFilteredSearchSuggestion, GlFilteredSearchSuggestion,
GlFilteredSearchTokenSegment, GlFilteredSearchTokenSegment,
GlNewDropdownDivider as GlDropdownDivider,
} from '@gitlab/ui'; } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
...@@ -31,13 +32,14 @@ const defaultStubs = { ...@@ -31,13 +32,14 @@ const defaultStubs = {
}, },
}; };
const createComponent = ({ function createComponent(options = {}) {
config = mockMilestoneToken, const {
value = { data: '' }, config = mockMilestoneToken,
active = false, value = { data: '' },
stubs = defaultStubs, active = false,
} = {}) => stubs = defaultStubs,
mount(MilestoneToken, { } = options;
return mount(MilestoneToken, {
propsData: { propsData: {
config, config,
value, value,
...@@ -49,6 +51,7 @@ const createComponent = ({ ...@@ -49,6 +51,7 @@ const createComponent = ({
}, },
stubs, stubs,
}); });
}
describe('MilestoneToken', () => { describe('MilestoneToken', () => {
let mock; let mock;
...@@ -176,6 +179,21 @@ describe('MilestoneToken', () => { ...@@ -176,6 +179,21 @@ describe('MilestoneToken', () => {
}); });
}); });
it('does not render divider when no defaultMilestones', async () => {
wrapper = createComponent({
active: true,
config: { ...mockMilestoneToken, defaultMilestones: [] },
stubs: { Portal: true },
});
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
const suggestionsSegment = tokenSegments.at(2);
suggestionsSegment.vm.$emit('activate');
await wrapper.vm.$nextTick();
expect(wrapper.contains(GlFilteredSearchSuggestion)).toBe(false);
expect(wrapper.contains(GlDropdownDivider)).toBe(false);
});
it('renders `DEFAULT_MILESTONES` as default suggestions', async () => { it('renders `DEFAULT_MILESTONES` as default suggestions', async () => {
wrapper = createComponent({ wrapper = createComponent({
active: true, active: true,
......
...@@ -7744,10 +7744,10 @@ lodash.values@^4.3.0: ...@@ -7744,10 +7744,10 @@ lodash.values@^4.3.0:
resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347" resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347"
integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c= integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c=
lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@~4.17.10: lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@~4.17.10:
version "4.17.15" version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
log-symbols@^2.1.0, log-symbols@^2.2.0: log-symbols@^2.1.0, log-symbols@^2.2.0:
version "2.2.0" version "2.2.0"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册