Merge remote-tracking branch 'origin/main' into koesie10/automodel-v2
This commit is contained in:
5
.github/workflows/main.yml
vendored
5
.github/workflows/main.yml
vendored
@@ -110,6 +110,11 @@ jobs:
|
||||
run: |
|
||||
npm run lint:scenarios
|
||||
|
||||
- name: Find deadcode
|
||||
working-directory: extensions/ql-vscode
|
||||
run: |
|
||||
npm run find-deadcode
|
||||
|
||||
unit-test:
|
||||
name: Unit Test
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@@ -318,7 +318,6 @@ This requires running a MRVA query and seeing the results view.
|
||||
1. Alphabetically
|
||||
2. By number of results
|
||||
3. By popularity
|
||||
4. By most recent commit
|
||||
9. Can filter repos
|
||||
10. Shows correct statistics
|
||||
1. Total number of results
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
## [UNRELEASED]
|
||||
|
||||
- Remove "last updated" information and sorting from variant analysis results view. [#2637](https://github.com/github/vscode-codeql/pull/2637)
|
||||
- Links to code on GitHub now include column numbers as well as line numbers. [#2406](https://github.com/github/vscode-codeql/pull/2406)
|
||||
- No longer highlight trailing commas for jump to definition. [#2615](https://github.com/github/vscode-codeql/pull/2615)
|
||||
|
||||
|
||||
@@ -15,9 +15,6 @@ export const config: webpack.Configuration = {
|
||||
devtool: isDevBuild ? "inline-source-map" : "source-map",
|
||||
resolve: {
|
||||
extensions: [".js", ".ts", ".tsx", ".json"],
|
||||
fallback: {
|
||||
path: require.resolve("path-browserify"),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
|
||||
163
extensions/ql-vscode/package-lock.json
generated
163
extensions/ql-vscode/package-lock.json
generated
@@ -31,7 +31,6 @@
|
||||
"nanoid": "^3.2.0",
|
||||
"node-fetch": "~2.6.7",
|
||||
"p-queue": "^6.0.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"semver": "~7.5.2",
|
||||
@@ -151,6 +150,7 @@
|
||||
"ts-loader": "^9.4.2",
|
||||
"ts-node": "^10.7.0",
|
||||
"ts-protoc-gen": "^0.9.0",
|
||||
"ts-unused-exports": "^9.0.5",
|
||||
"typescript": "^5.0.2",
|
||||
"webpack": "^5.76.0",
|
||||
"webpack-cli": "^5.0.1"
|
||||
@@ -30610,7 +30610,8 @@
|
||||
"node_modules/path-browserify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
|
||||
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
|
||||
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/path-dirname": {
|
||||
"version": "1.0.2",
|
||||
@@ -34708,6 +34709,100 @@
|
||||
"protoc-gen-ts": "bin/protoc-gen-ts"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-unused-exports": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ts-unused-exports/-/ts-unused-exports-9.0.5.tgz",
|
||||
"integrity": "sha512-1XAXaH2i4Al/aZO06pWDn9MUgTN0KQi+fvWudiWfHUTHAav45gzrx7Xq6JAsu6+LoMlVoyGvNvZSPW3KTjDncA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chalk": "^4.0.0",
|
||||
"tsconfig-paths": "^3.9.0"
|
||||
},
|
||||
"bin": {
|
||||
"ts-unused-exports": "bin/ts-unused-exports"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/pzavolinsky/ts-unused-exports?sponsor=1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=3.8.3"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/ts-unused-exports/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-unused-exports/node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-unused-exports/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-unused-exports/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ts-unused-exports/node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-unused-exports/node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
|
||||
@@ -59211,7 +59306,8 @@
|
||||
"path-browserify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
|
||||
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
|
||||
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
|
||||
"dev": true
|
||||
},
|
||||
"path-dirname": {
|
||||
"version": "1.0.2",
|
||||
@@ -62374,6 +62470,67 @@
|
||||
"integrity": "sha512-cFEUTY9U9o6C4DPPfMHk2ZUdIAKL91hZN1fyx5Stz3g56BDVOC7hk+r5fEMCAGaaIgi2akkT1a2hrxu1wo2Phg==",
|
||||
"dev": true
|
||||
},
|
||||
"ts-unused-exports": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ts-unused-exports/-/ts-unused-exports-9.0.5.tgz",
|
||||
"integrity": "sha512-1XAXaH2i4Al/aZO06pWDn9MUgTN0KQi+fvWudiWfHUTHAav45gzrx7Xq6JAsu6+LoMlVoyGvNvZSPW3KTjDncA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^4.0.0",
|
||||
"tsconfig-paths": "^3.9.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tsconfig-paths": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
|
||||
|
||||
@@ -350,13 +350,11 @@
|
||||
"enum": [
|
||||
"alphabetically",
|
||||
"popularity",
|
||||
"mostRecentCommit",
|
||||
"numberOfResults"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Sort repositories alphabetically in the results view.",
|
||||
"Sort repositories by popularity in the results view.",
|
||||
"Sort repositories by most recent commit in the results view.",
|
||||
"Sort repositories by number of results in the results view."
|
||||
],
|
||||
"description": "The default sorting order for repositories in the variant analysis results view."
|
||||
@@ -1732,6 +1730,7 @@
|
||||
"format": "prettier --write **/*.{ts,tsx} && eslint . --ext .ts,.tsx --fix",
|
||||
"lint": "eslint . --ext .js,.ts,.tsx --max-warnings=0",
|
||||
"lint:markdown": "markdownlint-cli2 \"../../**/*.{md,mdx}\" \"!**/node_modules/**\" \"!**/.vscode-test/**\" \"!**/build/cli/v*/**\"",
|
||||
"find-deadcode": "ts-node scripts/find-deadcode.ts",
|
||||
"format-staged": "lint-staged",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build",
|
||||
@@ -1762,7 +1761,6 @@
|
||||
"nanoid": "^3.2.0",
|
||||
"node-fetch": "~2.6.7",
|
||||
"p-queue": "^6.0.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"semver": "~7.5.2",
|
||||
@@ -1882,6 +1880,7 @@
|
||||
"ts-loader": "^9.4.2",
|
||||
"ts-node": "^10.7.0",
|
||||
"ts-protoc-gen": "^0.9.0",
|
||||
"ts-unused-exports": "^9.0.5",
|
||||
"typescript": "^5.0.2",
|
||||
"webpack": "^5.76.0",
|
||||
"webpack-cli": "^5.0.1"
|
||||
|
||||
47
extensions/ql-vscode/scripts/find-deadcode.ts
Normal file
47
extensions/ql-vscode/scripts/find-deadcode.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { basename, join, relative, resolve } from "path";
|
||||
import analyzeTsConfig from "ts-unused-exports";
|
||||
import { containsPath, pathsEqual } from "../src/common/files";
|
||||
import { exit } from "process";
|
||||
|
||||
function ignoreFile(file: string): boolean {
|
||||
return (
|
||||
containsPath("gulpfile.ts", file) ||
|
||||
containsPath(join("src", "stories"), file) ||
|
||||
pathsEqual(
|
||||
join("test", "vscode-tests", "jest-runner-installed-extensions.ts"),
|
||||
file,
|
||||
) ||
|
||||
basename(file) === "jest.config.ts" ||
|
||||
basename(file) === "index.tsx" ||
|
||||
basename(file) === "index.ts"
|
||||
);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const repositoryRoot = resolve(join(__dirname, ".."));
|
||||
|
||||
const result = analyzeTsConfig("tsconfig.deadcode.json");
|
||||
let foundUnusedExports = false;
|
||||
|
||||
for (const [filepath, exportNameAndLocations] of Object.entries(result)) {
|
||||
const relativeFilepath = relative(repositoryRoot, filepath);
|
||||
|
||||
if (ignoreFile(relativeFilepath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foundUnusedExports = true;
|
||||
|
||||
console.log(relativeFilepath);
|
||||
for (const exportNameAndLocation of exportNameAndLocations) {
|
||||
console.log(` ${exportNameAndLocation.exportName}`);
|
||||
}
|
||||
console.log();
|
||||
}
|
||||
|
||||
if (foundUnusedExports) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -500,13 +500,6 @@ interface SetExternalApiUsagesMessage {
|
||||
externalApiUsages: ExternalApiUsage[];
|
||||
}
|
||||
|
||||
export interface ShowProgressMessage {
|
||||
t: "showProgress";
|
||||
step: number;
|
||||
maxStep: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface LoadModeledMethodsMessage {
|
||||
t: "loadModeledMethods";
|
||||
modeledMethods: Record<string, ModeledMethod>;
|
||||
@@ -527,6 +520,10 @@ interface JumpToUsageMessage {
|
||||
location: ResolvableLocationValue;
|
||||
}
|
||||
|
||||
interface OpenDatabaseMessage {
|
||||
t: "openDatabase";
|
||||
}
|
||||
|
||||
interface OpenExtensionPackMessage {
|
||||
t: "openExtensionPack";
|
||||
}
|
||||
@@ -558,7 +555,6 @@ interface ModelDependencyMessage {
|
||||
export type ToDataExtensionsEditorMessage =
|
||||
| SetExtensionPackStateMessage
|
||||
| SetExternalApiUsagesMessage
|
||||
| ShowProgressMessage
|
||||
| LoadModeledMethodsMessage
|
||||
| AddModeledMethodsMessage;
|
||||
|
||||
@@ -566,6 +562,7 @@ export type FromDataExtensionsEditorMessage =
|
||||
| ViewLoadedMsg
|
||||
| SwitchModeMessage
|
||||
| RefreshExternalApiUsages
|
||||
| OpenDatabaseMessage
|
||||
| OpenExtensionPackMessage
|
||||
| JumpToUsageMessage
|
||||
| SaveModeledMethods
|
||||
|
||||
@@ -14,11 +14,7 @@ import {
|
||||
FromDataExtensionsEditorMessage,
|
||||
ToDataExtensionsEditorMessage,
|
||||
} from "../common/interface-types";
|
||||
import {
|
||||
ProgressCallback,
|
||||
ProgressUpdate,
|
||||
withProgress,
|
||||
} from "../common/vscode/progress";
|
||||
import { ProgressCallback, withProgress } from "../common/vscode/progress";
|
||||
import { QueryRunner } from "../query-server";
|
||||
import {
|
||||
showAndLogExceptionWithTelemetry,
|
||||
@@ -120,6 +116,13 @@ export class DataExtensionsEditorView extends AbstractWebview<
|
||||
case "viewLoaded":
|
||||
await this.onWebViewLoaded();
|
||||
|
||||
break;
|
||||
case "openDatabase":
|
||||
await this.app.commands.execute(
|
||||
"revealInExplorer",
|
||||
this.databaseItem.getSourceArchiveExplorerUri(),
|
||||
);
|
||||
|
||||
break;
|
||||
case "openExtensionPack":
|
||||
await this.app.commands.execute(
|
||||
@@ -238,255 +241,254 @@ export class DataExtensionsEditorView extends AbstractWebview<
|
||||
}
|
||||
|
||||
protected async loadExternalApiUsages(): Promise<void> {
|
||||
const cancellationTokenSource = new CancellationTokenSource();
|
||||
await withProgress(
|
||||
async (progress) => {
|
||||
try {
|
||||
const cancellationTokenSource = new CancellationTokenSource();
|
||||
const queryResult = await runQuery(
|
||||
this.mode === Mode.Framework
|
||||
? "frameworkModeQuery"
|
||||
: "applicationModeQuery",
|
||||
{
|
||||
cliServer: this.cliServer,
|
||||
queryRunner: this.queryRunner,
|
||||
databaseItem: this.databaseItem,
|
||||
queryStorageDir: this.queryStorageDir,
|
||||
progress: (update) => progress({ ...update, maxStep: 1500 }),
|
||||
token: cancellationTokenSource.token,
|
||||
},
|
||||
);
|
||||
if (!queryResult) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
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,
|
||||
},
|
||||
);
|
||||
if (!queryResult) {
|
||||
await this.clearProgress();
|
||||
return;
|
||||
}
|
||||
progress({
|
||||
message: "Decoding results",
|
||||
step: 1100,
|
||||
maxStep: 1500,
|
||||
});
|
||||
|
||||
await this.showProgress({
|
||||
message: "Decoding results",
|
||||
step: 1100,
|
||||
maxStep: 1500,
|
||||
});
|
||||
const bqrsChunk = await readQueryResults({
|
||||
cliServer: this.cliServer,
|
||||
bqrsPath: queryResult.outputDir.bqrsPath,
|
||||
});
|
||||
if (!bqrsChunk) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bqrsChunk = await readQueryResults({
|
||||
cliServer: this.cliServer,
|
||||
bqrsPath: queryResult.outputDir.bqrsPath,
|
||||
});
|
||||
if (!bqrsChunk) {
|
||||
await this.clearProgress();
|
||||
return;
|
||||
}
|
||||
progress({
|
||||
message: "Finalizing results",
|
||||
step: 1450,
|
||||
maxStep: 1500,
|
||||
});
|
||||
|
||||
await this.showProgress({
|
||||
message: "Finalizing results",
|
||||
step: 1450,
|
||||
maxStep: 1500,
|
||||
});
|
||||
const externalApiUsages = decodeBqrsToExternalApiUsages(bqrsChunk);
|
||||
|
||||
const externalApiUsages = decodeBqrsToExternalApiUsages(bqrsChunk);
|
||||
|
||||
await this.postMessage({
|
||||
t: "setExternalApiUsages",
|
||||
externalApiUsages,
|
||||
});
|
||||
|
||||
await this.clearProgress();
|
||||
} catch (err) {
|
||||
void showAndLogExceptionWithTelemetry(
|
||||
this.app.logger,
|
||||
this.app.telemetry,
|
||||
redactableError(
|
||||
asError(err),
|
||||
)`Failed to load external API usages: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
await this.postMessage({
|
||||
t: "setExternalApiUsages",
|
||||
externalApiUsages,
|
||||
});
|
||||
} catch (err) {
|
||||
void showAndLogExceptionWithTelemetry(
|
||||
this.app.logger,
|
||||
this.app.telemetry,
|
||||
redactableError(
|
||||
asError(err),
|
||||
)`Failed to load external API usages: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
{ cancellable: false },
|
||||
);
|
||||
}
|
||||
|
||||
protected async generateModeledMethods(): Promise<void> {
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
await withProgress(
|
||||
async (progress) => {
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
|
||||
let addedDatabase: DatabaseItem | undefined;
|
||||
let addedDatabase: DatabaseItem | undefined;
|
||||
|
||||
// In application mode, we need the database of a specific library to generate
|
||||
// the modeled methods. In framework mode, we'll use the current database.
|
||||
if (this.mode === Mode.Application) {
|
||||
addedDatabase = await this.promptImportDatabase((update) =>
|
||||
this.showProgress(update),
|
||||
);
|
||||
if (!addedDatabase) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await this.showProgress({
|
||||
step: 0,
|
||||
maxStep: 4000,
|
||||
message: "Generating modeled methods for library",
|
||||
});
|
||||
|
||||
try {
|
||||
await generateFlowModel({
|
||||
cliServer: this.cliServer,
|
||||
queryRunner: this.queryRunner,
|
||||
queryStorageDir: this.queryStorageDir,
|
||||
databaseItem: addedDatabase ?? this.databaseItem,
|
||||
onResults: async (modeledMethods) => {
|
||||
const modeledMethodsByName: Record<string, ModeledMethod> = {};
|
||||
|
||||
for (const modeledMethod of modeledMethods) {
|
||||
modeledMethodsByName[modeledMethod.signature] = modeledMethod;
|
||||
// In application mode, we need the database of a specific library to generate
|
||||
// the modeled methods. In framework mode, we'll use the current database.
|
||||
if (this.mode === Mode.Application) {
|
||||
addedDatabase = await this.promptImportDatabase(progress);
|
||||
if (!addedDatabase) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await this.postMessage({
|
||||
t: "addModeledMethods",
|
||||
modeledMethods: modeledMethodsByName,
|
||||
progress({
|
||||
step: 0,
|
||||
maxStep: 4000,
|
||||
message: "Generating modeled methods for library",
|
||||
});
|
||||
|
||||
try {
|
||||
await generateFlowModel({
|
||||
cliServer: this.cliServer,
|
||||
queryRunner: this.queryRunner,
|
||||
queryStorageDir: this.queryStorageDir,
|
||||
databaseItem: addedDatabase ?? this.databaseItem,
|
||||
onResults: async (modeledMethods) => {
|
||||
const modeledMethodsByName: Record<string, ModeledMethod> = {};
|
||||
|
||||
for (const modeledMethod of modeledMethods) {
|
||||
modeledMethodsByName[modeledMethod.signature] = modeledMethod;
|
||||
}
|
||||
|
||||
await this.postMessage({
|
||||
t: "addModeledMethods",
|
||||
modeledMethods: modeledMethodsByName,
|
||||
});
|
||||
},
|
||||
progress,
|
||||
token: tokenSource.token,
|
||||
});
|
||||
},
|
||||
progress: (update) => this.showProgress(update),
|
||||
token: tokenSource.token,
|
||||
});
|
||||
} catch (e: unknown) {
|
||||
void showAndLogExceptionWithTelemetry(
|
||||
this.app.logger,
|
||||
this.app.telemetry,
|
||||
redactableError(
|
||||
asError(e),
|
||||
)`Failed to generate flow model: ${getErrorMessage(e)}`,
|
||||
);
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
void showAndLogExceptionWithTelemetry(
|
||||
this.app.logger,
|
||||
this.app.telemetry,
|
||||
redactableError(
|
||||
asError(e),
|
||||
)`Failed to generate flow model: ${getErrorMessage(e)}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (addedDatabase) {
|
||||
// After the flow model has been generated, we can remove the temporary database
|
||||
// which we used for generating the flow model.
|
||||
await this.showProgress({
|
||||
step: 3900,
|
||||
maxStep: 4000,
|
||||
message: "Removing temporary database",
|
||||
});
|
||||
await this.databaseManager.removeDatabaseItem(addedDatabase);
|
||||
}
|
||||
|
||||
await this.clearProgress();
|
||||
if (addedDatabase) {
|
||||
// After the flow model has been generated, we can remove the temporary database
|
||||
// which we used for generating the flow model.
|
||||
progress({
|
||||
step: 3900,
|
||||
maxStep: 4000,
|
||||
message: "Removing temporary database",
|
||||
});
|
||||
await this.databaseManager.removeDatabaseItem(addedDatabase);
|
||||
}
|
||||
},
|
||||
{ cancellable: false },
|
||||
);
|
||||
}
|
||||
|
||||
private async generateModeledMethodsFromLlm(
|
||||
externalApiUsages: ExternalApiUsage[],
|
||||
modeledMethods: Record<string, ModeledMethod>,
|
||||
): Promise<void> {
|
||||
const maxStep = 3000;
|
||||
await withProgress(async (progress) => {
|
||||
const maxStep = 3000;
|
||||
|
||||
await this.showProgress({
|
||||
step: 0,
|
||||
maxStep,
|
||||
message: "Retrieving usages",
|
||||
progress({
|
||||
step: 0,
|
||||
maxStep,
|
||||
message: "Retrieving usages",
|
||||
});
|
||||
|
||||
let predictedModeledMethods: Record<string, ModeledMethod>;
|
||||
|
||||
if (useLlmGenerationV2()) {
|
||||
const usages = await runAutoModelQueries({
|
||||
mode: this.mode,
|
||||
cliServer: this.cliServer,
|
||||
queryRunner: this.queryRunner,
|
||||
queryStorageDir: this.queryStorageDir,
|
||||
databaseItem: this.databaseItem,
|
||||
progress: (update) => progress({ ...update, maxStep }),
|
||||
});
|
||||
if (!usages) {
|
||||
return;
|
||||
}
|
||||
|
||||
progress({
|
||||
step: 1800,
|
||||
maxStep,
|
||||
message: "Creating request",
|
||||
});
|
||||
|
||||
const request = await createAutoModelV2Request(this.mode, usages);
|
||||
|
||||
progress({
|
||||
step: 2000,
|
||||
maxStep,
|
||||
message: "Sending request",
|
||||
});
|
||||
|
||||
const response = await this.callAutoModelApiV2(request);
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
|
||||
progress({
|
||||
step: 2500,
|
||||
maxStep,
|
||||
message: "Parsing response",
|
||||
});
|
||||
|
||||
const models = loadYaml(response.models, {
|
||||
filename: "auto-model.yml",
|
||||
});
|
||||
|
||||
const modeledMethods = loadDataExtensionYaml(models);
|
||||
if (!modeledMethods) {
|
||||
return;
|
||||
}
|
||||
|
||||
predictedModeledMethods = modeledMethods;
|
||||
} else {
|
||||
const usages = await getAutoModelUsages({
|
||||
cliServer: this.cliServer,
|
||||
queryRunner: this.queryRunner,
|
||||
queryStorageDir: this.queryStorageDir,
|
||||
databaseItem: this.databaseItem,
|
||||
progress: (update) => progress({ ...update, maxStep }),
|
||||
});
|
||||
|
||||
progress({
|
||||
step: 1800,
|
||||
maxStep,
|
||||
message: "Creating request",
|
||||
});
|
||||
|
||||
const request = createAutoModelRequest(
|
||||
this.databaseItem.language,
|
||||
externalApiUsages,
|
||||
modeledMethods,
|
||||
usages,
|
||||
this.mode,
|
||||
);
|
||||
|
||||
progress({
|
||||
step: 2000,
|
||||
maxStep,
|
||||
message: "Sending request",
|
||||
});
|
||||
|
||||
const response = await this.callAutoModelApi(request);
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
|
||||
progress({
|
||||
step: 2500,
|
||||
maxStep,
|
||||
message: "Parsing response",
|
||||
});
|
||||
|
||||
predictedModeledMethods = parsePredictedClassifications(
|
||||
response.predicted || [],
|
||||
);
|
||||
}
|
||||
|
||||
progress({
|
||||
step: 2800,
|
||||
maxStep,
|
||||
message: "Applying results",
|
||||
});
|
||||
|
||||
await this.postMessage({
|
||||
t: "addModeledMethods",
|
||||
modeledMethods: predictedModeledMethods,
|
||||
});
|
||||
});
|
||||
|
||||
let predictedModeledMethods: Record<string, ModeledMethod>;
|
||||
|
||||
if (useLlmGenerationV2()) {
|
||||
const usages = await runAutoModelQueries({
|
||||
mode: this.mode,
|
||||
cliServer: this.cliServer,
|
||||
queryRunner: this.queryRunner,
|
||||
queryStorageDir: this.queryStorageDir,
|
||||
databaseItem: this.databaseItem,
|
||||
progress: (update) => this.showProgress(update, maxStep),
|
||||
});
|
||||
if (!usages) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.showProgress({
|
||||
step: 1800,
|
||||
maxStep,
|
||||
message: "Creating request",
|
||||
});
|
||||
|
||||
const request = await createAutoModelV2Request(this.mode, usages);
|
||||
|
||||
await this.showProgress({
|
||||
step: 2000,
|
||||
maxStep,
|
||||
message: "Sending request",
|
||||
});
|
||||
|
||||
const response = await this.callAutoModelApiV2(request);
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.showProgress({
|
||||
step: 2500,
|
||||
maxStep,
|
||||
message: "Parsing response",
|
||||
});
|
||||
|
||||
const models = loadYaml(response.models, {
|
||||
filename: "auto-model.yml",
|
||||
});
|
||||
|
||||
const modeledMethods = loadDataExtensionYaml(models);
|
||||
if (!modeledMethods) {
|
||||
return;
|
||||
}
|
||||
|
||||
predictedModeledMethods = modeledMethods;
|
||||
} else {
|
||||
const usages = await getAutoModelUsages({
|
||||
cliServer: this.cliServer,
|
||||
queryRunner: this.queryRunner,
|
||||
queryStorageDir: this.queryStorageDir,
|
||||
databaseItem: this.databaseItem,
|
||||
progress: (update) => this.showProgress(update, maxStep),
|
||||
});
|
||||
|
||||
await this.showProgress({
|
||||
step: 1800,
|
||||
maxStep,
|
||||
message: "Creating request",
|
||||
});
|
||||
|
||||
const request = createAutoModelRequest(
|
||||
this.databaseItem.language,
|
||||
externalApiUsages,
|
||||
modeledMethods,
|
||||
usages,
|
||||
this.mode,
|
||||
);
|
||||
|
||||
await this.showProgress({
|
||||
step: 2000,
|
||||
maxStep,
|
||||
message: "Sending request",
|
||||
});
|
||||
|
||||
const response = await this.callAutoModelApi(request);
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.showProgress({
|
||||
step: 2500,
|
||||
maxStep,
|
||||
message: "Parsing response",
|
||||
});
|
||||
|
||||
predictedModeledMethods = parsePredictedClassifications(
|
||||
response.predicted || [],
|
||||
);
|
||||
}
|
||||
|
||||
await this.showProgress({
|
||||
step: 2800,
|
||||
maxStep,
|
||||
message: "Applying results",
|
||||
});
|
||||
|
||||
await this.postMessage({
|
||||
t: "addModeledMethods",
|
||||
modeledMethods: predictedModeledMethods,
|
||||
});
|
||||
|
||||
await this.clearProgress();
|
||||
}
|
||||
|
||||
private async modelDependency(): Promise<void> {
|
||||
@@ -547,46 +549,12 @@ export class DataExtensionsEditorView extends AbstractWebview<
|
||||
return addedDatabase;
|
||||
}
|
||||
|
||||
/*
|
||||
* Progress in this class is a bit weird. Most of the progress is based on running the query.
|
||||
* Query progress is always between 0 and 1000. However, we still have some steps that need
|
||||
* to be done after the query has finished. Therefore, the maximum step is 1500. This captures
|
||||
* that there's 1000 steps of the query progress since that takes the most time, and then
|
||||
* an additional 500 steps for the rest of the work. The progress doesn't need to be 100%
|
||||
* accurate, so this is just a rough estimate.
|
||||
*
|
||||
* For generating the modeled methods for an external library, the max step is 4000. This is
|
||||
* based on the following steps:
|
||||
* - 1000 for the summary model
|
||||
* - 1000 for the sink model
|
||||
* - 1000 for the source model
|
||||
* - 1000 for the neutral model
|
||||
*/
|
||||
private async showProgress(update: ProgressUpdate, maxStep?: number) {
|
||||
await this.postMessage({
|
||||
t: "showProgress",
|
||||
step: update.step,
|
||||
maxStep: maxStep ?? update.maxStep,
|
||||
message: update.message,
|
||||
});
|
||||
}
|
||||
|
||||
private async clearProgress() {
|
||||
await this.showProgress({
|
||||
step: 0,
|
||||
maxStep: 0,
|
||||
message: "",
|
||||
});
|
||||
}
|
||||
|
||||
private async callAutoModelApi(
|
||||
request: ModelRequest,
|
||||
): Promise<ModelResponse | null> {
|
||||
try {
|
||||
return await autoModel(this.app.credentials, request);
|
||||
} catch (e) {
|
||||
await this.clearProgress();
|
||||
|
||||
if (e instanceof RequestError && e.status === 429) {
|
||||
void showAndLogExceptionWithTelemetry(
|
||||
this.app.logger,
|
||||
@@ -606,8 +574,6 @@ export class DataExtensionsEditorView extends AbstractWebview<
|
||||
try {
|
||||
return await autoModelV2(this.app.credentials, request);
|
||||
} catch (e) {
|
||||
await this.clearProgress();
|
||||
|
||||
if (e instanceof RequestError && e.status === 429) {
|
||||
void showAndLogExceptionWithTelemetry(
|
||||
this.app.logger,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { extLogger } from "../common/logging/vscode";
|
||||
import { promises } from "fs-extra";
|
||||
import { BaseLogger } from "../common/logging";
|
||||
|
||||
export type LockFileForStandardQueryResult = {
|
||||
type LockFileForStandardQueryResult = {
|
||||
cleanup?: () => Promise<void>;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { Meta, StoryFn } from "@storybook/react";
|
||||
|
||||
import { LastUpdated as LastUpdatedComponent } from "../../view/common/LastUpdated";
|
||||
|
||||
export default {
|
||||
title: "Last Updated",
|
||||
component: LastUpdatedComponent,
|
||||
} as Meta<typeof LastUpdatedComponent>;
|
||||
|
||||
const Template: StoryFn<typeof LastUpdatedComponent> = (args) => (
|
||||
<LastUpdatedComponent {...args} />
|
||||
);
|
||||
|
||||
export const LastUpdated = Template.bind({});
|
||||
|
||||
LastUpdated.args = {
|
||||
lastUpdated: new Date(Date.now() - 3_600_000).toISOString(), // 1 hour ago
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Repository, RepositoryWithMetadata } from "./repository";
|
||||
import { parseDate } from "../../common/date";
|
||||
import { assertNever } from "../../common/helpers-pure";
|
||||
|
||||
export enum FilterKey {
|
||||
@@ -10,7 +9,6 @@ export enum FilterKey {
|
||||
export enum SortKey {
|
||||
Alphabetically = "alphabetically",
|
||||
Popularity = "popularity",
|
||||
MostRecentCommit = "mostRecentCommit",
|
||||
NumberOfResults = "numberOfResults",
|
||||
}
|
||||
|
||||
@@ -81,16 +79,6 @@ export function compareRepository(
|
||||
}
|
||||
}
|
||||
|
||||
// Newest to oldest
|
||||
if (filterSortState?.sortKey === SortKey.MostRecentCommit) {
|
||||
const lastUpdated =
|
||||
(parseDate(right.updatedAt)?.getTime() ?? 0) -
|
||||
(parseDate(left.updatedAt)?.getTime() ?? 0);
|
||||
if (lastUpdated !== 0) {
|
||||
return lastUpdated;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back on name compare. Use en-US because the repository name does not contain
|
||||
// special characters due to restrictions in GitHub owner/repository names.
|
||||
return left.fullName.localeCompare(right.fullName, "en-US", {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { useMemo } from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { parseDate } from "../../common/date";
|
||||
import { humanizeRelativeTime } from "../../common/time";
|
||||
|
||||
import { Codicon } from "./icon";
|
||||
|
||||
const IconContainer = styled.span`
|
||||
flex-grow: 0;
|
||||
text-align: right;
|
||||
margin-right: 0;
|
||||
`;
|
||||
|
||||
const Duration = styled.span`
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
width: 8em;
|
||||
margin-left: 0.5em;
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
lastUpdated?: string | null;
|
||||
};
|
||||
|
||||
export const LastUpdated = ({ lastUpdated }: Props) => {
|
||||
const date = useMemo(() => parseDate(lastUpdated), [lastUpdated]);
|
||||
|
||||
if (!date) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconContainer>
|
||||
<Codicon name="repo-push" label="Most recent commit" />
|
||||
</IconContainer>
|
||||
<Duration>{humanizeRelativeTime(date.getTime() - Date.now())}</Duration>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,10 +1,11 @@
|
||||
import * as React from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { ToDataExtensionsEditorMessage } from "../../common/interface-types";
|
||||
import {
|
||||
ShowProgressMessage,
|
||||
ToDataExtensionsEditorMessage,
|
||||
} from "../../common/interface-types";
|
||||
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react";
|
||||
VSCodeButton,
|
||||
VSCodeCheckbox,
|
||||
VSCodeTag,
|
||||
} from "@vscode/webview-ui-toolkit/react";
|
||||
import styled from "styled-components";
|
||||
import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usage";
|
||||
import { ModeledMethod } from "../../data-extensions-editor/modeled-method";
|
||||
@@ -12,7 +13,6 @@ import { assertNever } from "../../common/helpers-pure";
|
||||
import { vscode } from "../vscode-api";
|
||||
import { calculateModeledPercentage } from "../../data-extensions-editor/shared/modeled-percentage";
|
||||
import { LinkIconButton } from "../variant-analysis/LinkIconButton";
|
||||
import { ViewTitle } from "../common";
|
||||
import { DataExtensionEditorViewState } from "../../data-extensions-editor/shared/view-state";
|
||||
import { ModeledMethodsList } from "./ModeledMethodsList";
|
||||
import { percentFormatter } from "./formatters";
|
||||
@@ -30,12 +30,35 @@ const DataExtensionsEditorContainer = styled.div`
|
||||
margin-top: 1rem;
|
||||
`;
|
||||
|
||||
const DetailsContainer = styled.div`
|
||||
const HeaderContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: end;
|
||||
`;
|
||||
|
||||
const HeaderColumn = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5em;
|
||||
`;
|
||||
|
||||
const HeaderSpacer = styled.div`
|
||||
flex-grow: 1;
|
||||
`;
|
||||
|
||||
const HeaderRow = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 1em;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const ViewTitle = styled.h1`
|
||||
font-size: 2em;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
`;
|
||||
|
||||
const EditorContainer = styled.div`
|
||||
margin-top: 1rem;
|
||||
`;
|
||||
@@ -46,17 +69,6 @@ const ButtonsContainer = styled.div`
|
||||
margin-bottom: 1rem;
|
||||
`;
|
||||
|
||||
type ProgressBarProps = {
|
||||
completion: number;
|
||||
};
|
||||
|
||||
const ProgressBar = styled.div<ProgressBarProps>`
|
||||
height: 10px;
|
||||
width: ${(props) => props.completion * 100}%;
|
||||
|
||||
background-color: var(--vscode-progressBar-background);
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
initialViewState?: DataExtensionEditorViewState;
|
||||
initialExternalApiUsages?: ExternalApiUsage[];
|
||||
@@ -82,11 +94,6 @@ export function DataExtensionsEditor({
|
||||
const [modeledMethods, setModeledMethods] = useState<
|
||||
Record<string, ModeledMethod>
|
||||
>(initialModeledMethods);
|
||||
const [progress, setProgress] = useState<Omit<ShowProgressMessage, "t">>({
|
||||
step: 0,
|
||||
maxStep: 0,
|
||||
message: "",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (evt: MessageEvent) => {
|
||||
@@ -99,9 +106,6 @@ export function DataExtensionsEditor({
|
||||
case "setExternalApiUsages":
|
||||
setExternalApiUsages(msg.externalApiUsages);
|
||||
break;
|
||||
case "showProgress":
|
||||
setProgress(msg);
|
||||
break;
|
||||
case "loadModeledMethods":
|
||||
setModeledMethods((oldModeledMethods) => {
|
||||
return {
|
||||
@@ -150,8 +154,6 @@ export function DataExtensionsEditor({
|
||||
[externalApiUsages],
|
||||
);
|
||||
|
||||
const unModeledPercentage = 100 - modeledPercentage;
|
||||
|
||||
const onChange = useCallback(
|
||||
(modelName: string, method: ExternalApiUsage, model: ModeledMethod) => {
|
||||
setModeledMethods((oldModeledMethods) => ({
|
||||
@@ -208,14 +210,6 @@ export function DataExtensionsEditor({
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onGenerateAllFromLlmClick = useCallback(() => {
|
||||
vscode.postMessage({
|
||||
t: "generateExternalApiFromLlm",
|
||||
externalApiUsages,
|
||||
modeledMethods,
|
||||
});
|
||||
}, [externalApiUsages, modeledMethods]);
|
||||
|
||||
const onModelDependencyClick = useCallback(() => {
|
||||
vscode.postMessage({
|
||||
t: "modelDependency",
|
||||
@@ -236,6 +230,12 @@ export function DataExtensionsEditor({
|
||||
[],
|
||||
);
|
||||
|
||||
const onOpenDatabaseClick = useCallback(() => {
|
||||
vscode.postMessage({
|
||||
t: "openDatabase",
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onOpenExtensionPackClick = useCallback(() => {
|
||||
vscode.postMessage({
|
||||
t: "openExtensionPack",
|
||||
@@ -252,91 +252,81 @@ export function DataExtensionsEditor({
|
||||
});
|
||||
}, [viewState?.mode]);
|
||||
|
||||
if (viewState === undefined) {
|
||||
if (viewState === undefined || externalApiUsages.length === 0) {
|
||||
return <LoadingContainer>Loading...</LoadingContainer>;
|
||||
}
|
||||
|
||||
return (
|
||||
<DataExtensionsEditorContainer>
|
||||
{progress.maxStep > 0 && (
|
||||
<p>
|
||||
<ProgressBar completion={progress.step / progress.maxStep} />{" "}
|
||||
{progress.message}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{externalApiUsages.length > 0 && (
|
||||
<>
|
||||
<ViewTitle>
|
||||
{getLanguageDisplayName(viewState.extensionPack.language)}
|
||||
</ViewTitle>
|
||||
<DetailsContainer>
|
||||
<HeaderContainer>
|
||||
<HeaderColumn>
|
||||
<HeaderRow>
|
||||
<ViewTitle>
|
||||
{getLanguageDisplayName(viewState.extensionPack.language)}
|
||||
</ViewTitle>
|
||||
<VSCodeTag>
|
||||
{percentFormatter.format(modeledPercentage / 100)} modeled
|
||||
</VSCodeTag>
|
||||
</HeaderRow>
|
||||
<HeaderRow>
|
||||
<>{viewState.extensionPack.name}</>
|
||||
</HeaderRow>
|
||||
<HeaderRow>
|
||||
<LinkIconButton onClick={onOpenDatabaseClick}>
|
||||
<span slot="start" className="codicon codicon-package"></span>
|
||||
Open database
|
||||
</LinkIconButton>
|
||||
<LinkIconButton onClick={onOpenExtensionPackClick}>
|
||||
<span slot="start" className="codicon codicon-package"></span>
|
||||
{viewState.extensionPack.name}
|
||||
Open extension pack
|
||||
</LinkIconButton>
|
||||
<div>
|
||||
{percentFormatter.format(modeledPercentage / 100)} modeled
|
||||
</div>
|
||||
<div>
|
||||
{percentFormatter.format(unModeledPercentage / 100)} unmodeled
|
||||
</div>
|
||||
{viewState.enableFrameworkMode && (
|
||||
<>
|
||||
<div>
|
||||
Mode:{" "}
|
||||
{viewState.mode === Mode.Framework
|
||||
? "Framework"
|
||||
: "Application"}
|
||||
</div>
|
||||
<div>
|
||||
<LinkIconButton onClick={onSwitchModeClick}>
|
||||
<span
|
||||
slot="start"
|
||||
className="codicon codicon-library"
|
||||
></span>
|
||||
Switch mode
|
||||
</LinkIconButton>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</DetailsContainer>
|
||||
|
||||
<EditorContainer>
|
||||
<ButtonsContainer>
|
||||
<VSCodeButton onClick={onSaveAllClick}>Apply</VSCodeButton>
|
||||
{viewState.enableFrameworkMode && (
|
||||
<VSCodeButton appearance="secondary" onClick={onRefreshClick}>
|
||||
Refresh
|
||||
</VSCodeButton>
|
||||
)}
|
||||
<VSCodeButton onClick={onGenerateFromSourceClick}>
|
||||
<LinkIconButton onClick={onSwitchModeClick}>
|
||||
<span slot="start" className="codicon codicon-library"></span>
|
||||
{viewState.mode === Mode.Framework
|
||||
? "Generate"
|
||||
: "Download and generate"}
|
||||
</VSCodeButton>
|
||||
{viewState.showLlmButton && (
|
||||
<>
|
||||
<VSCodeButton onClick={onGenerateAllFromLlmClick}>
|
||||
Generate using LLM
|
||||
</VSCodeButton>
|
||||
</>
|
||||
)}
|
||||
</ButtonsContainer>
|
||||
<ModeledMethodsList
|
||||
externalApiUsages={externalApiUsages}
|
||||
modeledMethods={modeledMethods}
|
||||
modifiedSignatures={modifiedSignatures}
|
||||
viewState={viewState}
|
||||
onChange={onChange}
|
||||
onSaveModelClick={onSaveModelClick}
|
||||
onGenerateFromLlmClick={onGenerateFromLlmClick}
|
||||
onGenerateFromSourceClick={onGenerateFromSourceClick}
|
||||
onModelDependencyClick={onModelDependencyClick}
|
||||
/>
|
||||
</EditorContainer>
|
||||
</>
|
||||
)}
|
||||
? "Model as application"
|
||||
: "Model as dependency"}
|
||||
</LinkIconButton>
|
||||
)}
|
||||
</HeaderRow>
|
||||
</HeaderColumn>
|
||||
<HeaderSpacer />
|
||||
<HeaderColumn>
|
||||
<VSCodeCheckbox>Hide modeled APIs</VSCodeCheckbox>
|
||||
</HeaderColumn>
|
||||
</HeaderContainer>
|
||||
|
||||
<EditorContainer>
|
||||
<ButtonsContainer>
|
||||
<VSCodeButton
|
||||
onClick={onSaveAllClick}
|
||||
disabled={modifiedSignatures.size === 0}
|
||||
>
|
||||
Save all
|
||||
</VSCodeButton>
|
||||
{viewState.enableFrameworkMode && (
|
||||
<VSCodeButton appearance="secondary" onClick={onRefreshClick}>
|
||||
Refresh
|
||||
</VSCodeButton>
|
||||
)}
|
||||
{viewState.mode === Mode.Framework && (
|
||||
<VSCodeButton onClick={onGenerateFromSourceClick}>
|
||||
Generate
|
||||
</VSCodeButton>
|
||||
)}
|
||||
</ButtonsContainer>
|
||||
<ModeledMethodsList
|
||||
externalApiUsages={externalApiUsages}
|
||||
modeledMethods={modeledMethods}
|
||||
modifiedSignatures={modifiedSignatures}
|
||||
viewState={viewState}
|
||||
onChange={onChange}
|
||||
onSaveModelClick={onSaveModelClick}
|
||||
onGenerateFromLlmClick={onGenerateFromLlmClick}
|
||||
onGenerateFromSourceClick={onGenerateFromSourceClick}
|
||||
onModelDependencyClick={onModelDependencyClick}
|
||||
/>
|
||||
</EditorContainer>
|
||||
</DataExtensionsEditorContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ function UnmodelableMethodRow(props: Props) {
|
||||
<MethodClassifications externalApiUsage={externalApiUsage} />
|
||||
</ApiOrMethodCell>
|
||||
<VSCodeDataGridCell gridColumn="span 4">
|
||||
Method modeled by CodeQL or a different extension pack
|
||||
Method already modeled
|
||||
</VSCodeDataGridCell>
|
||||
</VSCodeDataGridRow>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as React from "react";
|
||||
import * as Sarif from "sarif";
|
||||
import { isLineColumnLoc, isWholeFileLoc } from "../../../common/bqrs-utils";
|
||||
import { parseSarifLocation } from "../../../common/sarif-utils";
|
||||
import { basename } from "path";
|
||||
import { basename } from "../../../common/path";
|
||||
import { useMemo } from "react";
|
||||
import { Location } from "./Location";
|
||||
|
||||
|
||||
@@ -27,8 +27,7 @@ import {
|
||||
} from "./result-table-utils";
|
||||
import { vscode } from "../vscode-api";
|
||||
import { sendTelemetry } from "../common/telemetry";
|
||||
|
||||
const FILE_PATH_REGEX = /^(?:.+[\\/])*(.+)$/;
|
||||
import { basename } from "../../common/path";
|
||||
|
||||
/**
|
||||
* Properties for the `ResultTables` component.
|
||||
@@ -302,7 +301,7 @@ export class ResultTables extends React.Component<
|
||||
openFile(this.props.queryPath);
|
||||
sendTelemetry("local-results-open-query-file");
|
||||
};
|
||||
const fileName = FILE_PATH_REGEX.exec(this.props.queryPath)?.[1] || "query";
|
||||
const fileName = basename(this.props.queryPath);
|
||||
|
||||
return (
|
||||
<span className="vscode-codeql__table-selection-pagination">
|
||||
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
import { vscode } from "../vscode-api";
|
||||
import { AnalyzedRepoItemContent } from "./AnalyzedRepoItemContent";
|
||||
import StarCount from "../common/StarCount";
|
||||
import { LastUpdated } from "../common/LastUpdated";
|
||||
import { useTelemetryOnChange } from "../common/telemetry";
|
||||
import { DeterminateProgressRing } from "../common/DeterminateProgressRing";
|
||||
|
||||
@@ -297,7 +296,6 @@ export const RepoRow = ({
|
||||
<div>
|
||||
<StarCount starCount={repository.stargazersCount} />
|
||||
</div>
|
||||
<LastUpdated lastUpdated={repository.updatedAt} />
|
||||
</MetadataContainer>
|
||||
</TitleContainer>
|
||||
{isExpanded && expandableContentLoaded && (
|
||||
|
||||
@@ -34,9 +34,6 @@ export const RepositoriesSort = ({ value, onChange, className }: Props) => {
|
||||
Number of results
|
||||
</VSCodeOption>
|
||||
<VSCodeOption value={SortKey.Popularity}>Popularity</VSCodeOption>
|
||||
<VSCodeOption value={SortKey.MostRecentCommit}>
|
||||
Most recent commit
|
||||
</VSCodeOption>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -38,10 +38,7 @@ describe(RepoRow.name, () => {
|
||||
expect(
|
||||
screen.queryByRole("img", {
|
||||
// There should not be any icons, except for the icons which are always shown
|
||||
name: (name) =>
|
||||
!["expand", "stars count", "most recent commit"].includes(
|
||||
name.toLowerCase(),
|
||||
),
|
||||
name: (name) => !["expand", "stars count"].includes(name.toLowerCase()),
|
||||
}),
|
||||
).not.toBeInTheDocument();
|
||||
|
||||
@@ -279,26 +276,7 @@ describe(RepoRow.name, () => {
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows updated at", () => {
|
||||
render({
|
||||
repository: {
|
||||
...createMockRepositoryWithMetadata(),
|
||||
// 1 month ago
|
||||
updatedAt: new Date(
|
||||
Date.now() - 1000 * 60 * 60 * 24 * 30,
|
||||
).toISOString(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(screen.getByText("last month")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("img", {
|
||||
name: "Most recent commit",
|
||||
}),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not show star count and updated at when unknown", () => {
|
||||
it("does not show star count when unknown", () => {
|
||||
render({
|
||||
repository: {
|
||||
id: undefined,
|
||||
@@ -312,11 +290,6 @@ describe(RepoRow.name, () => {
|
||||
name: "Stars count",
|
||||
}),
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByRole("img", {
|
||||
name: "Most recent commit",
|
||||
}),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("can expand the repo item", async () => {
|
||||
|
||||
@@ -204,55 +204,6 @@ describe(compareRepository.name, () => {
|
||||
).toBeLessThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when sort key is 'Most recent commit'", () => {
|
||||
const sorter = compareRepository({
|
||||
...permissiveFilterSortState,
|
||||
sortKey: SortKey.MostRecentCommit,
|
||||
});
|
||||
|
||||
const left = {
|
||||
fullName: "github/galaxy",
|
||||
updatedAt: "2020-01-01T00:00:00Z",
|
||||
};
|
||||
const right = {
|
||||
fullName: "github/world",
|
||||
updatedAt: "2021-01-01T00:00:00Z",
|
||||
};
|
||||
|
||||
it("compares correctly", () => {
|
||||
expect(sorter(left, right)).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("compares the inverse correctly", () => {
|
||||
expect(sorter(right, left)).toBeLessThan(0);
|
||||
});
|
||||
|
||||
it("compares equal values correctly", () => {
|
||||
expect(sorter(left, left)).toBe(0);
|
||||
});
|
||||
|
||||
it("compares equal single values correctly", () => {
|
||||
expect(
|
||||
sorter(left, {
|
||||
...right,
|
||||
updatedAt: left.updatedAt,
|
||||
}),
|
||||
).toBeLessThan(0);
|
||||
});
|
||||
|
||||
it("compares missing single values correctly", () => {
|
||||
expect(
|
||||
sorter(
|
||||
{
|
||||
...left,
|
||||
updatedAt: undefined,
|
||||
},
|
||||
right,
|
||||
),
|
||||
).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(compareWithResults.name, () => {
|
||||
@@ -303,32 +254,6 @@ describe(compareWithResults.name, () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("when sort key is 'Most recent commit'", () => {
|
||||
const sorter = compareWithResults({
|
||||
...permissiveFilterSortState,
|
||||
sortKey: SortKey.MostRecentCommit,
|
||||
});
|
||||
|
||||
const left = {
|
||||
repository: {
|
||||
id: 11,
|
||||
fullName: "github/galaxy",
|
||||
updatedAt: "2020-01-01T00:00:00Z",
|
||||
},
|
||||
};
|
||||
const right = {
|
||||
repository: {
|
||||
id: 12,
|
||||
fullName: "github/world",
|
||||
updatedAt: "2021-01-01T00:00:00Z",
|
||||
},
|
||||
};
|
||||
|
||||
it("compares correctly", () => {
|
||||
expect(sorter(left, right)).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when sort key is results count", () => {
|
||||
const sorter = compareWithResults({
|
||||
...permissiveFilterSortState,
|
||||
|
||||
5
extensions/ql-vscode/tsconfig.deadcode.json
Normal file
5
extensions/ql-vscode/tsconfig.deadcode.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": ["**/*.ts*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user