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/next/components/share/configure-public-path.tsx
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { useEffect, useState } from "react";6import { Alert, Divider, Radio, Input, Select, Space } from "antd";7import useDatabase from "lib/hooks/database";8import useCustomize from "lib/use-customize";9import Loading from "./loading";10import { LICENSES } from "@cocalc/frontend/share/licenses";11import SaveButton from "components/misc/save-button";12import EditRow from "components/misc/edit-row";13import A from "components/misc/A";14import SelectSiteLicense from "components/misc/select-site-license";15import { Icon } from "@cocalc/frontend/components/icon";16import LaTeX from "components/landing/latex";17import {18SHARE_AUTHENTICATED_EXPLANATION,19SHARE_AUTHENTICATED_ICON,20SHARE_FLAGS,21} from "@cocalc/util/consts/ui";2223const { Option } = Select;2425interface Props {26id: string;27project_id: string;28path: string;29}3031const QUERY = {32name: null,33description: null,34disabled: null,35unlisted: null,36authenticated: null,37license: null,38compute_image: null,39};4041interface Info {42name?: string;43description?: string;44disabled?: boolean;45unlisted?: boolean;46authenticated?: boolean;47license?: string;48compute_image?: string;49site_license_id?: string;50}5152function get_visibility(edited) {53if (edited.disabled) return "private";54if (edited.unlisted) return "unlisted";55if (edited.authenticated) return "authenticated";56return "listed";57}5859export default function ConfigurePublicPath({ id, project_id, path }: Props) {60const publicPaths = useDatabase({61public_paths: { ...QUERY, id, project_id, path },62});63const siteLicense = useDatabase({64public_paths_site_license_id: {65site_license_id: null,66id,67project_id,68path,69},70});71const { onCoCalcCom } = useCustomize();72const [loaded, setLoaded] = useState<boolean>(false);73const [edited, setEdited] = useState<Info>({});74const [original, setOriginal] = useState<Info>({});75const [error, setError] = useState<string>("");7677// After loading finishes, either editor or error is set.78useEffect(() => {79if (publicPaths.loading || siteLicense.loading) return;80if (publicPaths.error) {81setError(publicPaths.error);82return;83}84if (siteLicense.error) {85setError(siteLicense.error);86return;87}88const { site_license_id } = siteLicense.value.public_paths_site_license_id;89const { public_paths } = publicPaths.value;90const x = { ...public_paths, site_license_id };91setEdited(x);92setOriginal(x);93setLoaded(true);94}, [publicPaths.loading, siteLicense.loading]);9596if (!loaded) {97return <Loading delay={0.2} />;98}99100// cheap to compute, so we compute every time.101const visibility = get_visibility(edited);102// we don't show "authenticated" on cocalc.com, unless it is set to it103const showAuthenticated = !onCoCalcCom || edited.authenticated;104105const save =106edited == null || original == null ? null : (107<SaveButton108edited={edited}109original={original}110setOriginal={setOriginal}111table="public_paths"112/>113);114115return (116<div117style={{118width: "100%",119border: "1px solid #eee",120padding: "15px",121marginTop: "15px",122}}123>124{error && <Alert type="error" message={error} showIcon />}125{save}126<Divider>How you are sharing "{path}"</Divider>127<Space direction="vertical" style={{ width: "100%" }}>128<EditRow129label="Describe what you are sharing"130description={131<>132Use relevant keywords, inspire curiosity by providing just enough133information to explain what this is about, and keep your134description to about two lines. Use Markdown and <LaTeX />. You135can change this at any time.136</>137}138>139<Input.TextArea140style={{ width: "100%" }}141value={edited.description}142onChange={(e) =>143setEdited({ ...edited, description: e.target.value })144}145autoSize={{ minRows: 2, maxRows: 6 }}146/>147</EditRow>148<EditRow149label="Choose a name for a nicer URL"150description="An optional name can provide a much nicer and more memorable URL. You must also name your project (in project settings) and the owner of the project to get a nice URL. (WARNING: Changing this once it is set can break links, since automatic redirection is not implemented.)"151>152<Input153style={{ maxWidth: "100%", width: "30em" }}154value={edited.name}155onChange={(e) => setEdited({ ...edited, name: e.target.value })}156/>157</EditRow>158<EditRow159label={160showAuthenticated161? "Listed, Unlisted, Authenticated or Private?"162: "Listed, Unlisted or Private?"163}164description="You make files or directories public to the world, either indexed by165search engines (listed), only visible with the link (unlisted), or only those who are authenticated.166Public files are automatically copied to the public server within about 30 seconds167after you explicitly edit them. You can also set a site license for unlisted public shares."168>169<Space direction="vertical">170<Radio.Group171value={visibility}172onChange={(e) => {173switch (e.target.value) {174case "listed":175setEdited({ ...edited, ...SHARE_FLAGS.LISTED });176break;177case "unlisted":178setEdited({ ...edited, ...SHARE_FLAGS.UNLISTED });179break;180case "authenticated":181setEdited({ ...edited, ...SHARE_FLAGS.AUTHENTICATED });182break;183case "private":184setEdited({ ...edited, ...SHARE_FLAGS.DISABLED, name: "" });185break;186}187}}188>189<Space direction="vertical">190<Radio value={"listed"}>191<Icon name="eye" /> <em>Public (listed): </em> anybody can192find this via search.193</Radio>194<Radio value={"unlisted"}>195<Icon name="eye-slash" /> <em>Public (unlisted):</em> only196people with the link can view this.197</Radio>198{showAuthenticated && (199<Radio value={"authenticated"}>200<Icon name={SHARE_AUTHENTICATED_ICON} />{" "}201<em>Authenticated:</em> {SHARE_AUTHENTICATED_EXPLANATION}.202</Radio>203)}204<Radio value={"private"}>205<Icon name="lock" /> <em>Private:</em> only collaborators on206the project can view this.207</Radio>208</Space>209</Radio.Group>210</Space>211</EditRow>212{visibility == "unlisted" && (213<EditRow214label="Upgrade with a site license?"215description={216<>217For unlisted shares, you can select a site license that you218manage, and anybody who edits a copy of this share will have219this site license applied to their project. You can track and220remove usage of this license in the{" "}221<A>license management page</A> (coming soon).222</>223}224>225<SelectSiteLicense226defaultLicenseId={original.site_license_id}227onChange={(site_license_id) => {228setEdited({ ...edited, site_license_id });229}}230/>231</EditRow>232)}233<EditRow234label="Permission"235description={236<>237An optional{" "}238<A href="https://opensource.org/licenses">open source license</A>{" "}239tells people how they may use what you are sharing.240</>241}242>243<License244license={edited.license}245onChange={(license) => setEdited({ ...edited, license })}246/>247</EditRow>248{/*TODO Image: {edited.compute_image} */}249</Space>250{save}251</div>252);253}254255function License({ license, onChange }) {256const options: JSX.Element[] = [];257for (const value in LICENSES) {258options.push(259<Option key={value} value={value}>260{LICENSES[value]}261</Option>262);263}264return (265<Select266showSearch267value={license}268style={{ width: "100%" }}269placeholder="Select an open source license"270optionFilterProp="children"271onChange={onChange}272filterOption={(input, option) =>273option274? `${option.children}`.toLowerCase().includes(input.toLowerCase())275: false276}277>278{options}279</Select>280);281}282283284