Skip to content

Commit 8d016a8

Browse files
authored
Merge pull request #2340 from github/koesie10/show-extension-pack-name
Show extension pack name in data extensions editor
2 parents d99b6c3 + 1ae5589 commit 8d016a8

File tree

7 files changed

+122
-25
lines changed

7 files changed

+122
-25
lines changed

extensions/ql-vscode/src/common/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export type BuiltInVsCodeCommands = {
8888
) => Promise<void>;
8989
"vscode.open": (uri: Uri) => Promise<void>;
9090
"vscode.openFolder": (uri: Uri) => Promise<void>;
91+
revealInExplorer: (uri: Uri) => Promise<void>;
9192
// We type the `config` property specifically as a CodeQL debug configuration, since that's the
9293
// only kinds we specify anyway.
9394
"workbench.action.debug.start": (options?: {

extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
CancellationTokenSource,
33
ExtensionContext,
4+
Uri,
45
ViewColumn,
56
window,
67
workspace,
@@ -34,6 +35,7 @@ import { readQueryResults, runQuery } from "./external-api-usage-query";
3435
import { createDataExtensionYaml, loadDataExtensionYaml } from "./yaml";
3536
import { ExternalApiUsage } from "./external-api-usage";
3637
import { ModeledMethod } from "./modeled-method";
38+
import { ExtensionPackModelFile } from "./extension-pack-picker";
3739

3840
function getQlSubmoduleFolder(): WorkspaceFolder | undefined {
3941
const workspaceFolder = workspace.workspaceFolders?.find(
@@ -60,7 +62,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
6062
private readonly queryRunner: QueryRunner,
6163
private readonly queryStorageDir: string,
6264
private readonly databaseItem: DatabaseItem,
63-
private readonly modelFilename: string,
65+
private readonly modelFile: ExtensionPackModelFile,
6466
) {
6567
super(ctx);
6668
}
@@ -93,10 +95,17 @@ export class DataExtensionsEditorView extends AbstractWebview<
9395
case "viewLoaded":
9496
await this.onWebViewLoaded();
9597

98+
break;
99+
case "openExtensionPack":
100+
await this.app.commands.execute(
101+
"revealInExplorer",
102+
Uri.file(this.modelFile.extensionPack.path),
103+
);
104+
96105
break;
97106
case "openModelFile":
98107
await window.showTextDocument(
99-
await workspace.openTextDocument(this.modelFilename),
108+
await workspace.openTextDocument(this.modelFile.filename),
100109
);
101110

102111
break;
@@ -127,7 +136,8 @@ export class DataExtensionsEditorView extends AbstractWebview<
127136
await Promise.all([
128137
this.postMessage({
129138
t: "setDataExtensionEditorInitialData",
130-
modelFilename: this.modelFilename,
139+
extensionPackName: this.modelFile.extensionPack.name,
140+
modelFilename: this.modelFile.filename,
131141
}),
132142
this.loadExternalApiUsages(),
133143
this.loadExistingModeledMethods(),
@@ -164,28 +174,30 @@ export class DataExtensionsEditorView extends AbstractWebview<
164174
modeledMethods,
165175
);
166176

167-
await outputFile(this.modelFilename, yaml);
177+
await outputFile(this.modelFile.filename, yaml);
168178

169-
void extLogger.log(`Saved data extension YAML to ${this.modelFilename}`);
179+
void extLogger.log(
180+
`Saved data extension YAML to ${this.modelFile.filename}`,
181+
);
170182
}
171183

172184
protected async loadExistingModeledMethods(): Promise<void> {
173185
try {
174-
if (!(await pathExists(this.modelFilename))) {
186+
if (!(await pathExists(this.modelFile.filename))) {
175187
return;
176188
}
177189

178-
const yaml = await readFile(this.modelFilename, "utf8");
190+
const yaml = await readFile(this.modelFile.filename, "utf8");
179191

180192
const data = loadYaml(yaml, {
181-
filename: this.modelFilename,
193+
filename: this.modelFile.filename,
182194
});
183195

184196
const existingModeledMethods = loadDataExtensionYaml(data);
185197

186198
if (!existingModeledMethods) {
187199
void showAndLogErrorMessage(
188-
`Failed to parse data extension YAML ${this.modelFilename}.`,
200+
`Failed to parse data extension YAML ${this.modelFile.filename}.`,
189201
);
190202
return;
191203
}
@@ -197,7 +209,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
197209
} catch (e: unknown) {
198210
void showAndLogErrorMessage(
199211
`Unable to read data extension YAML ${
200-
this.modelFilename
212+
this.modelFile.filename
201213
}: ${getErrorMessage(e)}`,
202214
);
203215
}

extensions/ql-vscode/src/data-extensions-editor/extension-pack-picker.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,42 +21,55 @@ const packNameRegex = new RegExp(
2121
);
2222
const packNameLength = 128;
2323

24+
export interface ExtensionPack {
25+
name: string;
26+
path: string;
27+
}
28+
29+
export interface ExtensionPackModelFile {
30+
filename: string;
31+
extensionPack: ExtensionPack;
32+
}
33+
2434
export async function pickExtensionPackModelFile(
2535
cliServer: Pick<CodeQLCliServer, "resolveQlpacks" | "resolveExtensions">,
2636
databaseItem: Pick<DatabaseItem, "name" | "language">,
2737
progress: ProgressCallback,
2838
token: CancellationToken,
29-
): Promise<string | undefined> {
30-
const extensionPackPath = await pickExtensionPack(
39+
): Promise<ExtensionPackModelFile | undefined> {
40+
const extensionPack = await pickExtensionPack(
3141
cliServer,
3242
databaseItem,
3343
progress,
3444
token,
3545
);
36-
if (!extensionPackPath) {
37-
return;
46+
if (!extensionPack) {
47+
return undefined;
3848
}
3949

4050
const modelFile = await pickModelFile(
4151
cliServer,
4252
databaseItem,
43-
extensionPackPath,
53+
extensionPack.path,
4454
progress,
4555
token,
4656
);
4757
if (!modelFile) {
4858
return;
4959
}
5060

51-
return modelFile;
61+
return {
62+
filename: modelFile,
63+
extensionPack,
64+
};
5265
}
5366

5467
async function pickExtensionPack(
5568
cliServer: Pick<CodeQLCliServer, "resolveQlpacks">,
5669
databaseItem: Pick<DatabaseItem, "name" | "language">,
5770
progress: ProgressCallback,
5871
token: CancellationToken,
59-
): Promise<string | undefined> {
72+
): Promise<ExtensionPack | undefined> {
6073
progress({
6174
message: "Resolving extension packs...",
6275
step: 1,
@@ -117,7 +130,10 @@ async function pickExtensionPack(
117130
return undefined;
118131
}
119132

120-
return extensionPackPaths[0];
133+
return {
134+
name: extensionPackOption.extensionPack,
135+
path: extensionPackPaths[0],
136+
};
121137
}
122138

123139
async function pickModelFile(
@@ -186,7 +202,7 @@ async function pickModelFile(
186202
async function pickNewExtensionPack(
187203
databaseItem: Pick<DatabaseItem, "name" | "language">,
188204
token: CancellationToken,
189-
): Promise<string | undefined> {
205+
): Promise<ExtensionPack | undefined> {
190206
const workspaceFolders = getOnDiskWorkspaceFoldersObjects();
191207
const workspaceFolderOptions = workspaceFolders.map((folder) => ({
192208
label: folder.name,
@@ -263,7 +279,10 @@ async function pickNewExtensionPack(
263279
}),
264280
);
265281

266-
return packPath;
282+
return {
283+
name: packName,
284+
path: packPath,
285+
};
267286
}
268287

269288
async function pickNewModelFile(

extensions/ql-vscode/src/pure/interface-types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ export type FromDataFlowPathsMessage = CommonFromViewMessages;
483483

484484
export interface SetDataExtensionEditorInitialDataMessage {
485485
t: "setDataExtensionEditorInitialData";
486+
extensionPackName: string;
486487
modelFilename: string;
487488
}
488489

@@ -516,6 +517,10 @@ export interface JumpToUsageMessage {
516517
location: ResolvableLocationValue;
517518
}
518519

520+
export interface OpenExtensionPackMessage {
521+
t: "openExtensionPack";
522+
}
523+
519524
export interface OpenModelFileMessage {
520525
t: "openModelFile";
521526
}
@@ -539,6 +544,7 @@ export type ToDataExtensionsEditorMessage =
539544
export type FromDataExtensionsEditorMessage =
540545
| ViewLoadedMsg
541546
| OpenModelFileMessage
547+
| OpenExtensionPackMessage
542548
| JumpToUsageMessage
543549
| SaveModeledMethods
544550
| GenerateExternalApiMessage;

extensions/ql-vscode/src/stories/data-extensions-editor/DataExtensionsEditor.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const Template: ComponentStory<typeof DataExtensionsEditorComponent> = (
1515

1616
export const DataExtensionsEditor = Template.bind({});
1717
DataExtensionsEditor.args = {
18+
initialExtensionPackName: "codeql/sql2o-models",
1819
initialModelFilename:
1920
"/home/user/vscode-codeql-starter/codeql-custom-queries-java/sql2o/models/sql2o.yml",
2021
initialExternalApiUsages: [

extensions/ql-vscode/src/view/data-extensions-editor/DataExtensionsEditor.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,21 @@ const ProgressBar = styled.div<ProgressBarProps>`
4747
`;
4848

4949
type Props = {
50+
initialExtensionPackName?: string;
5051
initialModelFilename?: string;
5152
initialExternalApiUsages?: ExternalApiUsage[];
5253
initialModeledMethods?: Record<string, ModeledMethod>;
5354
};
5455

5556
export function DataExtensionsEditor({
57+
initialExtensionPackName,
5658
initialModelFilename,
5759
initialExternalApiUsages = [],
5860
initialModeledMethods = {},
5961
}: Props): JSX.Element {
62+
const [extensionPackName, setExtensionPackName] = useState<
63+
string | undefined
64+
>(initialExtensionPackName);
6065
const [modelFilename, setModelFilename] = useState<string | undefined>(
6166
initialModelFilename,
6267
);
@@ -79,6 +84,7 @@ export function DataExtensionsEditor({
7984
const msg: ToDataExtensionsEditorMessage = evt.data;
8085
switch (msg.t) {
8186
case "setDataExtensionEditorInitialData":
87+
setExtensionPackName(msg.extensionPackName);
8288
setModelFilename(msg.modelFilename);
8389
break;
8490
case "setExternalApiUsages":
@@ -150,6 +156,12 @@ export function DataExtensionsEditor({
150156
});
151157
}, []);
152158

159+
const onOpenExtensionPackClick = useCallback(() => {
160+
vscode.postMessage({
161+
t: "openExtensionPack",
162+
});
163+
}, []);
164+
153165
const onOpenModelFileClick = useCallback(() => {
154166
vscode.postMessage({
155167
t: "openModelFile",
@@ -169,6 +181,12 @@ export function DataExtensionsEditor({
169181
<>
170182
<ViewTitle>Data extensions editor</ViewTitle>
171183
<DetailsContainer>
184+
{extensionPackName && (
185+
<LinkIconButton onClick={onOpenExtensionPackClick}>
186+
<span slot="start" className="codicon codicon-package"></span>
187+
{extensionPackName}
188+
</LinkIconButton>
189+
)}
172190
{modelFilename && (
173191
<LinkIconButton onClick={onOpenModelFileClick}>
174192
<span slot="start" className="codicon codicon-file-code"></span>

extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/extension-pack-picker.test.ts

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,13 @@ describe("pickExtensionPackModelFile", () => {
7373
progress,
7474
token,
7575
),
76-
).toEqual("/a/b/c/my-extension-pack/models/model.yml");
76+
).toEqual({
77+
filename: "/a/b/c/my-extension-pack/models/model.yml",
78+
extensionPack: {
79+
name: "my-extension-pack",
80+
path: "/a/b/c/my-extension-pack",
81+
},
82+
});
7783
expect(showQuickPickSpy).toHaveBeenCalledTimes(2);
7884
expect(showQuickPickSpy).toHaveBeenCalledWith(
7985
[
@@ -174,7 +180,13 @@ describe("pickExtensionPackModelFile", () => {
174180
progress,
175181
token,
176182
),
177-
).toEqual(join(tmpDir.path, "models/my-model.yml"));
183+
).toEqual({
184+
filename: join(tmpDir.path, "models/my-model.yml"),
185+
extensionPack: {
186+
name: "my-extension-pack",
187+
path: tmpDir.path,
188+
},
189+
});
178190
expect(showQuickPickSpy).toHaveBeenCalledTimes(2);
179191
expect(showQuickPickSpy).toHaveBeenCalledWith(
180192
[
@@ -264,7 +276,18 @@ describe("pickExtensionPackModelFile", () => {
264276
progress,
265277
token,
266278
),
267-
).toEqual(join(tmpDir.path, "my-extension-pack", "models", "my-model.yml"));
279+
).toEqual({
280+
filename: join(
281+
tmpDir.path,
282+
"my-extension-pack",
283+
"models",
284+
"my-model.yml",
285+
),
286+
extensionPack: {
287+
name: "my-extension-pack",
288+
path: join(tmpDir.path, "my-extension-pack"),
289+
},
290+
});
268291
expect(showQuickPickSpy).toHaveBeenCalledTimes(1);
269292
expect(showInputBoxSpy).toHaveBeenCalledTimes(2);
270293
expect(showInputBoxSpy).toHaveBeenCalledWith(
@@ -329,7 +352,18 @@ describe("pickExtensionPackModelFile", () => {
329352
progress,
330353
token,
331354
),
332-
).toEqual(join(tmpDir.path, "my-extension-pack", "models", "my-model.yml"));
355+
).toEqual({
356+
filename: join(
357+
tmpDir.path,
358+
"my-extension-pack",
359+
"models",
360+
"my-model.yml",
361+
),
362+
extensionPack: {
363+
name: "my-extension-pack",
364+
path: join(tmpDir.path, "my-extension-pack"),
365+
},
366+
});
333367
expect(showQuickPickSpy).toHaveBeenCalledTimes(1);
334368
expect(showInputBoxSpy).toHaveBeenCalledTimes(2);
335369
expect(showInputBoxSpy).toHaveBeenCalledWith(
@@ -508,7 +542,13 @@ describe("pickExtensionPackModelFile", () => {
508542
progress,
509543
token,
510544
),
511-
).toEqual(join(tmpDir.path, "models/my-model.yml"));
545+
).toEqual({
546+
filename: join(tmpDir.path, "models", "my-model.yml"),
547+
extensionPack: {
548+
name: "my-extension-pack",
549+
path: tmpDir.path,
550+
},
551+
});
512552
expect(showQuickPickSpy).toHaveBeenCalledTimes(1);
513553
expect(showInputBoxSpy).toHaveBeenCalledWith(
514554
{

0 commit comments

Comments
 (0)