* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+
import {
ButtonPrimary,
Checkbox,
}
componentDidMount() {
+ const { needIssueSync } = this.props;
+
this.mounted = true;
- Promise.all([this.loadIssues(), searchIssueTags({})]).then(
+ Promise.all([
+ this.loadIssues(),
+ needIssueSync ? Promise.resolve([]) : searchIssueTags({}),
+ ]).then(
([{ issues, paging }, tags]) => {
if (this.mounted) {
if (issues.length > MAX_PAGE_SIZE) {
const issueKeys = this.state.issues.map((issue) => issue.key);
this.setState({ submitting: true });
+
bulkChangeIssues(issueKeys, query).then(
() => {
this.setState({ submitting: false });
getAvailableTransitions(issues: Issue[]) {
const transitions: Dict<number> = {};
+
issues.forEach((issue) => {
if (issue.transitions) {
issue.transitions.forEach((t) => {
});
}
});
+
return sortBy(Object.keys(transitions)).map((transition) => ({
transition,
count: transitions[transition],
<FormField htmlFor={`issues-bulk-change-${field}`} label={translate(label)}>
<div className="sw-flex sw-items-center sw-justify-between">
{input}
+
{affected !== undefined && (
<LightLabel>
({translateWithParameters('issue_bulk_change.x_issues', affected)})
const options: LabelValueSelectOption<IssueType>[] = types.map((type) => ({
label: translate('issue.type', type),
value: type,
- Icon: <IssueTypeIcon height={16} type={type} />,
+ Icon: <IssueTypeIcon type={type} />,
}));
const input = (
const options: LabelValueSelectOption<IssueSeverity>[] = SEVERITIES.map((severity) => ({
label: translate('severity', severity),
value: severity,
- Icon: <IssueSeverityIcon height={16} severity={severity} />,
+ Icon: <IssueSeverityIcon severity={severity} />,
}));
const input = (
return (
<FormField
- label={translate('issue.comment.formlink')}
- htmlFor="comment"
help={
<div className="-sw-mt-1" title={translate('issue_bulk_change.comment.help')}>
<HelperHintIcon />
</div>
}
+ htmlFor="comment"
+ label={translate('issue.comment.formlink')}
>
<textarea
id="comment"
{this.renderTypeField()}
{this.renderSeverityField()}
{!needIssueSync && this.renderTagsField(InputField.addTags, 'issue.add_tags', true)}
+
{!needIssueSync &&
this.renderTagsField(InputField.removeTags, 'issue.remove_tags', false)}
+
{this.renderTransitionsField()}
{this.renderCommentField()}
{issues.length > 0 && this.renderNotificationsField()}
+
{issues.length === 0 && (
<FlagMessage variant="warning">{translate('issue_bulk_change.no_match')}</FlagMessage>
)}
return (
<Modal
- onClose={this.props.onClose}
+ body={this.renderForm()}
headerTitle={
loading
? translate('bulk_change')
}
isScrollable
loading={submitting}
- body={this.renderForm()}
+ onClose={this.props.onClose}
primaryButton={
<ButtonPrimary
- id="bulk-change-submit"
+ disabled={!canSubmit || submitting || issues.length === 0}
form="bulk-change-form"
+ id="bulk-change-submit"
type="submit"
- disabled={!canSubmit || submitting || issues.length === 0}
>
{translate('apply')}
</ButtonPrimary>
}
function hasAction(action: string) {
- return (issue: Issue) => issue.actions && issue.actions.includes(action);
+ return (issue: Issue) => issue.actions?.includes(action);
}
export default withBranchStatusRefresh(BulkChangeModal);
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+
import { act, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import * as React from 'react';
import BulkChangeModal, { MAX_PAGE_SIZE } from '../BulkChangeModal';
jest.mock('../../../../api/issues', () => ({
- searchIssueTags: jest.fn().mockResolvedValue(['tag1', 'tag2']),
bulkChangeIssues: jest.fn().mockResolvedValue({}),
+ searchIssueTags: jest.fn().mockResolvedValue(['tag1', 'tag2']),
}));
afterEach(() => {
it('should display warning when too many issues are passed', async () => {
const issues: Issue[] = [];
+
for (let i = MAX_PAGE_SIZE + 1; i > 0; i--) {
issues.push(mockIssue());
}
- renderBulkChangeModal(issues);
+
+ renderBulkChangeModal(issues, { needIssueSync: true });
expect(
await screen.findByText(`issue_bulk_change.form.title.${MAX_PAGE_SIZE}`)
).toBeInTheDocument();
+
expect(await screen.findByText('issue_bulk_change.max_issues_reached')).toBeInTheDocument();
});
it('should properly submit', async () => {
const onDone = jest.fn();
const user = userEvent.setup();
+
renderBulkChangeModal(
[
mockIssue(false, {
- key: 'issue1',
actions: ['assign', 'set_transition', 'set_tags', 'set_type', 'set_severity', 'comment'],
+ key: 'issue1',
transitions: ['Transition1', 'Transition2'],
}),
mockIssue(false, {
- key: 'issue2',
actions: ['assign', 'set_transition', 'set_tags', 'set_type', 'set_severity', 'comment'],
+ key: 'issue2',
transitions: ['Transition1', 'Transition2'],
}),
],
await user.click(
await screen.findByRole('combobox', { name: 'issue_bulk_change.assignee.change' })
);
+
await user.click(await screen.findByText('Toto'));
// Transition
expect(bulkChangeIssues).toHaveBeenCalledTimes(1);
expect(onDone).toHaveBeenCalledTimes(1);
+
expect(bulkChangeIssues).toHaveBeenCalledWith(['issue1', 'issue2'], {
+ add_tags: 'tag1,tag2',
assign: 'toto',
comment: 'some comment',
- set_severity: 'BLOCKER',
- add_tags: 'tag1,tag2',
do_transition: 'Transition2',
- set_type: IssueType.CodeSmell,
sendNotifications: true,
+ set_severity: 'BLOCKER',
+ set_type: IssueType.CodeSmell,
});
});