Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-02-25 21:10:59 +00:00
parent 01ae05ffd1
commit a53c0ca02c
9 changed files with 85 additions and 43 deletions

View File

@ -1 +1 @@
ef061fd0ccb16fadf3d8550c12b27c4cb3159990 59efecafe0838b6c940f67b00726c8c748d7dad5

View File

@ -3,6 +3,7 @@ import { buildApiUrl } from './api_utils';
import { DEFAULT_PER_PAGE } from './constants'; import { DEFAULT_PER_PAGE } from './constants';
const GROUPS_PATH = '/api/:version/groups.json'; const GROUPS_PATH = '/api/:version/groups.json';
const GROUPS_MEMBERS_SINGLE_PATH = '/api/:version/groups/:group_id/members/:id';
export function getGroups(query, options, callback = () => {}) { export function getGroups(query, options, callback = () => {}) {
const url = buildApiUrl(GROUPS_PATH); const url = buildApiUrl(GROUPS_PATH);
@ -20,3 +21,11 @@ export function getGroups(query, options, callback = () => {}) {
return data; return data;
}); });
} }
export function removeMemberFromGroup(groupId, memberId, options) {
const url = buildApiUrl(GROUPS_MEMBERS_SINGLE_PATH)
.replace(':group_id', groupId)
.replace(':id', memberId);
return axios.delete(url, { params: { ...options } });
}

View File

