Skip to content

Commit 2cb520d

Browse files
authored
Merge pull request #2717 from github/nora/hide-modeled-on-model-details-view
Respect the "Hide modeled APIs" checkbox in the model details view
2 parents 4a752d2 + 6cfd20e commit 2cb520d

File tree

7 files changed

+100
-23
lines changed

7 files changed

+100
-23
lines changed

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,11 @@ interface ModelDependencyMessage {
567567
t: "modelDependency";
568568
}
569569

570+
interface HideModeledApisMessage {
571+
t: "hideModeledApis";
572+
hideModeledApis: boolean;
573+
}
574+
570575
export type ToDataExtensionsEditorMessage =
571576
| SetExtensionPackStateMessage
572577
| SetExternalApiUsagesMessage
@@ -585,4 +590,5 @@ export type FromDataExtensionsEditorMessage =
585590
| GenerateExternalApiMessage
586591
| GenerateExternalApiFromLlmMessage
587592
| StopGeneratingExternalApiFromLlmMessage
588-
| ModelDependencyMessage;
593+
| ModelDependencyMessage
594+
| HideModeledApisMessage;

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { join } from "path";
4343
import { pickExtensionPack } from "./extension-pack-picker";
4444
import { getLanguageDisplayName } from "../common/query-language";
4545
import { AutoModeler } from "./auto-modeler";
46+
import { INITIAL_HIDE_MODELED_APIS_VALUE } from "./shared/hide-modeled-apis";
4647

4748
export class DataExtensionsEditorView extends AbstractWebview<
4849
ToDataExtensionsEditorMessage,
@@ -51,6 +52,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
5152
private readonly autoModeler: AutoModeler;
5253

5354
private externalApiUsages: ExternalApiUsage[];
55+
private hideModeledApis: boolean;
5456

5557
public constructor(
5658
ctx: ExtensionContext,
@@ -66,6 +68,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
6668
private readonly updateModelDetailsPanelState: (
6769
externalApiUsages: ExternalApiUsage[],
6870
databaseItem: DatabaseItem,
71+
hideModeledApis: boolean,
6972
) => Promise<void>,
7073
private readonly revealItemInDetailsPanel: (usage: Usage) => Promise<void>,
7174
private readonly handleViewBecameActive: (
@@ -98,6 +101,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
98101
},
99102
);
100103
this.externalApiUsages = [];
104+
this.hideModeledApis = INITIAL_HIDE_MODELED_APIS_VALUE;
101105
}
102106

103107
public async openView() {
@@ -110,6 +114,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
110114
await this.updateModelDetailsPanelState(
111115
this.externalApiUsages,
112116
this.databaseItem,
117+
this.hideModeledApis,
113118
);
114119
}
115120
});
@@ -235,6 +240,14 @@ export class DataExtensionsEditorView extends AbstractWebview<
235240

236241
await Promise.all([this.setViewState(), this.loadExternalApiUsages()]);
237242

