@@ -9,7 +9,7 @@ Create a new project
99
1010import { Button , Card , Col , Form , Input , Row } from "antd" ;
1111import { delay } from "awaiting" ;
12-
12+ import { BuyLicenseForProject } from "@cocalc/frontend/site-licenses/purchase/buy-license-for-project" ;
1313import { Alert , Well } from "@cocalc/frontend/antd-bootstrap" ;
1414import {
1515 CSS ,
@@ -48,9 +48,10 @@ interface Props {
4848
4949type EditState = "edit" | "view" | "saving" ;
5050
51- export const NewProjectCreator : React . FC < Props > = ( props : Props ) => {
52- const { start_in_edit_mode, default_value } = props ;
53-
51+ export const NewProjectCreator : React . FC < Props > = ( {
52+ start_in_edit_mode,
53+ default_value,
54+ } : Props ) => {
5455 const managed_licenses = useTypedRedux ( "billing" , "managed_licenses" ) ;
5556
5657 // view --> edit --> saving --> view
@@ -60,7 +61,6 @@ export const NewProjectCreator: React.FC<Props> = (props: Props) => {
6061 const [ title_text , set_title_text ] = useState < string > ( default_value ?? "" ) ;
6162 const [ error , set_error ] = useState < string > ( "" ) ;
6263 const [ show_advanced , set_show_advanced ] = useState < boolean > ( false ) ;
63- const [ show_add_license , set_show_add_license ] = useState < boolean > ( false ) ;
6464 const [ title_prefill , set_title_prefill ] = useState < boolean > ( false ) ;
6565 const [ license_id , set_license_id ] = useState < string > ( "" ) ;
6666 const [ warnBoost , setWarnBoost ] = useState < boolean > ( false ) ;
@@ -72,6 +72,12 @@ export const NewProjectCreator: React.FC<Props> = (props: Props) => {
7272
7373 const is_anonymous = useTypedRedux ( "account" , "is_anonymous" ) ;
7474 const customize_kucalc = useTypedRedux ( "customize" , "kucalc" ) ;
75+ const requireLicense = ! ! useTypedRedux (
76+ "customize" ,
77+ "require_license_to_create_project" ,
78+ ) ;
79+ const [ show_add_license , set_show_add_license ] =
80+ useState < boolean > ( requireLicense ) ;
7581
7682 // onprem and cocalc.com use licenses to adjust quota configs – but only cocalc.com has custom software images
7783 const show = useMemo (
@@ -110,7 +116,7 @@ export const NewProjectCreator: React.FC<Props> = (props: Props) => {
110116 set_error ( "" ) ;
111117 set_custom_software ( { } ) ;
112118 set_show_advanced ( false ) ;
113- set_show_add_license ( false ) ;
119+ set_show_add_license ( requireLicense ) ;
114120 set_title_prefill ( true ) ;
115121 set_license_id ( "" ) ;
116122 }
@@ -131,6 +137,7 @@ export const NewProjectCreator: React.FC<Props> = (props: Props) => {
131137 title : title_text ,
132138 image : await derive_project_img_name ( custom_software ) ,
133139 start : true , // used to not start, due to apply_default_upgrades, but upgrades are deprecated
140+ license : license_id ,
134141 } ;
135142 try {
136143 project_id = await actions . create_project ( opts ) ;
@@ -140,9 +147,6 @@ export const NewProjectCreator: React.FC<Props> = (props: Props) => {
140147 set_error ( `Error creating project -- ${ err } ` ) ;
141148 return ;
142149 }
143- if ( isValidUUID ( license_id ) ) {
144- await actions . add_site_license_to_project ( project_id , license_id ) ;
145- }
146150 track ( "create-project" , {
147151 how : "projects-page" ,
148152 project_id,
@@ -224,10 +228,13 @@ export const NewProjectCreator: React.FC<Props> = (props: Props) => {
224228 ) ;
225229 }
226230
227- function create_disabled ( ) {
231+ function isDisabled ( ) {
232+ if ( requireLicense && ! license_id ) {
233+ return true ;
234+ }
228235 return (
229236 // no name of new project
230- title_text === "" ||
237+ ! title_text ?. trim ( ) ||
231238 // currently saving (?)
232239 state === "saving" ||
233240 // user wants a non-default image, but hasn't selected one yet
@@ -283,8 +290,20 @@ export const NewProjectCreator: React.FC<Props> = (props: Props) => {
283290 function render_add_license ( ) {
284291 if ( ! show_add_license ) return ;
285292 return (
286- < Card size = "small" title = "Select license" style = { CARD_STYLE } >
293+ < Card
294+ size = "small"
295+ title = {
296+ < >
297+ < div style = { { float : "right" } } >
298+ < BuyLicenseForProject size = "small" />
299+ </ div >
300+ < Icon name = "key" /> Select License
301+ </ >
302+ }
303+ style = { CARD_STYLE }
304+ >
287305 < SiteLicenseInput
306+ requireValid
288307 confirmLabel = { "Add this license" }
289308 onChange = { addSiteLicense }
290309 />
@@ -322,6 +341,7 @@ export const NewProjectCreator: React.FC<Props> = (props: Props) => {
322341 return (
323342 < div style = { TOGGLE_STYLE } >
324343 < Button
344+ disabled = { requireLicense }
325345 onClick = { ( ) => set_show_add_license ( true ) }
326346 type = "link"
327347 style = { TOGGLE_BUTTON_STYLE }
@@ -345,7 +365,7 @@ export const NewProjectCreator: React.FC<Props> = (props: Props) => {
345365 >
346366 add/remove licenses
347367 </ A > { " " }
348- in the project settings later on .
368+ in project settings later.
349369 </ div >
350370 ) ;
351371 }
@@ -381,36 +401,48 @@ export const NewProjectCreator: React.FC<Props> = (props: Props) => {
381401 />
382402 </ Form . Item >
383403 </ Form >
404+ < div style = { { color : COLORS . GRAY , float : "right" } } >
405+ You can change the title at any time.
406+ </ div >
384407 </ Col >
385408 < Col sm = { 12 } >
386409 < div style = { { color : COLORS . GRAY , marginLeft : "30px" } } >
387- A < A href = "https://doc.cocalc.com/project.html" > project</ A > is an
388- isolated private computational workspace that you can share with
389- others. You can easily change the project's title at any time in
390- project settings.
410+ A < A href = "https://doc.cocalc.com/project.html" > project</ A > is a
411+ private computational workspace that you can use with
412+ collaborators that you explicitly invite. You can attach powerful{ " " }
413+ < A href = "https://doc.cocalc.com/compute_server.html" >
414+ GPUs, CPUs
415+ </ A > { " " }
416+ and{ " " }
417+ < A href = "https://doc.cocalc.com/cloud_file_system.html" >
418+ storage
419+ </ A > { " " }
420+ to a project.
391421 </ div >
392422 </ Col >
393423 </ Row >
394- { render_advanced_toggle ( ) }
395- { render_advanced ( ) }
396424 { render_add_license_toggle ( ) }
397425 { render_add_license ( ) }
398426 { render_license ( ) }
427+ { render_advanced_toggle ( ) }
428+ { render_advanced ( ) }
399429 < Row >
400430 < Col sm = { 24 } style = { { marginTop : "10px" } } >
401- < Button . Group >
402- < Button disabled = { state === "saving" } onClick = { cancel_editing } >
403- Cancel
404- </ Button >
405- < Button
406- disabled = { create_disabled ( ) }
407- onClick = { ( ) => create_project ( ) }
408- type = "primary"
409- >
410- Create Project
411- { create_disabled ( ) ? " (enter a title above!)" : "" }
412- </ Button >
413- </ Button . Group >
431+ < Button
432+ disabled = { state === "saving" }
433+ onClick = { cancel_editing }
434+ style = { { marginRight : "8px" } }
435+ >
436+ Cancel
437+ </ Button >
438+ < Button
439+ disabled = { isDisabled ( ) }
440+ onClick = { ( ) => create_project ( ) }
441+ type = "primary"
442+ >
443+ Create Project
444+ { requireLicense && ! license_id && < > (select license above)</ > }
445+ </ Button >
414446 </ Col >
415447 </ Row >
416448 < Row >
0 commit comments