diff --git a/frontend/src/assets/icons/pro-enterprise-feature-badge.svg b/frontend/src/assets/icons/pro-enterprise-feature-badge.svg
new file mode 100644
index 0000000000..c180559714
--- /dev/null
+++ b/frontend/src/assets/icons/pro-enterprise-feature-badge.svg
@@ -0,0 +1,5 @@
+
diff --git a/frontend/src/component/common/PermissionIconButton/PermissionIconButton.tsx b/frontend/src/component/common/PermissionIconButton/PermissionIconButton.tsx
index aa3c44c3c0..bd8c4fcdb5 100644
--- a/frontend/src/component/common/PermissionIconButton/PermissionIconButton.tsx
+++ b/frontend/src/component/common/PermissionIconButton/PermissionIconButton.tsx
@@ -1,10 +1,10 @@
import { IconButton, IconButtonProps } from '@mui/material';
-import React, { useContext, ReactNode } from 'react';
+import React, { ReactNode, useContext } from 'react';
import AccessContext from 'contexts/AccessContext';
import { Link } from 'react-router-dom';
import {
- TooltipResolver,
ITooltipResolverProps,
+ TooltipResolver,
} from 'component/common/TooltipResolver/TooltipResolver';
import { formatAccessText } from 'utils/formatAccessText';
import { useId } from 'hooks/useId';
diff --git a/frontend/src/component/common/ProFeatureTooltip/ProFeatureTooltip.tsx b/frontend/src/component/common/ProFeatureTooltip/ProFeatureTooltip.tsx
new file mode 100644
index 0000000000..937501eefc
--- /dev/null
+++ b/frontend/src/component/common/ProFeatureTooltip/ProFeatureTooltip.tsx
@@ -0,0 +1,42 @@
+import { ReactComponent as ProPlanIcon } from 'assets/icons/pro-enterprise-feature-badge.svg';
+import { Box, Link, styled, Typography } from '@mui/material';
+
+export interface ProFeatureTooltipProps {
+ text: string;
+}
+
+const ProFeatureTooltipWrapper = styled(Box)(({ theme }) => ({
+ display: 'flex',
+ flexDirection: 'column',
+ backgroundColor: theme.palette.background.paper,
+ padding: theme.spacing(1, 1.5),
+ borderRadius: theme.shape.borderRadius,
+ color: theme.palette.text.primary,
+ width: '100%',
+}));
+
+const StyledTitle = styled(Typography)(({ theme }) => ({
+ display: 'inline-flex',
+ justifyContent: 'flex-start',
+ flexDirection: 'row',
+ marginBottom: theme.spacing(1),
+}));
+
+export const ProFeatureTooltip = ({ text }: ProFeatureTooltipProps) => {
+ return (
+
+
+
+
+ Pro & Enterprise feature
+
+
+ {text}
+
+
+ Upgrade now
+
+
+
+ );
+};
diff --git a/frontend/src/component/common/ResponsiveButton/ResponsiveButton.tsx b/frontend/src/component/common/ResponsiveButton/ResponsiveButton.tsx
index 128c60ddaf..40923fa42f 100644
--- a/frontend/src/component/common/ResponsiveButton/ResponsiveButton.tsx
+++ b/frontend/src/component/common/ResponsiveButton/ResponsiveButton.tsx
@@ -1,11 +1,14 @@
+import React from 'react';
import { useMediaQuery } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import PermissionButton from '../PermissionButton/PermissionButton';
import PermissionIconButton from '../PermissionIconButton/PermissionIconButton';
-import React from 'react';
+import { ITooltipResolverProps } from '../TooltipResolver/TooltipResolver';
interface IResponsiveButtonProps {
Icon: React.ElementType;
+ endIcon?: React.ReactNode;
+ tooltipProps?: Omit;
onClick: () => void;
disabled?: boolean;
permission: string;
diff --git a/frontend/src/component/common/TooltipResolver/TooltipResolver.tsx b/frontend/src/component/common/TooltipResolver/TooltipResolver.tsx
index 237bb45ee5..e07ff9e6ae 100644
--- a/frontend/src/component/common/TooltipResolver/TooltipResolver.tsx
+++ b/frontend/src/component/common/TooltipResolver/TooltipResolver.tsx
@@ -1,20 +1,34 @@
+import React, { ReactNode } from 'react';
import { Tooltip, TooltipProps } from '@mui/material';
+import { HtmlTooltip } from '../HtmlTooltip/HtmlTooltip';
export interface ITooltipResolverProps extends Omit {
- title: string | undefined;
+ title?: string | undefined;
+ titleComponent?: ReactNode | undefined;
+ variant?: 'default' | 'white';
}
export const TooltipResolver = ({
title,
children,
+ variant = 'default',
+ titleComponent,
...rest
}: ITooltipResolverProps) => {
- if (!title) {
+ if (!title && !titleComponent) {
return children;
}
+ if (variant === 'white') {
+ return (
+
+ {children}
+
+ );
+ }
+
return (
-
+
{children}
);
diff --git a/frontend/src/component/project/ProjectList/ProjectList.tsx b/frontend/src/component/project/ProjectList/ProjectList.tsx
index 522ec04647..3be7399204 100644
--- a/frontend/src/component/project/ProjectList/ProjectList.tsx
+++ b/frontend/src/component/project/ProjectList/ProjectList.tsx
@@ -21,6 +21,9 @@ import { TablePlaceholder } from 'component/common/Table';
import { useMediaQuery } from '@mui/material';
import theme from 'themes/theme';
import { Search } from 'component/common/Search/Search';
+import { ProFeatureTooltip } from '../../common/ProFeatureTooltip/ProFeatureTooltip';
+import { ITooltipResolverProps } from '../../common/TooltipResolver/TooltipResolver';
+import { ReactComponent as ProPlanIcon } from 'assets/icons/pro-enterprise-feature-badge.svg';
type PageQueryType = Partial>;
@@ -28,20 +31,39 @@ type projectMap = {
[index: string]: boolean;
};
-function resolveCreateButtonData(isOss: boolean, hasAccess: boolean) {
+interface ICreateButtonData {
+ disabled: boolean;
+ tooltip?: Omit;
+}
+
+function resolveCreateButtonData(
+ isOss: boolean,
+ hasAccess: boolean
+): ICreateButtonData {
if (isOss) {
return {
- title: 'You must be on a paid subscription to create new projects',
disabled: true,
+ tooltip: {
+ titleComponent: (
+
+ ),
+ variant: 'white',
+ },
};
} else if (!hasAccess) {
return {
- title: 'You do not have permission to create new projects',
+ tooltip: {
+ title: 'You do not have permission to create new projects',
+ },
disabled: true,
};
} else {
return {
- title: 'Click to create a new project',
+ tooltip: { title: 'Click to create a new project' },
disabled: false,
};
}
@@ -174,10 +196,12 @@ export const ProjectListNew = () => {
/>
}
onClick={() => navigate('/projects/create')}
maxWidth="700px"
permission={CREATE_PROJECT}
disabled={createButtonData.disabled}
+ tooltipProps={createButtonData.tooltip}
>
New project
diff --git a/frontend/src/hooks/usePlausibleTracker.ts b/frontend/src/hooks/usePlausibleTracker.ts
index 0dfe62a3fc..4bce09b4a3 100644
--- a/frontend/src/hooks/usePlausibleTracker.ts
+++ b/frontend/src/hooks/usePlausibleTracker.ts
@@ -8,7 +8,7 @@ import { EventOptions, PlausibleOptions } from 'plausible-tracker';
* @see https://plausible.io/docs/custom-event-goals#2-create-a-custom-event-goal-in-your-plausible-analytics-account
* @example `'download | 'invite' | 'signup'`
**/
-type CustomEvents = 'invite';
+type CustomEvents = 'invite' | 'upgrade_plan_clicked';
export const usePlausibleTracker = () => {
const plausible = useContext(PlausibleContext);