Skip to content

Commit 1c38137

Browse files
OrKoNDevtools-frontend LUCI CQ
authored andcommitted
Refactor UserActionRow component
Aligns the UserActionRow presenter with the UI eng vision. Bug: none Change-Id: I8b95902ee93e7ad991951ef72dbec06d351102e9 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6177276 Commit-Queue: Alex Rudenko <[email protected]> Reviewed-by: Ergün Erdoğmuş <[email protected]>
1 parent da9a885 commit 1c38137

File tree

6 files changed

+500
-407
lines changed

6 files changed

+500
-407
lines changed

front_end/panels/ai_assistance/components/ChatView.ts

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// found in the LICENSE file.
44

55
import '../../../ui/components/spinners/spinners.js';
6-
import './UserActionRow.js';
76

87
import * as Common from '../../../core/common/common.js';
98
import * as Host from '../../../core/host/host.js';
@@ -20,7 +19,7 @@ import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
2019
import {AgentType, type ContextDetail, type ConversationContext, ErrorType} from '../agents/AiAgent.js';
2120

2221
import stylesRaw from './chatView.css.js';
23-
import type {UserActionRowProps} from './UserActionRow.js';
22+
import {UserActionRow} from './UserActionRow.js';
2423

2524
// TODO(crbug.com/391381439): Fully migrate off of constructed style sheets.
2625
const styles = new CSSStyleSheet();
@@ -574,25 +573,6 @@ export class ChatView extends HTMLElement {
574573
Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiAssistanceDynamicSuggestionClicked);
575574
};
576575

