Skip to content

Commit db3d242

Browse files
authored
Add empty states for modeling panel (#2914)
1 parent 1806108 commit db3d242

File tree

11 files changed

+227
-111
lines changed

11 files changed

+227
-111
lines changed

extensions/ql-vscode/src/common/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ export type PackagingCommands = {
323323

324324
export type ModelEditorCommands = {
325325
"codeQL.openModelEditor": () => Promise<void>;
326+
"codeQL.openModelEditorFromModelingPanel": () => Promise<void>;
326327
"codeQLModelEditor.jumpToUsageLocation": (
327328
method: Method,
328329
usage: Usage,

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,10 +610,15 @@ interface RevealInEditorMessage {
610610
method: Method;
611611
}
612612

613+
interface StartModelingMessage {
614+
t: "startModeling";
615+
}
616+
613617
export type FromMethodModelingMessage =
614618
| CommonFromViewMessages
615619
| SetModeledMethodMessage
616-
| RevealInEditorMessage;
620+
| RevealInEditorMessage
621+
| StartModelingMessage;
617622

618623
interface SetMethodMessage {
619624
t: "setMethod";

extensions/ql-vscode/src/common/vscode/abstract-webview-view-provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export abstract class AbstractWebviewViewProvider<
1313
private disposables: Disposable[] = [];
1414

1515
constructor(
16-
private readonly app: App,
16+
protected readonly app: App,
1717
private readonly webviewKind: WebviewKind,
1818
) {}
1919

extensions/ql-vscode/src/model-editor/method-modeling/method-modeling-view-provider.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
9292
await this.revealInModelEditor(msg.method);
9393

9494
break;
95+
96+
case "startModeling":
97+
await this.app.commands.execute(
98+
"codeQL.openModelEditorFromModelingPanel",
99+
);
100+
break;
95101
default:
96102
assertNever(msg);
97103
}

extensions/ql-vscode/src/model-editor/model-editor-module.ts

Lines changed: 115 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -73,115 +73,9 @@ export class ModelEditorModule extends DisposableObject {
7373

7474
public getCommands(): ModelEditorCommands {
7575
return {
76-
"codeQL.openModelEditor": async () => {
77-
const db = this.databaseManager.currentDatabaseItem;
78-
if (!db) {
79-
void showAndLogErrorMessage(this.app.logger, "No database selected");
80-
return;
81-
}
82-
83-
const language = db.language;
84-
if (
85-
!SUPPORTED_LANGUAGES.includes(language) ||
86-
!isQueryLanguage(language)
87-
) {
88-
void showAndLogErrorMessage(
89-
this.app.logger,
90-
`The CodeQL Model Editor is not supported for ${language} databases.`,
91-
);
92-
return;
93-
}
94-
95-
return withProgress(
96-
async (progress) => {
97-
const maxStep = 4;
98-
99-
if (!(await this.cliServer.cliConstraints.supportsQlpacksKind())) {
100-
void showAndLogErrorMessage(
101-
this.app.logger,
102-
`This feature requires CodeQL CLI version ${CliVersionConstraint.CLI_VERSION_WITH_QLPACKS_KIND.format()} or later.`,
103-
);
104-
return;
105-
}
106-
107-
if (
108-
!(await this.cliServer.cliConstraints.supportsResolveExtensions())
109-
) {
110-
void showAndLogErrorMessage(
111-
this.app.logger,
112-
`This feature requires CodeQL CLI version ${CliVersionConstraint.CLI_VERSION_WITH_RESOLVE_EXTENSIONS.format()} or later.`,
113-
);
114-
return;
115-
}
116-
117-
const modelFile = await pickExtensionPack(
118-
this.cliServer,
119-
db,
120-
this.app.logger,
121-
progress,
122-
maxStep,
123-
);
124-
if (!modelFile) {
125-
return;
126-
}
127-
128-
progress({
129-
message: "Installing dependencies...",
130-
step: 3,
131-
maxStep,
132-
});
133-
134-
// Create new temporary directory for query files and pack dependencies
135-
const { path: queryDir, cleanup: cleanupQueryDir } = await dir({
136-
unsafeCleanup: true,
137-
});
138-
139-
const success = await setUpPack(this.cliServer, queryDir, language);
140-
if (!success) {
141-
await cleanupQueryDir();
142-
return;
143-
}
144-
145-
progress({
146-
message: "Opening editor...",
147-
step: 4,
148-
maxStep,
149-
});
150-
151-
const view = new ModelEditorView(
152-
this.app,
153-
this.modelingStore,
154-
this.editorViewTracker,
155-
this.databaseManager,
156-
this.cliServer,
157-
this.queryRunner,
158-
this.queryStorageDir,
159-
queryDir,
160-
db,
161-
modelFile,
162-
Mode.Application,
163-
);
164-
165-
this.modelingStore.onDbClosed(async (dbUri) => {
166-
if (dbUri === db.databaseUri.toString()) {
167-
await cleanupQueryDir();
168-
}
169-
});
170-
171-
this.push(view);
172-
this.push({
173-
dispose(): void {
174-
void cleanupQueryDir();
175-
},
176-
});
177-
178-
await view.openView();
179-
},
180-
{
181-
title: "Opening CodeQL Model Editor",
182-
},
183-
);
184-
},
76+
"codeQL.openModelEditor": this.openModelEditor.bind(this),
77+
"codeQL.openModelEditorFromModelingPanel":
78+
this.openModelEditor.bind(this),
18579
"codeQLModelEditor.jumpToUsageLocation": async (
18680
method: Method,
18781
usage: Usage,
@@ -213,4 +107,116 @@ export class ModelEditorModule extends DisposableObject {
213107
await this.methodModelingPanel.setMethod(method);
214108
await showResolvableLocation(usage.url, databaseItem, this.app.logger);
215109
}
110+
111+
private async openModelEditor(): Promise<void> {
112+
{
113+
const db = this.databaseManager.currentDatabaseItem;
114+
if (!db) {
115+
void showAndLogErrorMessage(this.app.logger, "No database selected");
116+
return;
117+
}
118+
119+
const language = db.language;
120+
if (
121+
!SUPPORTED_LANGUAGES.includes(language) ||
122+
!isQueryLanguage(language)
123+
) {
124+
void showAndLogErrorMessage(
125+
this.app.logger,
126+
`The CodeQL Model Editor is not supported for ${language} databases.`,
127+
);
128+
return;
129+
}
130+
131+
return withProgress(
132+
async (progress) => {
133+
const maxStep = 4;
134+
135+
if (!(await this.cliServer.cliConstraints.supportsQlpacksKind())) {
136+
void showAndLogErrorMessage(
137+
this.app.logger,
138+
`This feature requires CodeQL CLI version ${CliVersionConstraint.CLI_VERSION_WITH_QLPACKS_KIND.format()} or later.`,
139+
);
140+
return;
141+
}
142+
143+
if (
144+
!(await this.cliServer.cliConstraints.supportsResolveExtensions())
145+
) {
146+
void showAndLogErrorMessage(
147+
this.app.logger,
148+
`This feature requires CodeQL CLI version ${CliVersionConstraint.CLI_VERSION_WITH_RESOLVE_EXTENSIONS.format()} or later.`,
149+
);
150+
return;
151+
}
152+
153+
const modelFile = await pickExtensionPack(
154+
this.cliServer,
155+
db,
156+
this.app.logger,
157+
progress,
158+
maxStep,
159+
);
160+
if (!modelFile) {
161+
return;
162+
}
163+
164+
progress({
165+
message: "Installing dependencies...",
166+
step: 3,
167+
maxStep,
168+
});
169+
170+
// Create new temporary directory for query files and pack dependencies
171+
const { path: queryDir, cleanup: cleanupQueryDir } = await dir({
172+
unsafeCleanup: true,
173+
});
174+
175+
const success = await setUpPack(this.cliServer, queryDir, language);
176+
if (!success) {
177+
await cleanupQueryDir();
178+
return;
179+
}
180+
181+
progress({
182+
message: "Opening editor...",
183+
step: 4,
184+
maxStep,
185+
});
186+
187+
const view = new ModelEditorView(
188+
this.app,
189+
this.modelingStore,
190+
this.editorViewTracker,
191+
this.databaseManager,
192+
this.cliServer,
193+
this.queryRunner,
194+
this.queryStorageDir,
195+
queryDir,
196+
db,
197+
modelFile,
198+
Mode.Application,
199+
);
200+
201+
this.modelingStore.onDbClosed(async (dbUri) => {
202+
if (dbUri === db.databaseUri.toString()) {
203+
await cleanupQueryDir();
204+
}
205+
});
206+
207+
this.push(view);
208+
this.push({
209+
dispose(): void {
210+
void cleanupQueryDir();
211+
},
212+
});
213+
214+
await view.openView();
215+
},
216+
{
217+
title: "Opening CodeQL Model Editor",
218+
},
219+
);
220+
}
221+
}
216222
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import * as React from "react";
2+
3+
import { Meta, StoryFn } from "@storybook/react";
4+
5+
import { ResponsiveContainer as ResponsiveContainerComponent } from "../../view/common/ResponsiveContainer";
6+
7+
export default {
8+
title: "Responsive Container",
9+
component: ResponsiveContainerComponent,
10+
} as Meta<typeof ResponsiveContainerComponent>;
11+
12+
const Template: StoryFn<typeof ResponsiveContainerComponent> = (args) => (
13+
<ResponsiveContainerComponent>
14+
<span>Hello</span>
15+
</ResponsiveContainerComponent>
16+
);
17+
18+
export const ResponsiveContainer = Template.bind({});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import * as React from "react";
2+
3+
import { Meta, StoryFn } from "@storybook/react";
4+
5+
import { NoMethodSelected as NoMethodSelectedComponent } from "../../view/method-modeling/NoMethodSelected";
6+
7+
export default {
8+
title: "Method Modeling/No Method Selected",
9+
component: NoMethodSelectedComponent,
10+
} as Meta<typeof NoMethodSelectedComponent>;
11+
12+
const Template: StoryFn<typeof NoMethodSelectedComponent> = () => (
13+
<NoMethodSelectedComponent />
14+
);
15+
16+
export const NoMethodSelected = Template.bind({});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import * as React from "react";
2+
3+
import { Meta, StoryFn } from "@storybook/react";
4+
5+
import { NotInModelingMode as NotInModelingModeComponent } from "../../view/method-modeling/NotInModelingMode";
6+
7+
export default {
8+
title: "Method Modeling/Not In Modeling Mode",
9+
component: NotInModelingModeComponent,
10+
} as Meta<typeof NotInModelingModeComponent>;
11+
12+
const Template: StoryFn<typeof NotInModelingModeComponent> = () => (
13+
<NotInModelingModeComponent />
14+
);
15+
16+
export const NotInModelingMode = Template.bind({});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { styled } from "styled-components";
2+
3+
export const ResponsiveContainer = styled.div`
4+
display: flex;
5+
flex-direction: column;
6+
align-items: flex-start;
7+
justify-content: flex-start;
8+
height: 100vh;
9+
10+
@media (min-height: 300px) {
11+
align-items: center;
12+
justify-content: center;
13+
text-align: center;
14+
}
15+
`;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import * as React from "react";
2+
import { ResponsiveContainer } from "../common/ResponsiveContainer";
3+
4+
export const NoMethodSelected = () => {
5+
return (
6+
<ResponsiveContainer>Select an API or method to model</ResponsiveContainer>
7+
);
8+
};

0 commit comments

Comments
 (0)