chore: update upgrade page (#17988)

* chore: upgrade page for usage

* fix: upgrade page scroll

* chore: scrollable and design upgrade for upgradePage

* fix: module imports
This commit is contained in:
f0c1s 2022-11-01 22:23:27 +05:30 committed by GitHub
parent 633493ac74
commit e4f8e8a755
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 249 additions and 78 deletions

View File

@ -10,8 +10,8 @@ const Header = {
};
const Carousel = {
Left: "[data-testid='t--carousel-left']",
Right: "[data-testid='t--carousel-right']",
Left: "[data-testid='t--carousel-triggers']",
Right: "[data-testid='t--carousel-targets']",
};
const UpgradePage = {

View File

@ -1281,7 +1281,34 @@ export const INVALID_URL = () =>
// Alert options and labels for showMessage types
export const ALERT_STYLE_OPTIONS = [
{ label: "Info", value: "'info'", id: "info" },
{ label: "Success", value: "'success'", id: "success" },
{
label: "Success",
value: "'success'",
id: "success",
},
{ label: "Error", value: "'error'", id: "error" },
{ label: "Warning", value: "'warning'", id: "warning" },
];
export const USAGE_AND_BILLING = {
usage: () => "Usage",
billing: () => "Billing",
usageAndBilling: () => "Usage & Billing",
usageOverNDays: (days: number) => `Usage over the past ${days} days!`,
usageDetails: () =>
"This is how much you have used Appsmith to build and run apps.",
unit: () => "minutes/day",
averaged: () => "*averaged",
approximated: () => "*approximated",
sell: () => "Figure out your usage before purchasing Appsmith",
upgradeToBusiness: () => "UPGRADE TO BUSINESS EDITION",
rbacHeading: () => "Role Based Access Control",
rbacDetails: () =>
"RBAC is here to allow you to control access to appsmith as easy as you maintain your organization.",
ssoHeading: () => "SSO and Custom Authentication",
ssoDetails: () => "SSO and custom auth allow you to onboard users faster.",
gitHeading: () => "Unlimited private git repositories",
gitDetails: () => "Expand your single source of truth capability to infinite",
exclusive: () =>
"These features are exclusively available on business edition.",
};

View File

@ -6,6 +6,10 @@ import { Category } from "@appsmith/pages/AdminSettings/config/types";
import { adminSettingsCategoryUrl } from "RouteBuilder";
import { useParams } from "react-router";
import { Icon, IconSize } from "design-system";
import { createMessage } from "design-system/build/constants/messages";
import { USAGE_AND_BILLING } from "@appsmith/constants/messages";
import { useSelector } from "react-redux";
import { selectFeatureFlags } from "selectors/usersSelectors";
export const Wrapper = styled.div`
flex-basis: ${(props) =>
@ -121,6 +125,7 @@ export function Categories({
}
export default function LeftPane() {
const features = useSelector(selectFeatureFlags);
const categories = getSettingsCategory();
const { category, selected: subCategory } = useParams() as any;
return (
@ -150,6 +155,20 @@ export default function LeftPane() {
<div>Audit logs</div>
</StyledLink>
</CategoryItem>
{features.USAGE && (
<CategoryItem>
<StyledLink
$active={category === "usage"}
data-testid="t--enterprise-settings-category-item-usage"
to="/settings/usage"
>
<div>
<Icon name="lock-2-line" size={IconSize.XL} />
</div>
<div>{createMessage(USAGE_AND_BILLING.usage)}</div>
</StyledLink>
</CategoryItem>
)}
</CategoryList>
</>
</Wrapper>

View File

@ -6,6 +6,7 @@ import { ADMIN_SETTINGS_CATEGORY_DEFAULT_PATH } from "constants/routes";
import SettingsForm from "pages/Settings/SettingsForm";
import { AuditLogsUpgradePage } from "../Upgrade/AuditLogsUpgradePage";
import { AccessControlUpgradePage } from "../Upgrade/AccessControlUpgradePage";
import { UsageUpgradePage } from "../Upgrade/UsageUpgradePage";
const Main = () => {
const params = useParams() as any;
@ -22,6 +23,9 @@ const Main = () => {
if (category === "audit-logs") {
return <AuditLogsUpgradePage />;
}
if (category === "usage") {
return <UsageUpgradePage />;
}
/* Old, still working flow; config, factory based */
if (!!wrapperCategory?.component) {

View File

@ -1,5 +1,5 @@
import React from "react";
import { Header } from "./types";
import { Carousel, Header } from "./types";
import UpgradePage from "./UpgradePage";
export function AccessControlUpgradePage() {
@ -7,7 +7,7 @@ export function AccessControlUpgradePage() {
heading: "Access Control",
subHeadings: ["sub heading 1", "sub heading 2"],
};
const carousel = {
const carousel: Carousel = {
triggers: [
{
icon: "lock-2-line",
@ -26,6 +26,7 @@ export function AccessControlUpgradePage() {
},
],
targets: ["first", "second", "third"],
design: "split-left-trigger",
};
const footer = {
onClick: () => null,

View File

@ -1,5 +1,5 @@
import React from "react";
import { Header } from "./types";
import { Carousel, Header } from "./types";
import UpgradePage from "./UpgradePage";
import DebuggingImage from "assets/svg/upgrade/audit-logs/debugging.svg";
import IncidentManagementImage from "assets/svg/upgrade/audit-logs/incident-management.svg";
@ -29,7 +29,7 @@ export function AuditLogsUpgradePage() {
heading: createMessage(INTRODUCING, createMessage(AUDIT_LOGS)),
subHeadings: [createMessage(AUDIT_LOGS_UPGRADE_PAGE_SUB_HEADING)],
};
const carousel = {
const carousel: Carousel = {
triggers: [
{
icon: "lock-2-line",
@ -63,6 +63,7 @@ export function AuditLogsUpgradePage() {
src={IncidentManagementImage}
/>,
],
design: "split-left-trigger",
};
const footer = {

View File

@ -4,17 +4,15 @@ import { Icon, IconSize, Text, TextType } from "design-system";
import { CarouselProps } from "./types";
const CarouselContainer = styled.div`
flex-grow: 1;
gap: 64px;
margin-bottom: 86px;
display: flex;
flex: 1 1;
gap: 64px;
justify-content: center;
align-items: center;
height: 542px;
padding: 16px;
& .carousel-left {
& .carousel-triggers {
display: flex;
flex-grow: 1;
flex-direction: column;
gap: 20px;
justify-content: center;
@ -29,7 +27,7 @@ const CarouselContainer = styled.div`
&.active {
height: max-content;
min-height: 152px;
min-height: 156px;
box-shadow: 0 2px 4px -2px rgba(0, 0, 0, 0.06),
0 4px 8px -2px rgba(0, 0, 0, 0.1);
@ -64,9 +62,14 @@ const CarouselContainer = styled.div`
}
}
}
& .carousel-targets {
width: auto;
height: auto;
}
}
& .carousel-right {
& .carousel-targets {
width: 680px;
height: 472px;
display: flex;
@ -82,39 +85,46 @@ const CarouselContainer = styled.div`
export function CarouselComponent(props: CarouselProps) {
const [active, setActive] = useState(0);
const [rightContent, setRightContent] = useState(null);
const { targets, triggers } = props;
const [targetContent, setTargetContent] = useState(null);
const { design, targets, triggers } = props;
useEffect(() => {
setRightContent(targets[active]);
setTargetContent(targets[active]);
}, [active]);
const isActive = (i: number) => i === active;
return (
<CarouselContainer
className="upgrade-page-carousel-container"
data-testid="t--upgrade-page-carousel-container"
const targetsComponent = (
<div
className={`carousel-targets ${design}`}
data-testid="t--carousel-targets"
>
<div className="carousel-left" data-testid="t--carousel-left">
{triggers.map((d, i) => {
return (
<div
className={`carousel-item-container carousel-trigger ${
isActive(i) ? "active" : ""
}`}
key={`carousel-item-${i}`}
onClick={() => setActive(i)}
role="button"
>
<div className={"trigger"}>
<div className="icon-container">
<Icon name={d.icon} size={IconSize.XXXXL} />
{targetContent}
</div>
);
const triggersComponent = (
<div
className={`carousel-triggers ${design}`}
data-testid="t--carousel-triggers"
>
{triggers.map((d, i) => {
return (
<div
className={`carousel-item-container carousel-trigger ${
isActive(i) ? "active" : ""
}`}
key={`carousel-item-${i}`}
onClick={() => setActive(i)}
role="button"
>
<div className={"trigger"}>
<div className="icon-container">
<Icon name={d.icon} size={IconSize.XXXXL} />
</div>
<div className="trigger-content">
<div className="trigger-heading">
<Text type={TextType.H1}>{d.heading}</Text>
</div>
<div className="trigger-content">
<div className="trigger-heading">
<Text type={TextType.H1}>{d.heading}</Text>
</div>
{isActive(i) && (
{isActive(i) && (
<>
<div className="trigger-details-container">
{d.details.map((detail, di) => {
return (
@ -127,16 +137,48 @@ export function CarouselComponent(props: CarouselProps) {
);
})}
</div>
)}
</div>
{design === "trigger-contains-target" && (
<div>{targetsComponent}</div>
)}
</>
)}
</div>
</div>
);
})}
</div>
<div className="carousel-right" data-testid="t--carousel-right">
{rightContent}
</div>
</div>
);
})}
</div>
);
let display = (
<>
{triggersComponent}
{targetsComponent}
</>
);
switch (design) {
case "no-target":
display = triggersComponent;
break;
case "trigger-contains-target":
display = triggersComponent;
break;
case "split-right-trigger":
display = (
<>
{targetsComponent}
{triggersComponent}
</>
);
break;
}
return (
<CarouselContainer
className="upgrade-page-carousel-container"
data-testid="t--upgrade-page-carousel-container"
>
{display}
</CarouselContainer>
);
}

View File

@ -4,14 +4,10 @@ import { HeaderProps } from "./types";
import { FontWeight, Text, TextType } from "design-system";
export const HeaderContainer = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
gap: 4px;
align-items: center;
width: 496px;
text-align: center;
height: 120px;
padding: 32px;
& .header-heading-container {
& .cs-text {

View File

@ -5,38 +5,31 @@ import { CarouselComponent as Carousel } from "./Carousel";
import { FooterComponent as Footer } from "./Footer";
import { UpgradePageProps } from "./types";
export const ExternalContainer = styled.div`
display: flex;
flex-grow: 1;
justify-content: center;
align-items: center;
min-height: calc(100vh - 50px);
max-height: 100vh;
border-left: thin solid var(--appsmith-color-black-50);
background-color: var(--ads-color-black-50);
`;
export const InternalContainer = styled.div`
export const Container = styled.div`
display: flex;
flex-direction: column;
flex-grow: 1;
gap: 32px;
justify-content: center;
flex: 1 1;
border-left: thin solid var(--appsmith-color-black-50);
background-color: var(--ads-color-black-50);
align-items: center;
justify-items: center;
height: calc(100vh - 50px - 112px);
min-width: 1180px;
min-height: 0;
overflow: auto;
gap: 32px;
`;
export default function UpgradePage(props: UpgradePageProps) {
const { carousel, footer, header } = props;
return (
<ExternalContainer
<Container
className="upgrade-page-container"
data-testid="t--upgrade-page-container"
>
<InternalContainer>
<Header {...header} />
<Carousel {...carousel} />
<Footer {...footer} />
</InternalContainer>
</ExternalContainer>
<Header {...header} />
<Carousel {...carousel} />
<Footer {...footer} />
</Container>
);
}

View File

@ -0,0 +1,82 @@
import React from "react";
import { Carousel, Header } from "./types";
import { createMessage } from "design-system/build/constants/messages";
import { USAGE_AND_BILLING } from "@appsmith/constants/messages";
import AnalyticsUtil from "utils/AnalyticsUtil";
import UpgradePage from "./UpgradePage";
import { getAppsmithConfigs } from "../../configs";
import { FontWeight, Text, TextType } from "design-system";
const { intercomAppID } = getAppsmithConfigs();
export function UsageUpgradePage() {
const header: Header = {
heading: createMessage(USAGE_AND_BILLING.usage),
subHeadings: [createMessage(USAGE_AND_BILLING.sell)],
};
const carousel: Carousel = {
triggers: [
{
icon: "lock-2-line",
heading: createMessage(USAGE_AND_BILLING.usageOverNDays, 20),
details: [createMessage(USAGE_AND_BILLING.usageDetails)],
},
{
icon: "search-eye-line",
heading: createMessage(USAGE_AND_BILLING.rbacHeading),
details: [createMessage(USAGE_AND_BILLING.rbacDetails)],
},
{
icon: "alert-line",
heading: createMessage(USAGE_AND_BILLING.ssoHeading),
details: [createMessage(USAGE_AND_BILLING.ssoDetails)],
},
{
icon: "alert-line",
heading: createMessage(USAGE_AND_BILLING.gitHeading),
details: [createMessage(USAGE_AND_BILLING.gitDetails)],
},
],
targets: [
<div key={"usage-over-past-n-days"}>
<div>
<Text type={TextType.H1} weight={FontWeight.BOLD}>
201
</Text>
&nbsp;
<Text type={TextType.P1}>
{createMessage(USAGE_AND_BILLING.unit)}{" "}
</Text>
</div>
<div>
<Text type={TextType.P3}>
{createMessage(USAGE_AND_BILLING.averaged)}{" "}
{createMessage(USAGE_AND_BILLING.approximated)}
</Text>
</div>
</div>,
null,
null,
null,
],
design: "trigger-contains-target",
};
const footer = {
onClick: () => {
AnalyticsUtil.logEvent("ADMIN_SETTINGS_UPGRADE_HOOK", {
source: "Usage",
});
if (intercomAppID && window.Intercom) {
window.Intercom(
"showNewMessage",
createMessage(USAGE_AND_BILLING.upgradeToBusiness),
);
}
},
message: createMessage(USAGE_AND_BILLING.exclusive),
};
const props = { header, carousel, footer };
return <UpgradePage {...props} />;
}

View File

@ -14,6 +14,11 @@ export type CarouselTrigger = {
export type Carousel = {
triggers: CarouselTrigger[];
targets: any[];
design:
| "split-left-trigger"
| "split-right-trigger"
| "trigger-contains-target"
| "no-target";
};
export type Footer = {

View File

@ -6,6 +6,7 @@ type FeatureFlags = {
TEMPLATES_PHASE_2?: boolean;
RBAC?: boolean;
CONTEXT_SWITCHING?: boolean;
USAGE?: boolean;
};
export default FeatureFlags;