mirror of
https://github.com/docmost/docmost.git
synced 2025-11-13 08:22:38 +10:00
upsell
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Group, Text, ScrollArea, ActionIcon } from "@mantine/core";
|
||||
import { Group, Text, ScrollArea, ActionIcon, Tooltip } from "@mantine/core";
|
||||
import {
|
||||
IconUser,
|
||||
IconSettings,
|
||||
@ -42,6 +42,7 @@ interface DataItem {
|
||||
isEnterprise?: boolean;
|
||||
isAdmin?: boolean;
|
||||
isSelfhosted?: boolean;
|
||||
showDisabledInNonEE?: boolean;
|
||||
}
|
||||
|
||||
interface DataGroup {
|
||||
@ -84,6 +85,7 @@ const groupedData: DataGroup[] = [
|
||||
isCloud: true,
|
||||
isEnterprise: true,
|
||||
isAdmin: true,
|
||||
showDisabledInNonEE: true,
|
||||
},
|
||||
{ label: "Groups", icon: IconUsersGroup, path: "/settings/groups" },
|
||||
{ label: "Spaces", icon: IconSpaces, path: "/settings/spaces" },
|
||||
@ -117,6 +119,12 @@ export default function SettingsSidebar() {
|
||||
}, [location.pathname]);
|
||||
|
||||
const canShowItem = (item: DataItem) => {
|
||||
// For items with showDisabledInCommunity, always show them but in disabled state
|
||||
if (item.showDisabledInNonEE && item.isEnterprise) {
|
||||
// Check admin permission regardless of license
|
||||
return item.isAdmin ? isAdmin : true;
|
||||
}
|
||||
|
||||
if (item.isCloud && item.isEnterprise) {
|
||||
if (!(isCloud() || workspace?.hasLicenseKey)) return false;
|
||||
return item.isAdmin ? isAdmin : true;
|
||||
@ -141,6 +149,13 @@ export default function SettingsSidebar() {
|
||||
return true;
|
||||
};
|
||||
|
||||
const isItemDisabled = (item: DataItem) => {
|
||||
if (item.showDisabledInNonEE && item.isEnterprise) {
|
||||
return !(isCloud() || workspace?.hasLicenseKey);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const menuItems = groupedData.map((group) => {
|
||||
if (group.heading === "System" && (!isAdmin || isCloud())) {
|
||||
return null;
|
||||
@ -185,23 +200,48 @@ export default function SettingsSidebar() {
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
const isDisabled = isItemDisabled(item);
|
||||
const linkElement = (
|
||||
<Link
|
||||
onMouseEnter={prefetchHandler}
|
||||
onMouseEnter={!isDisabled ? prefetchHandler : undefined}
|
||||
className={classes.link}
|
||||
data-active={active.startsWith(item.path) || undefined}
|
||||
data-disabled={isDisabled || undefined}
|
||||
key={item.label}
|
||||
to={item.path}
|
||||
onClick={() => {
|
||||
to={isDisabled ? "#" : item.path}
|
||||
onClick={(e) => {
|
||||
if (isDisabled) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
if (mobileSidebarOpened) {
|
||||
toggleMobileSidebar();
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
opacity: isDisabled ? 0.5 : 1,
|
||||
cursor: isDisabled ? "not-allowed" : "pointer",
|
||||
}}
|
||||
>
|
||||
<item.icon className={classes.linkIcon} stroke={2} />
|
||||
<span>{t(item.label)}</span>
|
||||
</Link>
|
||||
);
|
||||
|
||||
if (isDisabled) {
|
||||
return (
|
||||
<Tooltip
|
||||
key={item.label}
|
||||
label={t("Available in enterprise edition")}
|
||||
position="right"
|
||||
withArrow
|
||||
>
|
||||
{linkElement}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return linkElement;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -11,7 +11,7 @@ export default function OssDetails() {
|
||||
withTableBorder
|
||||
>
|
||||
<Table.Caption>
|
||||
To unlock enterprise features like SSO, contact sales@docmost.com.
|
||||
To unlock enterprise features like SSO, MFA, Resolve comments, contact sales@docmost.com.
|
||||
</Table.Caption>
|
||||
<Table.Tbody>
|
||||
<Table.Tr>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import { Group, Text, Button } from "@mantine/core";
|
||||
import { Group, Text, Button, Tooltip } from "@mantine/core";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@ -7,6 +7,8 @@ import { getMfaStatus } from "@/ee/mfa";
|
||||
import { MfaSetupModal } from "@/ee/mfa";
|
||||
import { MfaDisableModal } from "@/ee/mfa";
|
||||
import { MfaBackupCodesModal } from "@/ee/mfa";
|
||||
import { isCloud } from "@/lib/config.ts";
|
||||
import useLicense from "@/ee/hooks/use-license.tsx";
|
||||
|
||||
export function MfaSettings() {
|
||||
const { t } = useTranslation();
|
||||
@ -14,16 +16,19 @@ export function MfaSettings() {
|
||||
const [setupModalOpen, setSetupModalOpen] = useState(false);
|
||||
const [disableModalOpen, setDisableModalOpen] = useState(false);
|
||||
const [backupCodesModalOpen, setBackupCodesModalOpen] = useState(false);
|
||||
const { hasLicenseKey } = useLicense();
|
||||
|
||||
const { data: mfaStatus, isLoading } = useQuery({
|
||||
queryKey: ["mfa-status"],
|
||||
queryFn: getMfaStatus,
|
||||
});
|
||||
|
||||
if (isLoading) {
|
||||
if (isLoading || !mfaStatus) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const canUseMfa = isCloud() || hasLicenseKey;
|
||||
|
||||
// Check if MFA is truly enabled
|
||||
const isMfaEnabled = mfaStatus?.isEnabled === true;
|
||||
|
||||
@ -61,13 +66,19 @@ export function MfaSettings() {
|
||||
</div>
|
||||
|
||||
{!isMfaEnabled ? (
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={() => setSetupModalOpen(true)}
|
||||
style={{ whiteSpace: "nowrap" }}
|
||||
<Tooltip
|
||||
label={t("Available in enterprise edition")}
|
||||
disabled={canUseMfa}
|
||||
>
|
||||
{t("Add 2FA method")}
|
||||
</Button>
|
||||
<Button
|
||||
disabled={!canUseMfa}
|
||||
variant="default"
|
||||
onClick={() => setSetupModalOpen(true)}
|
||||
style={{ whiteSpace: "nowrap" }}
|
||||
>
|
||||
{t("Add 2FA method")}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Group gap="sm" wrap="nowrap">
|
||||
<Button
|
||||
|
||||
@ -319,7 +319,7 @@ function ImportFormatSelection({ spaceId, onClose }: ImportFormatSelection) {
|
||||
>
|
||||
{(props) => (
|
||||
<Tooltip
|
||||
label="Available in enterprise edition"
|
||||
label={t("Available in enterprise edition")}
|
||||
disabled={canUseConfluence}
|
||||
>
|
||||
<Button
|
||||
|
||||
@ -1,15 +1,6 @@
|
||||
import React from "react";
|
||||
import { isCloud } from "@/lib/config";
|
||||
import { useLicense } from "@/ee/hooks/use-license";
|
||||
import { MfaSettings } from "@/ee/mfa";
|
||||
|
||||
export function AccountMfaSection() {
|
||||
const { hasLicenseKey } = useLicense();
|
||||
const showMfa = isCloud() || hasLicenseKey;
|
||||
|
||||
if (!showMfa) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <MfaSettings />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user