Path: blob/master/src/packages/frontend/course/configuration/student-project-software-environment.tsx
1503 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45// cspell:ignore descr67import { Alert, Card, Divider, Radio, Space } from "antd";8import { useState } from "react";9import { FormattedMessage, useIntl } from "react-intl";1011import { redux, useTypedRedux } from "@cocalc/frontend/app-framework";12import { A, Icon, Markdown } from "@cocalc/frontend/components";13import {14ComputeImage,15ComputeImages,16ComputeImageTypes,17} from "@cocalc/frontend/custom-software/init";18import { SoftwareEnvironmentState } 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 { useProjectContext } from "@cocalc/frontend/project/context";26import { ComputeImageSelector } from "@cocalc/frontend/project/settings/compute-image-selector";27import { SoftwareImageDisplay } from "@cocalc/frontend/project/settings/software-image-display";28import {29KUCALC_COCALC_COM,30KUCALC_ON_PREMISES,31} from "@cocalc/util/db-schema/site-defaults";32import { ConfigurationActions } from "./actions";3334const CSI_HELP =35"https://doc.cocalc.com/software.html#custom-software-environment";3637interface Props {38actions: ConfigurationActions;39course_project_id: string;40software_image?: string;41inherit_compute_image?: boolean;42close?;43}4445export function StudentProjectSoftwareEnvironment({46actions,47course_project_id,48software_image,49inherit_compute_image,50close,51}: Props) {52const intl = useIntl();53const { onCoCalcCom } = useProjectContext();54const customize_kucalc = useTypedRedux("customize", "kucalc");55const customize_software = useTypedRedux("customize", "software");56const software_envs = customize_software.get("environments");57const default_compute_img = customize_software.get("default");5859// by default, we inherit the software image from the project where this course is run from60const inherit = inherit_compute_image ?? true;61const [state, set_state] = useState<SoftwareEnvironmentState>({});62const [changing, set_changing] = useState(false);6364async function handleSelect({65id,66display,67type,68}: {69id: string;70display: string;71type: ComputeImageTypes;72}) {73set_changing(true);74const nextState: SoftwareEnvironmentState = {75image_selected: id,76title_text: display,77image_type: type,78};79set_state(nextState);80await actions.set_software_environment(nextState);81set_changing(false);82close?.();83}84const current_environment = <SoftwareImageDisplay image={software_image} />;8586const custom_images: ComputeImages | undefined = useTypedRedux(87"compute_images",88"images",89);9091function on_inherit_change(inherit: boolean) {92if (inherit) {93// we have to get the compute image name from the course project94const projects_store = redux.getStore("projects");95const course_project_compute_image = projects_store.getIn([96"project_map",97course_project_id,98"compute_image",99]);100actions.set_inherit_compute_image(course_project_compute_image);101} else {102actions.set_inherit_compute_image();103}104}105106function csi_warning() {107return (108<Alert109type={"warning"}110message={111<>112<strong>Warning:</strong> Do not change a specialized software113environment after it has already been deployed and in use!114</>115}116description={117"The associated user files will not be updated and the software environment changes likely break the functionality of existing files."118}119/>120);121}122123function render_controls_body() {124return (125<Space direction="vertical" style={{ width: "100%" }}>126<ComputeImageSelector127current_image={software_image ?? default_compute_img}128layout={"dialog"}129onSelect={handleSelect}130hideCustomImages={!onCoCalcCom}131label={intl.formatMessage(labels.save)}132changing={changing}133/>134{state.image_type === "custom" && csi_warning()}135</Space>136);137}138139function render_controls() {140if (inherit) return;141return (142<>143<Divider orientation="left">144{intl.formatMessage(labels.configuration)}145</Divider>146{render_controls_body()}147</>148);149}150151function render_description() {152const img_id = software_image ?? default_compute_img;153let descr: string | undefined;154if (is_custom_image(img_id)) {155if (custom_images == null) return;156const base_id = compute_image2basename(img_id);157const img: ComputeImage | undefined = custom_images.get(base_id);158if (img != null) {159descr = img.get("desc");160}161} else {162const img = software_envs.get(img_id);163if (img != null) {164descr = `<i>(${img.get("descr")})</i>`;165}166}167if (descr) {168return (169<Markdown170style={{171display: "block",172maxHeight: "200px",173overflowY: "auto",174marginTop: "10px",175marginBottom: "10px",176}}177value={descr}178/>179);180}181}182183function render_custom_info() {184if (software_image != null && is_custom_image(software_image)) return;185return (186<p>187<FormattedMessage188id="course.student-project-software-environment.help"189defaultMessage={`If you need additional software or a fully <A>customized software environment</A>,190please contact {help}.`}191values={{192help: <HelpEmailLink />,193A: (c) => <A href={CSI_HELP}>{c}</A>,194}}195/>196</p>197);198}199200function render_inherit() {201// We use fontWeight: "normal" below because otherwise the default202// of bold for the entire label is a bit much for such a large label.203return (204<Radio.Group205onChange={(e) => on_inherit_change(e.target.value)}206value={inherit}207>208<Radio style={{ fontWeight: "normal" }} value={true}>209<FormattedMessage210id="course.student-project-software-environment.inherit.true"211defaultMessage={`<strong>Inherit</strong> student projects software environments from this teacher project`}212/>213</Radio>214<Radio style={{ fontWeight: "normal" }} value={false}>215<FormattedMessage216id="course.student-project-software-environment.inherit.false"217defaultMessage={`<strong>Explicitly</strong> specify student project software environments`}218/>219</Radio>220</Radio.Group>221);222}223224// this selector only make sense for cocalc.com and cocalc-onprem225if (226customize_kucalc !== KUCALC_COCALC_COM &&227customize_kucalc !== KUCALC_ON_PREMISES228)229return null;230231return (232<Card233title={234<>235<Icon name="laptop" />{" "}236{intl.formatMessage(labels.software_environment)}:{" "}237{current_environment}238</>239}240>241<p>242<FormattedMessage243id="course.student-project-software-environment.status"244defaultMessage={`Student projects will use the following software environment: <em>{env}</em>`}245values={{246em: (c) => <em>{c}</em>,247env: current_environment,248}}249/>250</p>251{render_description()}252{render_custom_info()}253{render_inherit()}254{render_controls()}255</Card>256);257}258259260