@@ -22,6 +22,7 @@ import {
22
22
Typography ,
23
23
} from "antd" ;
24
24
25
+ import { JsonEditor } from "@cocalc/frontend/admin/json-editor" ;
25
26
import {
26
27
CSS ,
27
28
React ,
@@ -33,6 +34,7 @@ import {
33
34
A ,
34
35
Gap ,
35
36
HelpIcon ,
37
+ NumberInput ,
36
38
Paragraph ,
37
39
TextInput ,
38
40
} from "@cocalc/frontend/components" ;
@@ -54,7 +56,6 @@ import { plural, round1, test_valid_jsonpatch } from "@cocalc/util/misc";
54
56
import { SiteLicenseQuota } from "@cocalc/util/types/site-licenses" ;
55
57
import { DEDICATED_VM_ONPREM_MACHINE } from "@cocalc/util/upgrades/consts" ;
56
58
import { Upgrades } from "@cocalc/util/upgrades/quota" ;
57
- import { JsonEditor } from "../../admin/json-editor" ;
58
59
59
60
const { Text } = Typography ;
60
61
@@ -101,10 +102,10 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
101
102
const max_upgrades = useTypedRedux ( "customize" , "max_upgrades" ) ;
102
103
103
104
const [ show_advanced , set_show_advanced ] = useState < boolean > (
104
- show_advanced_default ?? false
105
+ show_advanced_default ?? false ,
105
106
) ;
106
107
const [ jsonPatchError , setJSONPatchError ] = useState < string | undefined > (
107
- undefined
108
+ undefined ,
108
109
) ;
109
110
110
111
const hosting_multiplier = useMemo ( ( ) => {
@@ -191,12 +192,12 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
191
192
{ `${ money (
192
193
COSTS . user_discount [ user ( ) ] *
193
194
COSTS . custom_cost . cpu *
194
- hosting_multiplier
195
+ hosting_multiplier ,
195
196
) } /CPU cores per month per project`}
196
197
)
197
198
</ b >
198
199
{ render_explanation (
199
- "Google Cloud vCPUs shared with other projects (member hosting significantly reduces sharing)"
200
+ "Google Cloud vCPUs shared with other projects (member hosting significantly reduces sharing)" ,
200
201
) }
201
202
</ Col >
202
203
) }
@@ -236,7 +237,7 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
236
237
{ `${ money (
237
238
COSTS . user_discount [ user ( ) ] *
238
239
COSTS . custom_cost . ram *
239
- hosting_multiplier
240
+ hosting_multiplier ,
240
241
) } /GB RAM per month per project`}
241
242
)
242
243
</ b >
@@ -287,12 +288,12 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
287
288
{ `${ money (
288
289
COSTS . user_discount [ user ( ) ] *
289
290
COSTS . custom_cost . dedicated_cpu *
290
- hosting_multiplier
291
+ hosting_multiplier ,
291
292
) } /CPU cores per month per project`}
292
293
)
293
294
</ b >
294
295
{ render_explanation (
295
- "Google Cloud vCPUs NOT shared with other projects. You can enter a fractional value, e.g., 0.5 for a half dedicated core."
296
+ "Google Cloud vCPUs NOT shared with other projects. You can enter a fractional value, e.g., 0.5 for a half dedicated core." ,
296
297
) }
297
298
</ Col >
298
299
) }
@@ -338,7 +339,7 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
338
339
{ `${ money (
339
340
COSTS . user_discount [ user ( ) ] *
340
341
COSTS . custom_cost . dedicated_ram *
341
- hosting_multiplier
342
+ hosting_multiplier ,
342
343
) } /GB RAM per month per project`}
343
344
)
344
345
</ b >
@@ -380,12 +381,12 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
380
381
< b >
381
382
G Disk Space (
382
383
{ `${ money (
383
- COSTS . user_discount [ user ( ) ] * COSTS . custom_cost . disk
384
+ COSTS . user_discount [ user ( ) ] * COSTS . custom_cost . disk ,
384
385
) } /G disk per month per project`}
385
386
)
386
387
</ b >
387
388
{ render_explanation (
388
- "store a larger number of files. Snapshots and file edit history is included at no additional charge."
389
+ "store a larger number of files. Snapshots and file edit history is included at no additional charge." ,
389
390
) }
390
391
</ Col >
391
392
) }
@@ -415,7 +416,7 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
415
416
member hosting{ " " }
416
417
< b > (multiplies RAM/CPU price by { COSTS . custom_cost . member } )</ b >
417
418
{ render_explanation (
418
- "project runs on computers with far fewer other projects. If not selected your project runs on very, very heavily loaded trial servers, which might be OK depending on your application."
419
+ "project runs on computers with far fewer other projects. If not selected your project runs on very, very heavily loaded trial servers, which might be OK depending on your application." ,
419
420
) }
420
421
</ Col >
421
422
) }
@@ -519,6 +520,90 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
519
520
) ;
520
521
}
521
522
523
+ function render_gpu_help ( ) : JSX . Element {
524
+ return (
525
+ < HelpIcon title = "GPU Support" >
526
+ < Paragraph >
527
+ This configures a license, which will cause the project to run on a
528
+ GPU. You need to configure your VMs in your cluster in such a way,
529
+ that requesting a GPU is possible.
530
+ </ Paragraph >
531
+ < Paragraph >
532
+ In particular, the pod will get the following resource limit:{ " " }
533
+ < code > nvidia.com/gpu: 1</ code > .
534
+ </ Paragraph >
535
+ < Paragraph >
536
+ On top of that, you can optionally specify a taint, which will be
537
+ tolerated by that pod. This helps with keeping all other project pods
538
+ away from your GPU enabled nodes:{ " " }
539
+ < code >
540
+ tolerations:{ " " }
541
+ { JSON . stringify ( [
542
+ {
543
+ key : "gpu" ,
544
+ operator : "Equal" ,
545
+ value : "cocalc" ,
546
+ effect : "NoSchedule" ,
547
+ } ,
548
+ ] ) }
549
+ </ code >
550
+ .
551
+ </ Paragraph >
552
+ </ HelpIcon >
553
+ ) ;
554
+ }
555
+
556
+ function render_gpu ( ) : JSX . Element {
557
+ const { gpu } = quota ;
558
+ const { num = 0 , toleration = "" } =
559
+ typeof gpu === "object"
560
+ ? gpu
561
+ : typeof gpu === "number"
562
+ ? { num : gpu }
563
+ : { } ;
564
+ return (
565
+ < Row style = { ROW_STYLE } >
566
+ < Col md = { col . control } >
567
+ < Paragraph >
568
+ < Text strong > Request a GPU</ Text >
569
+ </ Paragraph > { " " }
570
+ < Paragraph >
571
+ < NumberInput
572
+ number = { num }
573
+ min = { 0 }
574
+ max = { 8 }
575
+ on_change = { ( num : number ) =>
576
+ onChange ( { gpu : { num, toleration } } )
577
+ }
578
+ /> { " " }
579
+ GPUs (< code > nvidia.com/gpu: { num } </ code > )
580
+ </ Paragraph >
581
+ < Paragraph >
582
+ < Text > (optional) Tolerate a taint:</ Text > { " " }
583
+ < TextInput
584
+ disabled = { disabled }
585
+ type = { "text" }
586
+ on_change = { ( tol ) =>
587
+ onChange ( { gpu : { num, toleration : tol . trim ( ) } } )
588
+ }
589
+ style = { {
590
+ fontWeight : "normal" ,
591
+ display : "inline-block" ,
592
+ margin : "0 10px" ,
593
+ } }
594
+ text = { toleration }
595
+ /> { " " }
596
+ (Enter < code > key=value</ code > of a node taint. e.g.{ " " }
597
+ < code > gpu=cocalc</ code > means to ignore nodes tatined with key{ " " }
598
+ < code > gpu</ code > and value < code > cocalc</ code > . Keep empty if you do
599
+ not use taints!)
600
+ </ Paragraph >
601
+ { render_gpu_help ( ) }
602
+ </ Col >
603
+ </ Row >
604
+ ) ;
605
+ }
606
+
522
607
function on_json_patch_change ( patch : string ) : void {
523
608
try {
524
609
const patchObj = JSON . parse ( patch ) ;
@@ -527,7 +612,7 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
527
612
onChange ( { patch } ) ; // we save the string, not the object!
528
613
} else {
529
614
setJSONPatchError (
530
- 'Must be a list of {`[{"op": "replace", "path": "…", "value": "…"}, …]`} objects.'
615
+ 'Must be a list of {`[{"op": "replace", "path": "…", "value": "…"}, …]`} objects.' ,
531
616
) ;
532
617
}
533
618
} catch ( err ) {
@@ -564,13 +649,13 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
564
649
ret . push (
565
650
< Select . Option key = { key } value = { key } >
566
651
{ it . label }
567
- </ Select . Option >
652
+ </ Select . Option > ,
568
653
) ;
569
654
}
570
655
ret . push (
571
656
< Select . Option key = { "always_running" } value = { "always_running" } >
572
657
Always running
573
- </ Select . Option >
658
+ </ Select . Option > ,
574
659
) ;
575
660
return ret ;
576
661
}
@@ -639,7 +724,7 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
639
724
< Col md = { col . desc } >
640
725
priority support
641
726
{ render_explanation (
642
- "we prioritize your support requests much higher (included with all licensed projects)"
727
+ "we prioritize your support requests much higher (included with all licensed projects)" ,
643
728
) }
644
729
</ Col >
645
730
) }
@@ -661,7 +746,7 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
661
746
< Col md = { col . desc } >
662
747
network access
663
748
{ render_explanation (
664
- "project can connect to the Internet to clone git repositories, download files, send emails, etc. (included with all licensed projects)"
749
+ "project can connect to the Internet to clone git repositories, download files, send emails, etc. (included with all licensed projects)" ,
665
750
) }
666
751
</ Col >
667
752
) }
@@ -708,6 +793,32 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
708
793
) ;
709
794
}
710
795
796
+ function render_advanced_onprem ( ) : JSX . Element | undefined {
797
+ if ( ! show_advanced || ! isOnPrem ) return ;
798
+ return (
799
+ < >
800
+ { render_ext_rw ( ) }
801
+ { render_dedicated_vm ( ) }
802
+ { render_gpu ( ) }
803
+ { render_patch_project_pod ( ) }
804
+ </ >
805
+ ) ;
806
+ }
807
+
808
+ function render_advanced ( ) : JSX . Element | undefined {
809
+ if ( ! show_advanced ) return ;
810
+ return (
811
+ < >
812
+ { render_member ( ) }
813
+ { render_idle_timeout ( ) }
814
+ { render_dedicated_cpu ( ) }
815
+ { render_dedicated_ram ( ) }
816
+ { ! hideExtra && render_dedicated ( ) }
817
+ { render_advanced_onprem ( ) }
818
+ </ >
819
+ ) ;
820
+ }
821
+
711
822
return (
712
823
< >
713
824
{ render_cpu ( ) }
@@ -716,14 +827,7 @@ export const QuotaEditor: React.FC<Props> = (props: Props) => {
716
827
{ ! hideExtra && render_support ( ) }
717
828
{ ! hideExtra && render_network ( ) }
718
829
{ render_show_advanced_link ( ) }
719
- { show_advanced && render_member ( ) }
720
- { show_advanced && render_idle_timeout ( ) }
721
- { show_advanced && render_dedicated_cpu ( ) }
722
- { show_advanced && render_dedicated_ram ( ) }
723
- { show_advanced && ! hideExtra && render_dedicated ( ) }
724
- { show_advanced && isOnPrem && render_ext_rw ( ) }
725
- { show_advanced && isOnPrem && render_dedicated_vm ( ) }
726
- { show_advanced && isOnPrem && render_patch_project_pod ( ) }
830
+ { render_advanced ( ) }
727
831
</ >
728
832
) ;
729
833
} ;
0 commit comments