577-
#renderUserActionRow(rpcId?: Host.AidaClient.RpcGlobalId, suggestions?: [string, ...string[]]): Lit.TemplateResult {
578-
// clang-format off
579-
return html`<devtools-user-action-row
580-
.props=${{
581-
showRateButtons: rpcId !== undefined,
582-
onFeedbackSubmit: (rating, feedback) => {
583-
if (!rpcId) {
584-
return;
585-
}
586-
this.#props.onFeedbackSubmit(rpcId, rating, feedback);
587-
},
588-
suggestions,
589-
handleSuggestionClick: this.#handleSuggestionClick,
590-
canShowFeedbackForm: this.#props.canShowFeedbackForm,
591-
} as UserActionRowProps}
592-
></devtools-user-action-row>`;
593-
// clang-format on
594-
}
595-
596576
#renderChangeSummary(): Lit.LitTemplate {
597577
if (!this.#props.changeSummary) {
598578
return Lit.nothing;
@@ -894,14 +874,21 @@ export class ChatView extends HTMLElement {
894874
? html`<p>${this.#renderTextAsMarkdown(message.answer, { animate: !this.#props.isReadOnly, ref: this.#handleLastAnswerMarkdownViewRef })}</p>`
895875
: Lit.nothing}
896876
${this.#renderError(message)}
897-
<div class="actions">
898-
${isLast && this.#props.isLoading
899-
? Lit.nothing
900-
: this.#renderUserActionRow(
901-
message.rpcId,
902-
isLast ? message.suggestions : undefined,
903-
)}
904-
</div>
877+
${isLast && this.#props.isLoading
878+
? Lit.nothing
879+
: html`<devtools-widget class="actions" .widgetConfig=${UI.Widget.widgetConfig(UserActionRow, {
880+
showRateButtons: message.rpcId !== undefined,
881+
onFeedbackSubmit: (rating: Host.AidaClient.Rating, feedback: string) => {
882+
if (!message.rpcId) {
883+
return;
884+
}
885+
this.#props.onFeedbackSubmit(message.rpcId, rating, feedback);
886+
},
887+
suggestions: isLast ? message.suggestions : undefined,
888+
onSuggestionClick: this.#handleSuggestionClick,
889+
canShowFeedbackForm: this.#props.canShowFeedbackForm,
890+
})}></devtools-widget>`
891+
}
905892
</section>
906893
`;
907894
// clang-format on

front_end/panels/ai_assistance/components/UserActionRow.test.ts

Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,97 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import {renderElementIntoDOM} from '../../../testing/DOMHelpers.js';
5+
import * as Host from '../../../core/host/host.js';
66
import {
77
describeWithEnvironment,
88
} from '../../../testing/EnvironmentHelpers.js';
99
import * as Freestyler from '../ai_assistance.js';
1010

1111
describeWithEnvironment('UserActionRow', () => {
12+
function createComponent(props: Freestyler.UserActionRowProps):
13+
[sinon.SinonStub<[Freestyler.ViewInput, Freestyler.ViewOutput, HTMLElement], void>, Freestyler.UserActionRow] {
14+
const view = sinon.stub<[Freestyler.ViewInput, Freestyler.ViewOutput, HTMLElement]>();
15+
const component = new Freestyler.UserActionRow(undefined, view);
16+
Object.assign(component, props);
17+
component.wasShown();
18+
return [view, component];
19+
}
20+
1221
it('should show the feedback form when canShowFeedbackForm is true', async () => {
13-
const component = new Freestyler.UserActionRow({
22+
const [view] = createComponent({
1423
showRateButtons: true,
15-
onFeedbackSubmit: sinon.stub(),
1624
canShowFeedbackForm: true,
17-
handleSuggestionClick: sinon.stub(),
25+
onSuggestionClick: sinon.stub(),
26+
onFeedbackSubmit: sinon.stub(),
1827
});
19-
renderElementIntoDOM(component);
20-
const button = component.shadowRoot!.querySelector('.rate-buttons devtools-button')! as HTMLElement;
21-
button.click();
2228

23-
assert(component.shadowRoot!.querySelector('.feedback-form'));
29+
assert.isTrue(view.calledOnce);
30+
31+
{
32+
const [viewInput] = view.args[0];
33+
expect(viewInput.isShowingFeedbackForm).equals(false);
34+
viewInput.onRatingClick(Host.AidaClient.Rating.POSITIVE);
35+
}
36+
37+
assert.isTrue(view.calledTwice);
38+
{
39+
const [viewInput] = view.args[0];
40+
expect(viewInput.isShowingFeedbackForm).equals(true);
41+
}
2442
});
2543

2644
it('should not show the feedback form when canShowFeedbackForm is false', async () => {
27-
const component = new Freestyler.UserActionRow({
45+
const [view] = createComponent({
2846
showRateButtons: true,
29-
onFeedbackSubmit: sinon.stub(),
3047
canShowFeedbackForm: false,
31-
handleSuggestionClick: sinon.stub(),
48+
onSuggestionClick: sinon.stub(),
49+
onFeedbackSubmit: sinon.stub(),
3250
});
33-
renderElementIntoDOM(component);
3451

35-
const button = component.shadowRoot!.querySelector('.rate-buttons devtools-button')! as HTMLElement;
36-
button.click();
52+
assert.isTrue(view.calledOnce);
53+
54+
{
55+
const [viewInput] = view.args[0];
56+
expect(viewInput.isShowingFeedbackForm).equals(false);
57+
viewInput.onRatingClick(Host.AidaClient.Rating.POSITIVE);
58+
}
3759

38-
assert.notExists(component.shadowRoot!.querySelector('.feedback-form'));
60+
assert.isTrue(view.calledTwice);
61+
{
62+
const [viewInput] = view.args[0];
63+
expect(viewInput.isShowingFeedbackForm).equals(false);
64+
}
3965
});
4066

4167
it('should disable the submit button when the input is empty', async () => {
42-
const component = new Freestyler.UserActionRow({
68+
const [view] = createComponent({
4369
showRateButtons: true,
44-
onFeedbackSubmit: sinon.stub(),
4570
canShowFeedbackForm: true,
46-
handleSuggestionClick: sinon.stub(),
71+
onSuggestionClick: sinon.stub(),
72+
onFeedbackSubmit: sinon.stub(),
4773
});
48-
renderElementIntoDOM(component);
49-
const button = component.shadowRoot!.querySelector('.rate-buttons devtools-button')! as HTMLElement;
50-
button.click();
51-
52-
assert(component.shadowRoot!.querySelector('.feedback-form'));
53-
const submitButton = component.shadowRoot!.querySelector('[aria-label="Submit"]') as HTMLButtonElement;
54-
assert.isTrue(submitButton?.disabled);
55-
const inputField = component.shadowRoot!.querySelector('.feedback-form input')! as HTMLInputElement;
56-
inputField.value = 'test';
57-
inputField.dispatchEvent(new Event('input'));
58-
assert.isFalse(submitButton?.disabled);
74+
75+
assert.isTrue(view.calledOnce);
76+
77+
{
78+
const [viewInput] = view.args[0];
79+
expect(viewInput.isSubmitButtonDisabled).equals(false);
80+
viewInput.onRatingClick(Host.AidaClient.Rating.POSITIVE);
81+
}
82+
83+
assert.isTrue(view.calledTwice);
84+
85+
{
86+
const [viewInput] = view.args[0];
87+
expect(viewInput.isSubmitButtonDisabled).equals(false);
88+
expect(viewInput.isShowingFeedbackForm).equals(true);
89+
viewInput.onInputChange('test');
90+
viewInput.onSubmit(new SubmitEvent('submit'));
91+
}
92+
93+
{
94+
const [viewInput] = view.args[0];
95+
expect(viewInput.isSubmitButtonDisabled).equals(true);
96+
}
5997
});
6098
});

0 commit comments

Comments
 (0)