Skip to content

Commit fd89f3f

Browse files
OrKoNDevtools-frontend LUCI CQ
authored andcommitted
[AI Assistance] create a fresh stylesheet for each frame
Fixed: 392781256 Change-Id: I95216051166be544d0032b904ce8c72213bbfe3d Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6225800 Commit-Queue: Alex Rudenko <[email protected]> Reviewed-by: Nikolay Vitkov <[email protected]>
1 parent 84113ef commit fd89f3f

File tree

5 files changed

+107
-33
lines changed

5 files changed

+107
-33
lines changed

front_end/core/sdk/CSSModel.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -609,8 +609,8 @@ export class CSSModel extends SDKModel<EventTypes> {
609609
}
610610
}
611611

612-
async createInspectorStylesheet(frameId: Protocol.Page.FrameId): Promise<CSSStyleSheetHeader|null> {
613-
const result = await this.agent.invoke_createStyleSheet({frameId});
612+
async createInspectorStylesheet(frameId: Protocol.Page.FrameId, force = false): Promise<CSSStyleSheetHeader|null> {
613+
const result = await this.agent.invoke_createStyleSheet({frameId, force});
614614
if (result.getError()) {
615615
throw new Error(result.getError());
616616
}

front_end/core/sdk/CSSStyleSheetHeader.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,33 @@ describe('CSSStyleSheetHeader', () => {
105105
assert.strictEqual(cssStyleSheetHeader.createPageResourceLoadInitiator().target, target);
106106
});
107107
});
108+
109+
describe('resourceURL()', () => {
110+
const frameId = '123' as Protocol.Page.FrameId;
111+
const styleSheetId = '456' as Protocol.CSS.StyleSheetId;
112+
const sourceURL = 'http://localhost/style.css';
113+
114+
it('returns a unique resourceURL for inspector originated stylesheet', () => {
115+
const target = sinon.createStubInstance(SDK.Target.Target);
116+
const cssModel = sinon.createStubInstance(SDK.CSSModel.CSSModel);
117+
cssModel.target.returns(target);
118+
const cssStyleSheetHeader = new SDK.CSSStyleSheetHeader.CSSStyleSheetHeader(cssModel, {
119+
styleSheetId,
120+
frameId,
121+
sourceURL,
122+
origin: Protocol.CSS.StyleSheetOrigin.Inspector,
123+
title: 'my-frame',
124+
disabled: false,
125+
isInline: false,
126+
isMutable: false,
127+
isConstructed: false,
128+
startLine: 0,
129+
startColumn: 0,
130+
length: 10,
131+
endLine: 1,
132+
endColumn: 8,
133+
});
134+
assert.strictEqual(cssStyleSheetHeader.resourceURL(), 'inspector://inspector-stylesheet#456');
135+
});
136+
});
108137
});

front_end/core/sdk/CSSStyleSheetHeader.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ export class CSSStyleSheetHeader implements TextUtils.ContentProvider.ContentPro
134134
}
135135

136136
private viaInspectorResourceURL(): Platform.DevToolsPath.UrlString {
137-
return `inspector://${this.getFrameURLPath()}inspector-stylesheet` as Platform.DevToolsPath.UrlString;
137+
return `inspector://${this.getFrameURLPath()}inspector-stylesheet#${this.id}` as Platform.DevToolsPath.UrlString;
138138
}
139139

