Merge branch 'main' into aeisenberg/multi-token
This commit is contained in:
2
.github/workflows/cli-test.yml
vendored
2
.github/workflows/cli-test.yml
vendored
@@ -62,7 +62,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.17.1'
|
||||
node-version: '18.15.0'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: extensions/ql-vscode/package-lock.json
|
||||
|
||||
|
||||
12
.github/workflows/main.yml
vendored
12
.github/workflows/main.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.17.1'
|
||||
node-version: '18.15.0'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: extensions/ql-vscode/package-lock.json
|
||||
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.17.1'
|
||||
node-version: '18.15.0'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: extensions/ql-vscode/package-lock.json
|
||||
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.17.1'
|
||||
node-version: '18.15.0'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: extensions/ql-vscode/package-lock.json
|
||||
|
||||
@@ -149,7 +149,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.17.1'
|
||||
node-version: '18.15.0'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: extensions/ql-vscode/package-lock.json
|
||||
|
||||
@@ -183,7 +183,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.17.1'
|
||||
node-version: '18.15.0'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: extensions/ql-vscode/package-lock.json
|
||||
|
||||
@@ -251,7 +251,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.17.1'
|
||||
node-version: '18.15.0'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: extensions/ql-vscode/package-lock.json
|
||||
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.17.1'
|
||||
node-version: '18.15.0'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
@@ -21,6 +21,7 @@ The following files will need to be updated:
|
||||
- `extensions/ql-vscode/.nvmrc` - this will enable nvm to automatically switch to the correct node version when you're in the project folder
|
||||
- `extensions/ql-vscode/package-lock.json` - the "engines.node: '[VERSION]'" setting
|
||||
- `extensions/ql-vscode/package.json` - the "engines.node: '[VERSION]'" setting
|
||||
- `extensions/ql-vscode/package.json` - the "@types/node: '[VERSION]'" dependency
|
||||
|
||||
## Node.js version used in tests
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
v16.17.1
|
||||
v18.15.0
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
## [UNRELEASED]
|
||||
|
||||
- Fix a bug where the query to Find Definitions in database source files would not be cancelled appropriately. [#2885](https://github.com/github/vscode-codeql/pull/2885)
|
||||
- It is now possible to show the language of query history items using the `%l` specifier in the `codeQL.queryHistory.format` setting. Note that this only works for queries run after this upgrade, and older items will show `unknown` as a language. [#2892](https://github.com/github/vscode-codeql/pull/2892)
|
||||
- Increase the required version of VS Code to 1.82.0. [#2877](https://github.com/github/vscode-codeql/pull/2877)
|
||||
- Fix a bug where the query server was restarted twice after configuration changes. [#2884](https://github.com/github/vscode-codeql/pull/2884).
|
||||
|
||||
## 1.9.1 - 29 September 2023
|
||||
|
||||
1083
extensions/ql-vscode/package-lock.json
generated
1083
extensions/ql-vscode/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,8 +13,8 @@
|
||||
"url": "https://github.com/github/vscode-codeql"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.67.0",
|
||||
"node": "^16.17.1",
|
||||
"vscode": "^1.82.0",
|
||||
"node": "^18.15.0",
|
||||
"npm": ">=7.20.6"
|
||||
},
|
||||
"categories": [
|
||||
@@ -2070,8 +2070,8 @@
|
||||
"prepare": "cd ../.. && husky install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/plugin-retry": "^4.1.6",
|
||||
"@octokit/rest": "^19.0.4",
|
||||
"@octokit/plugin-retry": "^6.0.1",
|
||||
"@octokit/rest": "^20.0.2",
|
||||
"@vscode/codicons": "^0.0.31",
|
||||
"@vscode/debugadapter": "^1.59.0",
|
||||
"@vscode/debugprotocol": "^1.59.0",
|
||||
@@ -2085,10 +2085,10 @@
|
||||
"fs-extra": "^11.1.1",
|
||||
"immutable": "^4.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"msw": "^1.2.0",
|
||||
"nanoid": "^3.2.0",
|
||||
"msw": "^0.0.0-fetch.rc-20",
|
||||
"nanoid": "^5.0.1",
|
||||
"node-fetch": "^2.6.7",
|
||||
"p-queue": "^6.0.0",
|
||||
"p-queue": "^7.4.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"semver": "^7.5.2",
|
||||
@@ -2115,7 +2115,7 @@
|
||||
"@babel/preset-typescript": "^7.21.4",
|
||||
"@faker-js/faker": "^8.0.2",
|
||||
"@github/markdownlint-github": "^0.3.0",
|
||||
"@octokit/plugin-throttling": "^5.0.1",
|
||||
"@octokit/plugin-throttling": "^8.0.0",
|
||||
"@storybook/addon-actions": "^7.1.0",
|
||||
"@storybook/addon-essentials": "^7.1.0",
|
||||
"@storybook/addon-interactions": "^7.1.0",
|
||||
@@ -2141,7 +2141,7 @@
|
||||
"@types/jest": "^29.0.2",
|
||||
"@types/js-yaml": "^4.0.6",
|
||||
"@types/nanoid": "^3.0.0",
|
||||
"@types/node": "^16.11.25",
|
||||
"@types/node": "18.15.0",
|
||||
"@types/node-fetch": "^2.5.2",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
@@ -2153,7 +2153,7 @@
|
||||
"@types/through2": "^2.0.36",
|
||||
"@types/tmp": "^0.1.0",
|
||||
"@types/unzipper": "^0.10.1",
|
||||
"@types/vscode": "^1.67.0",
|
||||
"@types/vscode": "^1.82.0",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"@types/webpack-env": "^1.18.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
import { pathExists, readJson, writeJson } from "fs-extra";
|
||||
import { resolve, relative } from "path";
|
||||
|
||||
import { Octokit, type RestEndpointMethodTypes } from "@octokit/rest";
|
||||
import { Octokit } from "@octokit/core";
|
||||
import { type RestEndpointMethodTypes } from "@octokit/rest";
|
||||
import { throttling } from "@octokit/plugin-throttling";
|
||||
|
||||
import { getFiles } from "./util/files";
|
||||
@@ -22,6 +23,7 @@ import type { GitHubApiRequest } from "../src/common/mock-gh-api/gh-api-request"
|
||||
import { isGetVariantAnalysisRequest } from "../src/common/mock-gh-api/gh-api-request";
|
||||
import { VariantAnalysis } from "../src/variant-analysis/gh-api/variant-analysis";
|
||||
import { RepositoryWithMetadata } from "../src/variant-analysis/gh-api/repository";
|
||||
import { AppOctokit } from "../src/common/octokit";
|
||||
|
||||
const extensionDirectory = resolve(__dirname, "..");
|
||||
const scenariosDirectory = resolve(
|
||||
@@ -31,7 +33,7 @@ const scenariosDirectory = resolve(
|
||||
|
||||
// Make sure we don't run into rate limits by automatically waiting until we can
|
||||
// make another request.
|
||||
const MyOctokit = Octokit.plugin(throttling);
|
||||
const MyOctokit = AppOctokit.plugin(throttling);
|
||||
|
||||
const auth = process.env.GITHUB_TOKEN;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import { Method, Usage } from "../model-editor/method";
|
||||
import { ModeledMethod } from "../model-editor/modeled-method";
|
||||
import { ModelEditorViewState } from "../model-editor/shared/view-state";
|
||||
import { Mode } from "../model-editor/shared/mode";
|
||||
import { QueryLanguage } from "./query-language";
|
||||
|
||||
/**
|
||||
* This module contains types and code that are shared between
|
||||
@@ -51,6 +52,7 @@ export const RAW_RESULTS_LIMIT = 10000;
|
||||
export interface DatabaseInfo {
|
||||
name: string;
|
||||
databaseUri: string;
|
||||
language?: QueryLanguage;
|
||||
}
|
||||
|
||||
/** Arbitrary query metadata */
|
||||
@@ -575,12 +577,18 @@ interface SetModeledMethodMessage {
|
||||
method: ModeledMethod;
|
||||
}
|
||||
|
||||
interface RevealMethodMessage {
|
||||
t: "revealMethod";
|
||||
method: Method;
|
||||
}
|
||||
|
||||
export type ToModelEditorMessage =
|
||||
| SetExtensionPackStateMessage
|
||||
| SetMethodsMessage
|
||||
| SetModeledMethodsMessage
|
||||
| SetModifiedMethodsMessage
|
||||
| SetInProgressMethodsMessage;
|
||||
| SetInProgressMethodsMessage
|
||||
| RevealMethodMessage;
|
||||
|
||||
export type FromModelEditorMessage =
|
||||
| ViewLoadedMsg
|
||||
@@ -597,9 +605,15 @@ export type FromModelEditorMessage =
|
||||
| HideModeledMethodsMessage
|
||||
| SetModeledMethodMessage;
|
||||
|
||||
interface RevealInEditorMessage {
|
||||
t: "revealInModelEditor";
|
||||
method: Method;
|
||||
}
|
||||
|
||||
export type FromMethodModelingMessage =
|
||||
| CommonFromViewMessages
|
||||
| SetModeledMethodMessage;
|
||||
| SetModeledMethodMessage
|
||||
| RevealInEditorMessage;
|
||||
|
||||
interface SetMethodMessage {
|
||||
t: "setMethod";
|
||||
|
||||
@@ -17,7 +17,7 @@ export enum RequestKind {
|
||||
AutoModel = "autoModel",
|
||||
}
|
||||
|
||||
interface BasicErorResponse {
|
||||
export interface BasicErrorResponse {
|
||||
message: string;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ interface GetRepoRequest {
|
||||
};
|
||||
response: {
|
||||
status: number;
|
||||
body: Repository | BasicErorResponse | undefined;
|
||||
body: Repository | BasicErrorResponse | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ interface SubmitVariantAnalysisRequest {
|
||||
};
|
||||
response: {
|
||||
status: number;
|
||||
body?: VariantAnalysis | BasicErorResponse;
|
||||
body?: VariantAnalysis | BasicErrorResponse;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ interface GetVariantAnalysisRequest {
|
||||
};
|
||||
response: {
|
||||
status: number;
|
||||
body?: VariantAnalysis | BasicErorResponse;
|
||||
body?: VariantAnalysis | BasicErrorResponse;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ interface GetVariantAnalysisRepoRequest {
|
||||
};
|
||||
response: {
|
||||
status: number;
|
||||
body?: VariantAnalysisRepoTask | BasicErorResponse;
|
||||
body?: VariantAnalysisRepoTask | BasicErrorResponse;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -74,6 +74,13 @@ export interface GetVariantAnalysisRepoResultRequest {
|
||||
};
|
||||
}
|
||||
|
||||
export interface CodeSearchResponse {
|
||||
total_count: number;
|
||||
items: Array<{
|
||||
repository: Repository;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface CodeSearchRequest {
|
||||
request: {
|
||||
kind: RequestKind.CodeSearch;
|
||||
@@ -81,16 +88,14 @@ interface CodeSearchRequest {
|
||||
};
|
||||
response: {
|
||||
status: number;
|
||||
body?: {
|
||||
total_count?: number;
|
||||
items?: Array<{
|
||||
repository: Repository;
|
||||
}>;
|
||||
};
|
||||
message?: string;
|
||||
body?: CodeSearchResponse | BasicErrorResponse;
|
||||
};
|
||||
}
|
||||
|
||||
export interface AutoModelResponse {
|
||||
models: string;
|
||||
}
|
||||
|
||||
interface AutoModelRequest {
|
||||
request: {
|
||||
kind: RequestKind.AutoModel;
|
||||
@@ -100,10 +105,7 @@ interface AutoModelRequest {
|
||||
};
|
||||
response: {
|
||||
status: number;
|
||||
body?: {
|
||||
models: string;
|
||||
};
|
||||
message?: string;
|
||||
body?: AutoModelResponse | BasicErrorResponse;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,30 +1,33 @@
|
||||
import { ensureDir, writeFile } from "fs-extra";
|
||||
import { join } from "path";
|
||||
|
||||
import { MockedRequest } from "msw";
|
||||
import { SetupServer } from "msw/node";
|
||||
import { IsomorphicResponse } from "@mswjs/interceptors";
|
||||
|
||||
import { Headers } from "headers-polyfill";
|
||||
import fetch from "node-fetch";
|
||||
import { SetupServer } from "msw/node";
|
||||
|
||||
import { DisposableObject } from "../disposable-object";
|
||||
import { gzipDecode } from "../zlib";
|
||||
|
||||
import {
|
||||
AutoModelResponse,
|
||||
BasicErrorResponse,
|
||||
CodeSearchResponse,
|
||||
GetVariantAnalysisRepoResultRequest,
|
||||
GitHubApiRequest,
|
||||
RequestKind,
|
||||
} from "./gh-api-request";
|
||||
import {
|
||||
VariantAnalysis,
|
||||
VariantAnalysisRepoTask,
|
||||
} from "../../variant-analysis/gh-api/variant-analysis";
|
||||
import { Repository } from "../../variant-analysis/gh-api/repository";
|
||||
|
||||
export class Recorder extends DisposableObject {
|
||||
private readonly allRequests = new Map<string, MockedRequest>();
|
||||
private currentRecordedScenario: GitHubApiRequest[] = [];
|
||||
|
||||
private _isRecording = false;
|
||||
|
||||
constructor(private readonly server: SetupServer) {
|
||||
super();
|
||||
this.onRequestStart = this.onRequestStart.bind(this);
|
||||
this.onResponseBypass = this.onResponseBypass.bind(this);
|
||||
}
|
||||
|
||||
@@ -45,7 +48,6 @@ export class Recorder extends DisposableObject {
|
||||
|
||||
this.clear();
|
||||
|
||||
this.server.events.on("request:start", this.onRequestStart);
|
||||
this.server.events.on("response:bypass", this.onResponseBypass);
|
||||
}
|
||||
|
||||
@@ -56,13 +58,11 @@ export class Recorder extends DisposableObject {
|
||||
|
||||
this._isRecording = false;
|
||||
|
||||
this.server.events.removeListener("request:start", this.onRequestStart);
|
||||
this.server.events.removeListener("response:bypass", this.onResponseBypass);
|
||||
}
|
||||
|
||||
public clear() {
|
||||
this.currentRecordedScenario = [];
|
||||
this.allRequests.clear();
|
||||
}
|
||||
|
||||
public async save(scenariosPath: string, name: string): Promise<string> {
|
||||
@@ -91,7 +91,7 @@ export class Recorder extends DisposableObject {
|
||||
|
||||
let bodyFileLink = undefined;
|
||||
if (writtenRequest.response.body) {
|
||||
await writeFile(bodyFilePath, writtenRequest.response.body || "");
|
||||
await writeFile(bodyFilePath, writtenRequest.response.body);
|
||||
bodyFileLink = `file:${bodyFileName}`;
|
||||
}
|
||||
|
||||
@@ -112,33 +112,18 @@ export class Recorder extends DisposableObject {
|
||||
return scenarioDirectory;
|
||||
}
|
||||
|
||||
private onRequestStart(request: MockedRequest): void {
|
||||
private async onResponseBypass(
|
||||
response: Response,
|
||||
request: Request,
|
||||
_requestId: string,
|
||||
): Promise<void> {
|
||||
if (request.headers.has("x-vscode-codeql-msw-bypass")) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.allRequests.set(request.id, request);
|
||||
}
|
||||
|
||||
private async onResponseBypass(
|
||||
response: IsomorphicResponse,
|
||||
requestId: string,
|
||||
): Promise<void> {
|
||||
const request = this.allRequests.get(requestId);
|
||||
this.allRequests.delete(requestId);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.body === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const gitHubApiRequest = await createGitHubApiRequest(
|
||||
request.url.toString(),
|
||||
response.status,
|
||||
response.body,
|
||||
response.headers,
|
||||
request.url,
|
||||
response,
|
||||
);
|
||||
if (!gitHubApiRequest) {
|
||||
return;
|
||||
@@ -150,14 +135,14 @@ export class Recorder extends DisposableObject {
|
||||
|
||||
async function createGitHubApiRequest(
|
||||
url: string,
|
||||
status: number,
|
||||
body: string,
|
||||
headers: Headers,
|
||||
response: Response,
|
||||
): Promise<GitHubApiRequest | undefined> {
|
||||
if (!url) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const status = response.status;
|
||||
|
||||
if (url.match(/\/repos\/[a-zA-Z0-9-_.]+\/[a-zA-Z0-9-_.]+$/)) {
|
||||
return {
|
||||
request: {
|
||||
@@ -165,7 +150,9 @@ async function createGitHubApiRequest(
|
||||
},
|
||||
response: {
|
||||
status,
|
||||
body: JSON.parse(body),
|
||||
body: await jsonResponseBody<
|
||||
Repository | BasicErrorResponse | undefined
|
||||
>(response),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -179,7 +166,9 @@ async function createGitHubApiRequest(
|
||||
},
|
||||
response: {
|
||||
status,
|
||||
body: JSON.parse(body),
|
||||
body: await jsonResponseBody<
|
||||
VariantAnalysis | BasicErrorResponse | undefined
|
||||
>(response),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -195,7 +184,9 @@ async function createGitHubApiRequest(
|
||||
},
|
||||
response: {
|
||||
status,
|
||||
body: JSON.parse(body),
|
||||
body: await jsonResponseBody<
|
||||
VariantAnalysis | BasicErrorResponse | undefined
|
||||
>(response),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -211,7 +202,9 @@ async function createGitHubApiRequest(
|
||||
},
|
||||
response: {
|
||||
status,
|
||||
body: JSON.parse(body),
|
||||
body: await jsonResponseBody<
|
||||
VariantAnalysisRepoTask | BasicErrorResponse | undefined
|
||||
>(response),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -238,9 +231,10 @@ async function createGitHubApiRequest(
|
||||
repositoryId: parseInt(repoDownloadMatch.groups.repositoryId, 10),
|
||||
},
|
||||
response: {
|
||||
status,
|
||||
status: response.status,
|
||||
body: responseBuffer,
|
||||
contentType: headers.get("content-type") ?? "application/octet-stream",
|
||||
contentType:
|
||||
response.headers.get("content-type") ?? "application/octet-stream",
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -254,7 +248,9 @@ async function createGitHubApiRequest(
|
||||
},
|
||||
response: {
|
||||
status,
|
||||
body: JSON.parse(body),
|
||||
body: await jsonResponseBody<
|
||||
CodeSearchResponse | BasicErrorResponse | undefined
|
||||
>(response),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -269,7 +265,9 @@ async function createGitHubApiRequest(
|
||||
},
|
||||
response: {
|
||||
status,
|
||||
body: JSON.parse(body),
|
||||
body: await jsonResponseBody<
|
||||
BasicErrorResponse | AutoModelResponse | undefined
|
||||
>(response),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -277,6 +275,26 @@ async function createGitHubApiRequest(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function responseBody(response: Response): Promise<Uint8Array> {
|
||||
const body = await response.arrayBuffer();
|
||||
const view = new Uint8Array(body);
|
||||
|
||||
if (view[0] === 0x1f && view[1] === 0x8b) {
|
||||
// Response body is gzipped, so we need to un-gzip it.
|
||||
|
||||
return await gzipDecode(view);
|
||||
} else {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
async function jsonResponseBody<T>(response: Response): Promise<T> {
|
||||
const body = await responseBody(response);
|
||||
const text = new TextDecoder("utf-8").decode(body);
|
||||
|
||||
return JSON.parse(text);
|
||||
}
|
||||
|
||||
function shouldWriteBodyToFile(
|
||||
request: GitHubApiRequest,
|
||||
): request is GetVariantAnalysisRepoResultRequest {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { join } from "path";
|
||||
import { readdir, readJson, readFile } from "fs-extra";
|
||||
import { DefaultBodyType, MockedRequest, rest, RestHandler } from "msw";
|
||||
import { RequestHandler, rest } from "msw";
|
||||
import {
|
||||
GitHubApiRequest,
|
||||
isAutoModelRequest,
|
||||
@@ -14,7 +14,19 @@ import {
|
||||
|
||||
const baseUrl = "https://api.github.com";
|
||||
|
||||
type RequestHandler = RestHandler<MockedRequest<DefaultBodyType>>;
|
||||
const jsonResponse = <T>(
|
||||
body: T,
|
||||
init?: ResponseInit,
|
||||
contentType = "application/json",
|
||||
): Response => {
|
||||
return new Response(JSON.stringify(body), {
|
||||
...init,
|
||||
headers: {
|
||||
"Content-Type": contentType,
|
||||
...init?.headers,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export async function createRequestHandlers(
|
||||
scenarioDirPath: string,
|
||||
@@ -82,11 +94,10 @@ function createGetRepoRequestHandler(
|
||||
|
||||
const getRepoRequest = getRepoRequests[0];
|
||||
|
||||
return rest.get(`${baseUrl}/repos/:owner/:name`, (_req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(getRepoRequest.response.status),
|
||||
ctx.json(getRepoRequest.response.body),
|
||||
);
|
||||
return rest.get(`${baseUrl}/repos/:owner/:name`, () => {
|
||||
return jsonResponse(getRepoRequest.response.body, {
|
||||
status: getRepoRequest.response.status,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -105,11 +116,10 @@ function createSubmitVariantAnalysisRequestHandler(
|
||||
|
||||
return rest.post(
|
||||
`${baseUrl}/repositories/:controllerRepoId/code-scanning/codeql/variant-analyses`,
|
||||
(_req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(getRepoRequest.response.status),
|
||||
ctx.json(getRepoRequest.response.body),
|
||||
);
|
||||
() => {
|
||||
return jsonResponse(getRepoRequest.response.body, {
|
||||
status: getRepoRequest.response.status,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -127,7 +137,7 @@ function createGetVariantAnalysisRequestHandler(
|
||||
// request, so keep an index of the request and return the appropriate response.
|
||||
return rest.get(
|
||||
`${baseUrl}/repositories/:controllerRepoId/code-scanning/codeql/variant-analyses/:variantAnalysisId`,
|
||||
(_req, res, ctx) => {
|
||||
() => {
|
||||
const request = getVariantAnalysisRequests[requestIndex];
|
||||
|
||||
if (requestIndex < getVariantAnalysisRequests.length - 1) {
|
||||
@@ -135,10 +145,9 @@ function createGetVariantAnalysisRequestHandler(
|
||||
requestIndex++;
|
||||
}
|
||||
|
||||
return res(
|
||||
ctx.status(request.response.status),
|
||||
ctx.json(request.response.body),
|
||||
);
|
||||
return jsonResponse(request.response.body, {
|
||||
status: request.response.status,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -152,18 +161,17 @@ function createGetVariantAnalysisRepoRequestHandler(
|
||||
|
||||
return rest.get(
|
||||
`${baseUrl}/repositories/:controllerRepoId/code-scanning/codeql/variant-analyses/:variantAnalysisId/repositories/:repoId`,
|
||||
(req, res, ctx) => {
|
||||
({ request, params }) => {
|
||||
const scenarioRequest = getVariantAnalysisRepoRequests.find(
|
||||
(r) => r.request.repositoryId.toString() === req.params.repoId,
|
||||
(r) => r.request.repositoryId.toString() === params.repoId,
|
||||
);
|
||||
if (!scenarioRequest) {
|
||||
throw Error(`No scenario request found for ${req.url}`);
|
||||
throw Error(`No scenario request found for ${request.url}`);
|
||||
}
|
||||
|
||||
return res(
|
||||
ctx.status(scenarioRequest.response.status),
|
||||
ctx.json(scenarioRequest.response.body),
|
||||
);
|
||||
return jsonResponse(scenarioRequest.response.body, {
|
||||
status: scenarioRequest.response.status,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -177,22 +185,23 @@ function createGetVariantAnalysisRepoResultRequestHandler(
|
||||
|
||||
return rest.get(
|
||||
"https://objects-origin.githubusercontent.com/codeql-query-console/codeql-variant-analysis-repo-tasks/:variantAnalysisId/:repoId/*",
|
||||
(req, res, ctx) => {
|
||||
({ request, params }) => {
|
||||
const scenarioRequest = getVariantAnalysisRepoResultRequests.find(
|
||||
(r) => r.request.repositoryId.toString() === req.params.repoId,
|
||||
(r) => r.request.repositoryId.toString() === params.repoId,
|
||||
);
|
||||
if (!scenarioRequest) {
|
||||
throw Error(`No scenario request found for ${req.url}`);
|
||||
throw Error(`No scenario request found for ${request.url}`);
|
||||
}
|
||||
|
||||
if (scenarioRequest.response.body) {
|
||||
return res(
|
||||
ctx.status(scenarioRequest.response.status),
|
||||
ctx.set("Content-Type", scenarioRequest.response.contentType),
|
||||
ctx.body(scenarioRequest.response.body),
|
||||
);
|
||||
return new Response(scenarioRequest.response.body, {
|
||||
status: scenarioRequest.response.status,
|
||||
headers: {
|
||||
"Content-Type": scenarioRequest.response.contentType,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
return res(ctx.status(scenarioRequest.response.status));
|
||||
return new Response(null, { status: scenarioRequest.response.status });
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -207,7 +216,7 @@ function createCodeSearchRequestHandler(
|
||||
// During a code search, there are multiple request to get pages of results. We
|
||||
// need to return different responses for each request, so keep an index of the
|
||||
// request and return the appropriate response.
|
||||
return rest.get(`${baseUrl}/search/code?q=*`, (_req, res, ctx) => {
|
||||
return rest.get(`${baseUrl}/search/code`, () => {
|
||||
const request = codeSearchRequests[requestIndex];
|
||||
|
||||
if (requestIndex < codeSearchRequests.length - 1) {
|
||||
@@ -215,10 +224,9 @@ function createCodeSearchRequestHandler(
|
||||
requestIndex++;
|
||||
}
|
||||
|
||||
return res(
|
||||
ctx.status(request.response.status),
|
||||
ctx.json(request.response.body),
|
||||
);
|
||||
return jsonResponse(request.response.body, {
|
||||
status: request.response.status,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -233,7 +241,7 @@ function createAutoModelRequestHandler(
|
||||
// so keep an index of the request and return the appropriate response.
|
||||
return rest.post(
|
||||
`${baseUrl}/repos/github/codeql/code-scanning/codeql/auto-model`,
|
||||
(_req, res, ctx) => {
|
||||
() => {
|
||||
const request = autoModelRequests[requestIndex];
|
||||
|
||||
if (requestIndex < autoModelRequests.length - 1) {
|
||||
@@ -241,10 +249,9 @@ function createAutoModelRequestHandler(
|
||||
requestIndex++;
|
||||
}
|
||||
|
||||
return res(
|
||||
ctx.status(request.response.status),
|
||||
ctx.json(request.response.body),
|
||||
);
|
||||
return jsonResponse(request.response.body, {
|
||||
status: request.response.status,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
10
extensions/ql-vscode/src/common/octokit.ts
Normal file
10
extensions/ql-vscode/src/common/octokit.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import * as Octokit from "@octokit/rest";
|
||||
import { retry } from "@octokit/plugin-retry";
|
||||
import fetch from "node-fetch";
|
||||
|
||||
export const AppOctokit = Octokit.Octokit.defaults({
|
||||
request: {
|
||||
fetch,
|
||||
},
|
||||
retry,
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as Octokit from "@octokit/rest";
|
||||
import { retry } from "@octokit/plugin-retry";
|
||||
import { Credentials } from "../authentication";
|
||||
import { AppOctokit } from "../octokit";
|
||||
|
||||
export const GITHUB_AUTH_PROVIDER_ID = "github";
|
||||
|
||||
@@ -32,9 +32,8 @@ export class VSCodeCredentials implements Credentials {
|
||||
|
||||
const accessToken = await this.getAccessToken();
|
||||
|
||||
return new Octokit.Octokit({
|
||||
return new AppOctokit({
|
||||
auth: accessToken,
|
||||
retry,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { retry } from "@octokit/plugin-retry";
|
||||
import { throttling } from "@octokit/plugin-throttling";
|
||||
import { Octokit } from "@octokit/rest";
|
||||
import { Progress, CancellationToken } from "vscode";
|
||||
import { Credentials } from "../common/authentication";
|
||||
import { BaseLogger } from "../common/logging";
|
||||
import { AppOctokit } from "../common/octokit";
|
||||
|
||||
export async function getCodeSearchRepositories(
|
||||
query: string,
|
||||
@@ -46,12 +46,11 @@ async function provideOctokitWithThrottling(
|
||||
credentials: Credentials,
|
||||
logger: BaseLogger,
|
||||
): Promise<Octokit> {
|
||||
const MyOctokit = Octokit.plugin(throttling);
|
||||
const MyOctokit = AppOctokit.plugin(throttling);
|
||||
const auth = await credentials.getAccessToken();
|
||||
|
||||
const octokit = new MyOctokit({
|
||||
auth,
|
||||
retry,
|
||||
throttle: {
|
||||
onRateLimit: (retryAfter: number, options: any): boolean => {
|
||||
void logger.log(
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
} from "fs-extra";
|
||||
import { basename, join } from "path";
|
||||
import * as Octokit from "@octokit/rest";
|
||||
import { retry } from "@octokit/plugin-retry";
|
||||
|
||||
import { DatabaseManager, DatabaseItem } from "./local-databases";
|
||||
import { tmpDir } from "../tmp-dir";
|
||||
@@ -32,6 +31,7 @@ import { Credentials } from "../common/authentication";
|
||||
import { AppCommandManager } from "../common/commands";
|
||||
import { allowHttp } from "../config";
|
||||
import { showAndLogInformationMessage } from "../common/logging";
|
||||
import { AppOctokit } from "../common/octokit";
|
||||
|
||||
/**
|
||||
* Prompts a user to fetch a database from a remote location. Database is assumed to be an archive file.
|
||||
@@ -186,7 +186,7 @@ export async function downloadGitHubDatabase(
|
||||
|
||||
const octokit = credentials
|
||||
? await credentials.getOctokit()
|
||||
: new Octokit.Octokit({ retry });
|
||||
: new AppOctokit();
|
||||
|
||||
const result = await convertGithubNwoToDatabaseUrl(
|
||||
nwo,
|
||||
|
||||
@@ -49,6 +49,7 @@ import { LocalQueryRun } from "./local-query-run";
|
||||
import { createMultiSelectionCommand } from "../common/vscode/selection-commands";
|
||||
import { findLanguage } from "../codeql-cli/query-language";
|
||||
import type { QueryTreeViewItem } from "../queries-panel/query-tree-view-item";
|
||||
import { tryGetQueryLanguage } from "../common/query-language";
|
||||
|
||||
interface DatabaseQuickPickItem extends QuickPickItem {
|
||||
databaseItem: DatabaseItem;
|
||||
@@ -364,6 +365,7 @@ export class LocalQueries extends DisposableObject {
|
||||
const initialInfo = await createInitialQueryInfo(selectedQuery, {
|
||||
databaseUri: dbItem.databaseUri.toString(),
|
||||
name: dbItem.name,
|
||||
language: tryGetQueryLanguage(dbItem.language),
|
||||
});
|
||||
|
||||
// When cancellation is requested from the query history view, we just stop the debug session.
|
||||
|
||||
@@ -4,14 +4,23 @@ import { DisposableObject } from "../../common/disposable-object";
|
||||
import { MethodModelingViewProvider } from "./method-modeling-view-provider";
|
||||
import { Method } from "../method";
|
||||
import { ModelingStore } from "../modeling-store";
|
||||
import { ModelEditorViewTracker } from "../model-editor-view-tracker";
|
||||
|
||||
export class MethodModelingPanel extends DisposableObject {
|
||||
private readonly provider: MethodModelingViewProvider;
|
||||
|
||||
constructor(app: App, modelingStore: ModelingStore) {
|
||||
constructor(
|
||||
app: App,
|
||||
modelingStore: ModelingStore,
|
||||
editorViewTracker: ModelEditorViewTracker,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.provider = new MethodModelingViewProvider(app, modelingStore);
|
||||
this.provider = new MethodModelingViewProvider(
|
||||
app,
|
||||
modelingStore,
|
||||
editorViewTracker,
|
||||
);
|
||||
this.push(
|
||||
window.registerWebviewViewProvider(
|
||||
MethodModelingViewProvider.viewType,
|
||||
|
||||
@@ -8,8 +8,10 @@ import { extLogger } from "../../common/logging/vscode/loggers";
|
||||
import { App } from "../../common/app";
|
||||
import { redactableError } from "../../common/errors";
|
||||
import { Method } from "../method";
|
||||
import { ModelingStore } from "../modeling-store";
|
||||
import { DbModelingState, ModelingStore } from "../modeling-store";
|
||||
import { AbstractWebviewViewProvider } from "../../common/vscode/abstract-webview-view-provider";
|
||||
import { assertNever } from "../../common/helpers-pure";
|
||||
import { ModelEditorViewTracker } from "../model-editor-view-tracker";
|
||||
|
||||
export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
|
||||
ToMethodModelingMessage,
|
||||
@@ -22,6 +24,7 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
|
||||
constructor(
|
||||
app: App,
|
||||
private readonly modelingStore: ModelingStore,
|
||||
private readonly editorViewTracker: ModelEditorViewTracker,
|
||||
) {
|
||||
super(app, "method-modeling");
|
||||
}
|
||||
@@ -77,19 +80,45 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
|
||||
break;
|
||||
|
||||
case "setModeledMethod": {
|
||||
const activeState = this.modelingStore.getStateForActiveDb();
|
||||
if (!activeState) {
|
||||
throw new Error("No active state found in modeling store");
|
||||
}
|
||||
const activeState = this.ensureActiveState();
|
||||
|
||||
this.modelingStore.updateModeledMethod(
|
||||
activeState.databaseItem,
|
||||
msg.method,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "revealInModelEditor":
|
||||
await this.revealInModelEditor(msg.method);
|
||||
|
||||
break;
|
||||
default:
|
||||
assertNever(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private async revealInModelEditor(method: Method): Promise<void> {
|
||||
const activeState = this.ensureActiveState();
|
||||
|
||||
const views = this.editorViewTracker.getViews(
|
||||
activeState.databaseItem.databaseUri.toString(),
|
||||
);
|
||||
if (views.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all(views.map((view) => view.revealMethod(method)));
|
||||
}
|
||||
|
||||
private ensureActiveState(): DbModelingState {
|
||||
const activeState = this.modelingStore.getStateForActiveDb();
|
||||
if (!activeState) {
|
||||
throw new Error("No active state found in modeling store");
|
||||
}
|
||||
|
||||
return activeState;
|
||||
}
|
||||
|
||||
private registerToModelingStoreEvents(): void {
|
||||
this.push(
|
||||
this.modelingStore.onModeledMethodsChanged(async (e) => {
|
||||
|
||||
@@ -20,12 +20,14 @@ import { setUpPack } from "./model-editor-queries";
|
||||
import { MethodModelingPanel } from "./method-modeling/method-modeling-panel";
|
||||
import { ModelingStore } from "./modeling-store";
|
||||
import { showResolvableLocation } from "../databases/local-databases/locations";
|
||||
import { ModelEditorViewTracker } from "./model-editor-view-tracker";
|
||||
|
||||
const SUPPORTED_LANGUAGES: string[] = ["java", "csharp"];
|
||||
|
||||
export class ModelEditorModule extends DisposableObject {
|
||||
private readonly queryStorageDir: string;
|
||||
private readonly modelingStore: ModelingStore;
|
||||
private readonly editorViewTracker: ModelEditorViewTracker<ModelEditorView>;
|
||||
private readonly methodsUsagePanel: MethodsUsagePanel;
|
||||
private readonly methodModelingPanel: MethodModelingPanel;
|
||||
|
||||
@@ -39,11 +41,12 @@ export class ModelEditorModule extends DisposableObject {
|
||||
super();
|
||||
this.queryStorageDir = join(baseQueryStorageDir, "model-editor-results");
|
||||
this.modelingStore = new ModelingStore(app);
|
||||
this.editorViewTracker = new ModelEditorViewTracker();
|
||||
this.methodsUsagePanel = this.push(
|
||||
new MethodsUsagePanel(this.modelingStore, cliServer),
|
||||
);
|
||||
this.methodModelingPanel = this.push(
|
||||
new MethodModelingPanel(app, this.modelingStore),
|
||||
new MethodModelingPanel(app, this.modelingStore, this.editorViewTracker),
|
||||
);
|
||||
|
||||
this.registerToModelingStoreEvents();
|
||||
@@ -148,6 +151,7 @@ export class ModelEditorModule extends DisposableObject {
|
||||
const view = new ModelEditorView(
|
||||
this.app,
|
||||
this.modelingStore,
|
||||
this.editorViewTracker,
|
||||
this.databaseManager,
|
||||
this.cliServer,
|
||||
this.queryRunner,
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Method } from "./method";
|
||||
|
||||
interface ModelEditorViewInterface {
|
||||
databaseUri: string;
|
||||
|
||||
revealMethod(method: Method): Promise<void>;
|
||||
}
|
||||
|
||||
export class ModelEditorViewTracker<
|
||||
T extends ModelEditorViewInterface = ModelEditorViewInterface,
|
||||
> {
|
||||
private readonly views = new Map<string, T[]>();
|
||||
|
||||
constructor() {}
|
||||
|
||||
public registerView(view: T): void {
|
||||
const databaseUri = view.databaseUri;
|
||||
|
||||
if (!this.views.has(databaseUri)) {
|
||||
this.views.set(databaseUri, []);
|
||||
}
|
||||
|
||||
this.views.get(databaseUri)?.push(view);
|
||||
}
|
||||
|
||||
public unregisterView(view: T): void {
|
||||
const views = this.views.get(view.databaseUri);
|
||||
if (!views) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = views.indexOf(view);
|
||||
if (index !== -1) {
|
||||
views.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public getViews(databaseUri: string): T[] {
|
||||
return this.views.get(databaseUri) ?? [];
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ import { getLanguageDisplayName } from "../common/query-language";
|
||||
import { AutoModeler } from "./auto-modeler";
|
||||
import { telemetryListener } from "../common/vscode/telemetry";
|
||||
import { ModelingStore } from "./modeling-store";
|
||||
import { ModelEditorViewTracker } from "./model-editor-view-tracker";
|
||||
|
||||
export class ModelEditorView extends AbstractWebview<
|
||||
ToModelEditorMessage,
|
||||
@@ -52,6 +53,7 @@ export class ModelEditorView extends AbstractWebview<
|
||||
public constructor(
|
||||
protected readonly app: App,
|
||||
private readonly modelingStore: ModelingStore,
|
||||
private readonly viewTracker: ModelEditorViewTracker<ModelEditorView>,
|
||||
private readonly databaseManager: DatabaseManager,
|
||||
private readonly cliServer: CodeQLCliServer,
|
||||
private readonly queryRunner: QueryRunner,
|
||||
@@ -66,6 +68,8 @@ export class ModelEditorView extends AbstractWebview<
|
||||
this.modelingStore.initializeStateForDb(databaseItem);
|
||||
this.registerToModelingStoreEvents();
|
||||
|
||||
this.viewTracker.registerView(this);
|
||||
|
||||
this.autoModeler = new AutoModeler(
|
||||
app,
|
||||
cliServer,
|
||||
@@ -181,7 +185,7 @@ export class ModelEditorView extends AbstractWebview<
|
||||
}
|
||||
|
||||
protected onPanelDispose(): void {
|
||||
// Nothing to do here
|
||||
this.viewTracker.unregisterView(this);
|
||||
}
|
||||
|
||||
protected async onMessage(msg: FromModelEditorMessage): Promise<void> {
|
||||
@@ -338,6 +342,19 @@ export class ModelEditorView extends AbstractWebview<
|
||||
]);
|
||||
}
|
||||
|
||||
public get databaseUri(): string {
|
||||
return this.databaseItem.databaseUri.toString();
|
||||
}
|
||||
|
||||
public async revealMethod(method: Method): Promise<void> {
|
||||
this.panel?.reveal();
|
||||
|
||||
await this.postMessage({
|
||||
t: "revealMethod",
|
||||
method,
|
||||
});
|
||||
}
|
||||
|
||||
private async setViewState(): Promise<void> {
|
||||
const showLlmButton =
|
||||
this.databaseItem.language === "java" && showLlmGeneration();
|
||||
@@ -497,6 +514,7 @@ export class ModelEditorView extends AbstractWebview<
|
||||
const view = new ModelEditorView(
|
||||
this.app,
|
||||
this.modelingStore,
|
||||
this.viewTracker,
|
||||
this.databaseManager,
|
||||
this.cliServer,
|
||||
this.queryRunner,
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Method, Usage } from "./method";
|
||||
import { ModeledMethod } from "./modeled-method";
|
||||
import { INITIAL_HIDE_MODELED_METHODS_VALUE } from "./shared/hide-modeled-methods";
|
||||
|
||||
interface DbModelingState {
|
||||
export interface DbModelingState {
|
||||
databaseItem: DatabaseItem;
|
||||
methods: Method[];
|
||||
hideModeledMethods: boolean;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { QueryHistoryConfig } from "../config";
|
||||
import { LocalQueryInfo } from "../query-results";
|
||||
import {
|
||||
buildRepoLabel,
|
||||
getLanguage,
|
||||
getRawQueryName,
|
||||
QueryHistoryInfo,
|
||||
} from "./query-history-info";
|
||||
@@ -19,6 +20,7 @@ interface InterpolateReplacements {
|
||||
r: string; // Result count/Empty
|
||||
s: string; // Status
|
||||
f: string; // Query file name
|
||||
l: string; // Query language
|
||||
"%": "%"; // Percent sign
|
||||
}
|
||||
|
||||
@@ -84,6 +86,7 @@ export class HistoryItemLabelProvider {
|
||||
r: `(${resultCount} results)`,
|
||||
s: statusString,
|
||||
f: item.getQueryFileName(),
|
||||
l: this.getLanguageLabel(item),
|
||||
"%": "%",
|
||||
};
|
||||
}
|
||||
@@ -103,7 +106,13 @@ export class HistoryItemLabelProvider {
|
||||
r: resultCount,
|
||||
s: humanizeQueryStatus(item.status),
|
||||
f: basename(item.variantAnalysis.query.filePath),
|
||||
l: this.getLanguageLabel(item),
|
||||
"%": "%",
|
||||
};
|
||||
}
|
||||
|
||||
private getLanguageLabel(item: QueryHistoryInfo): string {
|
||||
const language = getLanguage(item);
|
||||
return language === undefined ? "unknown" : `${language}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
hasRepoScanCompleted,
|
||||
getActionsWorkflowRunUrl as getVariantAnalysisActionsWorkflowRunUrl,
|
||||
} from "../variant-analysis/shared/variant-analysis";
|
||||
import { QueryLanguage } from "../common/query-language";
|
||||
|
||||
export type QueryHistoryInfo = LocalQueryInfo | VariantAnalysisHistoryItem;
|
||||
|
||||
@@ -49,6 +50,17 @@ export function getQueryText(item: QueryHistoryInfo): string {
|
||||
}
|
||||
}
|
||||
|
||||
export function getLanguage(item: QueryHistoryInfo): QueryLanguage | undefined {
|
||||
switch (item.t) {
|
||||
case "local":
|
||||
return item.initialInfo.databaseInfo.language;
|
||||
case "variant-analysis":
|
||||
return item.variantAnalysis.query.language;
|
||||
default:
|
||||
assertNever(item);
|
||||
}
|
||||
}
|
||||
|
||||
export function buildRepoLabel(item: VariantAnalysisHistoryItem): string {
|
||||
const totalScannedRepositoryCount =
|
||||
item.variantAnalysis.scannedRepos?.length ?? 0;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { assertNever } from "../../common/helpers-pure";
|
||||
import { QueryHistoryInfo } from "../query-history-info";
|
||||
import { mapLocalQueryInfoToDto } from "./query-history-local-query-domain-mapper";
|
||||
import { QueryHistoryItemDto } from "./query-history-dto";
|
||||
import { QueryHistoryItemDto, QueryLanguageDto } from "./query-history-dto";
|
||||
import { mapQueryHistoryVariantAnalysisToDto } from "./query-history-variant-analysis-domain-mapper";
|
||||
import { QueryLanguage } from "../../common/query-language";
|
||||
|
||||
export function mapQueryHistoryToDto(
|
||||
queries: QueryHistoryInfo[],
|
||||
@@ -17,3 +18,28 @@ export function mapQueryHistoryToDto(
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function mapQueryLanguageToDto(
|
||||
language: QueryLanguage,
|
||||
): QueryLanguageDto {
|
||||
switch (language) {
|
||||
case QueryLanguage.CSharp:
|
||||
return QueryLanguageDto.CSharp;
|
||||
case QueryLanguage.Cpp:
|
||||
return QueryLanguageDto.Cpp;
|
||||
case QueryLanguage.Go:
|
||||
return QueryLanguageDto.Go;
|
||||
case QueryLanguage.Java:
|
||||
return QueryLanguageDto.Java;
|
||||
case QueryLanguage.Javascript:
|
||||
return QueryLanguageDto.Javascript;
|
||||
case QueryLanguage.Python:
|
||||
return QueryLanguageDto.Python;
|
||||
case QueryLanguage.Ruby:
|
||||
return QueryLanguageDto.Ruby;
|
||||
case QueryLanguage.Swift:
|
||||
return QueryLanguageDto.Swift;
|
||||
default:
|
||||
assertNever(language);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { QueryHistoryInfo } from "../query-history-info";
|
||||
import { QueryHistoryItemDto } from "./query-history-dto";
|
||||
import { QueryHistoryItemDto, QueryLanguageDto } from "./query-history-dto";
|
||||
import { mapQueryHistoryVariantAnalysisToDomainModel } from "./query-history-variant-analysis-dto-mapper";
|
||||
import { mapLocalQueryItemToDomainModel } from "./query-history-local-query-dto-mapper";
|
||||
import { QueryLanguage } from "../../common/query-language";
|
||||
import { assertNever } from "../../common/helpers-pure";
|
||||
|
||||
export function mapQueryHistoryToDomainModel(
|
||||
queries: QueryHistoryItemDto[],
|
||||
@@ -20,3 +22,28 @@ export function mapQueryHistoryToDomainModel(
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function mapQueryLanguageToDomainModel(
|
||||
language: QueryLanguageDto,
|
||||
): QueryLanguage {
|
||||
switch (language) {
|
||||
case QueryLanguageDto.CSharp:
|
||||
return QueryLanguage.CSharp;
|
||||
case QueryLanguageDto.Cpp:
|
||||
return QueryLanguage.Cpp;
|
||||
case QueryLanguageDto.Go:
|
||||
return QueryLanguage.Go;
|
||||
case QueryLanguageDto.Java:
|
||||
return QueryLanguage.Java;
|
||||
case QueryLanguageDto.Javascript:
|
||||
return QueryLanguage.Javascript;
|
||||
case QueryLanguageDto.Python:
|
||||
return QueryLanguage.Python;
|
||||
case QueryLanguageDto.Ruby:
|
||||
return QueryLanguage.Ruby;
|
||||
case QueryLanguageDto.Swift:
|
||||
return QueryLanguage.Swift;
|
||||
default:
|
||||
assertNever(language);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,3 +12,14 @@ export interface QueryHistoryDto {
|
||||
export type QueryHistoryItemDto =
|
||||
| QueryHistoryLocalQueryDto
|
||||
| QueryHistoryVariantAnalysisDto;
|
||||
|
||||
export enum QueryLanguageDto {
|
||||
CSharp = "csharp",
|
||||
Cpp = "cpp",
|
||||
Go = "go",
|
||||
Java = "java",
|
||||
Javascript = "javascript",
|
||||
Python = "python",
|
||||
Ruby = "ruby",
|
||||
Swift = "swift",
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
SortDirection,
|
||||
SortedResultSetInfo,
|
||||
} from "../../common/interface-types";
|
||||
import { mapQueryLanguageToDto } from "./query-history-domain-mapper";
|
||||
|
||||
export function mapLocalQueryInfoToDto(
|
||||
query: LocalQueryInfo,
|
||||
@@ -101,6 +102,10 @@ function mapInitialQueryInfoToDto(
|
||||
databaseInfo: {
|
||||
databaseUri: localQueryInitialInfo.databaseInfo.databaseUri,
|
||||
name: localQueryInitialInfo.databaseInfo.name,
|
||||
language:
|
||||
localQueryInitialInfo.databaseInfo.language === undefined
|
||||
? undefined
|
||||
: mapQueryLanguageToDto(localQueryInitialInfo.databaseInfo.language),
|
||||
},
|
||||
start: localQueryInitialInfo.start,
|
||||
id: localQueryInitialInfo.id,
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
SortDirection,
|
||||
SortedResultSetInfo,
|
||||
} from "../../common/interface-types";
|
||||
import { mapQueryLanguageToDomainModel } from "./query-history-dto-mapper";
|
||||
|
||||
export function mapLocalQueryItemToDomainModel(
|
||||
localQuery: QueryHistoryLocalQueryDto,
|
||||
@@ -82,6 +83,10 @@ function mapInitialQueryInfoToDomainModel(
|
||||
databaseInfo: {
|
||||
databaseUri: initialInfo.databaseInfo.databaseUri,
|
||||
name: initialInfo.databaseInfo.name,
|
||||
language:
|
||||
initialInfo.databaseInfo.language === undefined
|
||||
? undefined
|
||||
: mapQueryLanguageToDomainModel(initialInfo.databaseInfo.language),
|
||||
},
|
||||
start: new Date(initialInfo.start),
|
||||
id: initialInfo.id,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Contains models and consts for the data we want to store in the query history store.
|
||||
// Changes to these models should be done carefully and account for backwards compatibility of data.
|
||||
|
||||
import { QueryLanguageDto } from "./query-history-dto";
|
||||
|
||||
export interface QueryHistoryLocalQueryDto {
|
||||
initialInfo: InitialQueryInfoDto;
|
||||
t: "local";
|
||||
@@ -27,6 +29,7 @@ export interface InitialQueryInfoDto {
|
||||
interface DatabaseInfoDto {
|
||||
name: string;
|
||||
databaseUri: string;
|
||||
language?: QueryLanguageDto;
|
||||
}
|
||||
|
||||
interface PositionDto {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
QueryHistoryVariantAnalysisDto,
|
||||
QueryLanguageDto,
|
||||
QueryStatusDto,
|
||||
VariantAnalysisDto,
|
||||
VariantAnalysisFailureReasonDto,
|
||||
@@ -22,9 +21,9 @@ import {
|
||||
VariantAnalysisStatus,
|
||||
} from "../../variant-analysis/shared/variant-analysis";
|
||||
import { assertNever } from "../../common/helpers-pure";
|
||||
import { QueryLanguage } from "../../common/query-language";
|
||||
import { QueryStatus } from "../query-status";
|
||||
import { VariantAnalysisHistoryItem } from "../variant-analysis-history-item";
|
||||
import { mapQueryLanguageToDto } from "./query-history-domain-mapper";
|
||||
|
||||
export function mapQueryHistoryVariantAnalysisToDto(
|
||||
item: VariantAnalysisHistoryItem,
|
||||
@@ -199,29 +198,6 @@ function mapVariantAnalysisStatusToDto(
|
||||
}
|
||||
}
|
||||
|
||||
function mapQueryLanguageToDto(language: QueryLanguage): QueryLanguageDto {
|
||||
switch (language) {
|
||||
case QueryLanguage.CSharp:
|
||||
return QueryLanguageDto.CSharp;
|
||||
case QueryLanguage.Cpp:
|
||||
return QueryLanguageDto.Cpp;
|
||||
case QueryLanguage.Go:
|
||||
return QueryLanguageDto.Go;
|
||||
case QueryLanguage.Java:
|
||||
return QueryLanguageDto.Java;
|
||||
case QueryLanguage.Javascript:
|
||||
return QueryLanguageDto.Javascript;
|
||||
case QueryLanguage.Python:
|
||||
return QueryLanguageDto.Python;
|
||||
case QueryLanguage.Ruby:
|
||||
return QueryLanguageDto.Ruby;
|
||||
case QueryLanguage.Swift:
|
||||
return QueryLanguageDto.Swift;
|
||||
default:
|
||||
assertNever(language);
|
||||
}
|
||||
}
|
||||
|
||||
function mapQueryStatusToDto(status: QueryStatus): QueryStatusDto {
|
||||
switch (status) {
|
||||
case QueryStatus.InProgress:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
QueryHistoryVariantAnalysisDto,
|
||||
QueryLanguageDto,
|
||||
QueryStatusDto,
|
||||
VariantAnalysisDto,
|
||||
VariantAnalysisFailureReasonDto,
|
||||
@@ -22,9 +21,9 @@ import {
|
||||
VariantAnalysisStatus,
|
||||
} from "../../variant-analysis/shared/variant-analysis";
|
||||
import { assertNever } from "../../common/helpers-pure";
|
||||
import { QueryLanguage } from "../../common/query-language";
|
||||
import { QueryStatus } from "../query-status";
|
||||
import { VariantAnalysisHistoryItem } from "../variant-analysis-history-item";
|
||||
import { mapQueryLanguageToDomainModel } from "./query-history-dto-mapper";
|
||||
|
||||
export function mapQueryHistoryVariantAnalysisToDomainModel(
|
||||
item: QueryHistoryVariantAnalysisDto,
|
||||
@@ -215,31 +214,6 @@ function mapVariantAnalysisStatusToDomainModel(
|
||||
}
|
||||
}
|
||||
|
||||
function mapQueryLanguageToDomainModel(
|
||||
language: QueryLanguageDto,
|
||||
): QueryLanguage {
|
||||
switch (language) {
|
||||
case QueryLanguageDto.CSharp:
|
||||
return QueryLanguage.CSharp;
|
||||
case QueryLanguageDto.Cpp:
|
||||
return QueryLanguage.Cpp;
|
||||
case QueryLanguageDto.Go:
|
||||
return QueryLanguage.Go;
|
||||
case QueryLanguageDto.Java:
|
||||
return QueryLanguage.Java;
|
||||
case QueryLanguageDto.Javascript:
|
||||
return QueryLanguage.Javascript;
|
||||
case QueryLanguageDto.Python:
|
||||
return QueryLanguage.Python;
|
||||
case QueryLanguageDto.Ruby:
|
||||
return QueryLanguage.Ruby;
|
||||
case QueryLanguageDto.Swift:
|
||||
return QueryLanguage.Swift;
|
||||
default:
|
||||
assertNever(language);
|
||||
}
|
||||
}
|
||||
|
||||
function mapQueryStatusToDomainModel(status: QueryStatusDto): QueryStatus {
|
||||
switch (status) {
|
||||
case QueryStatusDto.InProgress:
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Contains models and consts for the data we want to store in the query history store.
|
||||
// Changes to these models should be done carefully and account for backwards compatibility of data.
|
||||
|
||||
import { QueryLanguageDto } from "./query-history-dto";
|
||||
|
||||
export interface QueryHistoryVariantAnalysisDto {
|
||||
readonly t: "variant-analysis";
|
||||
failureReason?: string;
|
||||
@@ -97,17 +99,6 @@ export enum VariantAnalysisStatusDto {
|
||||
Canceled = "canceled",
|
||||
}
|
||||
|
||||
export enum QueryLanguageDto {
|
||||
CSharp = "csharp",
|
||||
Cpp = "cpp",
|
||||
Go = "go",
|
||||
Java = "java",
|
||||
Javascript = "javascript",
|
||||
Python = "python",
|
||||
Ruby = "ruby",
|
||||
Swift = "swift",
|
||||
}
|
||||
|
||||
export enum QueryStatusDto {
|
||||
InProgress = "InProgress",
|
||||
Completed = "Completed",
|
||||
|
||||
@@ -7,6 +7,7 @@ import { MethodName } from "../model-editor/MethodName";
|
||||
import { ModeledMethod } from "../../model-editor/modeled-method";
|
||||
import { MethodModelingInputs } from "./MethodModelingInputs";
|
||||
import { VSCodeTag } from "@vscode/webview-ui-toolkit/react";
|
||||
import { ReviewInEditorButton } from "./ReviewInEditorButton";
|
||||
|
||||
const Container = styled.div`
|
||||
padding: 0.3rem;
|
||||
@@ -64,6 +65,7 @@ export const MethodModeling = ({
|
||||
modeledMethod={modeledMethod}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<ReviewInEditorButton method={method} />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import * as React from "react";
|
||||
import { useCallback } from "react";
|
||||
import { styled } from "styled-components";
|
||||
import { vscode } from "../vscode-api";
|
||||
import TextButton from "../common/TextButton";
|
||||
import { Method } from "../../model-editor/method";
|
||||
|
||||
const Button = styled(TextButton)`
|
||||
margin-top: 0.5rem;
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
method: Method;
|
||||
};
|
||||
|
||||
export const ReviewInEditorButton = ({ method }: Props) => {
|
||||
const handleClick = useCallback(() => {
|
||||
vscode.postMessage({
|
||||
t: "revealInModelEditor",
|
||||
method,
|
||||
});
|
||||
}, [method]);
|
||||
|
||||
return <Button onClick={handleClick}>Review in editor</Button>;
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { styled } from "styled-components";
|
||||
import { Method } from "../../model-editor/method";
|
||||
import { ModeledMethod } from "../../model-editor/modeled-method";
|
||||
@@ -76,6 +76,7 @@ export type LibraryRowProps = {
|
||||
inProgressMethods: InProgressMethods;
|
||||
viewState: ModelEditorViewState;
|
||||
hideModeledMethods: boolean;
|
||||
revealedMethodSignature: string | null;
|
||||
onChange: (modeledMethod: ModeledMethod) => void;
|
||||
onSaveModelClick: (
|
||||
methods: Method[],
|
||||
@@ -100,6 +101,7 @@ export const LibraryRow = ({
|
||||
inProgressMethods,
|
||||
viewState,
|
||||
hideModeledMethods,
|
||||
revealedMethodSignature,
|
||||
onChange,
|
||||
onSaveModelClick,
|
||||
onGenerateFromLlmClick,
|
||||
@@ -117,6 +119,14 @@ export const LibraryRow = ({
|
||||
setExpanded((oldIsExpanded) => !oldIsExpanded);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// If any of the methods in this group is the one that should be revealed, we should expand
|
||||
// this group so the method can highlight itself.
|
||||
if (methods.some((m) => m.signature === revealedMethodSignature)) {
|
||||
setExpanded(true);
|
||||
}
|
||||
}, [methods, revealedMethodSignature]);
|
||||
|
||||
const handleModelWithAI = useCallback(
|
||||
async (e: React.MouseEvent) => {
|
||||
onGenerateFromLlmClick(title, methods, modeledMethods);
|
||||
@@ -227,6 +237,7 @@ export const LibraryRow = ({
|
||||
inProgressMethods={inProgressMethods}
|
||||
mode={viewState.mode}
|
||||
hideModeledMethods={hideModeledMethods}
|
||||
revealedMethodSignature={revealedMethodSignature}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<SectionDivider />
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
VSCodeProgressRing,
|
||||
} from "@vscode/webview-ui-toolkit/react";
|
||||
import * as React from "react";
|
||||
import { useCallback } from "react";
|
||||
import { forwardRef, useCallback, useEffect, useRef } from "react";
|
||||
import { styled } from "styled-components";
|
||||
import { vscode } from "../vscode-api";
|
||||
|
||||
@@ -47,6 +47,11 @@ const ProgressRing = styled(VSCodeProgressRing)`
|
||||
margin-left: auto;
|
||||
`;
|
||||
|
||||
const DataGridRow = styled(VSCodeDataGridRow)<{ focused?: boolean }>`
|
||||
outline: ${(props) =>
|
||||
props.focused ? "1px solid var(--vscode-focusBorder)" : "none"};
|
||||
`;
|
||||
|
||||
export type MethodRowProps = {
|
||||
method: Method;
|
||||
methodCanBeModeled: boolean;
|
||||
@@ -54,97 +59,126 @@ export type MethodRowProps = {
|
||||
methodIsUnsaved: boolean;
|
||||
modelingInProgress: boolean;
|
||||
mode: Mode;
|
||||
revealedMethodSignature: string | null;
|
||||
onChange: (modeledMethod: ModeledMethod) => void;
|
||||
};
|
||||
|
||||
export const MethodRow = (props: MethodRowProps) => {
|
||||
const { methodCanBeModeled } = props;
|
||||
const { method, methodCanBeModeled, revealedMethodSignature } = props;
|
||||
|
||||
const ref = useRef<HTMLElement>();
|
||||
|
||||
useEffect(() => {
|
||||
if (method.signature === revealedMethodSignature) {
|
||||
ref.current?.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
});
|
||||
}
|
||||
}, [method, revealedMethodSignature]);
|
||||
|
||||
if (methodCanBeModeled) {
|
||||
return <ModelableMethodRow {...props} />;
|
||||
return <ModelableMethodRow {...props} ref={ref} />;
|
||||
} else {
|
||||
return <UnmodelableMethodRow {...props} />;
|
||||
return <UnmodelableMethodRow {...props} ref={ref} />;
|
||||
}
|
||||
};
|
||||
|
||||
function ModelableMethodRow(props: MethodRowProps) {
|
||||
const { method, modeledMethod, methodIsUnsaved, mode, onChange } = props;
|
||||
const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
method,
|
||||
modeledMethod,
|
||||
methodIsUnsaved,
|
||||
mode,
|
||||
revealedMethodSignature,
|
||||
onChange,
|
||||
} = props;
|
||||
|
||||
const jumpToUsage = useCallback(
|
||||
() => sendJumpToUsageMessage(method),
|
||||
[method],
|
||||
);
|
||||
const jumpToUsage = useCallback(
|
||||
() => sendJumpToUsageMessage(method),
|
||||
[method],
|
||||
);
|
||||
|
||||
const modelingStatus = getModelingStatus(modeledMethod, methodIsUnsaved);
|
||||
const modelingStatus = getModelingStatus(modeledMethod, methodIsUnsaved);
|
||||
|
||||
return (
|
||||
<VSCodeDataGridRow data-testid="modelable-method-row">
|
||||
<ApiOrMethodCell gridColumn={1}>
|
||||
<ModelingStatusIndicator status={modelingStatus} />
|
||||
<MethodClassifications method={method} />
|
||||
<MethodName {...props.method} />
|
||||
{mode === Mode.Application && (
|
||||
<UsagesButton onClick={jumpToUsage}>
|
||||
{method.usages.length}
|
||||
</UsagesButton>
|
||||
return (
|
||||
<DataGridRow
|
||||
data-testid="modelable-method-row"
|
||||
ref={ref}
|
||||
focused={revealedMethodSignature === method.signature}
|
||||
>
|
||||
<ApiOrMethodCell gridColumn={1}>
|
||||
<ModelingStatusIndicator status={modelingStatus} />
|
||||
<MethodClassifications method={method} />
|
||||
<MethodName {...props.method} />
|
||||
{mode === Mode.Application && (
|
||||
<UsagesButton onClick={jumpToUsage}>
|
||||
{method.usages.length}
|
||||
</UsagesButton>
|
||||
)}
|
||||
<ViewLink onClick={jumpToUsage}>View</ViewLink>
|
||||
{props.modelingInProgress && <ProgressRing />}
|
||||
</ApiOrMethodCell>
|
||||
{props.modelingInProgress && (
|
||||
<>
|
||||
<VSCodeDataGridCell gridColumn={2}>
|
||||
<InProgressDropdown />
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={3}>
|
||||
<InProgressDropdown />
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={4}>
|
||||
<InProgressDropdown />
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={5}>
|
||||
<InProgressDropdown />
|
||||
</VSCodeDataGridCell>
|
||||
</>
|
||||
)}
|
||||
<ViewLink onClick={jumpToUsage}>View</ViewLink>
|
||||
{props.modelingInProgress && <ProgressRing />}
|
||||
</ApiOrMethodCell>
|
||||
{props.modelingInProgress && (
|
||||
<>
|
||||
<VSCodeDataGridCell gridColumn={2}>
|
||||
<InProgressDropdown />
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={3}>
|
||||
<InProgressDropdown />
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={4}>
|
||||
<InProgressDropdown />
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={5}>
|
||||
<InProgressDropdown />
|
||||
</VSCodeDataGridCell>
|
||||
</>
|
||||
)}
|
||||
{!props.modelingInProgress && (
|
||||
<>
|
||||
<VSCodeDataGridCell gridColumn={2}>
|
||||
<ModelTypeDropdown
|
||||
method={method}
|
||||
modeledMethod={modeledMethod}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={3}>
|
||||
<ModelInputDropdown
|
||||
method={method}
|
||||
modeledMethod={modeledMethod}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={4}>
|
||||
<ModelOutputDropdown
|
||||
method={method}
|
||||
modeledMethod={modeledMethod}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={5}>
|
||||
<ModelKindDropdown
|
||||
method={method}
|
||||
modeledMethod={modeledMethod}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</VSCodeDataGridCell>
|
||||
</>
|
||||
)}
|
||||
</VSCodeDataGridRow>
|
||||
);
|
||||
}
|
||||
{!props.modelingInProgress && (
|
||||
<>
|
||||
<VSCodeDataGridCell gridColumn={2}>
|
||||
<ModelTypeDropdown
|
||||
method={method}
|
||||
modeledMethod={modeledMethod}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={3}>
|
||||
<ModelInputDropdown
|
||||
method={method}
|
||||
modeledMethod={modeledMethod}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={4}>
|
||||
<ModelOutputDropdown
|
||||
method={method}
|
||||
modeledMethod={modeledMethod}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell gridColumn={5}>
|
||||
<ModelKindDropdown
|
||||
method={method}
|
||||
modeledMethod={modeledMethod}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</VSCodeDataGridCell>
|
||||
</>
|
||||
)}
|
||||
</DataGridRow>
|
||||
);
|
||||
},
|
||||
);
|
||||
ModelableMethodRow.displayName = "ModelableMethodRow";
|
||||
|
||||
function UnmodelableMethodRow(props: MethodRowProps) {
|
||||
const { method, mode } = props;
|
||||
const UnmodelableMethodRow = forwardRef<
|
||||
HTMLElement | undefined,
|
||||
MethodRowProps
|
||||
>((props, ref) => {
|
||||
const { method, mode, revealedMethodSignature } = props;
|
||||
|
||||
const jumpToUsage = useCallback(
|
||||
() => sendJumpToUsageMessage(method),
|
||||
@@ -152,7 +186,11 @@ function UnmodelableMethodRow(props: MethodRowProps) {
|
||||
);
|
||||
|
||||
return (
|
||||
<VSCodeDataGridRow data-testid="unmodelable-method-row">
|
||||
<DataGridRow
|
||||
data-testid="unmodelable-method-row"
|
||||
ref={ref}
|
||||
focused={revealedMethodSignature === method.signature}
|
||||
>
|
||||
<ApiOrMethodCell gridColumn={1}>
|
||||
<ModelingStatusIndicator status="saved" />
|
||||
<MethodName {...props.method} />
|
||||
@@ -167,9 +205,10 @@ function UnmodelableMethodRow(props: MethodRowProps) {
|
||||
<VSCodeDataGridCell gridColumn="span 4">
|
||||
Method already modeled
|
||||
</VSCodeDataGridCell>
|
||||
</VSCodeDataGridRow>
|
||||
</DataGridRow>
|
||||
);
|
||||
}
|
||||
});
|
||||
UnmodelableMethodRow.displayName = "UnmodelableMethodRow";
|
||||
|
||||
function sendJumpToUsageMessage(method: Method) {
|
||||
vscode.postMessage({
|
||||
|
||||
@@ -101,6 +101,10 @@ export function ModelEditor({
|
||||
initialHideModeledMethods,
|
||||
);
|
||||
|
||||
const [revealedMethodSignature, setRevealedMethodSignature] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
|
||||
useEffect(() => {
|
||||
vscode.postMessage({
|
||||
t: "hideModeledMethods",
|
||||
@@ -136,6 +140,10 @@ export function ModelEditor({
|
||||
new Set(msg.inProgressMethods),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case "revealMethod":
|
||||
setRevealedMethodSignature(msg.method.signature);
|
||||
|
||||
break;
|
||||
default:
|
||||
assertNever(msg);
|
||||
@@ -153,6 +161,20 @@ export function ModelEditor({
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// If there is a revealed method signature, hide it when the user clicks anywhere. In this case, we do need to
|
||||
// show the user where the method is anymore and they should have seen it.
|
||||
const listener = () => {
|
||||
setRevealedMethodSignature(null);
|
||||
};
|
||||
|
||||
window.addEventListener("click", listener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("click", listener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const modeledPercentage = useMemo(
|
||||
() => calculateModeledPercentage(methods),
|
||||
[methods],
|
||||
@@ -323,6 +345,7 @@ export function ModelEditor({
|
||||
inProgressMethods={inProgressMethods}
|
||||
viewState={viewState}
|
||||
hideModeledMethods={hideModeledMethods}
|
||||
revealedMethodSignature={revealedMethodSignature}
|
||||
onChange={onChange}
|
||||
onSaveModelClick={onSaveModelClick}
|
||||
onGenerateFromLlmClick={onGenerateFromLlmClick}
|
||||
|
||||
@@ -23,6 +23,7 @@ export type ModeledMethodDataGridProps = {
|
||||
inProgressMethods: InProgressMethods;
|
||||
mode: Mode;
|
||||
hideModeledMethods: boolean;
|
||||
revealedMethodSignature: string | null;
|
||||
onChange: (modeledMethod: ModeledMethod) => void;
|
||||
};
|
||||
|
||||
@@ -34,6 +35,7 @@ export const ModeledMethodDataGrid = ({
|
||||
inProgressMethods,
|
||||
mode,
|
||||
hideModeledMethods,
|
||||
revealedMethodSignature,
|
||||
onChange,
|
||||
}: ModeledMethodDataGridProps) => {
|
||||
const [methodsWithModelability, numHiddenMethods]: [
|
||||
@@ -94,6 +96,7 @@ export const ModeledMethodDataGrid = ({
|
||||
method.signature,
|
||||
)}
|
||||
mode={mode}
|
||||
revealedMethodSignature={revealedMethodSignature}
|
||||
onChange={onChange}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -16,6 +16,7 @@ export type ModeledMethodsListProps = {
|
||||
modeledMethods: Record<string, ModeledMethod>;
|
||||
modifiedSignatures: Set<string>;
|
||||
inProgressMethods: InProgressMethods;
|
||||
revealedMethodSignature: string | null;
|
||||
viewState: ModelEditorViewState;
|
||||
hideModeledMethods: boolean;
|
||||
onChange: (modeledMethod: ModeledMethod) => void;
|
||||
@@ -44,6 +45,7 @@ export const ModeledMethodsList = ({
|
||||
inProgressMethods,
|
||||
viewState,
|
||||
hideModeledMethods,
|
||||
revealedMethodSignature,
|
||||
onChange,
|
||||
onSaveModelClick,
|
||||
onGenerateFromLlmClick,
|
||||
@@ -89,6 +91,7 @@ export const ModeledMethodsList = ({
|
||||
inProgressMethods={inProgressMethods}
|
||||
viewState={viewState}
|
||||
hideModeledMethods={hideModeledMethods}
|
||||
revealedMethodSignature={revealedMethodSignature}
|
||||
onChange={onChange}
|
||||
onSaveModelClick={onSaveModelClick}
|
||||
onGenerateFromLlmClick={onGenerateFromLlmClick}
|
||||
|
||||
@@ -43,6 +43,7 @@ describe(LibraryRow.name, () => {
|
||||
inProgressMethods={new InProgressMethods()}
|
||||
viewState={viewState}
|
||||
hideModeledMethods={false}
|
||||
revealedMethodSignature={null}
|
||||
onChange={onChange}
|
||||
onSaveModelClick={onSaveModelClick}
|
||||
onGenerateFromLlmClick={onGenerateFromLlmClick}
|
||||
|
||||
@@ -39,6 +39,7 @@ describe(MethodRow.name, () => {
|
||||
modeledMethod={modeledMethod}
|
||||
methodIsUnsaved={false}
|
||||
modelingInProgress={false}
|
||||
revealedMethodSignature={null}
|
||||
mode={Mode.Application}
|
||||
onChange={onChange}
|
||||
{...props}
|
||||
|
||||
@@ -60,6 +60,7 @@ describe(ModeledMethodDataGrid.name, () => {
|
||||
inProgressMethods={new InProgressMethods()}
|
||||
mode={Mode.Application}
|
||||
hideModeledMethods={false}
|
||||
revealedMethodSignature={null}
|
||||
onChange={onChange}
|
||||
{...props}
|
||||
/>,
|
||||
|
||||
@@ -69,6 +69,7 @@ describe(ModeledMethodsList.name, () => {
|
||||
inProgressMethods={new InProgressMethods()}
|
||||
viewState={viewState}
|
||||
hideModeledMethods={false}
|
||||
revealedMethodSignature={null}
|
||||
onChange={onChange}
|
||||
onSaveModelClick={onSaveModelClick}
|
||||
onGenerateFromLlmClick={onGenerateFromLlmClick}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
FromCompareViewMessage,
|
||||
FromMethodModelingMessage,
|
||||
FromModelEditorMessage,
|
||||
FromResultsViewMsg,
|
||||
FromVariantAnalysisMessage,
|
||||
@@ -15,7 +16,8 @@ export interface VsCodeApi {
|
||||
| FromResultsViewMsg
|
||||
| FromCompareViewMessage
|
||||
| FromVariantAnalysisMessage
|
||||
| FromModelEditorMessage,
|
||||
| FromModelEditorMessage
|
||||
| FromMethodModelingMessage,
|
||||
): void;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { mockedObject } from "../../vscode-tests/utils/mocking.helpers";
|
||||
import { ModelEditorViewTracker } from "../../../src/model-editor/model-editor-view-tracker";
|
||||
import { ModelEditorView } from "../../../src/model-editor/model-editor-view";
|
||||
|
||||
export function createMockModelEditorViewTracker({
|
||||
registerView = jest.fn(),
|
||||
unregisterView = jest.fn(),
|
||||
getViews = jest.fn(),
|
||||
}: {
|
||||
registerView?: ModelEditorViewTracker["registerView"];
|
||||
unregisterView?: ModelEditorViewTracker["unregisterView"];
|
||||
getViews?: ModelEditorViewTracker["getViews"];
|
||||
} = {}): ModelEditorViewTracker<ModelEditorView> {
|
||||
return mockedObject<ModelEditorViewTracker<ModelEditorView>>({
|
||||
registerView,
|
||||
unregisterView,
|
||||
getViews,
|
||||
});
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { retry } from "@octokit/plugin-retry";
|
||||
import * as Octokit from "@octokit/rest";
|
||||
import { RequestInterface } from "@octokit/types/dist-types/RequestInterface";
|
||||
|
||||
import { Credentials } from "../../src/common/authentication";
|
||||
import { AppOctokit } from "../../src/common/octokit";
|
||||
|
||||
function makeTestOctokit(octokit: Octokit.Octokit): Credentials {
|
||||
return {
|
||||
@@ -38,5 +38,5 @@ export function testCredentialsWithStub(
|
||||
* optionally authenticated with a given token.
|
||||
*/
|
||||
export function testCredentialsWithRealOctokit(token?: string): Credentials {
|
||||
return makeTestOctokit(new Octokit.Octokit({ auth: token, retry }));
|
||||
return makeTestOctokit(new AppOctokit({ auth: token }));
|
||||
}
|
||||
|
||||
@@ -180,10 +180,10 @@ const config: Config = {
|
||||
},
|
||||
|
||||
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
||||
// 'transformIgnorePatterns': [
|
||||
// // These use ES modules, so need to be transformed
|
||||
// 'node_modules/(?!(?:@vscode/webview-ui-toolkit|@microsoft/.+|exenv-es6)/.*)'
|
||||
// ],
|
||||
transformIgnorePatterns: [
|
||||
// These use ES modules, so need to be transformed
|
||||
"node_modules/(?!(?:@vscode/webview-ui-toolkit|@microsoft/.+|exenv-es6|nanoid|p-queue|p-timeout)/.*)",
|
||||
],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
||||
// unmockedModulePathPatterns: undefined,
|
||||
|
||||
@@ -12,9 +12,7 @@ const rootDir = path.resolve(__dirname, "../..");
|
||||
|
||||
/** @type import("jest-runner-vscode").RunnerOptions */
|
||||
const config = {
|
||||
// Temporary until https://github.com/github/vscode-codeql/issues/2402 is fixed
|
||||
// version: "stable",
|
||||
version: "1.77.3",
|
||||
version: "stable",
|
||||
launchArgs: [
|
||||
"--disable-gpu",
|
||||
"--extensions-dir=" + path.join(rootDir, ".vscode-test", "extensions"),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Config } from "jest";
|
||||
import { resolve } from "path";
|
||||
|
||||
/*
|
||||
* For a detailed explanation regarding each configuration property and type check, visit:
|
||||
@@ -163,31 +164,27 @@ const config: Config = {
|
||||
// testRunner: "jest-circus/runner",
|
||||
|
||||
// A map from regular expressions to paths to transformers
|
||||
// transform: {
|
||||
// '^.+\\.tsx?$': [
|
||||
// 'ts-jest',
|
||||
// {
|
||||
// tsconfig: 'src/view/tsconfig.spec.json',
|
||||
// },
|
||||
// ],
|
||||
// 'node_modules': [
|
||||
// 'babel-jest',
|
||||
// {
|
||||
// presets: [
|
||||
// '@babel/preset-env'
|
||||
// ],
|
||||
// plugins: [
|
||||
// '@babel/plugin-transform-modules-commonjs',
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
transform: {
|
||||
"^.+\\.tsx?$": [
|
||||
"ts-jest",
|
||||
{
|
||||
tsconfig: resolve(__dirname, "../tsconfig.json"),
|
||||
},
|
||||
],
|
||||
node_modules: [
|
||||
"babel-jest",
|
||||
{
|
||||
presets: ["@babel/preset-env"],
|
||||
plugins: ["@babel/plugin-transform-modules-commonjs"],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
||||
// 'transformIgnorePatterns': [
|
||||
// // These use ES modules, so need to be transformed
|
||||
// 'node_modules/(?!(?:@vscode/webview-ui-toolkit|@microsoft/.+|exenv-es6)/.*)'
|
||||
// ],
|
||||
transformIgnorePatterns: [
|
||||
// These use ES modules, so need to be transformed
|
||||
"node_modules/(?!(?:@vscode/webview-ui-toolkit|@microsoft/.+|exenv-es6|nanoid|p-queue|p-timeout)/.*)",
|
||||
],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
||||
// unmockedModulePathPatterns: undefined,
|
||||
|
||||
@@ -9,10 +9,12 @@ import { mockEmptyDatabaseManager } from "../query-testing/test-runner-helpers";
|
||||
import { QueryRunner } from "../../../../src/query-server";
|
||||
import { ExtensionPack } from "../../../../src/model-editor/shared/extension-pack";
|
||||
import { createMockModelingStore } from "../../../__mocks__/model-editor/modelingStoreMock";
|
||||
import { createMockModelEditorViewTracker } from "../../../__mocks__/model-editor/modelEditorViewTrackerMock";
|
||||
|
||||
describe("ModelEditorView", () => {
|
||||
const app = createMockApp({});
|
||||
const modelingStore = createMockModelingStore();
|
||||
const viewTracker = createMockModelEditorViewTracker();
|
||||
const databaseManager = mockEmptyDatabaseManager();
|
||||
const cliServer = mockedObject<CodeQLCliServer>({});
|
||||
const queryRunner = mockedObject<QueryRunner>({});
|
||||
@@ -38,6 +40,7 @@ describe("ModelEditorView", () => {
|
||||
view = new ModelEditorView(
|
||||
app,
|
||||
modelingStore,
|
||||
viewTracker,
|
||||
databaseManager,
|
||||
cliServer,
|
||||
queryRunner,
|
||||
|
||||
Reference in New Issue
Block a user