mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 13:22:21 +08:00
ux: Add CTA for empty lists
This commit is contained in:
@ -1,10 +1,12 @@
|
|||||||
import { react2AngularDirective } from 'app/core/utils/react2angular';
|
import { react2AngularDirective } from 'app/core/utils/react2angular';
|
||||||
import { PasswordStrength } from './components/PasswordStrength';
|
import { PasswordStrength } from './components/PasswordStrength';
|
||||||
import PageHeader from './components/PageHeader';
|
import PageHeader from './components/PageHeader';
|
||||||
|
import EmptyListCTA from './components/EmptyListCTA/EmptyListCTA';
|
||||||
|
|
||||||
export function registerAngularDirectives() {
|
export function registerAngularDirectives() {
|
||||||
|
|
||||||
react2AngularDirective('passwordStrength', PasswordStrength, ['password']);
|
react2AngularDirective('passwordStrength', PasswordStrength, ['password']);
|
||||||
react2AngularDirective('pageHeader', PageHeader, ['model', "noTabs"]);
|
react2AngularDirective('pageHeader', PageHeader, ['model', "noTabs"]);
|
||||||
|
react2AngularDirective('emptyListCta', EmptyListCTA, ['model']);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import renderer from 'react-test-renderer';
|
||||||
|
import EmptyListCTA from './EmptyListCTA';
|
||||||
|
|
||||||
|
const model = {
|
||||||
|
title: 'Title',
|
||||||
|
buttonIcon: 'ga css class',
|
||||||
|
buttonLink: 'http://url/to/destination',
|
||||||
|
buttonTitle: 'Click me',
|
||||||
|
proTip: 'This is a tip',
|
||||||
|
proTipLink: 'http://url/to/tip/destination',
|
||||||
|
proTipLinkTitle: 'Learn more',
|
||||||
|
proTipTarget: '_blank'
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('CollorPalette', () => {
|
||||||
|
|
||||||
|
it('renders correctly', () => {
|
||||||
|
const tree = renderer.create(<EmptyListCTA model={model} />).toJSON();
|
||||||
|
expect(tree).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
34
public/app/core/components/EmptyListCTA/EmptyListCTA.tsx
Normal file
34
public/app/core/components/EmptyListCTA/EmptyListCTA.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
export interface IProps {
|
||||||
|
model: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmptyListCTA extends Component<IProps, any> {
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
title,
|
||||||
|
buttonIcon,
|
||||||
|
buttonLink,
|
||||||
|
buttonTitle,
|
||||||
|
proTip,
|
||||||
|
proTipLink,
|
||||||
|
proTipLinkTitle,
|
||||||
|
proTipTarget
|
||||||
|
} = this.props.model;
|
||||||
|
return (
|
||||||
|
<div className="empty-list-cta p-t-2 p-b-1">
|
||||||
|
<div className="empty-list-cta__title">{title}</div>
|
||||||
|
<a href={buttonLink} className="empty-list-cta__button btn btn-xlarge btn-success"><i className={buttonIcon} />{buttonTitle}</a>
|
||||||
|
<div className="empty-list-cta__pro-tip">
|
||||||
|
<i className="fa fa-rocket" /> ProTip: {proTip}
|
||||||
|
<a className="text-link empty-list-cta__pro-tip-link"
|
||||||
|
href={proTipLink}
|
||||||
|
target={proTipTarget}>{proTipLinkTitle}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EmptyListCTA;
|
@ -0,0 +1,38 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`CollorPalette renders correctly 1`] = `
|
||||||
|
<div
|
||||||
|
className="empty-list-cta p-t-2 p-b-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="empty-list-cta__title"
|
||||||
|
>
|
||||||
|
Title
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
className="empty-list-cta__button btn btn-xlarge btn-success"
|
||||||
|
href="http://url/to/destination"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="ga css class"
|
||||||
|
/>
|
||||||
|
Click me
|
||||||
|
</a>
|
||||||
|
<div
|
||||||
|
className="empty-list-cta__pro-tip"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa fa-rocket"
|
||||||
|
/>
|
||||||
|
ProTip:
|
||||||
|
This is a tip
|
||||||
|
<a
|
||||||
|
className="text-link empty-list-cta__pro-tip-link"
|
||||||
|
href="http://url/to/tip/destination"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Learn more
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
@ -1,46 +1,57 @@
|
|||||||
<page-header model="ctrl.navModel"></page-header>
|
<page-header model="ctrl.navModel"></page-header>
|
||||||
|
|
||||||
<div class="page-container page-body">
|
<div class="page-container page-body">
|
||||||
<div class="page-action-bar">
|
<div ng-if="ctrl.datasources.length">
|
||||||
<div class="page-action-bar__spacer"></div>
|
<div class="page-action-bar">
|
||||||
<a class="page-header__cta btn btn-success" href="datasources/new">
|
<div class="page-action-bar__spacer"></div>
|
||||||
<i class="fa fa-plus"></i>
|
<a class="page-header__cta btn btn-success" href="datasources/new">
|
||||||
Add data source
|
<i class="fa fa-plus"></i>
|
||||||
</a>
|
Add data source
|
||||||
</div>
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<section class="card-section" layout-mode>
|
<section class="card-section" layout-mode>
|
||||||
<layout-selector></layout-selector>
|
<layout-selector></layout-selector>
|
||||||
<ol class="card-list">
|
<ol class="card-list">
|
||||||
<li class="card-item-wrapper" ng-repeat="ds in ctrl.datasources">
|
<li class="card-item-wrapper" ng-repeat="ds in ctrl.datasources">
|
||||||
<a class="card-item" href="datasources/edit/{{ds.id}}/">
|
<a class="card-item" href="datasources/edit/{{ds.id}}/">
|
||||||
<div class="card-item-header">
|
<div class="card-item-header">
|
||||||
<div class="card-item-type">
|
<div class="card-item-type">
|
||||||
{{ds.type}}
|
{{ds.type}}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-item-body">
|
|
||||||
<figure class="card-item-figure">
|
|
||||||
<img ng-src="{{ds.typeLogoUrl}}">
|
|
||||||
</figure>
|
|
||||||
<div class="card-item-details">
|
|
||||||
<div class="card-item-name">
|
|
||||||
{{ds.name}}
|
|
||||||
<span ng-if="ds.isDefault">
|
|
||||||
<span class="btn btn-secondary btn-mini">default</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="card-item-sub-name">
|
|
||||||
{{ds.url}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="card-item-body">
|
||||||
</a>
|
<figure class="card-item-figure">
|
||||||
</li>
|
<img ng-src="{{ds.typeLogoUrl}}">
|
||||||
</ol>
|
</figure>
|
||||||
</section>
|
<div class="card-item-details">
|
||||||
|
<div class="card-item-name">
|
||||||
|
{{ds.name}}
|
||||||
|
<span ng-if="ds.isDefault">
|
||||||
|
<span class="btn btn-secondary btn-mini">default</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-item-sub-name">
|
||||||
|
{{ds.url}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div ng-if="ctrl.datasources.length === 0">
|
<div ng-if="ctrl.datasources.length === 0">
|
||||||
<em>No data sources defined</em>
|
<empty-list-cta model="{
|
||||||
|
title: 'There are no data sources defined yet',
|
||||||
|
buttonIcon: 'gicon gicon-dashboard-new',
|
||||||
|
buttonLink: '/datasources/new',
|
||||||
|
buttonTitle: 'Add data source',
|
||||||
|
proTip: 'You can also define data sources through configuration files.',
|
||||||
|
proTipLink: 'http://docs.grafana.org/administration/provisioning/#datasources',
|
||||||
|
proTipLinkTitle: 'Learn more',
|
||||||
|
proTipTarget: '_blank'
|
||||||
|
}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -86,6 +86,7 @@
|
|||||||
@import "components/dashboard_grid";
|
@import "components/dashboard_grid";
|
||||||
@import "components/dashboard_list";
|
@import "components/dashboard_list";
|
||||||
@import "components/page_header";
|
@import "components/page_header";
|
||||||
|
@import "components/empty_list_cta";
|
||||||
|
|
||||||
|
|
||||||
// PAGES
|
// PAGES
|
||||||
|
@ -218,8 +218,11 @@ $btn-font-weight: 500 !default;
|
|||||||
$btn-padding-x-sm: .5rem !default;
|
$btn-padding-x-sm: .5rem !default;
|
||||||
$btn-padding-y-sm: .25rem !default;
|
$btn-padding-y-sm: .25rem !default;
|
||||||
|
|
||||||
$btn-padding-x-lg: 1.5rem !default;
|
$btn-padding-x-lg: 21px !default;
|
||||||
$btn-padding-y-lg: .75rem !default;
|
$btn-padding-y-lg: 11px !default;
|
||||||
|
|
||||||
|
$btn-padding-x-xl: 21px !default;
|
||||||
|
$btn-padding-y-xl: 11px !default;
|
||||||
|
|
||||||
$btn-border-radius: 3px;
|
$btn-border-radius: 3px;
|
||||||
|
|
||||||
|
@ -48,6 +48,8 @@ a.text-success:hover,
|
|||||||
a.text-success:focus { color: darken($success-text-color, 10%); }
|
a.text-success:focus { color: darken($success-text-color, 10%); }
|
||||||
a { cursor: pointer; }
|
a { cursor: pointer; }
|
||||||
|
|
||||||
|
.text-link { text-decoration: underline; }
|
||||||
|
|
||||||
a:focus {
|
a:focus {
|
||||||
outline:0 none !important;
|
outline:0 none !important;
|
||||||
}
|
}
|
||||||
|
@ -51,10 +51,21 @@
|
|||||||
|
|
||||||
// Button Sizes
|
// Button Sizes
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
// XLarge
|
||||||
|
.btn-xlarge {
|
||||||
|
@include button-size($btn-padding-y-xl, $btn-padding-x-xl, $font-size-lg, $btn-border-radius);
|
||||||
|
font-weight: normal;
|
||||||
|
padding-bottom: $btn-padding-y-xl - 3;
|
||||||
|
.gicon {
|
||||||
|
font-size: 31px;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Large
|
// Large
|
||||||
.btn-large {
|
.btn-large {
|
||||||
@include button-size($btn-padding-y-lg, $btn-padding-x-lg, $font-size-lg, $btn-border-radius);
|
@include button-size($btn-padding-y-lg, $btn-padding-x-lg, $font-size-lg, $btn-border-radius);
|
||||||
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-small {
|
.btn-small {
|
||||||
|
21
public/sass/components/_empty_list_cta.scss
Normal file
21
public/sass/components/_empty_list_cta.scss
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.empty-list-cta {
|
||||||
|
background-color: $search-filter-box-bg;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-list-cta__title {
|
||||||
|
padding-bottom: 30px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-list-cta__button {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-list-cta__pro-tip {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-list-cta__pro-tip-link {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
Reference in New Issue
Block a user