140140
private dynamicStyleURL(): Platform.DevToolsPath.UrlString {

front_end/panels/ai_assistance/ChangeManager.test.ts

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,22 @@ import type * as Protocol from '../../generated/protocol.js';
88
import * as Freestyler from './ai_assistance.js';
99

1010
describe('ChangeManager', () => {
11-
const styleSheetId = '1' as Protocol.CSS.StyleSheetId;
11+
let styleSheetId = 0;
1212
const frameId = '1' as Protocol.Page.FrameId;
13+
const anotherFrameId = '2' as Protocol.Page.FrameId;
1314
const agentId = '1';
1415

16+
beforeEach(() => {
17+
styleSheetId = 0;
18+
});
19+
1520
function createModel() {
1621
const cssModel = sinon.createStubInstance(SDK.CSSModel.CSSModel, {
1722
// @ts-expect-error stub types
18-
createInspectorStylesheet: sinon.stub().callsFake(() => {
23+
createInspectorStylesheet: sinon.stub().callsFake(frameId => {
24+
styleSheetId++;
1925
return new SDK.CSSStyleSheetHeader.CSSStyleSheetHeader(cssModel, {
20-
styleSheetId,
26+
styleSheetId: String(styleSheetId) as Protocol.CSS.StyleSheetId,
2127
frameId,
2228
sourceURL: '',
2329
origin: 'inspector' as Protocol.CSS.StyleSheetOrigin,
@@ -50,9 +56,10 @@ describe('ChangeManager', () => {
5056
},
5157
});
5258
assert(cssModel.setStyleSheetText.calledOnce);
53-
assert.deepEqual(cssModel.setStyleSheetText.args, [
54-
[styleSheetId, '.ai-style-change-1 {\n div& {\n color: blue;\n }\n}', true],
55-
]);
59+
assert.deepEqual(
60+
cssModel.setStyleSheetText.lastCall.args,
61+
['1', '.ai-style-change-1 {\n div& {\n color: blue;\n }\n}', true],
62+
);
5663
});
5764

5865
it('can merge multiple changes with same className', async () => {
@@ -66,6 +73,10 @@ describe('ChangeManager', () => {
6673
color: 'blue',
6774
},
6875
});
76+
assert(cssModel.setStyleSheetText.calledOnce);
77+
assert.deepEqual(
78+
cssModel.setStyleSheetText.lastCall.args,
79+
['1', '.ai-style-change-1 {\n div& {\n color: blue;\n }\n}', true]);
6980
await changeManager.addChange(cssModel, frameId, {
7081
groupId: agentId,
7182
selector: 'span',
@@ -75,10 +86,9 @@ describe('ChangeManager', () => {
7586
},
7687
});
7788
assert(cssModel.setStyleSheetText.calledTwice);
78-
assert.deepEqual(cssModel.setStyleSheetText.args, [
79-
[styleSheetId, '.ai-style-change-1 {\n div& {\n color: blue;\n }\n}', true],
80-
[styleSheetId, '.ai-style-change-1 {\n div& {\n color: green;\n }\n}', true],
81-
]);
89+
assert.deepEqual(
90+
cssModel.setStyleSheetText.lastCall.args,
91+
['1', '.ai-style-change-1 {\n div& {\n color: green;\n }\n}', true]);
8292
});
8393

8494
it('can register multiple changes with the same selector', async () => {
@@ -95,19 +105,21 @@ describe('ChangeManager', () => {
95105
await changeManager.addChange(cssModel, frameId, {
96106
groupId: agentId,
97107
selector: 'div',
98-
className: 'ai-style-change-1',
108+
className: 'ai-style-change-2',
99109
styles: {
100110
color: 'green',
101111
},
102112
});
113+
103114
assert(cssModel.setStyleSheetText.calledTwice);
104-
assert.deepEqual(cssModel.setStyleSheetText.args, [
105-
[styleSheetId, '.ai-style-change-1 {\n div& {\n color: blue;\n }\n}', true],
106-
[styleSheetId, '.ai-style-change-1 {\n div& {\n color: green;\n }\n}', true],
115+
assert.deepEqual(cssModel.setStyleSheetText.lastCall.args, [
116+
'1',
117+
'.ai-style-change-1 {\n div& {\n color: blue;\n }\n}\n.ai-style-change-2 {\n div& {\n color: green;\n }\n}',
118+
true
107119
]);
108120
});
109121

110-
it('can clear changes', async () => {
122+
it('creates a stylesheet per frame', async () => {
111123
const changeManager = new Freestyler.ChangeManager();
112124
const cssModel = createModel();
113125
await changeManager.addChange(cssModel, frameId, {
@@ -119,10 +131,43 @@ describe('ChangeManager', () => {
119131
},
120132
});
121133
assert(cssModel.setStyleSheetText.calledOnce);
122-
assert.deepEqual(cssModel.setStyleSheetText.args, [
123-
[styleSheetId, '.ai-style-change-1 {\n div& {\n color: blue;\n }\n}', true],
124-
]);
134+
assert.deepEqual(
135+
cssModel.setStyleSheetText.lastCall.args,
136+
['1', '.ai-style-change-1 {\n div& {\n color: blue;\n }\n}', true]);
137+
138+
await changeManager.addChange(cssModel, anotherFrameId, {
139+
groupId: agentId,
140+
selector: 'div',
141+
className: 'ai-style-change-2',
142+
styles: {
143+
color: 'green',
144+
},
145+
});
146+
147+
assert(cssModel.setStyleSheetText.calledTwice);
148+
assert.deepEqual(
149+
cssModel.setStyleSheetText.lastCall.args,
150+
['2', '.ai-style-change-2 {\n div& {\n color: green;\n }\n}', true]);
151+
});
152+
153+
it('can clear changes', async () => {
154+
const changeManager = new Freestyler.ChangeManager();
155+
let cssModel = createModel();
156+
await changeManager.addChange(cssModel, frameId, {
157+
groupId: agentId,
158+
selector: 'div',
159+
className: 'ai-style-change-1',
160+
styles: {
161+
color: 'blue',
162+
},
163+
});
164+
assert(cssModel.setStyleSheetText.calledOnce);
165+
assert.deepEqual(
166+
cssModel.setStyleSheetText.lastCall.args,
167+
['1', '.ai-style-change-1 {\n div& {\n color: blue;\n }\n}', true],
168+
);
125169
await changeManager.clear();
170+
cssModel = createModel();
126171
await changeManager.addChange(cssModel, frameId, {
127172
groupId: agentId,
128173
selector: 'body',
@@ -131,11 +176,11 @@ describe('ChangeManager', () => {
131176
color: 'green',
132177
},
133178
});
134-
assert(cssModel.setStyleSheetText.calledTwice);
135-
assert.deepEqual(cssModel.setStyleSheetText.args, [
136-
[styleSheetId, '.ai-style-change-1 {\n div& {\n color: blue;\n }\n}', true], // before clear().
137-
[styleSheetId, '.ai-style-change-1 {\n body& {\n color: green;\n }\n}', true],
138-
]);
179+
assert(cssModel.setStyleSheetText.calledOnce);
180+
assert.deepEqual(
181+
cssModel.setStyleSheetText.lastCall.args,
182+
['2', '.ai-style-change-1 {\n body& {\n color: green;\n }\n}', true],
183+
);
139184
});
140185

141186
describe('format changes', () => {
@@ -153,13 +198,12 @@ describe('ChangeManager', () => {
153198
groupId: agentId,
154199
selector: 'div',
155200
className: 'ai-style-change-1',
156-
styles: {
157-
color: 'blue',
158-
},
201+
styles: {color: 'blue', 'background-color': 'green'},
159202
});
160203

161204
assert.strictEqual(changeManager.formatChanges(agentId), `div {
162205
color: blue;
206+
background-color: green;
163207
}`);
164208
});
165209
});

front_end/panels/ai_assistance/ChangeManager.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ export interface Change {
1616

1717
export const AI_ASSISTANCE_CSS_CLASS_NAME = 'ai-style-change';
1818

19-
function formatStyles(styles: Record<string, string>): string {
19+
function formatStyles(styles: Record<string, string>, indent = 2): string {
2020
const kebabStyles = Platform.StringUtilities.toKebabCaseKeys(styles);
21-
const lines = Object.entries(kebabStyles).map(([key, value]) => ` ${key}: ${value};`);
21+
const lines = Object.entries(kebabStyles).map(([key, value]) => `${' '.repeat(indent)}${key}: ${value};`);
2222
return lines.join('\n');
2323
}
2424

@@ -43,11 +43,12 @@ export class ChangeManager {
4343
}
4444
let stylesheetId = frameToStylesheet.get(frameId);
4545
if (!stylesheetId) {
46-
const styleSheetHeader = await cssModel.createInspectorStylesheet(frameId);
46+
const styleSheetHeader = await cssModel.createInspectorStylesheet(frameId, /* force */ true);
4747
if (!styleSheetHeader) {
4848
throw new Error('inspector-stylesheet is not found');
4949
}
5050
stylesheetId = styleSheetHeader.id;
51+
frameToStylesheet.set(frameId, stylesheetId);
5152
}
5253
return stylesheetId;
5354
});
@@ -118,7 +119,7 @@ ${formatStyles(change.styles)}
118119
.map(change => {
119120
return `.${change.className} {
120121
${change.selector}& {
121-
${formatStyles(change.styles)}
122+
${formatStyles(change.styles, 4)}
122123
}
123124
}`;
124125
})

0 commit comments

Comments
 (0)