* Highlights: add action prop
* Highlight team sync for trial users
* Add badges for trial highlights
* Move events to UpgradeBox
* Fix undefined license settings
* Update snapshot
* Update public/app/features/datasources/state/navModel.ts
Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>
* Update public/app/features/datasources/state/navModel.ts
Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>
* Update public/app/features/datasources/state/navModel.ts
Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>
* Update copy and event handling
Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>
(cherry picked from commit 9c0aa09a85)
Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
This commit is contained in:
co-authored by
Alex Khomenko
parent
f682ad8c60
commit
0a4b6dccfc
@@ -7,16 +7,17 @@ import { reportExperimentView } from '@grafana/runtime';
|
|||||||
export interface Props extends HTMLAttributes<HTMLSpanElement> {
|
export interface Props extends HTMLAttributes<HTMLSpanElement> {
|
||||||
text?: string;
|
text?: string;
|
||||||
experimentId?: string;
|
experimentId?: string;
|
||||||
|
eventVariant?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProBadge = ({ text = 'PRO', className, experimentId, ...htmlProps }: Props) => {
|
export const ProBadge = ({ text = 'PRO', className, experimentId, eventVariant = '', ...htmlProps }: Props) => {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (experimentId) {
|
if (experimentId) {
|
||||||
reportExperimentView(experimentId, 'test', '');
|
reportExperimentView(experimentId, 'test', eventVariant);
|
||||||
}
|
}
|
||||||
}, [experimentId]);
|
}, [experimentId, eventVariant]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={cx(styles.badge, className)} {...htmlProps}>
|
<span className={cx(styles.badge, className)} {...htmlProps}>
|
||||||
|
|||||||
@@ -1,24 +1,41 @@
|
|||||||
import React, { HTMLAttributes } from 'react';
|
import React, { HTMLAttributes, useEffect } from 'react';
|
||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { Icon, LinkButton, useStyles2 } from '@grafana/ui';
|
import { Button, Icon, LinkButton, useStyles2 } from '@grafana/ui';
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
|
import { reportExperimentView } from '@grafana/runtime/src';
|
||||||
|
|
||||||
type ComponentSize = 'sm' | 'md';
|
type ComponentSize = 'sm' | 'md';
|
||||||
|
|
||||||
export interface Props extends HTMLAttributes<HTMLOrSVGElement> {
|
export interface Props extends HTMLAttributes<HTMLOrSVGElement> {
|
||||||
featureName: string;
|
featureName: string;
|
||||||
size?: ComponentSize;
|
size?: ComponentSize;
|
||||||
|
text?: string;
|
||||||
|
eventVariant?: string;
|
||||||
|
featureId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UpgradeBox = ({ featureName, className, children, size = 'md', ...htmlProps }: Props) => {
|
export const UpgradeBox = ({
|
||||||
|
featureName,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
text,
|
||||||
|
featureId,
|
||||||
|
eventVariant = '',
|
||||||
|
size = 'md',
|
||||||
|
...htmlProps
|
||||||
|
}: Props) => {
|
||||||
const styles = useStyles2((theme) => getUpgradeBoxStyles(theme, size));
|
const styles = useStyles2((theme) => getUpgradeBoxStyles(theme, size));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reportExperimentView(`feature-highlights-${featureId}`, 'test', eventVariant);
|
||||||
|
}, [eventVariant, featureId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.box, className)} {...htmlProps}>
|
<div className={cx(styles.box, className)} {...htmlProps}>
|
||||||
<Icon name={'rocket'} className={styles.icon} />
|
<Icon name={'rocket'} className={styles.icon} />
|
||||||
<div className={styles.inner}>
|
<div className={styles.inner}>
|
||||||
<p className={styles.text}>
|
<p className={styles.text}>
|
||||||
You’ve discovered a Pro feature! Get the Grafana Pro plan to access {featureName}.
|
You’ve discovered a Pro feature! {text || `Get the Grafana Pro plan to access ${featureName}.`}
|
||||||
</p>
|
</p>
|
||||||
<LinkButton
|
<LinkButton
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
@@ -92,6 +109,11 @@ export interface UpgradeContentProps {
|
|||||||
description?: string;
|
description?: string;
|
||||||
listItems: string[];
|
listItems: string[];
|
||||||
caption?: string;
|
caption?: string;
|
||||||
|
action?: {
|
||||||
|
text: string;
|
||||||
|
link?: string;
|
||||||
|
onClick?: () => void;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UpgradeContent = ({
|
export const UpgradeContent = ({
|
||||||
@@ -101,6 +123,7 @@ export const UpgradeContent = ({
|
|||||||
featureName,
|
featureName,
|
||||||
description,
|
description,
|
||||||
caption,
|
caption,
|
||||||
|
action,
|
||||||
}: UpgradeContentProps) => {
|
}: UpgradeContentProps) => {
|
||||||
const styles = useStyles2(getUpgradeContentStyles);
|
const styles = useStyles2(getUpgradeContentStyles);
|
||||||
return (
|
return (
|
||||||
@@ -115,6 +138,16 @@ export const UpgradeContent = ({
|
|||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
{action?.link && (
|
||||||
|
<LinkButton variant={'primary'} href={action.link}>
|
||||||
|
{action.text}
|
||||||
|
</LinkButton>
|
||||||
|
)}
|
||||||
|
{action?.onClick && (
|
||||||
|
<Button variant={'primary'} onClick={action.onClick}>
|
||||||
|
{action.text}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
{featureUrl && (
|
{featureUrl && (
|
||||||
<LinkButton fill={'text'} href={featureUrl} className={styles.link} target="_blank" rel="noreferrer noopener">
|
<LinkButton fill={'text'} href={featureUrl} className={styles.link} target="_blank" rel="noreferrer noopener">
|
||||||
Learn more
|
Learn more
|
||||||
@@ -146,6 +179,9 @@ const getUpgradeContentStyles = (theme: GrafanaTheme2) => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
title: css`
|
||||||
|
color: ${theme.colors.text.maxContrast};
|
||||||
|
`,
|
||||||
description: css`
|
description: css`
|
||||||
color: ${theme.colors.text.primary};
|
color: ${theme.colors.text.primary};
|
||||||
font-weight: ${theme.typography.fontWeightLight};
|
font-weight: ${theme.typography.fontWeightLight};
|
||||||
@@ -168,9 +204,6 @@ const getUpgradeContentStyles = (theme: GrafanaTheme2) => {
|
|||||||
link: css`
|
link: css`
|
||||||
margin-left: ${theme.spacing(2)};
|
margin-left: ${theme.spacing(2)};
|
||||||
`,
|
`,
|
||||||
title: css`
|
|
||||||
color: ${theme.colors.text.maxContrast};
|
|
||||||
`,
|
|
||||||
caption: css`
|
caption: css`
|
||||||
font-weight: ${theme.typography.fontWeightLight};
|
font-weight: ${theme.typography.fontWeightLight};
|
||||||
margin: ${theme.spacing(1, 0, 0)};
|
margin: ${theme.spacing(1, 0, 0)};
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { config } from '@grafana/runtime/src';
|
||||||
|
|
||||||
|
export function isTrial() {
|
||||||
|
const settings = (config as any).licensing;
|
||||||
|
return settings?.isTrial;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const highlightTrial = () => isTrial() && config.featureToggles.featureHighlights;
|
||||||
@@ -5,6 +5,7 @@ import { contextSrv } from 'app/core/core';
|
|||||||
import { AccessControlAction } from 'app/types';
|
import { AccessControlAction } from 'app/types';
|
||||||
import { ProBadge } from 'app/core/components/Upgrade/ProBadge';
|
import { ProBadge } from 'app/core/components/Upgrade/ProBadge';
|
||||||
import { GenericDataSourcePlugin } from '../settings/PluginSettings';
|
import { GenericDataSourcePlugin } from '../settings/PluginSettings';
|
||||||
|
import { highlightTrial } from '../../admin/utils';
|
||||||
|
|
||||||
const loadingDSType = 'Loading';
|
const loadingDSType = 'Loading';
|
||||||
|
|
||||||
@@ -53,7 +54,8 @@ export function buildNavModel(dataSource: DataSourceSettings, plugin: GenericDat
|
|||||||
|
|
||||||
const isLoadingNav = dataSource.type === loadingDSType;
|
const isLoadingNav = dataSource.type === loadingDSType;
|
||||||
|
|
||||||
const dsPermissions = {
|
const permissionsExperimentId = 'feature-highlights-data-source-permissions-badge';
|
||||||
|
const dsPermissions: NavModelItem = {
|
||||||
active: false,
|
active: false,
|
||||||
icon: 'lock',
|
icon: 'lock',
|
||||||
id: `datasource-permissions-${dataSource.uid}`,
|
id: `datasource-permissions-${dataSource.uid}`,
|
||||||
@@ -61,6 +63,10 @@ export function buildNavModel(dataSource: DataSourceSettings, plugin: GenericDat
|
|||||||
url: `datasources/edit/${dataSource.uid}/permissions`,
|
url: `datasources/edit/${dataSource.uid}/permissions`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (highlightTrial() && !isLoadingNav) {
|
||||||
|
dsPermissions.tabSuffix = () => ProBadge({ experimentId: permissionsExperimentId, eventVariant: 'trial' });
|
||||||
|
}
|
||||||
|
|
||||||
if (featureEnabled('dspermissions')) {
|
if (featureEnabled('dspermissions')) {
|
||||||
if (contextSrv.hasPermission(AccessControlAction.DataSourcesPermissionsRead)) {
|
if (contextSrv.hasPermission(AccessControlAction.DataSourcesPermissionsRead)) {
|
||||||
navModel.children!.push(dsPermissions);
|
navModel.children!.push(dsPermissions);
|
||||||
@@ -69,11 +75,12 @@ export function buildNavModel(dataSource: DataSourceSettings, plugin: GenericDat
|
|||||||
navModel.children!.push({
|
navModel.children!.push({
|
||||||
...dsPermissions,
|
...dsPermissions,
|
||||||
url: dsPermissions.url + '/upgrade',
|
url: dsPermissions.url + '/upgrade',
|
||||||
tabSuffix: () => ProBadge({ experimentId: 'feature-highlights-data-source-permissions-badge' }),
|
tabSuffix: () => ProBadge({ experimentId: permissionsExperimentId }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const analytics = {
|
const analyticsExperimentId = 'feature-highlights-data-source-insights-badge';
|
||||||
|
const analytics: NavModelItem = {
|
||||||
active: false,
|
active: false,
|
||||||
icon: 'info-circle',
|
icon: 'info-circle',
|
||||||
id: `datasource-insights-${dataSource.uid}`,
|
id: `datasource-insights-${dataSource.uid}`,
|
||||||
@@ -81,17 +88,23 @@ export function buildNavModel(dataSource: DataSourceSettings, plugin: GenericDat
|
|||||||
url: `datasources/edit/${dataSource.uid}/insights`,
|
url: `datasources/edit/${dataSource.uid}/insights`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (highlightTrial() && !isLoadingNav) {
|
||||||
|
analytics.tabSuffix = () => ProBadge({ experimentId: analyticsExperimentId, eventVariant: 'trial' });
|
||||||
|
}
|
||||||
|
|
||||||
if (featureEnabled('analytics')) {
|
if (featureEnabled('analytics')) {
|
||||||
navModel.children!.push(analytics);
|
navModel.children!.push(analytics);
|
||||||
} else if (highlightsEnabled && !isLoadingNav) {
|
} else if (highlightsEnabled && !isLoadingNav) {
|
||||||
navModel.children!.push({
|
navModel.children!.push({
|
||||||
...analytics,
|
...analytics,
|
||||||
url: analytics.url + '/upgrade',
|
url: analytics.url + '/upgrade',
|
||||||
tabSuffix: () => ProBadge({ experimentId: 'feature-highlights-data-source-insights-badge' }),
|
tabSuffix: () => ProBadge({ experimentId: analyticsExperimentId }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const caching = {
|
const cachingExperimentId = 'feature-highlights-query-caching-badge';
|
||||||
|
|
||||||
|
const caching: NavModelItem = {
|
||||||
active: false,
|
active: false,
|
||||||
icon: 'database',
|
icon: 'database',
|
||||||
id: `datasource-cache-${dataSource.uid}`,
|
id: `datasource-cache-${dataSource.uid}`,
|
||||||
@@ -100,13 +113,17 @@ export function buildNavModel(dataSource: DataSourceSettings, plugin: GenericDat
|
|||||||
hideFromTabs: !pluginMeta.isBackend || !config.caching.enabled,
|
hideFromTabs: !pluginMeta.isBackend || !config.caching.enabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (highlightTrial() && !isLoadingNav) {
|
||||||
|
caching.tabSuffix = () => ProBadge({ experimentId: cachingExperimentId, eventVariant: 'trial' });
|
||||||
|
}
|
||||||
|
|
||||||
if (featureEnabled('caching')) {
|
if (featureEnabled('caching')) {
|
||||||
navModel.children!.push(caching);
|
navModel.children!.push(caching);
|
||||||
} else if (highlightsEnabled && !isLoadingNav) {
|
} else if (highlightsEnabled && !isLoadingNav) {
|
||||||
navModel.children!.push({
|
navModel.children!.push({
|
||||||
...caching,
|
...caching,
|
||||||
url: caching.url + '/upgrade',
|
url: caching.url + '/upgrade',
|
||||||
tabSuffix: () => ProBadge({ experimentId: 'feature-highlights-query-caching-badge' }),
|
tabSuffix: () => ProBadge({ experimentId: cachingExperimentId }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
|
|||||||
import { connect, ConnectedProps } from 'react-redux';
|
import { connect, ConnectedProps } from 'react-redux';
|
||||||
|
|
||||||
import { SlideDown } from 'app/core/components/Animations/SlideDown';
|
import { SlideDown } from 'app/core/components/Animations/SlideDown';
|
||||||
import { LegacyForms, Tooltip, Icon, Button } from '@grafana/ui';
|
import { LegacyForms, Tooltip, Icon, Button, useTheme2 } from '@grafana/ui';
|
||||||
const { Input } = LegacyForms;
|
const { Input } = LegacyForms;
|
||||||
|
|
||||||
import { StoreState, TeamGroup } from '../../types';
|
import { StoreState, TeamGroup } from '../../types';
|
||||||
@@ -10,6 +10,8 @@ import { addTeamGroup, loadTeamGroups, removeTeamGroup } from './state/actions';
|
|||||||
import { getTeamGroups } from './state/selectors';
|
import { getTeamGroups } from './state/selectors';
|
||||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||||
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
|
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
|
||||||
|
import { UpgradeBox, UpgradeContent, UpgradeContentProps } from 'app/core/components/Upgrade/UpgradeBox';
|
||||||
|
import { highlightTrial } from 'app/features/admin/utils';
|
||||||
|
|
||||||
function mapStateToProps(state: StoreState) {
|
function mapStateToProps(state: StoreState) {
|
||||||
return {
|
return {
|
||||||
@@ -90,14 +92,25 @@ export class TeamGroupSync extends PureComponent<Props, State> {
|
|||||||
render() {
|
render() {
|
||||||
const { isAdding, newGroupId } = this.state;
|
const { isAdding, newGroupId } = this.state;
|
||||||
const { groups, isReadOnly } = this.props;
|
const { groups, isReadOnly } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
{highlightTrial() && (
|
||||||
|
<UpgradeBox
|
||||||
|
featureId={'team-sync'}
|
||||||
|
eventVariant={'trial'}
|
||||||
|
featureName={'team sync'}
|
||||||
|
text={'Add a group to enable team sync for free during your trial of Grafana Pro.'}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div className="page-action-bar">
|
<div className="page-action-bar">
|
||||||
<h3 className="page-sub-heading">External group sync</h3>
|
{(!highlightTrial() || groups.length > 0) && (
|
||||||
<Tooltip placement="auto" content={headerTooltip}>
|
<>
|
||||||
<Icon className="icon--has-hover page-sub-heading-icon" name="question-circle" />
|
<h3 className="page-sub-heading">External group sync</h3>
|
||||||
</Tooltip>
|
<Tooltip placement="auto" content={headerTooltip}>
|
||||||
|
<Icon className="icon--has-hover page-sub-heading-icon" name="question-circle" />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className="page-action-bar__spacer" />
|
<div className="page-action-bar__spacer" />
|
||||||
{groups.length > 0 && (
|
{groups.length > 0 && (
|
||||||
<Button className="pull-right" onClick={this.onToggleAdding} disabled={isReadOnly}>
|
<Button className="pull-right" onClick={this.onToggleAdding} disabled={isReadOnly}>
|
||||||
@@ -131,19 +144,23 @@ export class TeamGroupSync extends PureComponent<Props, State> {
|
|||||||
</div>
|
</div>
|
||||||
</SlideDown>
|
</SlideDown>
|
||||||
|
|
||||||
{groups.length === 0 && !isAdding && (
|
{groups.length === 0 &&
|
||||||
<EmptyListCTA
|
!isAdding &&
|
||||||
onClick={this.onToggleAdding}
|
(highlightTrial() ? (
|
||||||
buttonIcon="users-alt"
|
<TeamSyncUpgradeContent action={{ onClick: this.onToggleAdding, text: 'Add group' }} />
|
||||||
title="There are no external groups to sync with"
|
) : (
|
||||||
buttonTitle="Add Group"
|
<EmptyListCTA
|
||||||
proTip={headerTooltip}
|
onClick={this.onToggleAdding}
|
||||||
proTipLinkTitle="Learn more"
|
buttonIcon="users-alt"
|
||||||
proTipLink="http://docs.grafana.org/auth/enhanced_ldap/"
|
title="There are no external groups to sync with"
|
||||||
proTipTarget="_blank"
|
buttonTitle="Add group"
|
||||||
buttonDisabled={isReadOnly}
|
proTip={headerTooltip}
|
||||||
/>
|
proTipLinkTitle="Learn more"
|
||||||
)}
|
proTipLink="https://docs.grafana.org/auth/enhanced_ldap/"
|
||||||
|
proTipTarget="_blank"
|
||||||
|
buttonDisabled={isReadOnly}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
{groups.length > 0 && (
|
{groups.length > 0 && (
|
||||||
<div className="admin-list-table">
|
<div className="admin-list-table">
|
||||||
@@ -163,4 +180,22 @@ export class TeamGroupSync extends PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const TeamSyncUpgradeContent = ({ action }: { action?: UpgradeContentProps['action'] }) => {
|
||||||
|
const theme = useTheme2();
|
||||||
|
return (
|
||||||
|
<UpgradeContent
|
||||||
|
action={action}
|
||||||
|
listItems={[
|
||||||
|
'Stop managing user access in two places - assign users to groups in SAML, LDAP or Oauth, and manage access at a Team level in Grafana',
|
||||||
|
'Update users’ permissions immediately when you add or remove them from an LDAP group, with no need for them to sign out and back in',
|
||||||
|
]}
|
||||||
|
image={`team-sync-${theme.isLight ? 'light' : 'dark'}.png`}
|
||||||
|
featureName={'team sync'}
|
||||||
|
featureUrl={'https://grafana.com/docs/grafana/latest/enterprise/team-sync'}
|
||||||
|
description={
|
||||||
|
'Team Sync makes it easier for you to manage users’ access in Grafana, by immediately updating each user’s Grafana teams and permissions based on their single sign-on group membership, instead of when users sign in.'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(TeamGroupSync);
|
export default connect(mapStateToProps, mapDispatchToProps)(TeamGroupSync);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import Page from 'app/core/components/Page/Page';
|
|||||||
import TeamMembers from './TeamMembers';
|
import TeamMembers from './TeamMembers';
|
||||||
import TeamPermissions from './TeamPermissions';
|
import TeamPermissions from './TeamPermissions';
|
||||||
import TeamSettings from './TeamSettings';
|
import TeamSettings from './TeamSettings';
|
||||||
import TeamGroupSync from './TeamGroupSync';
|
import TeamGroupSync, { TeamSyncUpgradeContent } from './TeamGroupSync';
|
||||||
import { AccessControlAction, StoreState } from 'app/types';
|
import { AccessControlAction, StoreState } from 'app/types';
|
||||||
import { loadTeam, loadTeamMembers } from './state/actions';
|
import { loadTeam, loadTeamMembers } from './state/actions';
|
||||||
import { getTeam, getTeamMembers, isSignedInUserTeamAdmin } from './state/selectors';
|
import { getTeam, getTeamMembers, isSignedInUserTeamAdmin } from './state/selectors';
|
||||||
@@ -15,9 +15,9 @@ import { getTeamLoadingNav } from './state/navModel';
|
|||||||
import { getNavModel } from 'app/core/selectors/navModel';
|
import { getNavModel } from 'app/core/selectors/navModel';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
import { NavModel } from '@grafana/data';
|
import { NavModel } from '@grafana/data';
|
||||||
import { featureEnabled, reportExperimentView } from '@grafana/runtime';
|
import { featureEnabled } from '@grafana/runtime';
|
||||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||||
import { UpgradeBox, UpgradeContent } from 'app/core/components/Upgrade/UpgradeBox';
|
import { UpgradeBox } from 'app/core/components/Upgrade/UpgradeBox';
|
||||||
|
|
||||||
interface TeamPageRouteParams {
|
interface TeamPageRouteParams {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -84,13 +84,6 @@ export class TeamPages extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
await this.fetchTeam();
|
await this.fetchTeam();
|
||||||
|
|
||||||
const { isSyncEnabled } = this.state;
|
|
||||||
const currentPage = this.getCurrentPage();
|
|
||||||
|
|
||||||
if (currentPage === PageTypes.GroupSync && !isSyncEnabled && config.featureToggles.featureHighlights) {
|
|
||||||
reportExperimentView('feature-highlights-team-sync', 'test', '');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchTeam() {
|
async fetchTeam() {
|
||||||
@@ -141,7 +134,7 @@ export class TeamPages extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
renderPage(isSignedInUserTeamAdmin: boolean): React.ReactNode {
|
renderPage(isSignedInUserTeamAdmin: boolean): React.ReactNode {
|
||||||
const { isSyncEnabled } = this.state;
|
const { isSyncEnabled } = this.state;
|
||||||
const { members, team, theme } = this.props;
|
const { members, team } = this.props;
|
||||||
const currentPage = this.getCurrentPage();
|
const currentPage = this.getCurrentPage();
|
||||||
|
|
||||||
const canReadTeam = contextSrv.hasAccessInMetadata(
|
const canReadTeam = contextSrv.hasAccessInMetadata(
|
||||||
@@ -177,19 +170,8 @@ export class TeamPages extends PureComponent<Props, State> {
|
|||||||
} else if (config.featureToggles.featureHighlights) {
|
} else if (config.featureToggles.featureHighlights) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<UpgradeBox featureName={'team sync'} />
|
<UpgradeBox featureName={'team sync'} featureId={'team-sync'} />
|
||||||
<UpgradeContent
|
<TeamSyncUpgradeContent />
|
||||||
listItems={[
|
|
||||||
'Stop managing user access in two places - assign users to groups in SAML, LDAP or Oauth, and manage access at a Team level in Grafana',
|
|
||||||
'Update users’ permissions immediately when you add or remove them from an LDAP group, with no need for them to sign out and back in',
|
|
||||||
]}
|
|
||||||
image={`team-sync-${theme.isLight ? 'light' : 'dark'}.png`}
|
|
||||||
featureName={'team sync'}
|
|
||||||
featureUrl={'https://grafana.com/docs/grafana/latest/enterprise/team-sync'}
|
|
||||||
description={
|
|
||||||
'Team Sync makes it easier for you to manage users’ access in Grafana, by immediately updating each user’s Grafana teams and permissions based on their single sign-on group membership, instead of when users sign in.'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,10 +67,10 @@ exports[`Render should render component 1`] = `
|
|||||||
<EmptyListCTA
|
<EmptyListCTA
|
||||||
buttonDisabled={false}
|
buttonDisabled={false}
|
||||||
buttonIcon="users-alt"
|
buttonIcon="users-alt"
|
||||||
buttonTitle="Add Group"
|
buttonTitle="Add group"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
proTip="Sync LDAP or OAuth groups with your Grafana teams."
|
proTip="Sync LDAP or OAuth groups with your Grafana teams."
|
||||||
proTipLink="http://docs.grafana.org/auth/enhanced_ldap/"
|
proTipLink="https://docs.grafana.org/auth/enhanced_ldap/"
|
||||||
proTipLinkTitle="Learn more"
|
proTipLinkTitle="Learn more"
|
||||||
proTipTarget="_blank"
|
proTipTarget="_blank"
|
||||||
title="There are no external groups to sync with"
|
title="There are no external groups to sync with"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { NavModelItem, NavModel } from '@grafana/data';
|
|||||||
import config from 'app/core/config';
|
import config from 'app/core/config';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
import { ProBadge } from 'app/core/components/Upgrade/ProBadge';
|
import { ProBadge } from 'app/core/components/Upgrade/ProBadge';
|
||||||
|
import { highlightTrial } from 'app/features/admin/utils';
|
||||||
|
|
||||||
const loadingTeam = {
|
const loadingTeam = {
|
||||||
avatarUrl: 'public/img/user_profile.png',
|
avatarUrl: 'public/img/user_profile.png',
|
||||||
@@ -51,7 +52,7 @@ export function buildNavModel(team: Team): NavModelItem {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const teamGroupSync = {
|
const teamGroupSync: NavModelItem = {
|
||||||
active: false,
|
active: false,
|
||||||
icon: 'sync',
|
icon: 'sync',
|
||||||
id: `team-groupsync-${team.id}`,
|
id: `team-groupsync-${team.id}`,
|
||||||
@@ -61,6 +62,11 @@ export function buildNavModel(team: Team): NavModelItem {
|
|||||||
|
|
||||||
const isLoadingTeam = team === loadingTeam;
|
const isLoadingTeam = team === loadingTeam;
|
||||||
|
|
||||||
|
if (highlightTrial()) {
|
||||||
|
teamGroupSync.tabSuffix = () =>
|
||||||
|
ProBadge({ experimentId: isLoadingTeam ? '' : 'feature-highlights-team-sync-badge', eventVariant: 'trial' });
|
||||||
|
}
|
||||||
|
|
||||||
// With both Legacy and FGAC the tab is protected being featureEnabled
|
// With both Legacy and FGAC the tab is protected being featureEnabled
|
||||||
// While team is loading we leave the teamsync tab
|
// While team is loading we leave the teamsync tab
|
||||||
// With FGAC the External Group Sync tab is available when user has ActionTeamsPermissionsRead for this team
|
// With FGAC the External Group Sync tab is available when user has ActionTeamsPermissionsRead for this team
|
||||||
|
|||||||
Reference in New Issue
Block a user