Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.

Commit 6987382

Browse files
committed
feat: prepare the community edition
- CE has unlimited seats for core functionalities: deployment and hosting - For EE features, a license is required now
1 parent be6a096 commit 6987382

44 files changed

Lines changed: 756 additions & 377 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/components/EmptyPage/EmptyPage.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,33 @@ import React from "react";
33
import Box from "@mui/material/Box";
44
import Typography from "@mui/material/Typography";
55
import emptyListSvg from "~/assets/images/empty-list.svg";
6+
import UpgradeButton from "~/components/UpgradeButton";
67

78
interface Props {
89
sx?: SxProps;
910
children?: React.ReactNode;
11+
paymentRequired?: boolean;
1012
}
1113

12-
export default function EmptyList({ sx, children }: Props) {
14+
export default function EmptyList({ sx, children, paymentRequired }: Props) {
1315
return (
1416
<Box sx={{ textAlign: "center", my: 12, ...sx }}>
1517
<img src={emptyListSvg} alt="Empty app list" className="m-auto" />
16-
<Typography fontSize="medium" sx={{ mt: 6 }}>
17-
{children || <>It's quite empty in here.</>}
18-
</Typography>
18+
{paymentRequired ? (
19+
<>
20+
<Typography
21+
fontSize="medium"
22+
sx={{ mt: 6, mb: 2, fontWeight: "bold" }}
23+
>
24+
You need to upgrade your plan to access this feature.
25+
</Typography>
26+
<UpgradeButton fullWidth={false} />
27+
</>
28+
) : (
29+
<Typography fontSize="medium" sx={{ mt: 6 }}>
30+
{children || <>It's quite empty in here.</>}
31+
</Typography>
32+
)}
1933
</Box>
2034
);
2135
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import LockIcon from "@mui/icons-material/Lock";
2+
import LaunchIcon from "@mui/icons-material/Launch";
3+
import Button from "@mui/material/Button";
4+
import Link from "@mui/material/Link";
5+
6+
interface Props {
7+
fullWidth?: boolean;
8+
text?: string;
9+
variant?: "contained" | "outlined" | "text";
10+
}
11+
12+
export default function UpgradeButton({
13+
fullWidth = true,
14+
text = "Upgrade to enterprise",
15+
variant = "contained",
16+
}: Props) {
17+
const Icon = text === "Upgrade to enterprise" ? LockIcon : LaunchIcon;
18+
const href = "https://app.stormkit.io/user/account";
19+
20+
if (variant === "text") {
21+
return (
22+
<Link
23+
href={href}
24+
color="secondary"
25+
target="_blank"
26+
rel="noopener noreferrer"
27+
sx={{ textDecoration: "underline !important" }}
28+
>
29+
{text}
30+
</Link>
31+
);
32+
}
33+
34+
return (
35+
<Button
36+
variant={variant}
37+
color="secondary"
38+
fullWidth={fullWidth}
39+
sx={{ mb: 1 }}
40+
startIcon={<Icon sx={{ fontSize: 16 }} />}
41+
target="_blank"
42+
rel="noopener noreferrer"
43+
href="https://app.stormkit.io/user/account"
44+
>
45+
{text}
46+
</Button>
47+
);
48+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from "./UpgradeButton";

src/layouts/AdminLayout/AdminLayout.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ export default function AdminLayout({ children }: Props) {
7272
pathname.includes("/admin/system") || pathname === "/admin",
7373
}}
7474
/>
75+
{/* <MenuLink
76+
item={{
77+
path: "/admin/users",
78+
text: "Users",
79+
isActive: pathname.includes("/admin/users"),
80+
}}
81+
/> */}
7582
<MenuLink
7683
item={{
7784
path: "/admin/subscription",

src/layouts/TopMenu/Teams/TeamMenu.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useContext } from "react";
12
import Box from "@mui/material/Box";
23
import Chip from "@mui/material/Chip";
34
import Link from "@mui/material/Link";
@@ -9,6 +10,8 @@ import Check from "@mui/icons-material/Check";
910
import Settings from "@mui/icons-material/Settings";
1011
import GroupAdd from "@mui/icons-material/GroupAdd";
1112
import ClickAwayListener from "@mui/material/ClickAwayListener";
13+
import { RootContext } from "~/pages/Root.context";
14+
import UpgradeButton from "~/components/UpgradeButton";
1215

1316
interface Props {
1417
selectedTeam?: Team;
@@ -27,6 +30,8 @@ export default function TeamMenu({
2730
onCreateTeamButtonClicked,
2831
onClickAway,
2932
}: Props) {
33+
const { details } = useContext(RootContext);
34+
3035
return (
3136
<ClickAwayListener onClickAway={onClickAway}>
3237
<Box>
@@ -118,19 +123,23 @@ export default function TeamMenu({
118123
)}
119124
</Box>
120125
))}
121-
<Button
122-
variant="contained"
123-
color="secondary"
124-
fullWidth
125-
sx={{ mb: 1 }}
126-
onClick={e => {
127-
e.preventDefault();
128-
onCreateTeamButtonClicked();
129-
}}
130-
>
131-
<Add sx={{ mr: 0.25, fontSize: 16 }} />
132-
Create team
133-
</Button>
126+
{details?.license?.edition === "community" ? (
127+
<UpgradeButton />
128+
) : (
129+
<Button
130+
variant="contained"
131+
color="secondary"
132+
fullWidth
133+
sx={{ mb: 1 }}
134+
startIcon={<Add sx={{ fontSize: 16 }} />}
135+
onClick={e => {
136+
e.preventDefault();
137+
onCreateTeamButtonClicked();
138+
}}
139+
>
140+
Create team
141+
</Button>
142+
)}
134143
</Box>
135144
</Box>
136145
</ClickAwayListener>

src/layouts/TopMenu/Teams/TeamModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export default function TeamModal({ onClose, reload }: Props) {
5151
onClose();
5252
navigate(`/${t.slug}`, { replace: true });
5353
})
54-
.catch(e => {
54+
.catch(() => {
5555
setError("Something went wrong while saving the team.");
5656
})
5757
.finally(() => {

src/layouts/TopMenu/Teams/TeamToggle.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ export default function TeamsToggle({ app }: Props) {
2828
arrow
2929
open={isMenuOpen}
3030
placement="bottom-start"
31-
PopperProps={{
32-
modifiers: [{ name: "offset", options: { offset: [0, 12] } }],
31+
slotProps={{
32+
popper: {
33+
modifiers: [{ name: "offset", options: { offset: [0, 12] } }],
34+
},
3335
}}
3436
title={
3537
<Box sx={{ p: 1 }}>

src/layouts/TopMenu/TopMenu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Box from "@mui/material/Box";
33
import Link from "@mui/material/Link";
44
import Logo from "~/components/Logo";
55
import UserButtons from "./UserButtons";
6-
import TeamsToggle from "./Teams/TeamToggle";
6+
import TeamToggle from "./Teams/TeamToggle";
77
import { grey } from "@mui/material/colors";
88

99
interface Props {
@@ -41,7 +41,7 @@ export default function TopMenu({ children, submenu, app, team }: Props) {
4141
<Link href={slug} sx={{ flex: "1", mr: 1 }}>
4242
<Logo iconSize={28} iconOnly />
4343
</Link>
44-
<TeamsToggle app={app} />
44+
<TeamToggle app={app} />
4545
</Box>
4646
<Box sx={{ flex: 1 }}>{children}</Box>
4747
<Box sx={{ display: "flex", alignItems: "center" }}>

src/pages/Root.context.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ type theme = "dark" | "light";
44

55
interface RootContextProps {
66
mode: theme;
7+
details?: InstanceDetails;
8+
loading?: boolean;
79
setMode: (v: theme) => void;
10+
setRefreshToken?: (token: number) => void;
811
}
912

1013
export const RootContext = createContext<RootContextProps>({

src/pages/Root.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import { useMemo, useState } from "react";
22
import { Route, Routes, BrowserRouter } from "react-router-dom";
33
import { StyledEngineProvider, ThemeProvider } from "@mui/material/styles";
44
import CssBaseline from "@mui/material/CssBaseline";
5+
import Alert from "@mui/material/Alert";
56
import AuthContext from "./auth/Auth.context";
7+
import { useFetchInstanceDetails } from "./auth/actions";
68
import routes from "./routes";
79
import createTheme from "./mui-theme";
810
import { RootContext } from "./Root.context";
@@ -14,6 +16,9 @@ interface Props {
1416
const LS_KEY = "STORMKIT_MODE";
1517

1618
export default function Root({ Router }: Props) {
19+
const [refreshToken, setRefreshToken] = useState(0);
20+
const { details, loading, error } = useFetchInstanceDetails(refreshToken);
21+
1722
const [mode, setMode] = useState<"dark" | "light">(
1823
(localStorage.getItem(LS_KEY) as "dark") || "dark"
1924
);
@@ -25,7 +30,10 @@ export default function Root({ Router }: Props) {
2530
return (
2631
<RootContext.Provider
2732
value={{
33+
details,
34+
loading,
2835
mode,
36+
setRefreshToken,
2937
setMode: v => {
3038
localStorage.setItem(LS_KEY, v);
3139
setMode(v);
@@ -35,6 +43,11 @@ export default function Root({ Router }: Props) {
3543
<StyledEngineProvider injectFirst>
3644
<ThemeProvider theme={theme}>
3745
<CssBaseline />
46+
{error && (
47+
<Alert severity="error" sx={{ mb: 4 }}>
48+
{error}
49+
</Alert>
50+
)}
3851
<Router>
3952
<AuthContext>
4053
<Routes>

0 commit comments

Comments
 (0)