243+
break;
244+
case "hideModeledApis":
245+
this.hideModeledApis = msg.hideModeledApis;
246+
await this.updateModelDetailsPanelState(
247+
this.externalApiUsages,
248+
this.databaseItem,
249+
this.hideModeledApis,
250+
);
238251
break;
239252
default:
240253
assertNever(msg);
@@ -340,6 +353,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
340353
await this.updateModelDetailsPanelState(
341354
this.externalApiUsages,
342355
this.databaseItem,
356+
this.hideModeledApis,
343357
);
344358
}
345359
} catch (err) {

extensions/ql-vscode/src/data-extensions-editor/model-details/model-details-data-provider.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { ExternalApiUsage, Usage } from "../external-api-usage";
1313
import { DatabaseItem } from "../../databases/local-databases";
1414
import { relative } from "path";
1515
import { CodeQLCliServer } from "../../codeql-cli/cli";
16+
import { INITIAL_HIDE_MODELED_APIS_VALUE } from "../shared/hide-modeled-apis";
1617

1718
export class ModelDetailsDataProvider
1819
extends DisposableObject
@@ -21,6 +22,7 @@ export class ModelDetailsDataProvider
2122
private externalApiUsages: ExternalApiUsage[] = [];
2223
private databaseItem: DatabaseItem | undefined = undefined;
2324
private sourceLocationPrefix: string | undefined = undefined;
25+
private hideModeledApis: boolean = INITIAL_HIDE_MODELED_APIS_VALUE;
2426

2527
private readonly onDidChangeTreeDataEmitter = this.push(
2628
new EventEmitter<void>(),
@@ -44,15 +46,19 @@ export class ModelDetailsDataProvider
4446
public async setState(
4547
externalApiUsages: ExternalApiUsage[],
4648
databaseItem: DatabaseItem,
49+
hideModeledApis: boolean,
4750
): Promise<void> {
4851
if (
4952
this.externalApiUsages !== externalApiUsages ||
50-
this.databaseItem !== databaseItem
53+
this.databaseItem !== databaseItem ||
54+
this.hideModeledApis !== hideModeledApis
5155
) {
5256
this.externalApiUsages = externalApiUsages;
5357
this.databaseItem = databaseItem;
5458
this.sourceLocationPrefix =
5559
await this.databaseItem.getSourceLocationPrefix(this.cliServer);
60+
this.hideModeledApis = hideModeledApis;
61+
5662
this.onDidChangeTreeDataEmitter.fire();
5763
}
5864
}
@@ -92,7 +98,11 @@ export class ModelDetailsDataProvider
9298

9399
getChildren(item?: ModelDetailsTreeViewItem): ModelDetailsTreeViewItem[] {
94100
if (item === undefined) {
95-
return this.externalApiUsages;
101+
if (this.hideModeledApis) {
102+
return this.externalApiUsages.filter((api) => !api.supported);
103+
} else {
104+
return this.externalApiUsages;
105+
}
96106
} else if (isExternalApiUsage(item)) {
97107
return item.usages;
98108
} else {

extensions/ql-vscode/src/data-extensions-editor/model-details/model-details-panel.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,18 @@ export class ModelDetailsPanel extends DisposableObject {
2626
public async setState(
2727
externalApiUsages: ExternalApiUsage[],
2828
databaseItem: DatabaseItem,
29+
hideModeledApis: boolean,
2930
): Promise<void> {
30-
await this.dataProvider.setState(externalApiUsages, databaseItem);
31+
await this.dataProvider.setState(
32+
externalApiUsages,
33+
databaseItem,
34+
hideModeledApis,
35+
);
36+
const numOfApis = hideModeledApis
37+
? externalApiUsages.filter((api) => !api.supported).length
38+
: externalApiUsages.length;
3139
this.treeView.badge = {
32-
value: externalApiUsages.length,
40+
value: numOfApis,
3341
tooltip: "Number of external APIs",
3442
};
3543
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const INITIAL_HIDE_MODELED_APIS_VALUE = true;

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { percentFormatter } from "./formatters";
1919
import { Mode } from "../../data-extensions-editor/shared/mode";
2020
import { InProgressMethods } from "../../data-extensions-editor/shared/in-progress-methods";
2121
import { getLanguageDisplayName } from "../../common/query-language";
22+
import { INITIAL_HIDE_MODELED_APIS_VALUE } from "../../data-extensions-editor/shared/hide-modeled-apis";
2223

2324
const LoadingContainer = styled.div`
2425
text-align: center;
@@ -74,12 +75,14 @@ type Props = {
7475
initialViewState?: DataExtensionEditorViewState;
7576
initialExternalApiUsages?: ExternalApiUsage[];
7677
initialModeledMethods?: Record<string, ModeledMethod>;
78+
initialHideModeledApis?: boolean;
7779
};
7880

7981
export function DataExtensionsEditor({
8082
initialViewState,
8183
initialExternalApiUsages = [],
8284
initialModeledMethods = {},
85+
initialHideModeledApis = INITIAL_HIDE_MODELED_APIS_VALUE,
8386
}: Props): JSX.Element {
8487
const [viewState, setViewState] = useState<
8588
DataExtensionEditorViewState | undefined
@@ -96,7 +99,16 @@ export function DataExtensionsEditor({
9699
new InProgressMethods(),
97100
);
98101

99-
const [hideModeledApis, setHideModeledApis] = useState(true);
102+
const [hideModeledApis, setHideModeledApis] = useState(
103+
initialHideModeledApis,
104+
);
105+
106+
useEffect(() => {
107+
vscode.postMessage({
108+
t: "hideModeledApis",
109+
hideModeledApis,
110+
});
111+
}, [hideModeledApis]);
100112

101113
const [modeledMethods, setModeledMethods] = useState<
102114
Record<string, ModeledMethod>

extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/model-details/model-details-data-provider.test.ts

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,57 +8,83 @@ describe("ModelDetailsDataProvider", () => {
88
const mockCliServer = mockedObject<CodeQLCliServer>({});
99

1010
describe("setState", () => {
11-
it("should not emit onDidChangeTreeData event when state has not changed", async () => {
12-
const externalApiUsages: ExternalApiUsage[] = [];
13-
const dbItem = mockedObject<DatabaseItem>({
14-
getSourceLocationPrefix: () => "test",
15-
});
11+
const hideModeledApis: boolean = false;
12+
const externalApiUsages: ExternalApiUsage[] = [];
13+
const dbItem = mockedObject<DatabaseItem>({
14+
getSourceLocationPrefix: () => "test",
15+
});
1616

17+
it("should not emit onDidChangeTreeData event when state has not changed", async () => {
1718
const dataProvider = new ModelDetailsDataProvider(mockCliServer);
18-
await dataProvider.setState(externalApiUsages, dbItem);
19+
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
1920

2021
const onDidChangeTreeDataListener = jest.fn();
2122
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
2223

23-
await dataProvider.setState(externalApiUsages, dbItem);
24+
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
2425

2526
expect(onDidChangeTreeDataListener).not.toHaveBeenCalled();
2627
});
2728

2829
it("should emit onDidChangeTreeData event when externalApiUsages has changed", async () => {
29-
const externalApiUsages1: ExternalApiUsage[] = [];
3030
const externalApiUsages2: ExternalApiUsage[] = [];
31-
const dbItem = mockedObject<DatabaseItem>({
32-
getSourceLocationPrefix: () => "test",
33-
});
3431

3532
const dataProvider = new ModelDetailsDataProvider(mockCliServer);
36-
await dataProvider.setState(externalApiUsages1, dbItem);
33+
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
3734

3835
const onDidChangeTreeDataListener = jest.fn();
3936
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
4037

41-
await dataProvider.setState(externalApiUsages2, dbItem);
38+
await dataProvider.setState(externalApiUsages2, dbItem, hideModeledApis);
4239

4340
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
4441
});
4542

4643
it("should emit onDidChangeTreeData event when dbItem has changed", async () => {
47-
const externalApiUsages: ExternalApiUsage[] = [];
48-
const dbItem1 = mockedObject<DatabaseItem>({
44+
const dbItem2 = mockedObject<DatabaseItem>({
4945
getSourceLocationPrefix: () => "test",
5046
});
47+
48+
const dataProvider = new ModelDetailsDataProvider(mockCliServer);
49+
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
50+
51+
const onDidChangeTreeDataListener = jest.fn();
52+
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
53+
54+
await dataProvider.setState(externalApiUsages, dbItem2, hideModeledApis);
55+
56+
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
57+
});
58+
59+
it("should emit onDidChangeTreeData event when hideModeledApis has changed", async () => {
60+
const dataProvider = new ModelDetailsDataProvider(mockCliServer);
61+
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
62+
63+
const onDidChangeTreeDataListener = jest.fn();
64+
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
65+
66+
await dataProvider.setState(externalApiUsages, dbItem, !hideModeledApis);
67+
68+
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
69+
});
70+
71+
it("should emit onDidChangeTreeData event when all entries have changed", async () => {
5172
const dbItem2 = mockedObject<DatabaseItem>({
5273
getSourceLocationPrefix: () => "test",
5374
});
75+
const externalApiUsages2: ExternalApiUsage[] = [];
5476

5577
const dataProvider = new ModelDetailsDataProvider(mockCliServer);
56-
await dataProvider.setState(externalApiUsages, dbItem1);
78+
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
5779

5880
const onDidChangeTreeDataListener = jest.fn();
5981
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
6082

61-
await dataProvider.setState(externalApiUsages, dbItem2);
83+
await dataProvider.setState(
84+
externalApiUsages2,
85+
dbItem2,
86+
!hideModeledApis,
87+
);
6288

6389
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
6490
});

0 commit comments

Comments
 (0)