Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/frontend/course/configuration/student-project-software-environment.tsx
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { Alert, Button, Card, Divider, Radio, Space } from "antd";6import { useEffect, useState } from "react";7import { FormattedMessage, useIntl } from "react-intl";89import { redux, useTypedRedux } from "@cocalc/frontend/app-framework";10import { A, Icon, Markdown } from "@cocalc/frontend/components";11import {12ComputeImage,13ComputeImages,14} from "@cocalc/frontend/custom-software/init";15import {16SoftwareEnvironment,17SoftwareEnvironmentState,18} from "@cocalc/frontend/custom-software/selector";19import {20compute_image2basename,21is_custom_image,22} from "@cocalc/frontend/custom-software/util";23import { HelpEmailLink } from "@cocalc/frontend/customize";24import { labels } from "@cocalc/frontend/i18n";25import { SoftwareImageDisplay } from "@cocalc/frontend/project/settings/software-image-display";26import {27KUCALC_COCALC_COM,28KUCALC_ON_PREMISES,29} from "@cocalc/util/db-schema/site-defaults";30import { ConfigurationActions } from "./actions";3132const CSI_HELP =33"https://doc.cocalc.com/software.html#custom-software-environment";3435interface Props {36actions: ConfigurationActions;37course_project_id: string;38software_image?: string;39inherit_compute_image?: boolean;40close?;41}4243export function StudentProjectSoftwareEnvironment({44actions,45course_project_id,46software_image,47inherit_compute_image,48close,49}: Props) {50const intl = useIntl();51const customize_kucalc = useTypedRedux("customize", "kucalc");52const customize_software = useTypedRedux("customize", "software");53const software_envs = customize_software.get("environments");54const dflt_compute_img = customize_software.get("default");5556// by default, we inherit the software image from the project where this course is run from57const inherit = inherit_compute_image ?? true;58const [state, set_state] = useState<SoftwareEnvironmentState>({});59const [changing, set_changing] = useState(false);6061function handleChange(state): void {62set_state(state);63}64const current_environment = <SoftwareImageDisplay image={software_image} />;6566const custom_images: ComputeImages | undefined = useTypedRedux(67"compute_images",68"images",69);7071function on_inherit_change(inherit: boolean) {72if (inherit) {73// we have to get the compute image name from the course project74const projects_store = redux.getStore("projects");75const course_project_compute_image = projects_store.getIn([76"project_map",77course_project_id,78"compute_image",79]);80actions.set_inherit_compute_image(course_project_compute_image);81} else {82actions.set_inherit_compute_image();83}84}8586useEffect(() => {87if (inherit) {88set_changing(false);89}90}, [inherit]);9192function csi_warning() {93return (94<Alert95type={"warning"}96message={97<>98<strong>Warning:</strong> Do not change a custom image once there is99already one setup and deployed!100</>101}102description={103"The associated user files will not be updated and the software environment changes might break the functionality of existing files."104}105/>106);107}108109function render_controls_body() {110if (!changing) {111return (112<Button onClick={() => set_changing(true)} disabled={changing}>113{intl.formatMessage(labels.change)}...114</Button>115);116} else {117return (118<div>119<SoftwareEnvironment120onChange={handleChange}121default_image={software_image}122/>123{state.image_type === "custom" && csi_warning()}124<br />125<Space>126<Button127onClick={() => {128set_changing(false);129}}130>131{intl.formatMessage(labels.cancel)}132</Button>133<Button134disabled={135state.image_type === "custom" && state.image_selected == null136}137type="primary"138onClick={async () => {139set_changing(false);140await actions.set_software_environment(state);141close?.();142}}143>144{intl.formatMessage(labels.save)}145</Button>146</Space>147</div>148);149}150}151152function render_controls() {153if (inherit) return;154return (155<>156<Divider orientation="left">157{intl.formatMessage(labels.configuration)}158</Divider>159{render_controls_body()}160</>161);162}163164function render_description() {165const img_id = software_image ?? dflt_compute_img;166let descr: string | undefined;167if (is_custom_image(img_id)) {168if (custom_images == null) return;169const base_id = compute_image2basename(img_id);170const img: ComputeImage | undefined = custom_images.get(base_id);171if (img != null) {172descr = img.get("desc");173}174} else {175const img = software_envs.get(img_id);176if (img != null) {177descr = `<i>(${img.get("descr")})</i>`;178}179}180if (descr) {181return (182<Markdown183style={{184display: "block",185maxHeight: "200px",186overflowY: "auto",187marginTop: "10px",188marginBottom: "10px",189}}190value={descr}191/>192);193}194}195196function render_custom_info() {197if (software_image != null && is_custom_image(software_image)) return;198return (199<p>200<FormattedMessage201id="course.student-project-software-environment.help"202defaultMessage={`If you need additional software or a fully <A>customized software environment</A>,203please contact {help}.`}204values={{205help: <HelpEmailLink />,206A: (c) => <A href={CSI_HELP}>{c}</A>,207}}208/>209</p>210);211}212213function render_inherit() {214// We use fontWeight: "normal" below because otherwise the default215// of bold for the entire label is a bit much for such a large label.216return (217<Radio.Group218onChange={(e) => on_inherit_change(e.target.value)}219value={inherit}220>221<Radio style={{ fontWeight: "normal" }} value={true}>222<FormattedMessage223id="course.student-project-software-environment.inherit.true"224defaultMessage={`<strong>Inherit</strong> student projects software environments from this teacher project`}225/>226</Radio>227<Radio style={{ fontWeight: "normal" }} value={false}>228<FormattedMessage229id="course.student-project-software-environment.inherit.false"230defaultMessage={`<strong>Explicitly</strong> specify student project software environments`}231/>232</Radio>233</Radio.Group>234);235}236237// this selector only make sense for cocalc.com and cocalc-onprem238if (239customize_kucalc !== KUCALC_COCALC_COM &&240customize_kucalc !== KUCALC_ON_PREMISES241)242return null;243244return (245<Card246title={247<>248<Icon name="laptop" />{" "}249{intl.formatMessage(labels.software_environment)}:{" "}250{current_environment}251</>252}253>254<p>255<FormattedMessage256id="course.student-project-software-environment.status"257defaultMessage={`Student projects will use the following software environment: <em>{env}</em>`}258values={{259em: (c) => <em>{c}</em>,260env: current_environment,261}}262/>263</p>264{render_description()}265{render_custom_info()}266{render_inherit()}267{render_controls()}268</Card>269);270}271272273