mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Refactor: EmptyListCTA (#18516)
* Rewrite EmptyListCTA props and start removing css classes * Add watchDepth onClick * EmptyListCTA with React in annotaitons/editor * Begin conversion of DashLinks editor EmptyListCTA * Use React component in DashLinks, Variables and TeamGroupSync * Remove scss file and add emotion styles * Update snapshot * Remove style import * Fix feedback * Update snapshot
This commit is contained in:
parent
299a0e20f4
commit
ec492e55dc
@ -18,7 +18,19 @@ export function registerAngularDirectives() {
|
||||
react2AngularDirective('functionEditor', FunctionEditor, ['func', 'onRemove', 'onMoveLeft', 'onMoveRight']);
|
||||
react2AngularDirective('appNotificationsList', AppNotificationList, []);
|
||||
react2AngularDirective('pageHeader', PageHeader, ['model', 'noTabs']);
|
||||
react2AngularDirective('emptyListCta', EmptyListCTA, ['model']);
|
||||
react2AngularDirective('emptyListCta', EmptyListCTA, [
|
||||
'title',
|
||||
'buttonIcon',
|
||||
'buttonLink',
|
||||
'buttonTitle',
|
||||
['onClick', { watchDepth: 'reference', wrapApply: true }],
|
||||
'proTip',
|
||||
'proTipLink',
|
||||
'proTipLinkTitle',
|
||||
'proTipTarget',
|
||||
'infoBox',
|
||||
'infoBoxTitle',
|
||||
]);
|
||||
react2AngularDirective('searchField', SearchField, [
|
||||
'query',
|
||||
'autoFocus',
|
||||
|
@ -1,38 +1,71 @@
|
||||
import React, { useContext } from 'react';
|
||||
import React, { useContext, MouseEvent } from 'react';
|
||||
import { CallToActionCard, LinkButton, ThemeContext } from '@grafana/ui';
|
||||
import { css } from 'emotion';
|
||||
export interface Props {
|
||||
model: any;
|
||||
title: string;
|
||||
buttonIcon: string;
|
||||
buttonLink?: string;
|
||||
buttonTitle: string;
|
||||
onClick?: (event: MouseEvent) => void;
|
||||
proTip?: string;
|
||||
proTipLink?: string;
|
||||
proTipLinkTitle?: string;
|
||||
proTipTarget?: string;
|
||||
infoBox?: { __html: string };
|
||||
infoBoxTitle?: string;
|
||||
}
|
||||
|
||||
const EmptyListCTA: React.FunctionComponent<Props> = props => {
|
||||
const ctaStyle = css`
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
const infoBoxStyles = css`
|
||||
max-width: 700px;
|
||||
margin: 0 auto;
|
||||
`;
|
||||
|
||||
const EmptyListCTA: React.FunctionComponent<Props> = ({
|
||||
title,
|
||||
buttonIcon,
|
||||
buttonLink,
|
||||
buttonTitle,
|
||||
onClick,
|
||||
proTip,
|
||||
proTipLink,
|
||||
proTipLinkTitle,
|
||||
proTipTarget,
|
||||
infoBox,
|
||||
infoBoxTitle,
|
||||
}) => {
|
||||
const theme = useContext(ThemeContext);
|
||||
|
||||
const {
|
||||
title,
|
||||
buttonIcon,
|
||||
buttonLink,
|
||||
buttonTitle,
|
||||
onClick,
|
||||
proTip,
|
||||
proTipLink,
|
||||
proTipLinkTitle,
|
||||
proTipTarget,
|
||||
} = props.model;
|
||||
const footer = () => {
|
||||
return (
|
||||
<>
|
||||
{proTip ? (
|
||||
<span key="proTipFooter">
|
||||
<i className="fa fa-rocket" />
|
||||
<> ProTip: {proTip} </>
|
||||
<a href={proTipLink} target={proTipTarget} className="text-link">
|
||||
{proTipLinkTitle}
|
||||
</a>
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
{infoBox ? (
|
||||
<div key="infoBoxHtml" className={`grafana-info-box ${infoBoxStyles}`}>
|
||||
{infoBoxTitle && <h5>{infoBoxTitle}</h5>}
|
||||
<div dangerouslySetInnerHTML={infoBox} />
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const footer = proTip ? (
|
||||
<span>
|
||||
<i className="fa fa-rocket" />
|
||||
<> ProTip: {proTip} </>
|
||||
<a href={proTipLink} target={proTipTarget} className="text-link">
|
||||
{proTipLinkTitle}
|
||||
</a>
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
|
||||
const ctaElementClassName = !footer
|
||||
const ctaElementClassName = !footer()
|
||||
? css`
|
||||
margin-bottom: 20px;
|
||||
`
|
||||
@ -44,7 +77,15 @@ const EmptyListCTA: React.FunctionComponent<Props> = props => {
|
||||
</LinkButton>
|
||||
);
|
||||
|
||||
return <CallToActionCard message={title} footer={footer} callToActionElement={ctaElement} theme={theme} />;
|
||||
return (
|
||||
<CallToActionCard
|
||||
className={ctaStyle}
|
||||
message={title}
|
||||
footer={footer()}
|
||||
callToActionElement={ctaElement}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmptyListCTA;
|
||||
|
@ -142,7 +142,7 @@ export class AlertTab extends PureComponent<Props> {
|
||||
<EditorTabBody heading="Alert" toolbarItems={toolbarItems}>
|
||||
<>
|
||||
<div ref={element => (this.element = element)} />
|
||||
{!alert && <EmptyListCTA model={model} />}
|
||||
{!alert && <EmptyListCTA {...model} />}
|
||||
</>
|
||||
</EditorTabBody>
|
||||
);
|
||||
|
@ -23,6 +23,25 @@ export class AnnotationsEditorCtrl {
|
||||
hide: false,
|
||||
};
|
||||
|
||||
emptyListCta = {
|
||||
title: 'There are no custom annotation queries added yet',
|
||||
buttonIcon: 'gicon gicon-annotation',
|
||||
buttonTitle: 'Add Annotation Query',
|
||||
infoBox: {
|
||||
__html: `<p>Annotations provide a way to integrate event data into your graphs. They are visualized as vertical lines
|
||||
and icons on all graph panels. When you hover over an annotation icon you can get event text & tags for
|
||||
the event. You can add annotation events directly from grafana by holding CTRL or CMD + click on graph (or
|
||||
drag region). These will be stored in Grafana's annotation database.
|
||||
</p>
|
||||
Checkout the
|
||||
<a class='external-link' target='_blank' href='http://docs.grafana.org/reference/annotations/'
|
||||
>Annotations documentation</a
|
||||
>
|
||||
for more information.`,
|
||||
},
|
||||
infoBoxTitle: 'What are annotations?',
|
||||
};
|
||||
|
||||
showOptions: any = [{ text: 'All Panels', value: 0 }, { text: 'Specific Panels', value: 1 }];
|
||||
|
||||
/** @ngInject */
|
||||
@ -63,10 +82,10 @@ export class AnnotationsEditorCtrl {
|
||||
this.mode = 'list';
|
||||
}
|
||||
|
||||
setupNew() {
|
||||
setupNew = () => {
|
||||
this.mode = 'new';
|
||||
this.reset();
|
||||
}
|
||||
};
|
||||
|
||||
backToList() {
|
||||
this.mode = 'list';
|
||||
|
@ -13,10 +13,10 @@
|
||||
class="btn btn-primary"
|
||||
ng-click="ctrl.setupNew();"
|
||||
ng-if="ctrl.annotations.length > 1"
|
||||
ng-hide="ctrl.mode === 'edit' || ctrl.mode === 'new'">
|
||||
New
|
||||
</a
|
||||
ng-hide="ctrl.mode === 'edit' || ctrl.mode === 'new'"
|
||||
>
|
||||
New
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div ng-if="ctrl.mode === 'list'">
|
||||
@ -62,27 +62,7 @@
|
||||
|
||||
<!-- empty list cta, there is always one built in query -->
|
||||
<div ng-if="ctrl.annotations.length === 1" class="p-t-2">
|
||||
<div class="empty-list-cta">
|
||||
<div class="empty-list-cta__title">There are no custom annotation queries added yet</div>
|
||||
<a ng-click="ctrl.setupNew()" class="empty-list-cta__button btn btn-large btn-primary">
|
||||
<i class="gicon gicon-annotation"></i>
|
||||
Add Annotation Query
|
||||
</a>
|
||||
<div class="grafana-info-box">
|
||||
<h5>What are Annotations?</h5>
|
||||
<p>
|
||||
Annotations provide a way to integrate event data into your graphs. They are visualized as vertical lines
|
||||
and icons on all graph panels. When you hover over an annotation icon you can get event text & tags for
|
||||
the event. You can add annotation events directly from grafana by holding CTRL or CMD + click on graph (or
|
||||
drag region). These will be stored in Grafana's annotation database.
|
||||
</p>
|
||||
Checkout the
|
||||
<a class="external-link" target="_blank" href="http://docs.grafana.org/reference/annotations/"
|
||||
>Annotations documentation</a
|
||||
>
|
||||
for more information.
|
||||
</div>
|
||||
</div>
|
||||
<empty-list-cta title="ctrl.emptyListCta.title" buttonIcon="ctrl.emptyListCta.buttonIcon" buttonTitle="ctrl.emptyListCta.buttonTitle" infoBox="ctrl.emptyListCta.infoBox" infoBoxTitle="ctrl.emptyListCta.infoBoxTitle" on-click="ctrl.setupNew"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -145,17 +145,12 @@ export class ApiKeysPage extends PureComponent<Props, any> {
|
||||
<>
|
||||
{!isAdding && (
|
||||
<EmptyListCTA
|
||||
model={{
|
||||
title: "You haven't added any API Keys yet.",
|
||||
buttonIcon: 'gicon gicon-apikeys',
|
||||
buttonLink: '#',
|
||||
onClick: this.onToggleAdding,
|
||||
buttonTitle: ' New API Key',
|
||||
proTip: 'Remember you can provide view-only API access to other applications.',
|
||||
proTipLink: '',
|
||||
proTipLinkTitle: '',
|
||||
proTipTarget: '_blank',
|
||||
}}
|
||||
title="You haven't added any API Keys yet."
|
||||
buttonIcon="gicon gicon-apikeys"
|
||||
buttonLink="#"
|
||||
onClick={this.onToggleAdding}
|
||||
buttonTitle=" New API Key"
|
||||
proTip="Remember you can provide view-only API access to other applications."
|
||||
/>
|
||||
)}
|
||||
{this.renderAddApiKeyForm()}
|
||||
|
@ -36,19 +36,12 @@ exports[`Render should render CTA if there are no API keys 1`] = `
|
||||
isLoading={false}
|
||||
>
|
||||
<EmptyListCTA
|
||||
model={
|
||||
Object {
|
||||
"buttonIcon": "gicon gicon-apikeys",
|
||||
"buttonLink": "#",
|
||||
"buttonTitle": " New API Key",
|
||||
"onClick": [Function],
|
||||
"proTip": "Remember you can provide view-only API access to other applications.",
|
||||
"proTipLink": "",
|
||||
"proTipLinkTitle": "",
|
||||
"proTipTarget": "_blank",
|
||||
"title": "You haven't added any API Keys yet.",
|
||||
}
|
||||
}
|
||||
buttonIcon="gicon gicon-apikeys"
|
||||
buttonLink="#"
|
||||
buttonTitle=" New API Key"
|
||||
onClick={[Function]}
|
||||
proTip="Remember you can provide view-only API access to other applications."
|
||||
title="You haven't added any API Keys yet."
|
||||
/>
|
||||
<Component
|
||||
in={false}
|
||||
|
@ -18,6 +18,19 @@ export class DashLinksEditorCtrl {
|
||||
mode: any;
|
||||
link: any;
|
||||
|
||||
emptyListCta = {
|
||||
title: 'There are no dashboard links added yet',
|
||||
buttonIcon: 'gicon gicon-link',
|
||||
buttonTitle: 'Add Dashboard Link',
|
||||
infoBox: {
|
||||
__html: `<p>
|
||||
Dashboard Links allow you to place links to other dashboards and web sites directly in below the dashboard
|
||||
header.
|
||||
</p>`,
|
||||
},
|
||||
infoBoxTitle: 'What are Dashboard Links?',
|
||||
};
|
||||
|
||||
/** @ngInject */
|
||||
constructor($scope: any, $rootScope: any) {
|
||||
this.iconMap = iconMap;
|
||||
@ -33,10 +46,10 @@ export class DashLinksEditorCtrl {
|
||||
this.mode = 'list';
|
||||
}
|
||||
|
||||
setupNew() {
|
||||
setupNew = () => {
|
||||
this.mode = 'new';
|
||||
this.link = { type: 'dashboards', icon: 'external link' };
|
||||
}
|
||||
};
|
||||
|
||||
addLink() {
|
||||
this.dashboard.links.push(this.link);
|
||||
|
@ -19,22 +19,7 @@
|
||||
|
||||
<div ng-if="ctrl.mode == 'list'">
|
||||
<div ng-if="ctrl.dashboard.links.length === 0">
|
||||
<div class="empty-list-cta">
|
||||
<div class="empty-list-cta__title">
|
||||
There are no dashboard links added yet
|
||||
</div>
|
||||
<a ng-click="ctrl.setupNew()" class="empty-list-cta__button btn btn-large btn-primary">
|
||||
<i class="gicon gicon-link"></i>
|
||||
Add Dashboard Link
|
||||
</a>
|
||||
<div class="grafana-info-box">
|
||||
<h5>What are Dashboard Links?</h5>
|
||||
<p>
|
||||
Dashboard Links allow you to place links to other dashboards and web sites directly in below the dashboard
|
||||
header.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<empty-list-cta on-click="ctrl.setupNew" title="ctrl.emptyListCta.title" buttonIcon="ctrl.emptyListCta.buttonIcon" buttonTitle="ctrl.emptyListCta.buttonTitle" infoBox="ctrl.emptyListCta.infoBox" infoBoxTitle="ctrl.emptyListCta.infoBoxTitle"/>
|
||||
</div>
|
||||
|
||||
<div ng-if="ctrl.dashboard.links.length > 0">
|
||||
|
@ -79,7 +79,7 @@ export class DataSourcesListPage extends PureComponent<Props> {
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={!hasFetched}>
|
||||
<>
|
||||
{hasFetched && dataSourcesCount === 0 && <EmptyListCTA model={emptyListModel} />}
|
||||
{hasFetched && dataSourcesCount === 0 && <EmptyListCTA {...emptyListModel} />}
|
||||
{hasFetched &&
|
||||
dataSourcesCount > 0 && [
|
||||
<OrgActionBar
|
||||
|
@ -7,6 +7,7 @@ import { Input, Tooltip } from '@grafana/ui';
|
||||
import { TeamGroup } from '../../types';
|
||||
import { addTeamGroup, loadTeamGroups, removeTeamGroup } from './state/actions';
|
||||
import { getTeamGroups } from './state/selectors';
|
||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||
|
||||
export interface Props {
|
||||
groups: TeamGroup[];
|
||||
@ -119,23 +120,16 @@ export class TeamGroupSync extends PureComponent<Props, State> {
|
||||
</SlideDown>
|
||||
|
||||
{groups.length === 0 && !isAdding && (
|
||||
<div className="empty-list-cta">
|
||||
<div className="empty-list-cta__title">There are no external groups to sync with</div>
|
||||
<button onClick={this.onToggleAdding} className="empty-list-cta__button btn btn-large btn-primary">
|
||||
<i className="gicon gicon-team" />
|
||||
Add Group
|
||||
</button>
|
||||
<div className="empty-list-cta__pro-tip">
|
||||
<i className="fa fa-rocket" /> {headerTooltip}
|
||||
<a
|
||||
className="text-link empty-list-cta__pro-tip-link"
|
||||
href="http://docs.grafana.org/auth/enhanced_ldap/"
|
||||
target="_blank"
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<EmptyListCTA
|
||||
onClick={this.onToggleAdding}
|
||||
buttonIcon="gicon gicon-team"
|
||||
title="There are no external groups to sync with"
|
||||
buttonTitle="Add Group"
|
||||
proTip={headerTooltip}
|
||||
proTipLinkTitle="Learn more"
|
||||
proTipLink="http://docs.grafana.org/auth/enhanced_ldap/"
|
||||
proTipTarget="_blank"
|
||||
/>
|
||||
)}
|
||||
|
||||
{groups.length > 0 && (
|
||||
|
@ -75,16 +75,14 @@ export class TeamList extends PureComponent<Props, any> {
|
||||
renderEmptyList() {
|
||||
return (
|
||||
<EmptyListCTA
|
||||
model={{
|
||||
title: "You haven't created any teams yet.",
|
||||
buttonIcon: 'gicon gicon-team',
|
||||
buttonLink: 'org/teams/new',
|
||||
buttonTitle: ' New team',
|
||||
proTip: 'Assign folder and dashboard permissions to teams instead of users to ease administration.',
|
||||
proTipLink: '',
|
||||
proTipLinkTitle: '',
|
||||
proTipTarget: '_blank',
|
||||
}}
|
||||
title="You haven't created any teams yet."
|
||||
buttonIcon="gicon gicon-team"
|
||||
buttonLink="org/teams/new"
|
||||
buttonTitle=" New team"
|
||||
proTip="Assign folder and dashboard permissions to teams instead of users to ease administration."
|
||||
proTipLink=""
|
||||
proTipLinkTitle=""
|
||||
proTipTarget="_blank"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -72,40 +72,16 @@ exports[`Render should render component 1`] = `
|
||||
</form>
|
||||
</div>
|
||||
</Component>
|
||||
<div
|
||||
className="empty-list-cta"
|
||||
>
|
||||
<div
|
||||
className="empty-list-cta__title"
|
||||
>
|
||||
There are no external groups to sync with
|
||||
</div>
|
||||
<button
|
||||
className="empty-list-cta__button btn btn-large btn-primary"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<i
|
||||
className="gicon gicon-team"
|
||||
/>
|
||||
Add Group
|
||||
</button>
|
||||
<div
|
||||
className="empty-list-cta__pro-tip"
|
||||
>
|
||||
<i
|
||||
className="fa fa-rocket"
|
||||
/>
|
||||
|
||||
Sync LDAP or OAuth groups with your Grafana teams.
|
||||
<a
|
||||
className="text-link empty-list-cta__pro-tip-link"
|
||||
href="http://docs.grafana.org/auth/enhanced_ldap/"
|
||||
target="_blank"
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<EmptyListCTA
|
||||
buttonIcon="gicon gicon-team"
|
||||
buttonTitle="Add Group"
|
||||
onClick={[Function]}
|
||||
proTip="Sync LDAP or OAuth groups with your Grafana teams."
|
||||
proTipLink="http://docs.grafana.org/auth/enhanced_ldap/"
|
||||
proTipLinkTitle="Learn more"
|
||||
proTipTarget="_blank"
|
||||
title="There are no external groups to sync with"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
@ -14,6 +14,24 @@ export class VariableEditorCtrl {
|
||||
$scope.namePattern = /^(?!__).*$/;
|
||||
$scope._ = _;
|
||||
$scope.optionsLimit = 20;
|
||||
$scope.emptyListCta = {
|
||||
title: 'There are no variables yet',
|
||||
buttonTitle: 'Add variable',
|
||||
buttonIcon: 'gicon gicon-variable',
|
||||
infoBox: {
|
||||
__html: ` <p>
|
||||
Variables enable more interactive and dynamic dashboards. Instead of hard-coding things like server or
|
||||
sensor names in your metric queries you can use variables in their place. Variables are shown as dropdown
|
||||
select boxes at the top of the dashboard. These dropdowns make it easy to change the data being displayed in
|
||||
your dashboard. Check out the
|
||||
<a class="external-link" href="http://docs.grafana.org/reference/templating/" target="_blank">
|
||||
Templating documentation
|
||||
</a>
|
||||
for more information.
|
||||
</p>`,
|
||||
infoBoxTitle: 'What do variables do?',
|
||||
},
|
||||
};
|
||||
|
||||
$scope.refreshOptions = [
|
||||
{ value: 0, text: 'Never' },
|
||||
@ -50,6 +68,10 @@ export class VariableEditorCtrl {
|
||||
$scope.mode = mode;
|
||||
};
|
||||
|
||||
$scope.setNewMode = () => {
|
||||
$scope.setMode('new');
|
||||
};
|
||||
|
||||
$scope.add = () => {
|
||||
if ($scope.isValid()) {
|
||||
variableSrv.addVariable($scope.current);
|
||||
|
@ -19,26 +19,14 @@
|
||||
|
||||
<div ng-if="mode === 'list'">
|
||||
<div ng-if="variables.length === 0">
|
||||
<div class="empty-list-cta">
|
||||
<div class="empty-list-cta__title">There are no variables added yet</div>
|
||||
<a ng-click="setMode('new')" class="empty-list-cta__button btn btn-large btn-primary">
|
||||
<i class="gicon gicon-variable"></i>
|
||||
Add variable
|
||||
</a>
|
||||
<div class="grafana-info-box">
|
||||
<h5>What do variables do?</h5>
|
||||
<p>
|
||||
Variables enable more interactive and dynamic dashboards. Instead of hard-coding things like server or
|
||||
sensor names in your metric queries you can use variables in their place. Variables are shown as dropdown
|
||||
select boxes at the top of the dashboard. These dropdowns make it easy to change the data being displayed in
|
||||
your dashboard. Check out the
|
||||
<a class="external-link" href="http://docs.grafana.org/reference/templating/" target="_blank">
|
||||
Templating documentation
|
||||
</a>
|
||||
for more information.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<empty-list-cta
|
||||
on-click="setNewMode"
|
||||
title="emptyListCta.title"
|
||||
infoBox="emptyListCta.infoBox"
|
||||
infoBoxTitle="emptyListCta.infoBoxTitle"
|
||||
buttonTitle="emptyListCta.buttonTitle"
|
||||
buttonIcon="emptyListCta.buttonIcon"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div ng-if="variables.length">
|
||||
|
@ -90,7 +90,6 @@
|
||||
@import 'components/dashboard_list';
|
||||
@import 'components/page_header';
|
||||
@import 'components/dashboard_settings';
|
||||
@import 'components/empty_list_cta';
|
||||
@import 'components/panel_editor';
|
||||
@import 'components/toolbar';
|
||||
@import 'components/add_data_source.scss';
|
||||
|
@ -1,24 +0,0 @@
|
||||
.empty-list-cta {
|
||||
background-color: $empty-list-cta-bg;
|
||||
text-align: center;
|
||||
padding: $spacer * 2;
|
||||
border-radius: $border-radius;
|
||||
|
||||
.grafana-info-box {
|
||||
max-width: 700px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-list-cta__title {
|
||||
padding-bottom: $spacer * 3;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.empty-list-cta__button {
|
||||
margin-bottom: $spacer * 3;
|
||||
}
|
||||
|
||||
.empty-list-cta__pro-tip-link {
|
||||
margin-left: 5px;
|
||||
}
|
Loading…
Reference in New Issue
Block a user