Path: blob/master/src/packages/frontend/custom-software/selector.tsx
5801 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// num images > 1 to not show the standard default84// https://github.com/sagemathinc/cocalc/issues/851085() => (customize_software.get("environments")?.size ?? 0) > 1,86[customize_software],87);8889// ID of the image, custom images without "CUSTOM_PREFIX/" – that info is in the image_type variable.90const [image_selected, set_image_selected] = useState<string | undefined>(91undefined,92);93const [image_type, set_image_type] = useState<ComputeImageTypes>("standard");9495const [softwareInfo, setSoftwareInfo] = useState<SoftwareInfo | null>(null);9697function setState(98image_selected: string,99title_text: string,100image_type: ComputeImageTypes,101): void {102const id =103image_type === "custom"104? custom_image_name(image_selected)105: image_selected;106set_image_selected(id);107set_image_type(image_type);108onChange({ image_selected, title_text, image_type });109}110111// initialize selection, if there is a default image set112React.useEffect(() => {113if (default_image == null || default_image === dflt_software_img) {114// do nothing, that's the initial state already!115} else if (is_custom_image(default_image)) {116if (images == null) return;117const id = compute_image2basename(default_image);118const img: ComputeImage | undefined = images.get(id);119if (img == null) {120// ignore, user has to select from scratch121} else {122setState(id, img.get("display", ""), "custom");123}124} else {125// must be standard image126const img = software_images.get(default_image);127const display = img != null ? img.get("title") ?? "" : "";128setState(default_image, display, "standard");129}130}, []);131132function render_custom_images_config() {133if (image_type !== "custom") return;134135return (136<>137<Col sm={12}>138<FormattedMessage139id="custom-software.selector.select-custom-image"140defaultMessage={`<p>Specialized software environment are provided by 3rd parties and usually contain accompanying files to work with.</p>141142<p>Note: A <em>specialized</em> software environment is tied to the project.143In order to work in a different environment, create another project.144You can always <A>copy files between projects</A> as well.</p>`}145values={{146em: (c) => <em>{c}</em>,147p: (c) => <Paragraph type="secondary">{c}</Paragraph>,148A: (c) => (149<A150href={151"https://doc.cocalc.com/project-files.html#file-actions-on-one-file"152}153>154{c}155</A>156),157}}158/>159</Col>160</>161);162}163164function render_software_form_label() {165return (166<span>167<Icon name={SOFTWARE_ENVIRONMENT_ICON} />{" "}168{intl.formatMessage(labels.software)}169</span>170);171}172173function render_onprem() {174const selected = image_selected ?? dflt_software_img;175return (176<>177<Col sm={24}>178<Form>179<Form.Item180label={render_software_form_label()}181style={{ marginBottom: "0px", width: "100%" }}182>183<ComputeImageSelector184size={"middle"}185current_image={selected}186layout={"horizontal"}187hideCustomImages={true}188onSelect={({ id }) => {189const display = software_images.get(id)?.get("title") ?? id;190setState(id, display, "standard");191}}192/>193</Form.Item>194</Form>195</Col>196</>197);198}199200function render_software_env_help() {201return (202<HelpIcon title={intl.formatMessage(labels.software_environment)}>203<Paragraph>204<FormattedMessage205id="custom-software.selector.explanation.cocalc_com"206defaultMessage={`<em>Standard</em> software environments are well tested and207maintained by {company}, while <em>specialized</em> software environments are provided by 3rd parties208and tied to a given project – <A2>more info...</A2>.209`}210values={{211em: (c) => <em>{c}</em>,212company: organization_name,213A2: (c) => <A href={CUSTOM_SOFTWARE_HELP_URL}>{c}</A>,214}}215/>216</Paragraph>217<SoftwareEnvironmentInformation />218</HelpIcon>219);220}221222function render_standard_image_selector() {223const isCustom = is_custom_image(image_selected ?? dflt_software_img);224return (225<>226<Col sm={12}>227<Form>228<Form.Item229label={render_software_form_label()}230style={{ marginBottom: "0px" }}231>232<ComputeImageSelector233size="middle"234current_image={image_selected ?? dflt_software_img}235layout={"dropdown"}236setSoftwareInfo={setSoftwareInfo}237onSelect={({ id, display, type }) => {238setState(id, display, type);239}}240/>241</Form.Item>242</Form>243</Col>244<Col sm={12}>245<Paragraph type="secondary">246<FormattedMessage247id="custom-software.selector.explanation.onprem"248defaultMessage={`The software environment provides programming languages, tools and libraries for the project.`}249/>{" "}250{render_software_env_help()}251</Paragraph>252</Col>253{softwareInfo?.extra != null && (254<>255<Col256sm={isCustom ? 12 : 24}257style={{258paddingBottom: "30px",259}}260>261{softwareInfo.extra}262</Col>263{isCustom && render_custom_images_config()}264</>265)}266</>267);268}269270if (!haveSoftwareImages) {271return;272}273274if (onCoCalcCom) {275return render_standard_image_selector();276} else {277return render_onprem();278}279}280281282