Skip to content

Commit c6bc741

Browse files
authored
feat: add premium license behavior for create organization page (coder#14650)
* fix: type * chore: paywall improvements * feat: update create org for premium license * fix: remove [] * feat: update licensing pills to reflect new premium tier (coder#14670) * feat: update licensing pills to reflect new premium tier * fix: format
1 parent 9006b21 commit c6bc741

File tree

16 files changed

+257
-153
lines changed

16 files changed

+257
-153
lines changed

site/src/components/Badges/Badges.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,32 @@ export const DisabledBadge: FC = forwardRef<
106106
);
107107
});
108108

109+
export const EnterpriseBadge: FC = () => {
110+
return (
111+
<span
112+
css={[
113+
styles.badge,
114+
(theme) => ({
115+
backgroundColor: theme.branding.enterprise.background,
116+
border: `1px solid ${theme.branding.enterprise.border}`,
117+
color: theme.branding.enterprise.text,
118+
}),
119+
]}
120+
>
121+
Enterprise
122+
</span>
123+
);
124+
};
125+
109126
export const PremiumBadge: FC = () => {
110127
return (
111128
<span
112129
css={[
113130
styles.badge,
114131
(theme) => ({
115-
backgroundColor: theme.branding.background,
116-
border: `1px solid ${theme.branding.border}`,
117-
color: theme.roles.notice.text,
132+
backgroundColor: theme.branding.premium.background,
133+
border: `1px solid ${theme.branding.premium.border}`,
134+
color: theme.branding.premium.text,
118135
}),
119136
]}
120137
>

site/src/components/Paywall/Paywall.tsx

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,7 @@ export const Paywall: FC<PaywallProps> = ({
1919
documentationLink,
2020
}) => {
2121
return (
22-
<div
23-
css={[
24-
styles.root,
25-
(theme) => ({
26-
backgroundImage: `linear-gradient(160deg, transparent, ${theme.branding.background})`,
27-
border: `1px solid ${theme.branding.border}`,
28-
}),
29-
]}
30-
>
22+
<div css={styles.root}>
3123
<div>
3224
<Stack direction="row" alignItems="center" css={{ marginBottom: 24 }}>
3325
<h5 css={styles.title}>{message}</h5>
@@ -45,7 +37,7 @@ export const Paywall: FC<PaywallProps> = ({
4537
</Link>
4638
</div>
4739
<div css={styles.separator} />
48-
<Stack direction="column" alignItems="center" spacing={3}>
40+
<Stack direction="column" alignItems="left" spacing={3}>
4941
<ul css={styles.featureList}>
5042
<li css={styles.feature}>
5143
<FeatureIcon />
@@ -64,16 +56,18 @@ export const Paywall: FC<PaywallProps> = ({
6456
Unlimited Git & external auth integrations
6557
</li>
6658
</ul>
67-
<Button
68-
href={docs("/enterprise")}
69-
target="_blank"
70-
rel="noreferrer"
71-
startIcon={<span css={{ fontSize: 22 }}>&rarr;</span>}
72-
variant="outlined"
73-
color="neutral"
74-
>
75-
Learn about Premium
76-
</Button>
59+
<div css={styles.learnButton}>
60+
<Button
61+
href={docs("/enterprise")}
62+
target="_blank"
63+
rel="noreferrer"
64+
startIcon={<span css={{ fontSize: 22 }}>&rarr;</span>}
65+
variant="outlined"
66+
color="neutral"
67+
>
68+
Learn about Premium
69+
</Button>
70+
</div>
7771
</Stack>
7872
</div>
7973
);
@@ -84,15 +78,15 @@ const FeatureIcon: FC = () => {
8478
<TaskAltIcon
8579
css={[
8680
(theme) => ({
87-
color: theme.branding.border,
81+
color: theme.branding.premium.border,
8882
}),
8983
]}
9084
/>
9185
);
9286
};
9387

9488
const styles = {
95-
root: () => ({
89+
root: (theme) => ({
9690
display: "flex",
9791
flexDirection: "row",
9892
justifyContent: "center",
@@ -101,6 +95,8 @@ const styles = {
10195
padding: 24,
10296
borderRadius: 8,
10397
gap: 32,
98+
backgroundImage: `linear-gradient(160deg, transparent, ${theme.branding.premium.background})`,
99+
border: `1px solid ${theme.branding.premium.border}`,
104100
}),
105101
title: {
106102
fontWeight: 600,
@@ -116,9 +112,12 @@ const styles = {
116112
separator: (theme) => ({
117113
width: 1,
118114
height: 220,
119-
backgroundColor: theme.branding.divider,
115+
backgroundColor: theme.branding.premium.divider,
120116
marginLeft: 8,
121117
}),
118+
learnButton: {
119+
padding: "0 28px",
120+
},
122121
featureList: {
123122
listStyle: "none",
124123
margin: 0,

site/src/components/Paywall/PopoverPaywall.tsx

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ export const PopoverPaywall: FC<PopoverPaywallProps> = ({
2323
css={[
2424
styles.root,
2525
(theme) => ({
26-
backgroundImage: `linear-gradient(160deg, transparent, ${theme.branding.background})`,
27-
border: `1px solid ${theme.branding.border}`,
26+
backgroundImage: `linear-gradient(160deg, transparent, ${theme.branding.premium.background})`,
27+
border: `1px solid ${theme.branding.premium.border}`,
2828
}),
2929
]}
3030
>
@@ -45,7 +45,7 @@ export const PopoverPaywall: FC<PopoverPaywallProps> = ({
4545
</Link>
4646
</div>
4747
<div css={styles.separator} />
48-
<Stack direction="column" alignItems="center" spacing={2}>
48+
<Stack direction="column" alignItems="left" spacing={2}>
4949
<ul css={styles.featureList}>
5050
<li css={styles.feature}>
5151
<FeatureIcon /> High availability & workspace proxies
@@ -60,16 +60,18 @@ export const PopoverPaywall: FC<PopoverPaywallProps> = ({
6060
<FeatureIcon /> Unlimited Git & external auth integrations
6161
</li>
6262
</ul>
63-
<Button
64-
href={docs("/enterprise")}
65-
target="_blank"
66-
rel="noreferrer"
67-
startIcon={<span css={{ fontSize: 22 }}>&rarr;</span>}
68-
variant="outlined"
69-
color="neutral"
70-
>
71-
Learn about Premium
72-
</Button>
63+
<div css={styles.learnButton}>
64+
<Button
65+
href={docs("/enterprise")}
66+
target="_blank"
67+
rel="noreferrer"
68+
startIcon={<span css={{ fontSize: 22 }}>&rarr;</span>}
69+
variant="outlined"
70+
color="neutral"
71+
>
72+
Learn about Premium
73+
</Button>
74+
</div>
7375
</Stack>
7476
</div>
7577
);
@@ -80,7 +82,7 @@ const FeatureIcon: FC = () => {
8082
<TaskAltIcon
8183
css={[
8284
(theme) => ({
83-
color: theme.branding.border,
85+
color: theme.branding.premium.border,
8486
}),
8587
]}
8688
/>
@@ -92,7 +94,7 @@ const styles = {
9294
display: "flex",
9395
flexDirection: "row",
9496
alignItems: "center",
95-
maxWidth: 600,
97+
maxWidth: 770,
9698
padding: "24px 36px",
9799
borderRadius: 8,
98100
gap: 18,
@@ -106,7 +108,7 @@ const styles = {
106108
description: (theme) => ({
107109
marginTop: 8,
108110
fontFamily: "inherit",
109-
maxWidth: 420,
111+
maxWidth: 360,
110112
lineHeight: "160%",
111113
color: theme.palette.text.secondary,
112114
fontSize: 14,
@@ -121,10 +123,13 @@ const styles = {
121123
listStyle: "none",
122124
margin: 0,
123125
marginRight: 8,
124-
padding: "0 12px",
126+
padding: "0 0 0 24px",
125127
fontSize: 13,
126128
fontWeight: 500,
127129
},
130+
learnButton: {
131+
padding: "0 28px",
132+
},
128133
feature: {
129134
display: "flex",
130135
alignItems: "center",

site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AppearanceSettingsPage.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { appearanceConfigKey, updateAppearance } from "api/queries/appearance";
33
import type { UpdateAppearanceConfig } from "api/typesGenerated";
44
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
55
import { useDashboard } from "modules/dashboard/useDashboard";
6+
import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility";
67
import type { FC } from "react";
78
import { Helmet } from "react-helmet-async";
89
import { useMutation, useQueryClient } from "react-query";
@@ -15,6 +16,7 @@ import { AppearanceSettingsPageView } from "./AppearanceSettingsPageView";
1516
// the command line would be a significantly worse user experience.
1617
const AppearanceSettingsPage: FC = () => {
1718
const { appearance, entitlements } = useDashboard();
19+
const { multiple_organizations: hasPremiumLicense } = useFeatureVisibility();
1820
const queryClient = useQueryClient();
1921
const updateAppearanceMutation = useMutation(updateAppearance(queryClient));
2022

@@ -46,6 +48,7 @@ const AppearanceSettingsPage: FC = () => {
4648
isEntitled={
4749
entitlements.features.appearance.entitlement !== "not_entitled"
4850
}
51+
isPremium={hasPremiumLicense}
4952
/>
5053
</>
5154
);

site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AppearanceSettingsPageView.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import TextField from "@mui/material/TextField";
44
import type { UpdateAppearanceConfig } from "api/typesGenerated";
55
import {
66
Badges,
7-
DisabledBadge,
8-
EntitledBadge,
7+
EnterpriseBadge,
98
PremiumBadge,
109
} from "components/Badges/Badges";
1110
import { PopoverPaywall } from "components/Paywall/PopoverPaywall";
@@ -24,14 +23,15 @@ import { AnnouncementBannerSettings } from "./AnnouncementBannerSettings";
2423
export type AppearanceSettingsPageViewProps = {
2524
appearance: UpdateAppearanceConfig;
2625
isEntitled: boolean;
26+
isPremium: boolean;
2727
onSaveAppearance: (
2828
newConfig: Partial<UpdateAppearanceConfig>,
2929
) => Promise<void>;
3030
};
3131

3232
export const AppearanceSettingsPageView: FC<
3333
AppearanceSettingsPageViewProps
34-
> = ({ appearance, isEntitled, onSaveAppearance }) => {
34+
> = ({ appearance, isEntitled, isPremium, onSaveAppearance }) => {
3535
const applicationNameForm = useFormik<{
3636
application_name: string;
3737
}>({
@@ -60,13 +60,17 @@ export const AppearanceSettingsPageView: FC<
6060
/>
6161

6262
<Badges>
63-
{isEntitled ? <EntitledBadge /> : <DisabledBadge />}
6463
<Popover mode="hover">
65-
<PopoverTrigger>
66-
<span>
67-
<PremiumBadge />
68-
</span>
69-
</PopoverTrigger>
64+
{isEntitled && !isPremium ? (
65+
<EnterpriseBadge />
66+
) : (
67+
<PopoverTrigger>
68+
<span>
69+
<PremiumBadge />
70+
</span>
71+
</PopoverTrigger>
72+
)}
73+
7074
<PopoverContent css={{ transform: "translateY(-28px)" }}>
7175
<PopoverPaywall
7276
message="Appearance"

site/src/pages/DeploySettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPage.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Loader } from "components/Loader/Loader";
22
import { useDashboard } from "modules/dashboard/useDashboard";
3+
import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility";
34
import type { FC } from "react";
45
import { Helmet } from "react-helmet-async";
56
import { pageTitle } from "utils/page";
@@ -9,6 +10,7 @@ import { ObservabilitySettingsPageView } from "./ObservabilitySettingsPageView";
910
const ObservabilitySettingsPage: FC = () => {
1011
const { deploymentValues } = useDeploySettings();
1112
const { entitlements } = useDashboard();
13+
const { multiple_organizations: hasPremiumLicense } = useFeatureVisibility();
1214

1315
return (
1416
<>
@@ -20,6 +22,7 @@ const ObservabilitySettingsPage: FC = () => {
2022
<ObservabilitySettingsPageView
2123
options={deploymentValues.options}
2224
featureAuditLogEnabled={entitlements.features.audit_log.enabled}
25+
isPremium={hasPremiumLicense}
2326
/>
2427
) : (
2528
<Loader />

site/src/pages/DeploySettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPageView.tsx

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import type { SerpentOption } from "api/typesGenerated";
22
import {
33
Badges,
4-
DisabledBadge,
5-
EnabledBadge,
4+
EnterpriseBadge,
65
PremiumBadge,
76
} from "components/Badges/Badges";
7+
import { PopoverPaywall } from "components/Paywall/PopoverPaywall";
8+
import {
9+
Popover,
10+
PopoverContent,
11+
PopoverTrigger,
12+
} from "components/Popover/Popover";
813
import { SettingsHeader } from "components/SettingsHeader/SettingsHeader";
914
import { Stack } from "components/Stack/Stack";
1015
import type { FC } from "react";
@@ -15,11 +20,12 @@ import OptionsTable from "../OptionsTable";
1520
export type ObservabilitySettingsPageViewProps = {
1621
options: SerpentOption[];
1722
featureAuditLogEnabled: boolean;
23+
isPremium: boolean;
1824
};
1925

2026
export const ObservabilitySettingsPageView: FC<
2127
ObservabilitySettingsPageViewProps
22-
> = ({ options, featureAuditLogEnabled }) => {
28+
> = ({ options, featureAuditLogEnabled, isPremium }) => {
2329
return (
2430
<>
2531
<Stack direction="column" spacing={6}>
@@ -33,8 +39,25 @@ export const ObservabilitySettingsPageView: FC<
3339
/>
3440

3541
<Badges>
36-
{featureAuditLogEnabled ? <EnabledBadge /> : <DisabledBadge />}
37-
<PremiumBadge />
42+
<Popover mode="hover">
43+
{featureAuditLogEnabled && !isPremium ? (
44+
<EnterpriseBadge />
45+
) : (
46+
<PopoverTrigger>
47+
<span>
48+
<PremiumBadge />
49+
</span>
50+
</PopoverTrigger>
51+
)}
52+
53+
<PopoverContent css={{ transform: "translateY(-28px)" }}>
54+
<PopoverPaywall
55+
message="Observability"
56+
description="With a Premium license, you can monitor your application with logs and metrics."
57+
documentationLink="https://coder.com/docs/admin/appearance"
58+
/>
59+
</PopoverContent>
60+
</Popover>
3861
</Badges>
3962
</div>
4063

0 commit comments

Comments
 (0)