@ -5,6 +5,7 @@ import $ from 'jquery';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { uniq } from 'lodash'; import { uniq } from 'lodash';
import * as Emoji from '~/emoji'; import * as Emoji from '~/emoji';
import { scrollToElement } from '~/lib/utils/common_utils';
import { dispose, fixTitle } from '~/tooltips'; import { dispose, fixTitle } from '~/tooltips';
import { deprecatedCreateFlash as flash } from './flash'; import { deprecatedCreateFlash as flash } from './flash';
import axios from './lib/utils/axios_utils'; import axios from './lib/utils/axios_utils';
@ -495,12 +496,7 @@ export class AwardsHandler {
} }
scrollToAwards() { scrollToAwards() {
const options = { scrollToElement('.awards', { offset: -110 });
scrollTop: $('.awards').offset().top - 110,
};
// eslint-disable-next-line no-jquery/no-animate
return $('body, html').animate(options, 200);
} }
addEmojiToFrequentlyUsedList(emoji) { addEmojiToFrequentlyUsedList(emoji) {

View File

@ -12,8 +12,6 @@ function showDenylistType() {
} }
export default function adminInit() { export default function adminInit() {
const modal = $('.change-owner-holder');
$('input#user_force_random_password').on('change', function randomPasswordClick() { $('input#user_force_random_password').on('change', function randomPasswordClick() {
const $elems = $('#user_password, #user_password_confirmation'); const $elems = $('#user_password, #user_password_confirmation');
if ($(this).attr('checked')) { if ($(this).attr('checked')) {
@ -28,36 +26,6 @@ export default function adminInit() {
$('.js-toggle-colors-container').toggleClass('hide'); $('.js-toggle-colors-container').toggleClass('hide');
}); });
$('.log-tabs a').on('click', function logTabsClick(e) {
e.preventDefault();
$(this).tab('show');
});
$('.log-bottom').on('click', (e) => {
e.preventDefault();
const $visibleLog = $('.file-content:visible');
// eslint-disable-next-line no-jquery/no-animate
$visibleLog.animate(
{
scrollTop: $visibleLog.find('ol').height(),
},
'fast',
);
});
$('.change-owner-link').on('click', function changeOwnerLinkClick(e) {
e.preventDefault();
$(this).hide();
modal.show();
});
$('.change-owner-cancel-link').on('click', (e) => {
e.preventDefault();
modal.hide();
$('.change-owner-link').show();
});
$('li.project_member, li.group_member').on('ajax:success', refreshCurrentPage); $('li.project_member, li.group_member').on('ajax:success', refreshCurrentPage);
$("input[name='denylist_type']").on('click', showDenylistType); $("input[name='denylist_type']").on('click', showDenylistType);

View File

@ -90,7 +90,10 @@ Please update your Git repository remotes as soon as possible.`),
this.isRequestPending = false; this.isRequestPending = false;
}) })
.catch((error) => { .catch((error) => {
Flash(error.response.data.message); Flash(
error?.response?.data?.message ||
s__('Profiles|An error occurred while updating your username, please try again.'),
);
this.isRequestPending = false; this.isRequestPending = false;
throw error; throw error;
}); });
@ -121,7 +124,8 @@ Please update your Git repository remotes as soon as possible.`),
</div> </div>
<gl-button <gl-button
v-gl-modal-directive="$options.modalId" v-gl-modal-directive="$options.modalId"
:disabled="isRequestPending || newUsername === username" :disabled="newUsername === username"
:loading="isRequestPending"
category="primary" category="primary"
variant="warning" variant="warning"
data-testid="username-change-confirmation-modal" data-testid="username-change-confirmation-modal"

View File

@ -0,0 +1,5 @@
---
title: Add loading indicator to "Update username" button in account settings
merge_request: 53142
author: Kev @KevSlashNull
type: changed

View File

@ -5661,6 +5661,16 @@ State of a requirement.
| `ARCHIVED` | | | `ARCHIVED` | |
| `OPENED` | | | `OPENED` | |
### RequirementStatusFilter
Status of a requirement based on last test report.
| Value | Description |
| ----- | ----------- |
| `FAILED` | |
| `MISSING` | Requirements without any test report. |
| `PASSED` | |
### SastUiComponentSize ### SastUiComponentSize
Size of UI component in SAST configuration page. Size of UI component in SAST configuration page.

View File

@ -4739,6 +4739,9 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list" msgid "Billing|An error occurred while loading billable members list"
msgstr "" msgstr ""
msgid "Billing|An error occurred while removing a billable member"
msgstr ""
msgid "Billing|Enter at least three characters to search." msgid "Billing|Enter at least three characters to search."
msgstr "" msgstr ""
@ -4751,12 +4754,24 @@ msgstr ""
msgid "Billing|Private" msgid "Billing|Private"
msgstr "" msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
msgid "Billing|Type %{username} to confirm"
msgstr ""
msgid "Billing|Type to search" msgid "Billing|Type to search"
msgstr "" msgstr ""
msgid "Billing|User was successfully removed"
msgstr ""
msgid "Billing|Users occupying seats in" msgid "Billing|Users occupying seats in"
msgstr "" msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
msgid "Bitbucket Server Import" msgid "Bitbucket Server Import"
msgstr "" msgstr ""
@ -22807,6 +22822,9 @@ msgstr ""
msgid "Profiles|Add status emoji" msgid "Profiles|Add status emoji"
msgstr "" msgstr ""
msgid "Profiles|An error occurred while updating your username, please try again."
msgstr ""
msgid "Profiles|Avatar cropper" msgid "Profiles|Avatar cropper"
msgstr "" msgstr ""
@ -24908,6 +24926,9 @@ msgstr ""
msgid "Remove time estimate" msgid "Remove time estimate"
msgstr "" msgstr ""
msgid "Remove user"
msgstr ""
msgid "Remove user & report" msgid "Remove user & report"
msgstr "" msgstr ""

View File

@ -2,10 +2,13 @@ import { GlModal } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import UpdateUsername from '~/profile/account/components/update_username.vue'; import UpdateUsername from '~/profile/account/components/update_username.vue';
jest.mock('~/flash');
describe('UpdateUsername component', () => { describe('UpdateUsername component', () => {
const rootUrl = TEST_HOST; const rootUrl = TEST_HOST;
const actionUrl = `${TEST_HOST}/update/username`; const actionUrl = `${TEST_HOST}/update/username`;
@ -105,7 +108,8 @@ describe('UpdateUsername component', () => {
axiosMock.onPut(actionUrl).replyOnce(() => { axiosMock.onPut(actionUrl).replyOnce(() => {
expect(input.attributes('disabled')).toBe('disabled'); expect(input.attributes('disabled')).toBe('disabled');
expect(openModalBtn.props('disabled')).toBe(true); expect(openModalBtn.props('disabled')).toBe(false);
expect(openModalBtn.props('loading')).toBe(true);
return [200, { message: 'Username changed' }]; return [200, { message: 'Username changed' }];
}); });
@ -115,6 +119,7 @@ describe('UpdateUsername component', () => {
expect(input.attributes('disabled')).toBe(undefined); expect(input.attributes('disabled')).toBe(undefined);
expect(openModalBtn.props('disabled')).toBe(true); expect(openModalBtn.props('disabled')).toBe(true);
expect(openModalBtn.props('loading')).toBe(false);
}); });
it('does not set the username after a erroneous update', async () => { it('does not set the username after a erroneous update', async () => {
@ -122,7 +127,8 @@ describe('UpdateUsername component', () => {
axiosMock.onPut(actionUrl).replyOnce(() => { axiosMock.onPut(actionUrl).replyOnce(() => {
expect(input.attributes('disabled')).toBe('disabled'); expect(input.attributes('disabled')).toBe('disabled');
expect(openModalBtn.props('disabled')).toBe(true); expect(openModalBtn.props('disabled')).toBe(false);
expect(openModalBtn.props('loading')).toBe(true);
return [400, { message: 'Invalid username' }]; return [400, { message: 'Invalid username' }];
}); });
@ -130,6 +136,29 @@ describe('UpdateUsername component', () => {
await expect(wrapper.vm.onConfirm()).rejects.toThrow(); await expect(wrapper.vm.onConfirm()).rejects.toThrow();
expect(input.attributes('disabled')).toBe(undefined); expect(input.attributes('disabled')).toBe(undefined);
expect(openModalBtn.props('disabled')).toBe(false); expect(openModalBtn.props('disabled')).toBe(false);
expect(openModalBtn.props('loading')).toBe(false);
});
it('shows an error message if the error response has a `message` property', async () => {
axiosMock.onPut(actionUrl).replyOnce(() => {
return [400, { message: 'Invalid username' }];
});
await expect(wrapper.vm.onConfirm()).rejects.toThrow();
expect(createFlash).toBeCalledWith('Invalid username');
});
it("shows a fallback error message if the error response doesn't have a `message` property", async () => {
axiosMock.onPut(actionUrl).replyOnce(() => {
return [400];
});
await expect(wrapper.vm.onConfirm()).rejects.toThrow();
expect(createFlash).toBeCalledWith(
'An error occurred while updating your username, please try again.',
);
}); });
}); });
}); });