diff --git a/extensions/ql-vscode/src/common/interface-types.ts b/extensions/ql-vscode/src/common/interface-types.ts index 558c43a1a..fc4756f84 100644 --- a/extensions/ql-vscode/src/common/interface-types.ts +++ b/extensions/ql-vscode/src/common/interface-types.ts @@ -20,6 +20,7 @@ import { DataFlowPaths } from "../variant-analysis/shared/data-flow-paths"; import { ExternalApiUsage } from "../data-extensions-editor/external-api-usage"; import { ModeledMethod } from "../data-extensions-editor/modeled-method"; import { DataExtensionEditorViewState } from "../data-extensions-editor/shared/view-state"; +import { Mode } from "../data-extensions-editor/shared/mode"; /** * This module contains types and code that are shared between @@ -521,6 +522,11 @@ export interface AddModeledMethodsMessage { overrideNone?: boolean; } +export interface SwitchModeMessage { + t: "switchMode"; + mode: Mode; +} + export interface JumpToUsageMessage { t: "jumpToUsage"; location: ResolvableLocationValue; @@ -559,6 +565,7 @@ export type ToDataExtensionsEditorMessage = export type FromDataExtensionsEditorMessage = | ViewLoadedMsg + | SwitchModeMessage | OpenModelFileMessage | OpenExtensionPackMessage | JumpToUsageMessage diff --git a/extensions/ql-vscode/src/data-extensions-editor/auto-model-usages-query.ts b/extensions/ql-vscode/src/data-extensions-editor/auto-model-usages-query.ts index 3a4757017..e78c2395e 100644 --- a/extensions/ql-vscode/src/data-extensions-editor/auto-model-usages-query.ts +++ b/extensions/ql-vscode/src/data-extensions-editor/auto-model-usages-query.ts @@ -32,7 +32,7 @@ export async function getAutoModelUsages({ // This will re-run the query that was already run when opening the data extensions editor. This // might be unnecessary, but this makes it really easy to get the path to the BQRS file which we // need to interpret the results. - const queryResult = await runQuery({ + const queryResult = await runQuery("applicationModeQuery", { cliServer, queryRunner, queryStorageDir, diff --git a/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts b/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts index 32063b89b..ad44c5412 100644 --- a/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts +++ b/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts @@ -51,6 +51,7 @@ import { import { showLlmGeneration } from "../config"; import { getAutoModelUsages } from "./auto-model-usages-query"; import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders"; +import { Mode } from "./shared/mode"; export class DataExtensionsEditorView extends AbstractWebview< ToDataExtensionsEditorMessage, @@ -65,6 +66,7 @@ export class DataExtensionsEditorView extends AbstractWebview< private readonly queryStorageDir: string, private readonly databaseItem: DatabaseItem, private readonly extensionPack: ExtensionPack, + private mode: Mode = Mode.Application, ) { super(ctx); } @@ -138,6 +140,12 @@ export class DataExtensionsEditorView extends AbstractWebview< msg.modeledMethods, ); + break; + case "switchMode": + this.mode = msg.mode; + + await Promise.all([this.setViewState(), this.loadExternalApiUsages()]); + break; default: assertNever(msg); @@ -160,6 +168,7 @@ export class DataExtensionsEditorView extends AbstractWebview< viewState: { extensionPack: this.extensionPack, showLlmButton: showLlmGeneration(), + mode: this.mode, }, }); } @@ -255,16 +264,21 @@ export class DataExtensionsEditorView extends AbstractWebview< const cancellationTokenSource = new CancellationTokenSource(); try { - const queryResult = await runQuery({ - cliServer: this.cliServer, - queryRunner: this.queryRunner, - databaseItem: this.databaseItem, - queryStorageDir: this.queryStorageDir, - progress: (progressUpdate: ProgressUpdate) => { - void this.showProgress(progressUpdate, 1500); + const queryResult = await runQuery( + this.mode === Mode.Framework + ? "frameworkModeQuery" + : "applicationModeQuery", + { + cliServer: this.cliServer, + queryRunner: this.queryRunner, + databaseItem: this.databaseItem, + queryStorageDir: this.queryStorageDir, + progress: (progressUpdate: ProgressUpdate) => { + void this.showProgress(progressUpdate, 1500); + }, + token: cancellationTokenSource.token, }, - token: cancellationTokenSource.token, - }); + ); if (!queryResult) { await this.clearProgress(); return; diff --git a/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts b/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts index 08ad094ba..f8a71bf51 100644 --- a/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts +++ b/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts @@ -15,6 +15,7 @@ import { QueryResultType } from "../query-server/new-messages"; import { join } from "path"; import { redactableError } from "../common/errors"; import { telemetryListener } from "../common/vscode/telemetry"; +import { Query } from "./queries/query"; export type RunQueryOptions = { cliServer: Pick; @@ -26,14 +27,17 @@ export type RunQueryOptions = { token: CancellationToken; }; -export async function runQuery({ - cliServer, - queryRunner, - databaseItem, - queryStorageDir, - progress, - token, -}: RunQueryOptions): Promise { +export async function runQuery( + queryName: keyof Omit, + { + cliServer, + queryRunner, + databaseItem, + queryStorageDir, + progress, + token, + }: RunQueryOptions, +): Promise { // The below code is temporary to allow for rapid prototyping of the queries. Once the queries are stabilized, we will // move these queries into the `github/codeql` repository and use them like any other contextual (e.g. AST) queries. // This is intentionally not pretty code, as it will be removed soon. @@ -61,7 +65,7 @@ export async function runQuery({ const queryDir = (await dir({ unsafeCleanup: true })).path; const queryFile = join(queryDir, "FetchExternalApis.ql"); - await writeFile(queryFile, query.applicationModeQuery, "utf8"); + await writeFile(queryFile, query[queryName], "utf8"); if (query.dependencies) { for (const [filename, contents] of Object.entries(query.dependencies)) { diff --git a/extensions/ql-vscode/src/data-extensions-editor/shared/mode.ts b/extensions/ql-vscode/src/data-extensions-editor/shared/mode.ts new file mode 100644 index 000000000..14adb6a07 --- /dev/null +++ b/extensions/ql-vscode/src/data-extensions-editor/shared/mode.ts @@ -0,0 +1,4 @@ +export enum Mode { + Application = "application", + Framework = "framework", +} diff --git a/extensions/ql-vscode/src/data-extensions-editor/shared/view-state.ts b/extensions/ql-vscode/src/data-extensions-editor/shared/view-state.ts index b43557dd1..195d0842e 100644 --- a/extensions/ql-vscode/src/data-extensions-editor/shared/view-state.ts +++ b/extensions/ql-vscode/src/data-extensions-editor/shared/view-state.ts @@ -1,6 +1,8 @@ import { ExtensionPack } from "./extension-pack"; +import { Mode } from "./mode"; export interface DataExtensionEditorViewState { extensionPack: ExtensionPack; showLlmButton: boolean; + mode: Mode; } diff --git a/extensions/ql-vscode/src/stories/data-extensions-editor/DataExtensionsEditor.stories.tsx b/extensions/ql-vscode/src/stories/data-extensions-editor/DataExtensionsEditor.stories.tsx index 7962f8b43..4716a8492 100644 --- a/extensions/ql-vscode/src/stories/data-extensions-editor/DataExtensionsEditor.stories.tsx +++ b/extensions/ql-vscode/src/stories/data-extensions-editor/DataExtensionsEditor.stories.tsx @@ -2,6 +2,7 @@ import * as React from "react"; import { ComponentMeta, ComponentStory } from "@storybook/react"; +import { Mode } from "../../data-extensions-editor/shared/mode"; import { DataExtensionsEditor as DataExtensionsEditorComponent } from "../../view/data-extensions-editor/DataExtensionsEditor"; export default { @@ -26,6 +27,7 @@ DataExtensionsEditor.args = { dataExtensions: [], }, showLlmButton: true, + mode: Mode.Application, }, initialExternalApiUsages: [ { diff --git a/extensions/ql-vscode/src/view/data-extensions-editor/DataExtensionsEditor.tsx b/extensions/ql-vscode/src/view/data-extensions-editor/DataExtensionsEditor.tsx index 5cce094f0..1a1151768 100644 --- a/extensions/ql-vscode/src/view/data-extensions-editor/DataExtensionsEditor.tsx +++ b/extensions/ql-vscode/src/view/data-extensions-editor/DataExtensionsEditor.tsx @@ -16,6 +16,7 @@ import { ViewTitle } from "../common"; import { DataExtensionEditorViewState } from "../../data-extensions-editor/shared/view-state"; import { ModeledMethodsList } from "./ModeledMethodsList"; import { percentFormatter } from "./formatters"; +import { Mode } from "../../data-extensions-editor/shared/mode"; const DataExtensionsEditorContainer = styled.div` margin-top: 1rem; @@ -166,6 +167,16 @@ export function DataExtensionsEditor({ }); }, []); + const onSwitchModeClick = useCallback(() => { + const newMode = + viewState?.mode === Mode.Framework ? Mode.Application : Mode.Framework; + + vscode.postMessage({ + t: "switchMode", + mode: newMode, + }); + }, [viewState?.mode]); + return ( {progress.maxStep > 0 && ( @@ -193,6 +204,16 @@ export function DataExtensionsEditor({
{percentFormatter.format(unModeledPercentage / 100)} unmodeled
+
+ Mode:{" "} + {viewState?.mode === Mode.Framework ? "Framework" : "Application"} +
+
+ + + Switch mode + +
diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/external-api-usage-query.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/external-api-usage-query.test.ts index 4a1371b13..3ce757c2a 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/external-api-usage-query.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/external-api-usage-query.test.ts @@ -67,7 +67,7 @@ describe("runQuery", () => { onCancellationRequested: jest.fn(), }, }; - const result = await runQuery(options); + const result = await runQuery("applicationModeQuery", options); expect(result?.resultType).toEqual(QueryResultType.SUCCESS);