diff --git a/.betterer.results b/.betterer.results index 238e002601c..ee83f06d95e 100644 --- a/.betterer.results +++ b/.betterer.results @@ -284,7 +284,7 @@ exports[`no enzyme tests`] = { "public/app/features/teams/TeamMembers.test.tsx:3993436101": [ [1, 19, 13, "RegExp match", "2409514259"] ], - "public/app/features/teams/TeamPages.test.tsx:2493626076": [ + "public/app/features/teams/TeamPages.test.tsx:1265047708": [ [1, 19, 13, "RegExp match", "2409514259"] ], "public/app/features/teams/TeamSettings.test.tsx:2628968507": [ diff --git a/public/app/core/components/Upgrade/ProBadge.tsx b/public/app/core/components/Upgrade/ProBadge.tsx index eb839467deb..27b92f9279f 100644 --- a/public/app/core/components/Upgrade/ProBadge.tsx +++ b/public/app/core/components/Upgrade/ProBadge.tsx @@ -32,7 +32,7 @@ const getStyles = (theme: GrafanaTheme2) => { border-radius: ${theme.shape.borderRadius(5)}; background-color: ${theme.colors.success.main}; padding: ${theme.spacing(0.25, 0.75)}; - color: ${theme.colors.text.maxContrast}; + color: white; // use the same color for both themes font-weight: ${theme.typography.fontWeightMedium}; font-size: ${theme.typography.pxToRem(10)}; `, diff --git a/public/app/core/components/Upgrade/UpgradeBox.tsx b/public/app/core/components/Upgrade/UpgradeBox.tsx index 996f1588272..7b1efb2f929 100644 --- a/public/app/core/components/Upgrade/UpgradeBox.tsx +++ b/public/app/core/components/Upgrade/UpgradeBox.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode, HTMLAttributes } from 'react'; +import React, { HTMLAttributes } from 'react'; import { css, cx } from '@emotion/css'; import { Icon, LinkButton, useStyles2 } from '@grafana/ui'; import { GrafanaTheme2 } from '@grafana/data'; @@ -6,48 +6,30 @@ import { GrafanaTheme2 } from '@grafana/data'; type ComponentSize = 'sm' | 'md'; export interface Props extends HTMLAttributes { - text?: string; + featureName: string; size?: ComponentSize; - children?: ReactNode; - secondaryAction?: { - url: string; - text: string; - }; } -export const UpgradeBox = ({ text, className, children, secondaryAction, size = 'md', ...htmlProps }: Props) => { +export const UpgradeBox = ({ featureName, className, children, size = 'md', ...htmlProps }: Props) => { const styles = useStyles2((theme) => getUpgradeBoxStyles(theme, size)); return (
-
-

You’ve found a Pro feature!

- {text &&

{text}

} - {children} +
+

+ You’ve discovered a Pro feature! Get the Grafana Pro plan to access {featureName}. +

- Upgrade to Pro + Upgrade - - {secondaryAction && ( - - {secondaryAction.text} - - )}
); @@ -60,26 +42,35 @@ const getUpgradeBoxStyles = (theme: GrafanaTheme2, size: ComponentSize) => { return { box: css` display: flex; + align-items: center; position: relative; border-radius: ${borderRadius}; - background: ${theme.colors.primary.transparent}; - border: 1px solid ${theme.colors.primary.shade}; + background: ${theme.colors.success.transparent}; padding: ${theme.spacing(2)}; - color: ${theme.colors.primary.text}; + color: ${theme.colors.success.text}; font-size: ${theme.typography[fontBase].fontSize}; text-align: left; line-height: 16px; + margin: ${theme.spacing(0, 'auto', 3, 'auto')}; + max-width: ${theme.breakpoints.values.xxl}px; + width: 100%; + `, + inner: css` + display: flex; + align-items: center; + width: 100%; + justify-content: space-between; `, text: css` - margin-bottom: 0; - padding: ${theme.spacing(2, 0)}; - line-height: 1.5; + margin: 0; `, button: css` - margin-top: ${theme.spacing(2)}; + background-color: ${theme.colors.success.main}; + font-weight: ${theme.typography.fontWeightLight}; + color: white; - &:first-of-type { - margin-right: ${theme.spacing(1)}; + &:hover { + background-color: ${theme.colors.success.main}; } &:focus-visible { @@ -88,11 +79,154 @@ const getUpgradeBoxStyles = (theme: GrafanaTheme2, size: ComponentSize) => { outline: 2px solid ${theme.colors.primary.main}; } `, - buttonSecondary: css` - color: ${theme.colors.text.secondary}; - `, icon: css` margin: ${theme.spacing(0.5, 1, 0.5, 0.5)}; `, }; }; + +export interface UpgradeContentProps { + image: string; + featureUrl?: string; + featureName: string; + description?: string; + listItems: string[]; + caption?: string; +} + +export const UpgradeContent = ({ + listItems, + image, + featureUrl, + featureName, + description, + caption, +}: UpgradeContentProps) => { + const styles = useStyles2(getUpgradeContentStyles); + return ( +
+
+

Get started with {featureName}

+ {description &&
{description}
} +
    + {listItems.map((item, index) => ( +
  • + {item} +
  • + ))} +
+ {featureUrl && ( + + Learn more + + )} +
+
+ {'Feature + {caption &&

{caption}

} +
+
+ ); +}; + +const getUpgradeContentStyles = (theme: GrafanaTheme2) => { + return { + container: css` + display: flex; + justify-content: space-between; + `, + content: css` + width: 45%; + margin-right: ${theme.spacing(4)}; + `, + media: css` + width: 55%; + + img { + width: 100%; + } + `, + description: css` + color: ${theme.colors.text.primary}; + font-weight: ${theme.typography.fontWeightLight}; + `, + list: css` + list-style: none; + margin: ${theme.spacing(4, 0, 2, 0)}; + + li { + display: flex; + align-items: flex-start; + color: ${theme.colors.text.primary}; + padding: ${theme.spacing(1, 0)}; + } + `, + icon: css` + color: ${theme.colors.success.main}; + margin-right: ${theme.spacing(1)}; + `, + link: css` + margin-left: ${theme.spacing(2)}; + `, + title: css` + color: ${theme.colors.text.maxContrast}; + `, + caption: css` + font-weight: ${theme.typography.fontWeightLight}; + margin: ${theme.spacing(1, 0, 0)}; + `, + }; +}; + +export const UpgradeContentVertical = ({ + featureName, + description, + featureUrl, + image, +}: Omit) => { + const styles = useStyles2(getContentVerticalStyles); + return ( +
+

Get started with {featureName}

+ {description &&
{description}
} + + Learn more + +
+ {'Feature +
+
+ ); +}; + +const getContentVerticalStyles = (theme: GrafanaTheme2) => { + return { + container: css` + overflow: auto; + height: 100%; + `, + title: css` + color: ${theme.colors.text.maxContrast}; + `, + description: css` + color: ${theme.colors.text.primary}; + font-weight: ${theme.typography.fontWeightLight}; + `, + media: css` + width: 100%; + margin-top: ${theme.spacing(2)}; + + img { + width: 100%; + } + `, + }; +}; + +const getImgUrl = (urlOrId: string) => { + if (urlOrId.startsWith('http')) { + return urlOrId; + } + + return '/public/img/enterprise/highlights/' + urlOrId; +}; diff --git a/public/app/core/components/Upgrade/UpgradeModal.tsx b/public/app/core/components/Upgrade/UpgradeModal.tsx deleted file mode 100644 index 40951c7aa67..00000000000 --- a/public/app/core/components/Upgrade/UpgradeModal.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React, { useEffect } from 'react'; -import { Modal } from '@grafana/ui'; -import { reportExperimentView } from '@grafana/runtime'; -import { UpgradeBox } from './UpgradeBox'; - -export interface Props { - title: string; - text: string; - isOpen?: boolean; - onDismiss?: () => void; - experimentId?: string; -} - -export const UpgradeModal = ({ title, text, isOpen, onDismiss, experimentId }: Props) => { - useEffect(() => { - if (experimentId) { - reportExperimentView(experimentId, 'test', ''); - } - }, [experimentId]); - - return ( - - - - ); -}; diff --git a/public/app/features/teams/TeamPages.test.tsx b/public/app/features/teams/TeamPages.test.tsx index c4f852b2bf6..54eb487585c 100644 --- a/public/app/features/teams/TeamPages.test.tsx +++ b/public/app/features/teams/TeamPages.test.tsx @@ -4,7 +4,7 @@ import { Props, TeamPages } from './TeamPages'; import { OrgRole, Team, TeamMember } from '../../types'; import { getMockTeam } from './__mocks__/teamMocks'; import { User } from 'app/core/services/context_srv'; -import { NavModel } from '@grafana/data'; +import { NavModel, createTheme } from '@grafana/data'; import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps'; jest.mock('@grafana/runtime/src/config', () => ({ @@ -35,6 +35,7 @@ const setup = (propOverrides?: object) => { team: {} as Team, members: [] as TeamMember[], editorsCanAdmin: false, + theme: createTheme(), signedInUser: { id: 1, isGrafanaAdmin: false, diff --git a/public/app/features/teams/TeamPages.tsx b/public/app/features/teams/TeamPages.tsx index 7da89e296be..685f7d1b5ac 100644 --- a/public/app/features/teams/TeamPages.tsx +++ b/public/app/features/teams/TeamPages.tsx @@ -1,6 +1,7 @@ import React, { PureComponent } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { includes } from 'lodash'; +import { Themeable2, withTheme2 } from '@grafana/ui'; import config from 'app/core/config'; import Page from 'app/core/components/Page/Page'; import TeamMembers from './TeamMembers'; @@ -16,14 +17,14 @@ import { contextSrv } from 'app/core/services/context_srv'; import { NavModel } from '@grafana/data'; import { featureEnabled, reportExperimentView } from '@grafana/runtime'; import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; -import { UpgradeBox } from 'app/core/components/Upgrade/UpgradeBox'; +import { UpgradeBox, UpgradeContent } from 'app/core/components/Upgrade/UpgradeBox'; interface TeamPageRouteParams { id: string; page: string | null; } -export interface OwnProps extends GrafanaRouteComponentProps {} +export interface OwnProps extends GrafanaRouteComponentProps, Themeable2 {} interface State { isSyncEnabled: boolean; @@ -140,7 +141,7 @@ export class TeamPages extends PureComponent { renderPage(isSignedInUserTeamAdmin: boolean): React.ReactNode { const { isSyncEnabled } = this.state; - const { members, team } = this.props; + const { members, team, theme } = this.props; const currentPage = this.getCurrentPage(); const canReadTeam = contextSrv.hasAccessInMetadata( @@ -175,11 +176,21 @@ export class TeamPages extends PureComponent { } } else if (config.featureToggles.featureHighlights) { return ( - + <> + + + ); } } @@ -201,4 +212,4 @@ export class TeamPages extends PureComponent { } } -export default connector(TeamPages); +export default connector(withTheme2(TeamPages)); diff --git a/public/img/enterprise/highlights/datasource-insights-dark.png b/public/img/enterprise/highlights/datasource-insights-dark.png new file mode 100644 index 00000000000..bb0742f2366 Binary files /dev/null and b/public/img/enterprise/highlights/datasource-insights-dark.png differ diff --git a/public/img/enterprise/highlights/datasource-insights-light.png b/public/img/enterprise/highlights/datasource-insights-light.png new file mode 100644 index 00000000000..d1dc1c9d426 Binary files /dev/null and b/public/img/enterprise/highlights/datasource-insights-light.png differ diff --git a/public/img/enterprise/highlights/ds-permissions-dark.png b/public/img/enterprise/highlights/ds-permissions-dark.png new file mode 100644 index 00000000000..b1318c0a3f8 Binary files /dev/null and b/public/img/enterprise/highlights/ds-permissions-dark.png differ diff --git a/public/img/enterprise/highlights/ds-permissions-light.png b/public/img/enterprise/highlights/ds-permissions-light.png new file mode 100644 index 00000000000..f87bd78ccb4 Binary files /dev/null and b/public/img/enterprise/highlights/ds-permissions-light.png differ diff --git a/public/img/enterprise/highlights/query-caching-dark.png b/public/img/enterprise/highlights/query-caching-dark.png new file mode 100644 index 00000000000..455c096ed68 Binary files /dev/null and b/public/img/enterprise/highlights/query-caching-dark.png differ diff --git a/public/img/enterprise/highlights/query-caching-light.png b/public/img/enterprise/highlights/query-caching-light.png new file mode 100644 index 00000000000..2f6344b44ef Binary files /dev/null and b/public/img/enterprise/highlights/query-caching-light.png differ diff --git a/public/img/enterprise/highlights/recorded-queries-dark.png b/public/img/enterprise/highlights/recorded-queries-dark.png new file mode 100644 index 00000000000..9bc966fb25c Binary files /dev/null and b/public/img/enterprise/highlights/recorded-queries-dark.png differ diff --git a/public/img/enterprise/highlights/recorded-queries-light.png b/public/img/enterprise/highlights/recorded-queries-light.png new file mode 100644 index 00000000000..493d137ec00 Binary files /dev/null and b/public/img/enterprise/highlights/recorded-queries-light.png differ diff --git a/public/img/enterprise/highlights/reporting-email.png b/public/img/enterprise/highlights/reporting-email.png new file mode 100644 index 00000000000..8b5c1ad19d2 Binary files /dev/null and b/public/img/enterprise/highlights/reporting-email.png differ diff --git a/public/img/enterprise/highlights/team-sync-dark.png b/public/img/enterprise/highlights/team-sync-dark.png new file mode 100644 index 00000000000..24ded659ef2 Binary files /dev/null and b/public/img/enterprise/highlights/team-sync-dark.png differ diff --git a/public/img/enterprise/highlights/team-sync-light.png b/public/img/enterprise/highlights/team-sync-light.png new file mode 100644 index 00000000000..774725cd738 Binary files /dev/null and b/public/img/enterprise/highlights/team-sync-light.png differ diff --git a/public/img/enterprise/highlights/usage-insights-dark.png b/public/img/enterprise/highlights/usage-insights-dark.png new file mode 100644 index 00000000000..191a2a59c9d Binary files /dev/null and b/public/img/enterprise/highlights/usage-insights-dark.png differ diff --git a/public/img/enterprise/highlights/usage-insights-light.png b/public/img/enterprise/highlights/usage-insights-light.png new file mode 100644 index 00000000000..e1aac5abc72 Binary files /dev/null and b/public/img/enterprise/highlights/usage-insights-light.png differ