Skip to content

Commit 34ef89c

Browse files
authored
Add Pipeline functionality (#139)
1 parent f86dd4c commit 34ef89c

File tree

30 files changed

+737
-162
lines changed

30 files changed

+737
-162
lines changed

src/webview/WebviewProvider/index.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ import {
1212
fetchRuns,
1313
getRepoInfo,
1414
queryWorkspace,
15-
getContainer
15+
getContainer,
16+
addPipeline
1617
} from "./lib";
1718
import { AuthProvider, getAccessToken } from "../../auth";
1819
import { jwtExpired } from "../../auth/AuthProvider/utils/jwt";
1920
import { sleep } from "./lib/utils";
21+
import { Pipeline } from "./lib/platform/types";
22+
import fetchHubPipelines from "./lib/platform/fetchHubPipelines";
2023

2124
class WebviewProvider implements vscode.WebviewViewProvider {
2225
_currentView?: vscode.WebviewView;
@@ -71,12 +74,19 @@ class WebviewProvider implements vscode.WebviewViewProvider {
7174
case "fetchComputeEnvs":
7275
if (!workspaceId) return;
7376
this.fetchComputeEnvs(workspaceId);
77+
break;
7478
case "createTest":
7579
this.createTest(message.filePath);
7680
break;
7781
case "getContainer":
7882
this.getContainer(message.filePath);
7983
break;
84+
case "fetchHubPipelines":
85+
this.fetchHubPipelines();
86+
break;
87+
case "addPipeline":
88+
this.addPipeline(message);
89+
break;
8090
}
8191
});
8292

@@ -115,6 +125,24 @@ class WebviewProvider implements vscode.WebviewViewProvider {
115125
});
116126
}
117127

