CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/next/components/project/create.tsx
Views: 687
1
/* Create a new project.
2
*/
3
4
import { useState } from "react";
5
import { Alert, Button, Divider, Input, Space } from "antd";
6
import Loading from "components/share/loading";
7
import A from "components/misc/A";
8
import { Icon } from "@cocalc/frontend/components/icon";
9
import apiPost from "lib/api/post";
10
import editURL from "lib/share/edit-url";
11
12
interface Props {
13
label?: string;
14
image?: string; // optional compute image
15
defaultTitle?: string;
16
start?: boolean; // start as soon as it is created.
17
onCreate: (project: { project_id: string; title: string }) => void;
18
public_path_id?: string; // if given, project is being created in order to use this public path, so a license might be applied.
19
}
20
21
export default function CreateProject({
22
label,
23
image,
24
defaultTitle,
25
start,
26
onCreate,
27
public_path_id,
28
}: Props) {
29
const [title, setTitle] = useState<string>(defaultTitle ?? "");
30
const [project_id, setProjectID] = useState<string>("");
31
const [error, setError] = useState<string>("");
32
const [state, setState] = useState<
33
"config" | "creating" | "starting" | "created"
34
>("config");
35
36
async function create(title: string) {
37
setError("");
38
setState("creating");
39
try {
40
const response = await apiPost("/projects/create", {
41
title,
42
image,
43
public_path_id,
44
});
45
if (response.error) {
46
throw Error(response.error);
47
}
48
if (start) {
49
setState("starting");
50
await apiPost("/projects/start", { project_id: response.project_id });
51
}
52
setProjectID(response.project_id);
53
setState("created");
54
onCreate({ project_id: response.project_id, title });
55
} catch (err) {
56
setState("config");
57
setError(`${err}`);
58
}
59
}
60
61
return (
62
<div>
63
<Divider style={{ color: "#666" }}>{label ?? "Create a Project"}</Divider>
64
<Space direction="vertical" style={{ width: "100%" }}>
65
{error && <Alert type="error" message={error} showIcon />}
66
{state == "creating" && (
67
<div style={{ textAlign: "center" }}>
68
<Loading style={{ fontSize: "16pt" }}>
69
Creating project "{title}"...
70
</Loading>
71
</div>
72
)}
73
{state == "starting" && (
74
<div style={{ textAlign: "center" }}>
75
<Loading style={{ fontSize: "16pt" }}>
76
Starting project "{title}"...
77
</Loading>
78
</div>
79
)}
80
{state == "created" && (
81
<div>
82
<Icon
83
name="check"
84
style={{ color: "darkgreen", fontSize: "16pt" }}
85
/>{" "}
86
Created project{" "}
87
{project_id && title ? (
88
<A
89
href={editURL({
90
type: "collaborator",
91
project_id,
92
})}
93
external
94
>
95
{title}
96
</A>
97
) : (
98
""
99
)}
100
.
101
</div>
102
)}
103
<Input
104
allowClear
105
defaultValue={defaultTitle}
106
disabled={state != "config"}
107
placeholder="Project title (easily change this at any time)"
108
onChange={(e) => setTitle(e.target.value)}
109
onPressEnter={(e) => {
110
e.preventDefault();
111
create(title);
112
}}
113
/>
114
{state == "config" && (
115
<Button
116
disabled={!title || state != "config"}
117
type={title ? "primary" : undefined}
118
onClick={() => create(title)}
119
>
120
<Icon name="plus-circle" /> Create New Project
121
</Button>
122
)}
123
</Space>
124
</div>
125
);
126
}
127
128