Skip to content

Commit

Permalink
require license
Browse files Browse the repository at this point in the history
  • Loading branch information
williamstein committed Jul 11, 2024
1 parent 7896d9c commit 6b3542d
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 26 deletions.
1 change: 1 addition & 0 deletions src/packages/frontend/customize.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ export interface CustomizeState {
max_upgrades: TypedMap<Partial<Upgrades>>;
nonfree_countries?: List<string>;
limit_free_project_uptime: number; // minutes
require_license_to_create_project?: boolean;
onprem_quota_heading: string;
organization_email: string;
organization_name: string;
Expand Down
39 changes: 29 additions & 10 deletions src/packages/frontend/projects/create-project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Create a new project

import { Button, Card, Col, Form, Input, Row } from "antd";
import { delay } from "awaiting";

import { BuyLicenseForProject } from "@cocalc/frontend/site-licenses/purchase/buy-license-for-project";
import { Alert, Well } from "@cocalc/frontend/antd-bootstrap";
import {
CSS,
Expand Down Expand Up @@ -61,7 +61,6 @@ export const NewProjectCreator: React.FC<Props> = ({
const [title_text, set_title_text] = useState<string>(default_value ?? "");
const [error, set_error] = useState<string>("");
const [show_advanced, set_show_advanced] = useState<boolean>(false);
const [show_add_license, set_show_add_license] = useState<boolean>(false);
const [title_prefill, set_title_prefill] = useState<boolean>(false);
const [license_id, set_license_id] = useState<string>("");
const [warnBoost, setWarnBoost] = useState<boolean>(false);
Expand All @@ -73,15 +72,19 @@ export const NewProjectCreator: React.FC<Props> = ({

const is_anonymous = useTypedRedux("account", "is_anonymous");
const customize_kucalc = useTypedRedux("customize", "kucalc");
const requireLicense = !!useTypedRedux(
"customize",
"require_license_to_create_project",
);
const [show_add_license, set_show_add_license] =
useState<boolean>(requireLicense);

// onprem and cocalc.com use licenses to adjust quota configs – but only cocalc.com has custom software images
const show = useMemo(
() => [KUCALC_COCALC_COM, KUCALC_ON_PREMISES].includes(customize_kucalc),
[customize_kucalc],
);

//const requireLicense = customize_kucalc == KUCALC_COCALC_COM;

const [form] = Form.useForm();

useEffect(() => {
Expand Down Expand Up @@ -113,7 +116,7 @@ export const NewProjectCreator: React.FC<Props> = ({
set_error("");
set_custom_software({});
set_show_advanced(false);
set_show_add_license(false);
set_show_add_license(requireLicense);
set_title_prefill(true);
set_license_id("");
}
Expand Down Expand Up @@ -227,7 +230,10 @@ export const NewProjectCreator: React.FC<Props> = ({
);
}

function create_disabled() {
function isDisabled() {
if (requireLicense && !license_id) {
return true;
}
return (
// no name of new project
!title_text?.trim() ||
Expand Down Expand Up @@ -286,8 +292,20 @@ export const NewProjectCreator: React.FC<Props> = ({
function render_add_license() {
if (!show_add_license) return;
return (
<Card size="small" title="Select license" style={CARD_STYLE}>
<Card
size="small"
title={
<>
<div style={{ float: "right" }}>
<BuyLicenseForProject size="small" />
</div>
<Icon name="key" /> Select License
</>
}
style={CARD_STYLE}
>
<SiteLicenseInput
requireValid
confirmLabel={"Add this license"}
onChange={addSiteLicense}
/>
Expand Down Expand Up @@ -325,6 +343,7 @@ export const NewProjectCreator: React.FC<Props> = ({
return (
<div style={TOGGLE_STYLE}>
<Button
disabled={requireLicense}
onClick={() => set_show_add_license(true)}
type="link"
style={TOGGLE_BUTTON_STYLE}
Expand All @@ -348,7 +367,7 @@ export const NewProjectCreator: React.FC<Props> = ({
>
add/remove licenses
</A>{" "}
in the project settings later on.
in project settings later.
</div>
);
}
Expand Down Expand Up @@ -419,12 +438,12 @@ export const NewProjectCreator: React.FC<Props> = ({
Cancel
</Button>
<Button
disabled={create_disabled()}
disabled={isDisabled()}
onClick={() => create_project()}
type="primary"
>
Create Project
{create_disabled() ? " (enter a title above!)" : ""}
{requireLicense && !license_id && <> (select license above)</>}
</Button>
</Col>
</Row>
Expand Down
3 changes: 3 additions & 0 deletions src/packages/frontend/site-licenses/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ interface Props {
style?: CSS;
extra?: React.ReactNode;
extraButtons?: React.ReactNode;
requireValid?: boolean;
}

export const SiteLicenseInput: React.FC<Props> = (props: Props) => {
Expand All @@ -46,6 +47,7 @@ export const SiteLicenseInput: React.FC<Props> = (props: Props) => {
confirmLabel = "Apply License",
extra,
extraButtons,
requireValid,
} = props;

const managedLicenses = useManagedLicenses();
Expand All @@ -63,6 +65,7 @@ export const SiteLicenseInput: React.FC<Props> = (props: Props) => {
style={style}
extra={extra}
extraButtons={extraButtons}
requireValid={requireValid}
/>
);
};
40 changes: 24 additions & 16 deletions src/packages/frontend/site-licenses/select-license.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ interface Props {
style?: CSS;
extra?: ReactNode; // plain-text node is ok
extraButtons?: ReactNode;
requireValid?: boolean;
}

export default function SelectLicense(props: Props) {
Expand All @@ -49,6 +50,7 @@ export default function SelectLicense(props: Props) {
style,
extra,
extraButtons,
requireValid,
} = props;
const isBlurredRef = useRef<boolean>(true);
const [licenseId, setLicenseId] = useState<string>(defaultLicenseId ?? "");
Expand Down Expand Up @@ -154,24 +156,30 @@ export default function SelectLicense(props: Props) {
style={{ width: "100%", ...style }}
>
<div>
{(showAll || licenseIds.length < len(managedLicenses)) && (
<Checkbox
style={{
flex: "1 0 0",
margin: "5px 0",
color: COLORS.GRAY_M,
whiteSpace: "nowrap",
}}
checked={showAll}
onChange={() => setShowAll(!showAll)}
>
Show expired
</Checkbox>
)}{" "}
{!requireValid &&
(showAll || licenseIds.length < len(managedLicenses)) && (
<Checkbox
style={{
flex: "1 0 0",
margin: "5px 0",
color: COLORS.GRAY_M,
whiteSpace: "nowrap",
}}
checked={showAll}
onChange={() => setShowAll(!showAll)}
>
Show expired
</Checkbox>
)}{" "}
<Select
style={{ width: "100%", flex: "1 1 0", marginRight: "10px" }}
style={{
width: "100%",
height: licenseId ? "100px" : undefined,
flex: "1 1 0",
marginRight: "10px",
}}
placeholder={
"Enter license code " +
`Enter${requireValid ? " valid " : " "}license code ` +
(options.length > 0
? `or select from the ${options.length} licenses you manage`
: "")
Expand Down
9 changes: 9 additions & 0 deletions src/packages/util/db-schema/site-defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export type SiteSettingsKeys =
| "max_trial_projects"
| "nonfree_countries"
| "limit_free_project_uptime"
| "require_license_to_create_project"
| "google_analytics"
| "kucalc"
| "dns"
Expand Down Expand Up @@ -576,6 +577,14 @@ export const site_settings_conf: SiteSettings = {
show: only_cocalc_com,
to_display: (val) => `${val} minutes`,
},
require_license_to_create_project: {
name: "Require License to Create Project",
desc: "If yes the 'New Project' creation form on the projects page requires the user to enter a valid license. This has no other impact and only impacts the frontend UI. Users can circumvent this via the API or a course.",
default: "no",
valid: only_booleans,
show: only_cocalc_com,
to_val: to_bool,
},
datastore: {
name: "Datastore",
desc: `Show the '${DATASTORE_TITLE}' panel in the project settings`,
Expand Down

0 comments on commit 6b3542d

Please sign in to comment.