128+
private async addPipeline(message: any) {
129+
const accessToken = await this.getAccessToken();
130+
if (!accessToken) return;
131+
const response = await addPipeline(accessToken, message);
132+
const responseBody = await response.json();
133+
this._currentView?.webview.postMessage({
134+
pipelineAdded: true,
135+
responseBody
136+
});
137+
}
138+
139+
private async fetchHubPipelines() {
140+
const hubPipelines = await fetchHubPipelines();
141+
this._currentView?.webview.postMessage({
142+
hubPipelines
143+
});
144+
}
145+
118146
private async fetchPipelines(workspaceId: number) {
119147
const accessToken = await this.getAccessToken();
120148
if (!accessToken) return;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { HubPipeline } from "./hubTypes";
2+
3+
import { SEQERA_HUB_API_URL } from "../../../../constants";
4+
5+
const fetchPipelines = async (): Promise<HubPipeline[]> => {
6+
const response = await fetch(`${SEQERA_HUB_API_URL}/pipelines`, {
7+
credentials: "include",
8+
method: "GET",
9+
headers: new Headers({ "content-type": "application/json" })
10+
});
11+
12+
const data = await response.json();
13+
const { status } = response;
14+
15+
if (status !== 200) {
16+
console.error(status, data);
17+
return [];
18+
}
19+
20+
return data as HubPipeline[];
21+
};
22+
23+
export default fetchPipelines;
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
export type HubPipeline = {
2+
id: number;
3+
latest_release_at: string;
4+
description: string;
5+
watchers: number;
6+
nextflow_main_lang: boolean;
7+
nf_files_in_root: string[];
8+
contributors: number;
9+
nextflow_code_chars: number;
10+
nf_files_in_subfolders: string[];
11+
created_at: string;
12+
forks: number;
13+
slugified_name: string;
14+
url: string;
15+
main_nf_file: string;
16+
updated_at: string;
17+
head_fork: null;
18+
readme_name: null;
19+
revision: string;
20+
alive: boolean;
21+
last_commit_at: string;
22+
open_issues: number;
23+
readme_contains_nextflow: null;
24+
highlighted: boolean;
25+
website: string;
26+
open_prs: number;
27+
hidden: boolean;
28+
stars: number;
29+
default_branch: string;
30+
name: string;
31+
languages: {
32+
Nextflow: number;
33+
Groovy: number;
34+
Python: number;
35+
R: number;
36+
Perl: number;
37+
HTML: number;
38+
};
39+
owner: string;
40+
topics: string[];
41+
launch_config: LaunchConfig;
42+
};
43+
44+
export type LaunchConfig = {
45+
workspaceId: string;
46+
computeEnvId: string;
47+
workDir: string;
48+
pipeline: string;
49+
revision: string;
50+
};
51+
52+
export type AddPipelineRequest = {
53+
name: string;
54+
description: string;
55+
launch: LaunchConfig;
56+
};
57+
58+
export type AddPipelineResponse = {
59+
pipeline?: {
60+
computeEnv: null;
61+
deleted: boolean;
62+
description: string;
63+
icon: string;
64+
labels: null;
65+
lastUpdated: string;
66+
name: string;
67+
optimizationId: null;
68+
optimizationStatus: null;
69+
optimizationTargets: null;
70+
orgId: number;
71+
orgName: string;
72+
pipelineId: number;
73+
repository: string;
74+
userFirstName: string | null;
75+
userId: number;
76+
userLastName: string | null;
77+
userName: string;
78+
visibility: string;
79+
workspaceId: number;
80+
workspaceName: string;
81+
};
82+
message?: string;
83+
};

src/webview/WebviewProvider/lib/platform/types.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
import { LaunchConfig } from "./hubTypes";
2+
3+
export type { HubPipeline } from "./hubTypes";
4+
export type { AddPipelineRequest } from "./hubTypes";
5+
export type { AddPipelineResponse } from "./hubTypes";
6+
17
export type RepoInfo = {
28
url: string;
39
name: string;
@@ -11,13 +17,6 @@ export type TowerConfig = {
1117
apiURL?: string;
1218
};
1319

14-
export type LaunchConfig = {
15-
name?: string;
16-
id?: number;
17-
nf_files_in_root?: string[];
18-
description?: string;
19-
};
20-
2120
export type ComputeEnv = {
2221
id: string;
2322
name: string;
@@ -123,11 +122,6 @@ export type UserInfo = {
123122

124123
export type UserInfoResponse = UserInfo & { message?: string };
125124

126-
export type FormData = {
127-
name: string;
128-
description: string;
129-
};
130-
131125
export type WorkflowStatus =
132126
| "SUBMITTED"
133127
| "RUNNING"

src/webview/WebviewProvider/lib/platform/utils/addPipeline.ts

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,26 @@
1-
import type { Pipeline, ComputeEnv, WorkspaceID } from "../types";
2-
import type { FormData } from "../types";
3-
import type { AuthenticationSession } from "vscode";
41
import { SEQERA_API_URL } from "../../../../../constants";
2+
import { AddPipelineRequest } from "../hubTypes";
3+
4+
type Message = {
5+
requestBody: AddPipelineRequest;
6+
};
57

68
const addPipeline = async (
7-
session: AuthenticationSession | null,
8-
pipeline: Pipeline,
9-
workspaceID: WorkspaceID,
10-
computeEnv: ComputeEnv | undefined,
11-
formData: FormData
9+
accessToken: string,
10+
message: Message
1211
): Promise<Response> => {
13-
const accessToken = session?.accessToken;
14-
const name = formData.name || pipeline.name;
15-
const description = formData.description;
16-
17-
const launchConfig = pipeline.launch_config || {};
18-
let envConfig = {};
19-
if (computeEnv)
20-
envConfig = {
21-
workDir: computeEnv.workDir,
22-
computeEnvId: computeEnv.id
23-
};
12+
const { requestBody } = message;
13+
const { workspaceId } = requestBody.launch;
14+
console.log("🟢 addPipeline", requestBody);
2415

25-
return await fetch(`${SEQERA_API_URL}/pipelines?workspaceId=${workspaceID}`, {
16+
return await fetch(`${SEQERA_API_URL}/pipelines?workspaceId=${workspaceId}`, {
2617
credentials: "include",
2718
method: "POST",
2819
headers: new Headers({
2920
"Content-Type": "application/json",
3021
Authorization: `Bearer ${accessToken}`
3122
}),
32-
body: JSON.stringify({
33-
name,
34-
description,
35-
launch: {
36-
...launchConfig,
37-
...envConfig,
38-
pipeline: pipeline.url,
39-
workspaceId: workspaceID || ""
40-
}
41-
})
23+
body: JSON.stringify(requestBody)
4224
});
4325
};
4426

webview-ui/src/Context/TowerProvider/index.tsx

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import {
1212
Workflow,
1313
Dataset,
1414
DataLink,
15-
WorkspaceID
15+
WorkspaceID,
16+
HubPipeline,
17+
AddPipelineRequest
1618
} from "../types";
1719
import { AuthState } from "..";
1820
import {
@@ -42,6 +44,7 @@ type PlatformData = {
4244
pipelines?: PipelinesResponse;
4345
datasets?: Dataset[];
4446
dataLinks?: DataLink[];
47+
hubPipelines?: HubPipeline[];
4548
};
4649

4750
type TowerContextType = {
@@ -70,10 +73,13 @@ type TowerContextType = {
7073
tokenExpiry?: number;
7174
repoInfo?: RepoInfo;
7275
pipelines?: Pipeline[];
76+
hubPipelines?: HubPipeline[];
7377
datasets?: Dataset[];
7478
dataLinks?: DataLink[];
7579
useLocalContext: boolean;
7680
setUseLocalContext: (n: boolean) => void;
81+
addPipeline: (requestBody: AddPipelineRequest) => void;
82+
fetchHubPipelines: () => void;
7783
};
7884

7985
const TowerProvider: React.FC<Props> = ({
@@ -90,7 +96,8 @@ const TowerProvider: React.FC<Props> = ({
9096
pipelines,
9197
datasets,
9298
dataLinks,
93-
repoInfo
99+
repoInfo,
100+
hubPipelines
94101
} = platformData;
95102

96103
const organizations: Organization[] = useMemo(
@@ -150,6 +157,14 @@ const TowerProvider: React.FC<Props> = ({
150157
vscode.postMessage({ command: "fetchComputeEnvs", workspaceId });
151158
}
152159

160+
function fetchHubPipelines() {
161+
vscode.postMessage({ command: "fetchHubPipelines" });
162+
}
163+
164+
function addPipeline(requestBody: AddPipelineRequest) {
165+
vscode.postMessage({ command: "addPipeline", requestBody });
166+
}
167+
153168
return (
154169
<TowerContext.Provider
155170
value={{
@@ -181,7 +196,10 @@ const TowerProvider: React.FC<Props> = ({
181196
tokenExpiry: auth.tokenExpiry,
182197
repoInfo,
183198
datasets,
184-
dataLinks
199+
dataLinks,
200+
fetchHubPipelines,
201+
hubPipelines,
202+
addPipeline
185203
}}
186204
>
187205
{children}

webview-ui/src/Context/WorkspaceProvider/index.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const WorkspaceProvider = ({ children, vscode, viewID, isCursor }: Props) => {
5959
const [selectedItems, setSelectedItems] = useState<string[]>(
6060
state?.selectedItems || []
6161
);
62-
const [selectedView, setSelectedView] = useState<string>("runs");
62+
const [selectedView, setSelectedView] = useState<string>("pipelines");
6363

6464
useEffect(() => {
6565
vscode.setState({ selectedItems });
@@ -95,11 +95,10 @@ const WorkspaceProvider = ({ children, vscode, viewID, isCursor }: Props) => {
9595
}
9696

9797
function findChildren(node: TreeNode): TreeNode[] {
98-
if (!node.children)
99-
return [];
100-
return node.children.flatMap((call) => (
98+
if (!node.children) return [];
99+
return node.children.flatMap((call) =>
101100
nodes.filter((n) => n.path === call.path && n.name === call.name)
102-
));
101+
);
103102
}
104103

105104
function openFile(filePath: string, line: number) {

0 commit comments

Comments
 (0)