Merge pull request #2340 from github/koesie10/show-extension-pack-name

Show extension pack name in data extensions editor
This commit is contained in:
Koen Vlaswinkel
2023-04-18 11:15:29 +02:00
committed by GitHub
7 changed files with 122 additions and 25 deletions

View File

@@ -88,6 +88,7 @@ export type BuiltInVsCodeCommands = {
) => Promise<void>;
"vscode.open": (uri: Uri) => Promise<void>;
"vscode.openFolder": (uri: Uri) => Promise<void>;
revealInExplorer: (uri: Uri) => Promise<void>;
// We type the `config` property specifically as a CodeQL debug configuration, since that's the
// only kinds we specify anyway.
"workbench.action.debug.start": (options?: {

View File

@@ -1,6 +1,7 @@
import {
CancellationTokenSource,
ExtensionContext,
Uri,
ViewColumn,
window,
workspace,
@@ -34,6 +35,7 @@ import { readQueryResults, runQuery } from "./external-api-usage-query";
import { createDataExtensionYaml, loadDataExtensionYaml } from "./yaml";
import { ExternalApiUsage } from "./external-api-usage";
import { ModeledMethod } from "./modeled-method";
import { ExtensionPackModelFile } from "./extension-pack-picker";
function getQlSubmoduleFolder(): WorkspaceFolder | undefined {
const workspaceFolder = workspace.workspaceFolders?.find(
@@ -60,7 +62,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
private readonly queryRunner: QueryRunner,
private readonly queryStorageDir: string,
private readonly databaseItem: DatabaseItem,
private readonly modelFilename: string,
private readonly modelFile: ExtensionPackModelFile,
) {
super(ctx);
}
@@ -93,10 +95,17 @@ export class DataExtensionsEditorView extends AbstractWebview<
case "viewLoaded":
await this.onWebViewLoaded();
break;
case "openExtensionPack":
await this.app.commands.execute(
"revealInExplorer",
Uri.file(this.modelFile.extensionPack.path),
);
break;
case "openModelFile":
await window.showTextDocument(
await workspace.openTextDocument(this.modelFilename),
await workspace.openTextDocument(this.modelFile.filename),
);
break;
@@ -127,7 +136,8 @@ export class DataExtensionsEditorView extends AbstractWebview<
await Promise.all([
this.postMessage({
t: "setDataExtensionEditorInitialData",
modelFilename: this.modelFilename,
extensionPackName: this.modelFile.extensionPack.name,
modelFilename: this.modelFile.filename,
}),
this.loadExternalApiUsages(),
this.loadExistingModeledMethods(),
@@ -164,28 +174,30 @@ export class DataExtensionsEditorView extends AbstractWebview<
modeledMethods,
);
await outputFile(this.modelFilename, yaml);
await outputFile(this.modelFile.filename, yaml);
void extLogger.log(`Saved data extension YAML to ${this.modelFilename}`);
void extLogger.log(
`Saved data extension YAML to ${this.modelFile.filename}`,
);
}
protected async loadExistingModeledMethods(): Promise<void> {
try {
if (!(await pathExists(this.modelFilename))) {
if (!(await pathExists(this.modelFile.filename))) {
return;
}
const yaml = await readFile(this.modelFilename, "utf8");
const yaml = await readFile(this.modelFile.filename, "utf8");
const data = loadYaml(yaml, {
filename: this.modelFilename,
filename: this.modelFile.filename,
});
const existingModeledMethods = loadDataExtensionYaml(data);
if (!existingModeledMethods) {
void showAndLogErrorMessage(
`Failed to parse data extension YAML ${this.modelFilename}.`,
`Failed to parse data extension YAML ${this.modelFile.filename}.`,
);
return;
}
@@ -197,7 +209,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
} catch (e: unknown) {
void showAndLogErrorMessage(
`Unable to read data extension YAML ${
this.modelFilename
this.modelFile.filename
}: ${getErrorMessage(e)}`,
);
}

View File

@@ -21,26 +21,36 @@ const packNameRegex = new RegExp(
);
const packNameLength = 128;
export interface ExtensionPack {
name: string;
path: string;
}
export interface ExtensionPackModelFile {
filename: string;
extensionPack: ExtensionPack;
}
export async function pickExtensionPackModelFile(
cliServer: Pick<CodeQLCliServer, "resolveQlpacks" | "resolveExtensions">,
databaseItem: Pick<DatabaseItem, "name" | "language">,
progress: ProgressCallback,
token: CancellationToken,
): Promise<string | undefined> {
const extensionPackPath = await pickExtensionPack(
): Promise<ExtensionPackModelFile | undefined> {
const extensionPack = await pickExtensionPack(
cliServer,
databaseItem,
progress,
token,
);
if (!extensionPackPath) {
return;
if (!extensionPack) {
return undefined;
}
const modelFile = await pickModelFile(
cliServer,
databaseItem,
extensionPackPath,
extensionPack.path,
progress,
token,
);
@@ -48,7 +58,10 @@ export async function pickExtensionPackModelFile(
return;
}
return modelFile;
return {
filename: modelFile,
extensionPack,
};
}
async function pickExtensionPack(
@@ -56,7 +69,7 @@ async function pickExtensionPack(
databaseItem: Pick<DatabaseItem, "name" | "language">,
progress: ProgressCallback,
token: CancellationToken,
): Promise<string | undefined> {
): Promise<ExtensionPack | undefined> {
progress({
message: "Resolving extension packs...",
step: 1,
@@ -117,7 +130,10 @@ async function pickExtensionPack(
return undefined;
}
return extensionPackPaths[0];
return {
name: extensionPackOption.extensionPack,
path: extensionPackPaths[0],
};
}
async function pickModelFile(
@@ -186,7 +202,7 @@ async function pickModelFile(
async function pickNewExtensionPack(
databaseItem: Pick<DatabaseItem, "name" | "language">,
token: CancellationToken,
): Promise<string | undefined> {
): Promise<ExtensionPack | undefined> {
const workspaceFolders = getOnDiskWorkspaceFoldersObjects();
const workspaceFolderOptions = workspaceFolders.map((folder) => ({
label: folder.name,
@@ -263,7 +279,10 @@ async function pickNewExtensionPack(
}),
);
return packPath;
return {
name: packName,
path: packPath,
};
}
async function pickNewModelFile(

View File

@@ -483,6 +483,7 @@ export type FromDataFlowPathsMessage = CommonFromViewMessages;
export interface SetDataExtensionEditorInitialDataMessage {
t: "setDataExtensionEditorInitialData";
extensionPackName: string;
modelFilename: string;
}
@@ -516,6 +517,10 @@ export interface JumpToUsageMessage {
location: ResolvableLocationValue;
}
export interface OpenExtensionPackMessage {
t: "openExtensionPack";
}
export interface OpenModelFileMessage {
t: "openModelFile";
}
@@ -539,6 +544,7 @@ export type ToDataExtensionsEditorMessage =
export type FromDataExtensionsEditorMessage =
| ViewLoadedMsg
| OpenModelFileMessage
| OpenExtensionPackMessage
| JumpToUsageMessage
| SaveModeledMethods
| GenerateExternalApiMessage;

View File

@@ -15,6 +15,7 @@ const Template: ComponentStory<typeof DataExtensionsEditorComponent> = (
export const DataExtensionsEditor = Template.bind({});
DataExtensionsEditor.args = {
initialExtensionPackName: "codeql/sql2o-models",
initialModelFilename:
"/home/user/vscode-codeql-starter/codeql-custom-queries-java/sql2o/models/sql2o.yml",
initialExternalApiUsages: [

View File

@@ -47,16 +47,21 @@ const ProgressBar = styled.div<ProgressBarProps>`
`;
type Props = {
initialExtensionPackName?: string;
initialModelFilename?: string;
initialExternalApiUsages?: ExternalApiUsage[];
initialModeledMethods?: Record<string, ModeledMethod>;
};
export function DataExtensionsEditor({
initialExtensionPackName,
initialModelFilename,
initialExternalApiUsages = [],
initialModeledMethods = {},
}: Props): JSX.Element {
const [extensionPackName, setExtensionPackName] = useState<
string | undefined
>(initialExtensionPackName);
const [modelFilename, setModelFilename] = useState<string | undefined>(
initialModelFilename,
);
@@ -79,6 +84,7 @@ export function DataExtensionsEditor({
const msg: ToDataExtensionsEditorMessage = evt.data;
switch (msg.t) {
case "setDataExtensionEditorInitialData":
setExtensionPackName(msg.extensionPackName);
setModelFilename(msg.modelFilename);
break;
case "setExternalApiUsages":
@@ -150,6 +156,12 @@ export function DataExtensionsEditor({
});
}, []);
const onOpenExtensionPackClick = useCallback(() => {
vscode.postMessage({
t: "openExtensionPack",
});
}, []);
const onOpenModelFileClick = useCallback(() => {
vscode.postMessage({
t: "openModelFile",
@@ -169,6 +181,12 @@ export function DataExtensionsEditor({
<>
<ViewTitle>Data extensions editor</ViewTitle>
<DetailsContainer>
{extensionPackName && (
<LinkIconButton onClick={onOpenExtensionPackClick}>
<span slot="start" className="codicon codicon-package"></span>
{extensionPackName}
</LinkIconButton>
)}
{modelFilename && (
<LinkIconButton onClick={onOpenModelFileClick}>
<span slot="start" className="codicon codicon-file-code"></span>

View File

@@ -73,7 +73,13 @@ describe("pickExtensionPackModelFile", () => {
progress,
token,
),
).toEqual("/a/b/c/my-extension-pack/models/model.yml");
).toEqual({
filename: "/a/b/c/my-extension-pack/models/model.yml",
extensionPack: {
name: "my-extension-pack",
path: "/a/b/c/my-extension-pack",
},
});
expect(showQuickPickSpy).toHaveBeenCalledTimes(2);
expect(showQuickPickSpy).toHaveBeenCalledWith(
[
@@ -174,7 +180,13 @@ describe("pickExtensionPackModelFile", () => {
progress,
token,
),
).toEqual(join(tmpDir.path, "models/my-model.yml"));
).toEqual({
filename: join(tmpDir.path, "models/my-model.yml"),
extensionPack: {
name: "my-extension-pack",
path: tmpDir.path,
},
});
expect(showQuickPickSpy).toHaveBeenCalledTimes(2);
expect(showQuickPickSpy).toHaveBeenCalledWith(
[
@@ -264,7 +276,18 @@ describe("pickExtensionPackModelFile", () => {
progress,
token,
),
).toEqual(join(tmpDir.path, "my-extension-pack", "models", "my-model.yml"));
).toEqual({
filename: join(
tmpDir.path,
"my-extension-pack",
"models",
"my-model.yml",
),
extensionPack: {
name: "my-extension-pack",
path: join(tmpDir.path, "my-extension-pack"),
},
});
expect(showQuickPickSpy).toHaveBeenCalledTimes(1);
expect(showInputBoxSpy).toHaveBeenCalledTimes(2);
expect(showInputBoxSpy).toHaveBeenCalledWith(
@@ -329,7 +352,18 @@ describe("pickExtensionPackModelFile", () => {
progress,
token,
),
).toEqual(join(tmpDir.path, "my-extension-pack", "models", "my-model.yml"));
).toEqual({
filename: join(
tmpDir.path,
"my-extension-pack",
"models",
"my-model.yml",
),
extensionPack: {
name: "my-extension-pack",
path: join(tmpDir.path, "my-extension-pack"),
},
});
expect(showQuickPickSpy).toHaveBeenCalledTimes(1);
expect(showInputBoxSpy).toHaveBeenCalledTimes(2);
expect(showInputBoxSpy).toHaveBeenCalledWith(
@@ -508,7 +542,13 @@ describe("pickExtensionPackModelFile", () => {
progress,
token,
),
).toEqual(join(tmpDir.path, "models/my-model.yml"));
).toEqual({
filename: join(tmpDir.path, "models", "my-model.yml"),
extensionPack: {
name: "my-extension-pack",
path: tmpDir.path,
},
});
expect(showQuickPickSpy).toHaveBeenCalledTimes(1);
expect(showInputBoxSpy).toHaveBeenCalledWith(
{