Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add premium license banner for custom roles page#14595

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
jaaydenh merged 11 commits intomainfromjaaydenh/premium-banners
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletionssite/src/components/Badges/Badges.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -112,8 +112,8 @@ export const EnterpriseBadge: FC = () => {
css={[
styles.badge,
(theme) => ({
backgroundColor: theme.roles.notice.background,
border: `1px solid ${theme.roles.notice.outline}`,
backgroundColor: theme.branding.badge.enterprise.background,
border: `1px solid ${theme.branding.badge.enterprise.border}`,
color: theme.roles.notice.text,
}),
]}
Expand All@@ -129,8 +129,8 @@ export const PremiumBadge: FC = () => {
css={[
styles.badge,
(theme) => ({
backgroundColor: theme.roles.notice.background,
border: `1px solid ${theme.roles.notice.outline}`,
backgroundColor: theme.branding.badge.premium.background,
border: `1px solid ${theme.branding.badge.premium.border}`,
color: theme.roles.notice.text,
}),
]}
Expand Down
12 changes: 10 additions & 2 deletionssite/src/components/Paywall/Paywall.stories.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,12 +9,20 @@ const meta: Meta<typeof Paywall> = {
export default meta;
type Story = StoryObj<typeof Paywall>;

constExample: Story = {
exportconstEnterprise: Story = {
args: {
type: "enterprise",
message: "Black Lotus",
description:
"Adds 3 mana of any single color of your choice to your mana pool, then is discarded. Tapping this artifact can be played as an interrupt.",
},
};

export { Example as Paywall };
export const Premium: Story = {
args: {
type: "premium",
message: "Black Lotus",
description:
"Adds 3 mana of any single color of your choice to your mana pool, then is discarded. Tapping this artifact can be played as an interrupt.",
},
};
73 changes: 51 additions & 22 deletionssite/src/components/Paywall/Paywall.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,28 +2,39 @@ import type { Interpolation, Theme } from "@emotion/react";
import TaskAltIcon from "@mui/icons-material/TaskAlt";
import Button from "@mui/material/Button";
import Link from "@mui/material/Link";
import { EnterpriseBadge } from "components/Badges/Badges";
import { EnterpriseBadge, PremiumBadge } from "components/Badges/Badges";
import { Stack } from "components/Stack/Stack";
import type { FC, ReactNode } from "react";
import theme from "theme";
import { docs } from "utils/docs";

export interface PaywallProps {
type: "enterprise" | "premium";
message: string;
description?: ReactNode;
documentationLink?: string;
}

export const Paywall: FC<PaywallProps> = ({
type,
message,
description,
documentationLink,
}) => {
return (
<div css={styles.root}>
<div
css={[
styles.root,
(theme) => ({
backgroundImage: `linear-gradient(160deg, transparent, ${theme.branding.paywall[type].background})`,
border: `1px solid ${theme.branding.paywall[type].border}`,
}),
]}
>
<div>
<Stack direction="row" alignItems="center" css={{ marginBottom: 24 }}>
<h5 css={styles.title}>{message}</h5>
<EnterpriseBadge />
{type === "enterprise" ?<EnterpriseBadge /> : <PremiumBadge />}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

My main worry with this setup is that because the conditional "flip" for displaying the text is getting repeated so much, there's a higher risk of someone making a typo and accidentally mixing text and bullet points between paywall types

I know it isn't DRY, but just to keep things firmly grouped together, my preference would be to have two variants of the component (that can be kept un-exported as private implementation details) – one for premium and one for enterprise

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Basically, I don't think there's a great way to fully DRY up the code, so we have to choose between DRYing up the content or the markup/styling. But because this potentially involves a lot of money, I'd always choose content and making sure customers can't ever get incorrect information. A single missed!== instead of a=== breaks that

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This was meant to be a temporary solution as I originally thought the enterprise license would only remain for a short time longer. But now I am going to update this to completely remove the enterprise license and leave only the premium

</Stack>

{description && <p css={styles.description}>{description}</p>}
Expand All@@ -36,20 +47,32 @@ export const Paywall: FC<PaywallProps> = ({
Read the documentation
</Link>
</div>
<div css={styles.separator}></div>
<div css={styles.separator} />
<Stack direction="column" alignItems="center" spacing={3}>
<ul css={styles.featureList}>
<li css={styles.feature}>
<FeatureIcon /> Template access control
<FeatureIcon type={type} />
{type === "premium"
? "High availability & workspace proxies"
: "Template access control"}
</li>
<li css={styles.feature}>
<FeatureIcon /> User groups
<FeatureIcon type={type} />
{type === "premium"
? "Multi-org & role-based access control"
: "User groups"}
</li>
<li css={styles.feature}>
<FeatureIcon /> 24 hour support
<FeatureIcon type={type} />
{type === "premium"
? "24x7 global support with SLA"
: "24 hour support"}
</li>
<li css={styles.feature}>
<FeatureIcon /> Audit logs
<FeatureIcon type={type} />
{type === "premium"
? "Unlimited Git & external auth integrations"
: "Audit logs"}
</li>
</ul>
<Button
Expand All@@ -60,15 +83,27 @@ export const Paywall: FC<PaywallProps> = ({
variant="outlined"
color="neutral"
>
Learn about Enterprise
Learn about{type === "enterprise" ? "Enterprise" : "Premium"}
</Button>
</Stack>
</div>
);
};

const FeatureIcon: FC = () => {
return <TaskAltIcon css={styles.featureIcon} />;
export interface FeatureIconProps {
type: "enterprise" | "premium";
}

const FeatureIcon: FC<FeatureIconProps> = ({ type }) => {
return (
<TaskAltIcon
css={[
(theme) => ({
color: theme.branding.paywall[type].border,
}),
]}
/>
);
};

const styles = {
Expand All@@ -77,12 +112,9 @@ const styles = {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
minHeight: 300,
maxWidth: 920,
margin: "auto",
minHeight: 280,
marginBottom: 32,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Ireally disagree with having any kind of external margin value on a general-purpose component

Again, maybe not DRY, but since the external spacing is strictly something the parent component would need to be worried about, I'd move that logic here. The margin isn't inherently tied to the content of the component, and now we can't use it for other purposes without having a hard-coded margin value be enforced

jaaydenh and aslilac reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

got it, removed the marginBottom

padding: 24,
backgroundImage: `linear-gradient(160deg, transparent, ${theme.roles.active.background})`,
border: `1px solid ${theme.roles.active.fill.outline}`,
borderRadius: 8,
gap: 32,
}),
Expand All@@ -93,12 +125,9 @@ const styles = {
margin: 0,
},
description: (theme) => ({
marginTop: 16,
fontFamily: "inherit",
maxWidth: 420,
lineHeight: "160%",
color: theme.palette.text.secondary,
fontSize: 16,
maxWidth: 460,
fontSize: 14,
}),
separator: (theme) => ({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Making a note for myself: we should update our color theme so that it works better on colored backgrounds. The gray divider color looks really washed out on a saturated colored background

Copy link
Member

@ParkreinerParkreinerSep 9, 2024
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Before:
Screenshot 2024-09-09 at 10 20 08 AM

After:
Screenshot 2024-09-09 at 10 20 14 AM

Same thing applies to the border around the button, but I don't want to pop open an MUI library component

jaaydenh reacted with thumbs up emoji
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

ooooh, purple divider looksrad

width: 1,
Expand All@@ -110,7 +139,7 @@ const styles = {
listStyle: "none",
margin: 0,
marginRight: 8,
padding: "012px",
padding: "024px",
fontSize: 14,
fontWeight: 500,
},
Expand Down
44 changes: 29 additions & 15 deletionssite/src/components/Paywall/PopoverPaywall.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,15 @@ export const PopoverPaywall: FC<PopoverPaywallProps> = ({
licenseType = "enterprise",
}) => {
return (
<div css={styles.root}>
<div
css={[
styles.root,
(theme) => ({
backgroundImage: `linear-gradient(160deg, transparent, ${theme.branding.paywall[licenseType].background})`,
border: `1px solid ${theme.branding.paywall[licenseType].border}`,
}),
]}
>
<div>
<Stack direction="row" alignItems="center" css={{ marginBottom: 18 }}>
<h5 css={styles.title}>{message}</h5>
Expand All@@ -38,24 +46,24 @@ export const PopoverPaywall: FC<PopoverPaywallProps> = ({
Read the documentation
</Link>
</div>
<div css={styles.separator}></div>
<div css={styles.separator} />
<Stack direction="column" alignItems="center" spacing={2}>
<ul css={styles.featureList}>
<li css={styles.feature}>
<FeatureIcon /> Template access control
<FeatureIcontype={licenseType}/> Template access control
</li>
<li css={styles.feature}>
<FeatureIcon /> User groups
<FeatureIcontype={licenseType}/> User groups
</li>
<li css={styles.feature}>
<FeatureIcon /> 24 hour support
<FeatureIcontype={licenseType}/> 24 hour support
</li>
<li css={styles.feature}>
<FeatureIcon /> Audit logs
<FeatureIcontype={licenseType}/> Audit logs
</li>
{licenseType === "premium" && (
<li css={styles.feature}>
<FeatureIcon /> Organizations
<FeatureIcontype={licenseType}/> Organizations
</li>
)}
</ul>
Expand All@@ -74,8 +82,20 @@ export const PopoverPaywall: FC<PopoverPaywallProps> = ({
);
};

const FeatureIcon: FC = () => {
return <TaskAltIcon css={styles.featureIcon} />;
export interface FeatureIconProps {
type: "enterprise" | "premium";
}

const FeatureIcon: FC<FeatureIconProps> = ({ type }) => {
return (
<TaskAltIcon
css={[
(theme) => ({
color: theme.branding.paywall[type].border,
}),
]}
/>
);
};

const styles = {
Expand All@@ -85,8 +105,6 @@ const styles = {
alignItems: "center",
maxWidth: 600,
padding: "24px 36px",
backgroundImage: `linear-gradient(160deg, transparent, ${theme.roles.active.background})`,
border: `1px solid ${theme.roles.active.fill.outline}`,
borderRadius: 8,
gap: 18,
}),
Expand DownExpand Up@@ -118,10 +136,6 @@ const styles = {
fontSize: 13,
fontWeight: 500,
},
featureIcon: (theme) => ({
color: theme.roles.active.fill.outline,
fontSize: "1.5em",
}),
feature: {
display: "flex",
alignItems: "center",
Expand Down
1 change: 1 addition & 0 deletionssite/src/pages/AuditPage/AuditPageView.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -137,6 +137,7 @@ export const AuditPageView: FC<AuditPageViewProps> = ({

<Cond>
<Paywall
type="enterprise"
message="Audit logs"
description="Audit logs allow you to monitor user operations on your deployment. You need an Enterprise license to use this feature."
documentationLink={docs("/admin/audit-logs")}
Expand Down
3 changes: 2 additions & 1 deletionsite/src/pages/GroupsPage/GroupsPageView.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ export const GroupsPageView: FC<GroupsPageViewProps> = ({
<ChooseOne>
<Cond condition={!isTemplateRBACEnabled}>
<Paywall
type="enterprise"
message="Groups"
description="Organize users into groups with restricted access to templates. You need an Enterprise license to use this feature."
documentationLink={docs("/admin/groups")}
Expand All@@ -58,7 +59,7 @@ export const GroupsPageView: FC<GroupsPageViewProps> = ({
<TableRow>
<TableCell width="50%">Name</TableCell>
<TableCell width="49%">Users</TableCell>
<TableCell width="1%"></TableCell>
<TableCell width="1%" />
</TableRow>
</TableHead>
<TableBody>
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,14 @@ export const NotEnabled: Story = {
},
};

export const NotEnabledEmptyTable: Story = {
args: {
roles: [],
canAssignOrgRole: true,
isCustomRolesEnabled: false,
},
};

export const Enabled: Story = {
args: {
roles: [MockRoleWithOrgPermissions],
Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp