Merge "Fix link color in formatted text"
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-topic-flow/gr-change-list-topic-flow.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-topic-flow/gr-change-list-topic-flow.ts
index 31a7a36..a9c6526 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-topic-flow/gr-change-list-topic-flow.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-topic-flow/gr-change-list-topic-flow.ts
@@ -31,7 +31,7 @@
@state() private topicToAdd: TopicName = '' as TopicName;
- @state() private topicsToRemove: Set<TopicName> = new Set();
+ @state() private selectedExistingTopics: Set<TopicName> = new Set();
@state() private existingTopicSuggestions: TopicName[] = [];
@@ -140,8 +140,8 @@
<div slot="dropdown-content">
${when(
this.selectedChanges.some(change => change.topic),
- () => this.renderRemoveMode(),
- () => this.renderAddMode()
+ () => this.renderExistingTopicsMode(),
+ () => this.renderNoExistingTopicsMode()
)}
</div>
`
@@ -150,22 +150,29 @@
`;
}
- private renderRemoveMode() {
+ private renderExistingTopicsMode() {
const topics = this.selectedChanges
.map(change => change.topic)
.filter(notUndefined)
.filter(unique);
const removeDisabled =
- this.topicsToRemove.size === 0 ||
+ this.selectedExistingTopics.size === 0 ||
this.overallProgress === ProgressStatus.RUNNING;
return html`
<div class="chips">
- ${topics.map(name => this.renderTopicRemoveChip(name))}
+ ${topics.map(name => this.renderExistingTopicChip(name))}
</div>
<div class="footer">
<div class="loadingOrError">${this.renderLoadingOrError()}</div>
<div class="buttons">
<gr-button
+ id="apply-to-all-button"
+ flatten
+ ?disabled=${this.selectedExistingTopics.size !== 1}
+ @click=${this.applyTopicToAll}
+ >Apply to all</gr-button
+ >
+ <gr-button
id="remove-topics-button"
flatten
?disabled=${removeDisabled}
@@ -177,15 +184,15 @@
`;
}
- private renderTopicRemoveChip(name: TopicName) {
+ private renderExistingTopicChip(name: TopicName) {
const chipClasses = {
chip: true,
- selected: this.topicsToRemove.has(name),
+ selected: this.selectedExistingTopics.has(name),
};
return html`
<span
class=${classMap(chipClasses)}
- @click=${() => this.toggleTopicToRemove(name)}
+ @click=${() => this.toggleExistingTopicSelected(name)}
>
${name}
</span>
@@ -196,7 +203,7 @@
if (this.overallProgress === ProgressStatus.RUNNING) {
return html`
<span class="loadingSpin"></span>
- <span>${this.loadingText}</span>
+ <span class="loadingText">${this.loadingText}</span>
`;
} else if (this.errorText !== undefined) {
return html`<div class="error">${this.errorText}</div>`;
@@ -204,7 +211,7 @@
return nothing;
}
- private renderAddMode() {
+ private renderNoExistingTopicsMode() {
const isCreateNewTopicDisabled =
this.topicToAdd === '' ||
this.existingTopicSuggestions.includes(this.topicToAdd) ||
@@ -257,7 +264,7 @@
this.dropdown?.close();
} else {
this.topicToAdd = '' as TopicName;
- this.topicsToRemove = new Set();
+ this.selectedExistingTopics = new Set();
this.overallProgress = ProgressStatus.NOT_STARTED;
this.errorText = undefined;
this.isDropdownOpen = true;
@@ -282,16 +289,31 @@
private removeTopics() {
this.loadingText = `Removing ${pluralize(
- this.topicsToRemove.size,
+ this.selectedExistingTopics.size,
'topic'
)}...`;
this.trackPromises(
this.selectedChanges
- .filter(change => change.topic && this.topicsToRemove.has(change.topic))
+ .filter(
+ change =>
+ change.topic && this.selectedExistingTopics.has(change.topic)
+ )
.map(change => this.restApiService.setChangeTopic(change._number, ''))
);
}
+ private applyTopicToAll() {
+ this.loadingText = 'Applying to all';
+ this.trackPromises(
+ this.selectedChanges.map(change =>
+ this.restApiService.setChangeTopic(
+ change._number,
+ Array.from(this.selectedExistingTopics.values())[0]
+ )
+ )
+ );
+ }
+
private addTopic(loadingText: string) {
this.loadingText = loadingText;
this.trackPromises(
@@ -315,11 +337,11 @@
}
}
- private toggleTopicToRemove(name: TopicName) {
- if (this.topicsToRemove.has(name)) {
- this.topicsToRemove.delete(name);
+ private toggleExistingTopicSelected(name: TopicName) {
+ if (this.selectedExistingTopics.has(name)) {
+ this.selectedExistingTopics.delete(name);
} else {
- this.topicsToRemove.add(name);
+ this.selectedExistingTopics.add(name);
}
this.requestUpdate();
}
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-topic-flow/gr-change-list-topic-flow_test.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-topic-flow/gr-change-list-topic-flow_test.ts
index 4203b85..677aeb4 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-topic-flow/gr-change-list-topic-flow_test.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-topic-flow/gr-change-list-topic-flow_test.ts
@@ -192,7 +192,7 @@
await flush();
});
- test('renders remove flow', () => {
+ test('renders existing-topics flow', () => {
expect(element).shadowDom.to.equal(
/* HTML */ `
<gr-button
@@ -217,6 +217,15 @@
<div class="loadingOrError"></div>
<div class="buttons">
<gr-button
+ id="apply-to-all-button"
+ flatten=""
+ aria-disabled="true"
+ disabled=""
+ role="button"
+ tabindex="-1"
+ >Apply to all</gr-button
+ >
+ <gr-button
id="remove-topics-button"
flatten=""
aria-disabled="true"
@@ -241,6 +250,13 @@
queryAll<HTMLSpanElement>(element, 'span.chip')[0].click();
await element.updateComplete;
queryAndAssert<GrButton>(element, '#remove-topics-button').click();
+ await element.updateComplete;
+
+ assert.equal(
+ queryAndAssert(element, '.loadingText').textContent,
+ 'Removing 1 topic...'
+ );
+
await resolvePromises();
await element.updateComplete;
@@ -257,6 +273,13 @@
queryAll<HTMLSpanElement>(element, 'span.chip')[1].click();
await element.updateComplete;
queryAndAssert<GrButton>(element, '#remove-topics-button').click();
+ await element.updateComplete;
+
+ assert.equal(
+ queryAndAssert(element, '.loadingText').textContent,
+ 'Removing 2 topics...'
+ );
+
await resolvePromises();
await element.updateComplete;
@@ -271,6 +294,52 @@
'',
]);
});
+
+ test('can only apply a single topic', async () => {
+ assert.isTrue(
+ queryAndAssert<GrButton>(element, '#apply-to-all-button').disabled
+ );
+
+ queryAll<HTMLSpanElement>(element, 'span.chip')[0].click();
+ await element.updateComplete;
+
+ assert.isFalse(
+ queryAndAssert<GrButton>(element, '#apply-to-all-button').disabled
+ );
+
+ queryAll<HTMLSpanElement>(element, 'span.chip')[1].click();
+ await element.updateComplete;
+
+ assert.isTrue(
+ queryAndAssert<GrButton>(element, '#apply-to-all-button').disabled
+ );
+ });
+
+ test('applies topic to all changes', async () => {
+ queryAll<HTMLSpanElement>(element, 'span.chip')[0].click();
+ await element.updateComplete;
+
+ queryAndAssert<GrButton>(element, '#apply-to-all-button').click();
+ await element.updateComplete;
+
+ assert.equal(
+ queryAndAssert(element, '.loadingText').textContent,
+ 'Applying to all'
+ );
+
+ await resolvePromises();
+ await element.updateComplete;
+
+ assert.isTrue(setChangeTopicStub.calledTwice);
+ assert.deepEqual(setChangeTopicStub.firstCall.args, [
+ changesWithTopics[0]._number,
+ 'topic1',
+ ]);
+ assert.deepEqual(setChangeTopicStub.secondCall.args, [
+ changesWithTopics[1]._number,
+ 'topic1',
+ ]);
+ });
});
suite('change have no existing topics', () => {
@@ -334,7 +403,7 @@
await flush();
});
- test('renders create/apply flow', () => {
+ test('renders no-existing-topics flow', () => {
expect(element).shadowDom.to.equal(
/* HTML */ `
<gr-button
@@ -405,6 +474,13 @@
);
queryAndAssert<GrButton>(element, '#create-new-topic-button').click();
+ await element.updateComplete;
+
+ assert.equal(
+ queryAndAssert(element, '.loadingText').textContent,
+ 'Creating topic...'
+ );
+
await resolvePromises();
await element.updateComplete;
@@ -437,6 +513,13 @@
);
queryAndAssert<GrButton>(element, '#apply-topic-button').click();
+ await element.updateComplete;
+
+ assert.equal(
+ queryAndAssert(element, '.loadingText').textContent,
+ 'Applying topic...'
+ );
+
await resolvePromises();
assert.isTrue(setChangeTopicStub.calledTwice);
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
index 23d0860..ae6f001 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
@@ -404,7 +404,7 @@
case 'code':
return html`<code>${block.text}</code>`;
case 'pre':
- return html`<code>${block.text}</code>`;
+ return html`<pre><code>${block.text}</code></pre>`;
case 'list':
return html`
<ul>