Path: blob/master/src/packages/frontend/custom-software/selector.tsx
1496 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45// cSpell:ignore descr disp dflt67import { Col, Form } from "antd";8import { FormattedMessage, useIntl } from "react-intl";910import {11React,12redux,13useMemo,14useState,15useTypedRedux,16} from "@cocalc/frontend/app-framework";17import { A, HelpIcon, Icon, Paragraph } from "@cocalc/frontend/components";18import { labels } from "@cocalc/frontend/i18n";19import { ComputeImageSelector } from "@cocalc/frontend/project/settings/compute-image-selector";20import { SOFTWARE_ENVIRONMENT_ICON } from "@cocalc/frontend/project/settings/software-consts";21import { SoftwareEnvironmentInformation } from "@cocalc/frontend/project/settings/software-env-info";22import { SoftwareInfo } from "@cocalc/frontend/project/settings/types";23import { KUCALC_COCALC_COM } from "@cocalc/util/db-schema/site-defaults";24import { unreachable } from "@cocalc/util/misc";25import { ComputeImage, ComputeImageTypes, ComputeImages } from "./init";26import {27CUSTOM_SOFTWARE_HELP_URL,28compute_image2basename,29custom_image_name,30is_custom_image,31} from "./util";3233export interface SoftwareEnvironmentState {34image_selected?: string;35title_text?: string;36image_type?: ComputeImageTypes;37}3839// this is used in create-project and course/configuration/actions40// this derives the proper image name from the image type & image selection of SoftwareEnvironmentState41export async function derive_project_img_name(42custom_software: SoftwareEnvironmentState,43): Promise<string> {44const { image_type, image_selected } = custom_software;45const dflt_software_img = await redux46.getStore("customize")47.getDefaultComputeImage();48if (image_selected == null || image_type == null) {49return dflt_software_img;50}51switch (image_type) {52case "custom":53return custom_image_name(image_selected);54case "standard":55return image_selected;56default:57unreachable(image_type);58return dflt_software_img; // make TS happy59}60}6162interface Props {63onChange: (obj: SoftwareEnvironmentState) => void;64default_image?: string; // which one to initialize state to65}6667// this is a selector for the software environment of a project68export function SoftwareEnvironment(props: Props) {69const { onChange, default_image } = props;70const intl = useIntl();71const images: ComputeImages | undefined = useTypedRedux(72"compute_images",73"images",74);75const customize_kucalc = useTypedRedux("customize", "kucalc");76const onCoCalcCom = customize_kucalc === KUCALC_COCALC_COM;77const customize_software = useTypedRedux("customize", "software");78const organization_name = useTypedRedux("customize", "organization_name");79const dflt_software_img = customize_software.get("default");80const software_images = customize_software.get("environments");8182const haveSoftwareImages: boolean = useMemo(83() => (customize_software.get("environments")?.size ?? 0) > 0,84[customize_software],85);8687// ID of the image, custom images without "CUSTOM_PREFIX/" – that info is in the image_type variable.88const [image_selected, set_image_selected] = useState<string | undefined>(89undefined,90);91const [image_type, set_image_type] = useState<ComputeImageTypes>("standard");9293const [softwareInfo, setSoftwareInfo] = useState<SoftwareInfo | null>(null);9495function setState(96image_selected: string,97title_text: string,98image_type: ComputeImageTypes,99): void {100const id =101image_type === "custom"102? custom_image_name(image_selected)103: image_selected;104set_image_selected(id);105set_image_type(image_type);106onChange({ image_selected, title_text, image_type });107}108109// initialize selection, if there is a default image set110React.useEffect(() => {111if (default_image == null || default_image === dflt_software_img) {112// do nothing, that's the initial state already!113} else if (is_custom_image(default_image)) {114if (images == null) return;115const id = compute_image2basename(default_image);116const img: ComputeImage | undefined = images.get(id);117if (img == null) {118// ignore, user has to select from scratch119} else {120setState(id, img.get("display", ""), "custom");121}122} else {123// must be standard image124const img = software_images.get(default_image);125const display = img != null ? img.get("title") ?? "" : "";126setState(default_image, display, "standard");127}128}, []);129130function render_custom_images_config() {131if (image_type !== "custom") return;132133return (134<>135<Col sm={12}>136<FormattedMessage137id="custom-software.selector.select-custom-image"138defaultMessage={`<p>Specialized software environment are provided by 3rd parties and usually contain accompanying files to work with.</p>139140<p>Note: A <em>specialized</em> software environment is tied to the project.141In order to work in a different environment, create another project.142You can always <A>copy files between projects</A> as well.</p>`}143values={{144em: (c) => <em>{c}</em>,145p: (c) => <Paragraph type="secondary">{c}</Paragraph>,146A: (c) => (147<A148href={149"https://doc.cocalc.com/project-files.html#file-actions-on-one-file"150}151>152{c}153</A>154),155}}156/>157</Col>158</>159);160}161162function render_software_form_label() {163return (164<span>165<Icon name={SOFTWARE_ENVIRONMENT_ICON} />{" "}166{intl.formatMessage(labels.software)}167</span>168);169}170171function render_onprem() {172const selected = image_selected ?? dflt_software_img;173return (174<>175<Col sm={24}>176<Form>177<Form.Item178label={render_software_form_label()}179style={{ marginBottom: "0px", width: "100%" }}180>181<ComputeImageSelector182size={"middle"}183current_image={selected}184layout={"horizontal"}185hideCustomImages={true}186onSelect={({ id }) => {187const display = software_images.get(id)?.get("title") ?? id;188setState(id, display, "standard");189}}190/>191</Form.Item>192</Form>193</Col>194</>195);196}197198function render_software_env_help() {199return (200<HelpIcon title={intl.formatMessage(labels.software_environment)}>201<Paragraph>202<FormattedMessage203id="custom-software.selector.explanation.cocalc_com"204defaultMessage={`<em>Standard</em> software environments are well tested and205maintained by {company}, while <em>specialized</em> software environments are provided by 3rd parties206and tied to a given project – <A2>more info...</A2>.207`}208values={{209em: (c) => <em>{c}</em>,210company: organization_name,211A2: (c) => <A href={CUSTOM_SOFTWARE_HELP_URL}>{c}</A>,212}}213/>214</Paragraph>215<SoftwareEnvironmentInformation />216</HelpIcon>217);218}219220function render_standard_image_selector() {221const isCustom = is_custom_image(image_selected ?? dflt_software_img);222return (223<>224<Col sm={12}>225<Form>226<Form.Item227label={render_software_form_label()}228style={{ marginBottom: "0px" }}229>230<ComputeImageSelector231size="middle"232current_image={image_selected ?? dflt_software_img}233layout={"dropdown"}234setSoftwareInfo={setSoftwareInfo}235onSelect={({ id, display, type }) => {236setState(id, display, type);237}}238/>239</Form.Item>240</Form>241</Col>242<Col sm={12}>243<Paragraph type="secondary">244<FormattedMessage245id="custom-software.selector.explanation.onprem"246defaultMessage={`The software environment provides programming languages, tools and libraries for the project.`}247/>{" "}248{render_software_env_help()}249</Paragraph>250</Col>251{softwareInfo?.extra != null && (252<>253<Col254sm={isCustom ? 12 : 24}255style={{256paddingBottom: "30px",257}}258>259{softwareInfo.extra}260</Col>261{isCustom && render_custom_images_config()}262</>263)}264</>265);266}267268if (!haveSoftwareImages) {269return;270}271272if (onCoCalcCom) {273return render_standard_image_selector();274} else {275return render_onprem();276}277}278279280