Commit e348ec8c by Torkel Ödegaard

Merge branch 'develop-new-page-header' into develop

parents d83692aa 75bb8944
......@@ -24,11 +24,13 @@ type NavLink struct {
Id string `json:"id,omitempty"`
Text string `json:"text,omitempty"`
Description string `json:"description,omitempty"`
SubTitle string `json:"subTitle,omitempty"`
Icon string `json:"icon,omitempty"`
Img string `json:"img,omitempty"`
Url string `json:"url,omitempty"`
Target string `json:"target,omitempty"`
Divider bool `json:"divider,omitempty"`
HideFromMenu bool `json:"hideFromMenu,omitempty"`
HideFromTabs bool `json:"hideFromTabs,omitempty"`
Children []*NavLink `json:"children,omitempty"`
}
......@@ -101,38 +101,41 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
}
dashboardChildNavs := []*dtos.NavLink{
{Text: "Home", Url: setting.AppSubUrl + "/", Icon: "fa fa-fw fa-home"},
{Text: "Home", Url: setting.AppSubUrl + "/", Icon: "fa fa-fw fa-home", HideFromTabs: true},
{Divider: true},
{Text: "Manage", Id: "dashboards", Url: setting.AppSubUrl + "/dashboards", Icon: "fa fa-fw fa-sitemap"},
{Text: "Playlists", Id: "playlists", Url: setting.AppSubUrl + "/playlists", Icon: "fa fa-fw fa-film"},
{Text: "Snapshots", Id: "snapshots", Url: setting.AppSubUrl + "/dashboard/snapshots", Icon: "icon-gf icon-gf-fw icon-gf-snapshot"},
{Text: "Dashboard List", Description: "Manage Dashboards And Folders", Id: "dashboards", Url: setting.AppSubUrl + "/dashboards", Icon: "fa fa-fw fa-bars"},
}
data.NavTree = append(data.NavTree, &dtos.NavLink{
Text: "Dashboards",
Id: "dashboards",
SubTitle: "Manage dashboards & folders",
Icon: "gicon gicon-dashboard",
Url: setting.AppSubUrl + "/",
Url: setting.AppSubUrl + "/dashboards",
Children: dashboardChildNavs,
})
if c.IsSignedIn {
profileNode := &dtos.NavLink{
Text: c.SignedInUser.Login,
Text: c.SignedInUser.Name,
SubTitle: c.SignedInUser.Login,
Id: "profile",
Img: data.User.GravatarUrl,
Url: setting.AppSubUrl + "/profile",
HideFromMenu: true,
Children: []*dtos.NavLink{
{Text: "Your profile", Url: setting.AppSubUrl + "/profile", Icon: "fa fa-fw fa-sliders"},
{Text: "Preferences", Id: "profile-settings", Url: setting.AppSubUrl + "/profile", Icon: "fa fa-fw fa-sliders"},
{Text: "Change Password", Id: "change-password", Url: setting.AppSubUrl + "/profile/password", Icon: "fa fa-fw fa-lock", HideFromMenu: true},
},
}
if !setting.DisableSignoutMenu {
// add sign out first
profileNode.Children = append([]*dtos.NavLink{
{Text: "Sign out", Url: setting.AppSubUrl + "/logout", Icon: "fa fa-fw fa-sign-out", Target: "_self"},
}, profileNode.Children...)
profileNode.Children = append(profileNode.Children, &dtos.NavLink{
Text: "Sign out", Id: "sign-out", Url: setting.AppSubUrl + "/logout", Icon: "fa fa-fw fa-sign-out", Target: "_self",
})
}
data.NavTree = append(data.NavTree, profileNode)
......@@ -140,12 +143,13 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
if setting.AlertingEnabled && (c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR) {
alertChildNavs := []*dtos.NavLink{
{Text: "Alert List", Id: "alert-list", Url: setting.AppSubUrl + "/alerting/list", Icon: "fa fa-fw fa-list-ul"},
{Text: "Notification channels", Id: "channels", Url: setting.AppSubUrl + "/alerting/notifications", Icon: "fa fa-fw fa-bell-o"},
{Text: "Alert Rules", Id: "alert-list", Url: setting.AppSubUrl + "/alerting/list", Icon: "fa fa-fw fa-list-ul"},
{Text: "Notification channels", Id: "channels", Url: setting.AppSubUrl + "/alerting/notifications", Icon: "gicon gicon-alert-notification-channel"},
}
data.NavTree = append(data.NavTree, &dtos.NavLink{
Text: "Alerting",
SubTitle: "Alert rules & notifications",
Id: "alerting",
Icon: "gicon gicon-alert",
Url: setting.AppSubUrl + "/alerting/list",
......@@ -202,10 +206,11 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
if c.OrgRole == m.ROLE_ADMIN {
cfgNode := &dtos.NavLink{
Id: "cfg",
Text: "Configuration",
Icon: "fa fa-fw fa-cogs",
Url: setting.AppSubUrl + "/configuration",
Id: "cfg",
Text: "Configuration",
SubTitle: "Organization: " + c.OrgName,
Icon: "fa fa-fw fa-cog",
Url: setting.AppSubUrl + "/datasources",
Children: []*dtos.NavLink{
{
Text: "Data Sources",
......@@ -213,29 +218,6 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
Description: "Add and configure data sources",
Id: "datasources",
Url: setting.AppSubUrl + "/datasources",
Children: []*dtos.NavLink{
{Text: "List", Url: setting.AppSubUrl + "/datasources", Icon: "gicon gicon-datasources"},
{Text: "New", Url: setting.AppSubUrl + "/datasources", Icon: "fa fa-fw fa-plus"},
},
},
{
Text: "Preferences",
Id: "org",
Description: "Organization preferences",
Icon: "fa fa-fw fa-sliders",
Url: setting.AppSubUrl + "/org",
},
{
Text: "Plugins",
Id: "plugins",
Description: "View and configure plugins",
Icon: "icon-gf icon-gf-fw icon-gf-apps",
Url: setting.AppSubUrl + "/plugins",
Children: []*dtos.NavLink{
{Text: "Panels", Url: setting.AppSubUrl + "/plugins?type=panel", Icon: "fa fa-fw fa-stop"},
{Text: "Data sources", Url: setting.AppSubUrl + "/plugins?type=datasource", Icon: "icon-gf icon-gf-datasources"},
{Text: "Apps", Url: setting.AppSubUrl + "/plugins?type=app", Icon: "icon-gf icon-gf-apps"},
},
},
{
Text: "Members",
......@@ -245,13 +227,33 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
Url: setting.AppSubUrl + "/org/users",
},
{
Text: "Groups",
Id: "users",
Text: "Teams",
Id: "teams",
Description: "Manage org groups",
Icon: "fa fa-fw fa-users",
Icon: "gicon gicon-user-group",
Url: setting.AppSubUrl + "/org/user-groups",
},
{
Text: "Plugins",
Id: "plugins",
Description: "View and configure plugins",
Icon: "icon-gf icon-gf-fw icon-gf-apps",
Url: setting.AppSubUrl + "/plugins",
// Children: []*dtos.NavLink{
// {Text: "Panels", Url: setting.AppSubUrl + "/plugins?type=panel", Icon: "fa fa-fw fa-stop"},
// {Text: "Data sources", Url: setting.AppSubUrl + "/plugins?type=datasource", Icon: "icon-gf icon-gf-datasources"},
// {Text: "Apps", Url: setting.AppSubUrl + "/plugins?type=app", Icon: "icon-gf icon-gf-apps"},
// },
},
{
Text: "Preferences",
Id: "org-settings",
Description: "Organization preferences",
Icon: "fa fa-fw fa-sliders",
Url: setting.AppSubUrl + "/org",
},
{
Text: "API Keys",
Id: "apikeys",
Description: "Create & manage API keys",
......@@ -261,21 +263,21 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
},
}
if c.IsGrafanaAdmin {
cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{
Text: "Server Admin",
Id: "admin",
Icon: "fa fa-fw fa-shield",
Url: setting.AppSubUrl + "/admin",
Children: []*dtos.NavLink{
{Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users"},
{Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs"},
{Text: "Server Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings"},
{Text: "Server Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats"},
{Text: "Style Guide", Id: "styleguide", Url: setting.AppSubUrl + "/styleguide"},
},
})
}
// if c.IsGrafanaAdmin {
// cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{
// Text: "Server Admin",
// Id: "admin",
// Icon: "fa fa-fw fa-shield",
// Url: setting.AppSubUrl + "/admin",
// Children: []*dtos.NavLink{
// {Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users"},
// {Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs"},
// {Text: "Server Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings"},
// {Text: "Server Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats"},
// {Text: "Style Guide", Id: "styleguide", Url: setting.AppSubUrl + "/styleguide"},
// },
// })
// }
data.NavTree = append(data.NavTree, cfgNode)
}
......
import { react2AngularDirective } from 'app/core/utils/react2angular';
import { PasswordStrength } from './components/PasswordStrength';
import PageHeader from './components/PageHeader';
export function registerAngularDirectives() {
react2AngularDirective('passwordStrength', PasswordStrength, ['password']);
react2AngularDirective('pageHeader', PageHeader, ['model', "noTabs"]);
}
import React from 'react';
import { NavModel, NavModelItem } from '../nav_model_srv';
import classNames from 'classnames';
export interface IProps {
model: NavModel;
}
// function BreadcrumbItem(item: NavModelItem) {
// return (
// <a className="breadcrumb-item" href={item.url} key={item.id}>
// {item.text}
// </a>
// );
// }
//
// function Breadcrumb(model: NavModel) {
// return (
// <div className="page-nav">
// <div className="page-breadcrumbs">
// <a className="breadcrumb-item active" href="/">
// <i className="fa fa-home" />
// </a>
// {model.breadcrumbs.map(BreadcrumbItem)}
// </div>
// </div>
// );
// }
function TabItem(tab: NavModelItem) {
if (tab.hideFromTabs || tab.divider) {
return (null);
}
let tabClasses = classNames({
'gf-tabs-link': true,
active: tab.active,
});
return (
<li className="gf-tabs-item" key={tab.url}>
<a className={tabClasses} href={tab.url}>
<i className={tab.icon} />
{tab.text}
</a>
</li>
);
}
function Tabs({main}: {main: NavModelItem}) {
return <ul className="gf-tabs">{main.children.map(TabItem)}</ul>;
}
export default class PageHeader extends React.Component<IProps, any> {
constructor(props) {
super(props);
}
renderHeaderTitle(main) {
return (
<div className="page-header__inner">
<span className="page-header__logo">
{main.icon && <i className={`page-header__icon ${main.icon}`} />}
{main.img && <img className="page-header__img" src={main.img} />}
</span>
<div className="page-header__info-block">
<h1 className="page-header__title">{main.text}</h1>
{main.subTitle && <div className="page-header__sub-title">{main.subTitle}</div>}
{main.subType && (
<div className="page-header__stamps">
<i className={main.subType.icon} />
{main.subType.text}
</div>
)}
</div>
</div>
);
}
render() {
return (
<div className="page-header-canvas">
<div className="page-container">
<div className="page-header">
{this.renderHeaderTitle(this.props.model.main)}
{this.props.model.main.children && <Tabs main={this.props.model.main} />}
</div>
</div>
</div>
);
}
}
<div class="page-nav">
<div class="container">
<div class="page-breadcrumbs">
<a class="breadcrumb-item active" href="/">
<i class="fa fa-home"></i>
</a>
<a class="breadcrumb-item" ng-href="{{::item.url}}" ng-repeat="item in ctrl.model.breadcrumbs">
{{::item.text}}
</a>
</div>
<div class="page-breadcrumbs">
<a class="breadcrumb-item active" href="/">
<i class="fa fa-home"></i>
</a>
<a class="breadcrumb-item" ng-href="{{::item.url}}" ng-repeat="item in ctrl.model.breadcrumbs">
{{::item.text}}
</a>
</div>
</div>
......
......@@ -39,10 +39,10 @@ export function pageH1() {
return {
restrict: 'E',
template: `
<h1>
<i class="{{::model.node.icon}}" ng-if="::model.node.icon"></i>
<img ng-src="{{::model.node.img}}" ng-if="::model.node.img"></i>
{{model.node.text}}
<h1 class="page-header__title">
<i class="page-header__icon {{::model.header.icon}}" ng-if="::model.header.icon"></i>
<img class="page-header__img" ng-src="{{::model.header.img}}" ng-if="::model.header.img"></i>
{{model.header.text}}
</h1>
`,
scope: {
......
///<reference path="../headers/common.d.ts" />
import coreModule from 'app/core/core_module';
import config from 'app/core/config';
import _ from 'lodash';
export interface NavModelItem {
title: string;
text: string;
url: string;
icon?: string;
iconUrl?: string;
img?: string;
id: string;
active?: boolean;
hideFromTabs?: boolean;
divider?: boolean;
children: NavModelItem[];
}
export interface NavModel {
section: NavModelItem;
menu: NavModelItem[];
export class NavModel {
breadcrumbs: NavModelItem[];
main: NavModelItem;
node: NavModelItem;
constructor() {
this.breadcrumbs = [];
}
}
export class NavModelSrv {
......@@ -31,15 +39,32 @@ export class NavModelSrv {
getNav(...args) {
var children = this.navItems;
var nav = {breadcrumbs: [], node: null};
var nav = new NavModel();
for (let id of args) {
// if its a number then it's the index to use for main
if (_.isNumber(id)) {
nav.main = nav.breadcrumbs[id];
break;
}
let node = _.find(children, {id: id});
nav.breadcrumbs.push(node);
nav.node = node;
nav.main = node;
children = node.children;
}
if (nav.main.children) {
for (let item of nav.main.children) {
item.active = false;
if (item.url === nav.node.url) {
item.active = true;
}
}
}
return nav;
}
......
<navbar model="ctrl.navModel"></navbar>
<div class="page-container">
<div class="page-header">
<page-h1 model="ctrl.navModel"></page-h1>
</div>
<page-header model="ctrl.navModel" no-tabs="true"></page-header>
<div class="page-container page-body">
<section class="card-section card-list-layout-grid">
<ol class="card-list">
<li class="card-item-wrapper" ng-repeat="navItem in ctrl.navModel.node.children">
......@@ -29,4 +26,4 @@
</li>
</ol>
</section>
</div>
\ No newline at end of file
</div>
......@@ -23,7 +23,7 @@ export class AlertListCtrl {
/** @ngInject */
constructor(private backendSrv, private $location, navModelSrv) {
this.navModel = navModelSrv.getNav('alerting');
this.navModel = navModelSrv.getNav('alerting', 'alert-list', 0);
var params = $location.search();
this.filters.state = params.state || null;
......
......@@ -9,7 +9,7 @@ export class AlertNotificationEditCtrl {
testSeverity = "critical";
notifiers: any;
notifierTemplateId: string;
isNew: boolean;
model: any;
defaults: any = {
type: 'email',
......@@ -23,7 +23,8 @@ export class AlertNotificationEditCtrl {
/** @ngInject */
constructor(private $routeParams, private backendSrv, private $location, private $templateCache, navModelSrv) {
this.navModel = navModelSrv.getNav('alerting', 'channels');
this.navModel = navModelSrv.getNav('alerting', 'channels', 0);
this.isNew = !this.$routeParams.id;
this.backendSrv.get(`/api/alert-notifiers`).then(notifiers => {
this.notifiers = notifiers;
......
......@@ -9,7 +9,7 @@ export class AlertNotificationsListCtrl {
/** @ngInject */
constructor(private backendSrv, navModelSrv) {
this.loadNotifications();
this.navModel = navModelSrv.getNav('alerting', 'channels');
this.navModel = navModelSrv.getNav('alerting', 'channels', 0);
}
loadNotifications() {
......
<navbar model="ctrl.navModel"></navbar>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container" >
<div class="page-header">
<page-h1 model="ctrl.navModel"></page-h1>
<div class="page-container page-body">
<a class="btn btn-secondary" ng-click="ctrl.openHowTo()">
<i class="fa fa-info-circle"></i>
How to add an alert
</a>
<a class="btn btn-inverse" href="alerting/notifications" >
<i class="fa fa-bell"></i>
Notification channels
</a>
</div>
<div class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label">Filter by state</label>
<div class="gf-form-select-wrapper width-13">
<select class="gf-form-input" ng-model="ctrl.filters.state" ng-options="f.value as f.text for f in ctrl.stateFilters" ng-change="ctrl.filtersChanged()">
</select>
</div>
<div class="page-action-bar">
<div class="gf-form">
<label class="gf-form-label">Filter by state</label>
<div class="gf-form-select-wrapper width-13">
<select class="gf-form-input" ng-model="ctrl.filters.state" ng-options="f.value as f.text for f in ctrl.stateFilters" ng-change="ctrl.filtersChanged()">
</select>
</div>
</div>
<div class="page-action-bar__spacer">
</div>
<a class="btn btn-secondary" ng-click="ctrl.openHowTo()">
<i class="fa fa-info-circle"></i>
How to add an alert
</a>
</div>
<section class="card-section card-list-layout-list">
......
<navbar model="ctrl.navModel"></navbar>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container">
<div class="page-header">
<page-h1 model="ctrl.navModel"></page-h1>
</div>
<div class="page-container page-body">
<h3 class="page-sub-heading" ng-hide="ctrl.isNew">Edit Notification Channel</h3>
<h3 class="page-sub-heading" ng-show="ctrl.isNew">New Notification Channel</h3>
<form name="ctrl.theForm" ng-if="ctrl.notifiers">
<div class="gf-form-group">
......
<navbar model="ctrl.navModel"></navbar>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container" >
<div class="page-header">
<page-h1 model="ctrl.navModel"></page-h1>
<div class="page-container page-body">
<div class="page-action-bar">
<div class="page-action-bar__spacer">
</div>
<a href="alerting/notification/new" class="btn btn-success pull-right">
<a href="alerting/notification/new" class="btn btn-success">
<i class="fa fa-plus"></i>
New Channel
</a>
</div>
......
......@@ -17,7 +17,7 @@ export class DashboardListCtrl {
/** @ngInject */
constructor(private backendSrv, navModelSrv, private $q, private searchSrv: SearchSrv) {
this.navModel = navModelSrv.getNav('dashboards', 'dashboards');
this.navModel = navModelSrv.getNav('dashboards', 'dashboards', 0);
this.query = {query: '', mode: 'tree', tag: [], starred: false};
this.selectedStarredFilter = this.starredFilterOptions[0];
......
<navbar model="ctrl.navModel"></navbar>
<div class="page-container" style="height: 95%">
<div class="page-header">
<h1>Dashboards</h1>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container page-body">
<div class="page-action-bar">
<div class="gf-form width-15">
<label class="gf-form-label">Search</label>
<input type="text" class="gf-form-input" placeholder="Find Dashboard by name" tabindex="1" give-focus="true" ng-model="ctrl.query.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.onQueryChange()" />
</div>
<div class="page-action-bar__spacer"></div>
<a class="btn btn-inverse" href="/dashboard/new">
<i class="gicon gicon-dashboard-new"></i>
Dashboard
......@@ -12,14 +16,6 @@
Folder
</a>
</div>
<div class="gf-form-group">
<div class="gf-form width-15">
<span style="position: relative;">
<input type="text" class="gf-form-input" placeholder="Find Dashboard by name" tabindex="1" give-focus="true"
ng-model="ctrl.query.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.onQueryChange()" />
</span>
</div>
</div>
<div class="gf-form" ng-if="ctrl.query.tag.length">
Filters:
......
......@@ -5,6 +5,7 @@ import './select_org_ctrl';
import './change_password_ctrl';
import './new_org_ctrl';
import './user_invite_ctrl';
import './user_groups_ctrl';
import './org_api_keys_ctrl';
import './org_details_ctrl';
import './prefs_control';
......@@ -4,7 +4,7 @@ export class OrgApiKeysCtrl {
/** @ngInject **/
constructor ($scope, $http, backendSrv, navModelSrv) {
$scope.navModel = navModelSrv.getNav('cfg', 'apikeys');
$scope.navModel = navModelSrv.getNav('cfg', 'apikeys', 0);
$scope.roleTypes = ['Viewer', 'Editor', 'Admin'];
$scope.token = { role: 'Viewer' };
......
......@@ -6,7 +6,7 @@ export class OrgDetailsCtrl {
constructor($scope, $http, backendSrv, contextSrv, navModelSrv) {
$scope.init = function() {
$scope.getOrgInfo();
$scope.navModel = navModelSrv.getNav('cfg', 'org');
$scope.navModel = navModelSrv.getNav('cfg', 'org-settings', 0);
};
$scope.getOrgInfo = function() {
......
......@@ -23,7 +23,7 @@ export class OrgUsersCtrl {
role: 'Viewer',
};
this.navModel = navModelSrv.getNav('cfg', 'users');
this.navModel = navModelSrv.getNav('cfg', 'users', 0);
this.get();
this.editor = { index: 0 };
......@@ -44,8 +44,7 @@ export class OrgUsersCtrl {
if (this.externalUserMngLinkName) {
return this.externalUserMngLinkName;
}
return "Add Members";
return "Add Member";
}
get() {
......
<navbar model="navModel"></navbar>
<page-header model="navModel"></page-header>
<div class="page-container">
<div class="page-header">
<page-h1 model="navModel"></page-h1>
</div>
<div class="page-container page-body">
<h3 class="section-heading">Add new</h3>
<h3 class="page-heading">Add new</h3>
<form name="addTokenForm" class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form max-width-21">
......@@ -22,7 +20,7 @@
</div>
</form>
<h3 class="page-heading">Existing Keys</h3>
<h3 class="section-heading">Existing Keys</h3>
<table class="filter-table">
<thead>
<tr>
......
<navbar model="navModel"></navbar>
<!-- <div class="page&#45;header&#45;canvas"> -->
<!-- <div class="page&#45;container" > -->
<!-- <navbar model="navModel"></navbar> -->
<!-- -->
<!-- <div class="page&#45;header"> -->
<!-- <page&#45;h1 model="navModel"></page&#45;h1> -->
<!-- -->
<!-- <ul class="gf&#45;tabs"> -->
<!-- <li class="gf&#45;tabs&#45;item"> -->
<!-- <a class="gf&#45;tabs&#45;link active" href="org"> -->
<!-- <i class="fa fa&#45;fw fa&#45;sliders"></i> -->
<!-- Preferences -->
<!-- </a> -->
<!-- </li> -->
<!-- <li class="gf&#45;tabs&#45;item"> -->
<!-- <a class="gf&#45;tabs&#45;link" href="org/users"> -->
<!-- <i class="icon&#45;gf icon&#45;gf&#45;fw icon&#45;gf&#45;users"></i> -->
<!-- Members -->
<!-- </a> -->
<!-- </li> -->
<!-- <li class="gf&#45;tabs&#45;item"> -->
<!-- <a class="gf&#45;tabs&#45;link" href="org/user&#45;groups"> -->
<!-- <i class="gicon gicon&#45;user&#45;group"></i> -->
<!-- Teams -->
<!-- </a> -->
<!-- </li> -->
<!-- </ul> -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<div class="page-container">
<div class="page-header">
<page-h1 model="navModel"></page-h1>
</div>
<page-header model="navModel"></page-header>
<h3 class="page-heading">General</h3>
<form name="orgForm" class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form max-width-28">
<span class="gf-form-label">Organization name</span>
<input class="gf-form-input" type="text" required ng-model="org.name">
</div>
</div>
<div class="page-container page-body">
<h3 class="page-sub-heading">Organization profile</h3>
<form name="orgForm" class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form max-width-28">
<span class="gf-form-label">Organization name</span>
<input class="gf-form-input" type="text" required ng-model="org.name">
</div>
</div>
<div class="gf-form-button-row">
<button type="submit" class="btn btn-success" ng-click="update()">Save</button>
</div>
</form>
<prefs-control mode="org"></prefs-control>
</form>
<prefs-control mode="org"></prefs-control>
</div>
<navbar model="ctrl.navModel"></navbar>
<!-- <navbar model="ctrl.navModel"></navbar> -->
<!-- -->
<!-- <div class="page&#45;container"> -->
<!-- <div class="page&#45;header"> -->
<!-- <page&#45;h1 model="ctrl.navModel"></page&#45;h1> -->
<!-- -->
<!-- <button class="btn btn&#45;success" ng&#45;click="ctrl.openAddUsersView()" ng&#45;hide="ctrl.externalUserMngLinkUrl"> -->
<!-- <span>{{ctrl.addUsersBtnName}}</span> -->
<!-- </button> -->
<!-- -->
<!-- <div class="page&#45;header&#45;tabs"> -->
<!-- -->
<!-- <a class="btn btn&#45;inverse" ng&#45;href="{{ctrl.externalUserMngLinkUrl}}" target="_blank" ng&#45;if="ctrl.externalUserMngLinkUrl"> -->
<!-- <i class="fa fa&#45;external&#45;link&#45;square"></i> -->
<!-- {{ctrl.addUsersBtnName}} -->
<!-- </a> -->
<!-- -->
<!-- <ul class="gf&#45;tabs"> -->
<!-- <li class="gf&#45;tabs&#45;item"> -->
<!-- <a class="gf&#45;tabs&#45;link" ng&#45;click="ctrl.editor.index = 0" ng&#45;class="{active: ctrl.editor.index === 0}"> -->
<!-- Users ({{ctrl.users.length}}) -->
<!-- </a> -->
<!-- </li> -->
<!-- <li class="gf&#45;tabs&#45;item" ng&#45;show="ctrl.pendingInvites.length"> -->
<!-- <a class="gf&#45;tabs&#45;link" ng&#45;click="ctrl.editor.index = 1" ng&#45;class="{active: ctrl.editor.index === 1}"> -->
<!-- Pending Invites ({{ctrl.pendingInvites.length}}) -->
<!-- </a> -->
<!-- </li> -->
<!-- </ul> -->
<!-- </div> -->
<!-- </div> -->
<div class="page-container">
<div class="page-header">
<page-h1 model="ctrl.navModel"></page-h1>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container page-body">
<div class="page-action-bar">
<div class="page-action-bar__spacer"></div>
<button class="btn btn-inverse" ng-show="ctrl.pendingInvites.length" ng-click="ctrl.editor.index = 1">
Pending Invites ({{ctrl.pendingInvites.length}})
</button>
<button class="btn btn-success" ng-click="ctrl.openAddUsersView()" ng-hide="ctrl.externalUserMngLinkUrl">
<i class="fa fa-plus"></i>
<span>{{ctrl.addUsersBtnName}}</span>
</button>
<div class="page-header-tabs">
<a class="btn btn-inverse" ng-href="{{ctrl.externalUserMngLinkUrl}}" target="_blank" ng-if="ctrl.externalUserMngLinkUrl">
<i class="fa fa-external-link-square"></i>
{{ctrl.addUsersBtnName}}
</a>
<ul class="gf-tabs">
<li class="gf-tabs-item">
<a class="gf-tabs-link" ng-click="ctrl.editor.index = 0" ng-class="{active: ctrl.editor.index === 0}">
Users ({{ctrl.users.length}})
</a>
</li>
<li class="gf-tabs-item" ng-show="ctrl.pendingInvites.length">
<a class="gf-tabs-link" ng-click="ctrl.editor.index = 1" ng-class="{active: ctrl.editor.index === 1}">
Pending Invites ({{ctrl.pendingInvites.length}})
</a>
</li>
</ul>
</div>
</div>
<a class="btn btn-inverse" ng-href="{{ctrl.externalUserMngLinkUrl}}" target="_blank" ng-if="ctrl.externalUserMngLinkUrl">
<i class="fa fa-external-link-square"></i>
{{ctrl.addUsersBtnName}}
</a>
</div>
<div class="grafana-info-box" ng-if="ctrl.externalUserMngInfo">
<span ng-bind-html="ctrl.externalUserMngInfo"></span>
......@@ -41,26 +59,26 @@
<th></th>
<th>Login</th>
<th>Email</th>
<th>
Seen
<tip>Time since user was seen using Grafana</tip>
</th>
<th>
Seen
<tip>Time since user was seen using Grafana</tip>
</th>
<th>Role</th>
<th style="width: 34px;"></th>
</tr>
</thead>
<tr ng-repeat="user in ctrl.users">
<td class="width-4 text-center">
<img class="filter-table__avatar" ng-src="{{user.avatarUrl}}"></img>
</td>
<img class="filter-table__avatar" ng-src="{{user.avatarUrl}}"></img>
</td>
<td>{{user.login}}</td>
<td><span class="ellipsis">{{user.email}}</span></td>
<td>{{user.lastSeenAtAge}}</td>
<td>{{user.lastSeenAtAge}}</td>
<td>
<div class="gf-form-select-wrapper width-9">
<select type="text" ng-model="user.role" class="gf-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']" ng-change="ctrl.updateOrgUser(user)">
</select>
</div>
<div class="gf-form-select-wrapper width-9">
<select type="text" ng-model="user.role" class="gf-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']" ng-change="ctrl.updateOrgUser(user)">
</select>
</div>
</td>
<td>
<a ng-click="ctrl.removeUser(user)" class="btn btn-danger btn-mini">
......
<navbar model="ctrl.navModel"></navbar>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container">
<div class="page-header">
<page-h1 model="ctrl.navModel"></page-h1>
</div>
<div class="page-container page-body">
<h3 class="page-sub-heading">User Profile</h3>
<form name="ctrl.userForm" class="gf-form-group">
<h3 class="page-heading">Information</h3>
<div class="gf-form max-width-30">
<span class="gf-form-label width-8">Name</span>
......
<navbar model="ctrl.navModel"></navbar>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container">
<div class="page-header">
<h1>User Groups</h1>
<div class="page-container page-body">
<div class="page-action-bar">
<div class="gf-form width-15">
<label class="gf-form-label">Search</label>
<input type="text" class="gf-form-input" placeholder="Find User Group by name" tabindex="1" give-focus="true"
ng-model="ctrl.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.get()" />
</div>
<div class="page-action-bar__spacer"></div>
<a class="btn btn-success" ng-click="ctrl.openUserGroupModal()">
<i class="fa fa-plus"></i>
Create User Group
</a>
</div>
<div class="gf-form width-15 gf-form-group">
<span style="position: relative;">
<input type="text" class="gf-form-input" placeholder="Find User Group by name" tabindex="1" give-focus="true"
ng-model="ctrl.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.get()" />
</span>
</div>
<div class="admin-list-table">
<table class="filter-table form-inline" ng-show="ctrl.userGroups.length > 0">
<thead>
......@@ -42,7 +44,6 @@
</td>
</tr>
</tbody>
</table>
</div>
......
......@@ -49,7 +49,7 @@ export class PrefsControlCtrl {
var template = `
<form name="ctrl.prefsForm" class="section gf-form-group">
<h3 class="page-heading">Preferences</h3>
<h3 class="section-heading">Preferences</h3>
<div class="gf-form">
<span class="gf-form-label width-11">UI Theme</span>
......
......@@ -14,7 +14,7 @@ export class ProfileCtrl {
constructor(private backendSrv, private contextSrv, private $location, navModelSrv) {
this.getUser();
this.getUserOrgs();
this.navModel = navModelSrv.getNav('profile');
this.navModel = navModelSrv.getNav('profile', 'profile-settings', 0);
}
getUser() {
......
......@@ -15,7 +15,7 @@ export class UserGroupsCtrl {
/** @ngInject */
constructor(private backendSrv, navModelSrv) {
this.navModel = navModelSrv.getNav('cfg', 'users');
this.navModel = navModelSrv.getNav('cfg', 'teams', 0);
this.get();
}
......
<navbar model="ctrl.navModel"></navbar>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container" ng-form="playlistEditForm">
<div class="page-header">
<page-h1 model="ctrl.navModel"></page-h1>
</div>
<div class="page-container page-body" ng-form="playlistEditForm">
<h3 class="page-sub-heading" ng-hide="ctrl.isNew">Edit Playlist</h3>
<h3 class="page-sub-heading" ng-show="ctrl.isNew">New Playlist</h3>
<p class="playlist-description">A playlist rotates through a pre-selected list of Dashboards. A Playlist can be a great way to build situational awareness, or just show off your metrics to your team or visitors.</p>
......@@ -103,7 +103,7 @@
<div class="clearfix"></div>
<div class="gf-form-button-row">
<a class="btn btn-success " ng-show="ctrl.isNew()"
<a class="btn btn-success " ng-show="ctrl.isNew"
ng-disabled="ctrl.playlistEditForm.$invalid || ctrl.isPlaylistEmpty()"
ng-click="ctrl.savePlaylist(ctrl.playlist, ctrl.playlistItems)">Create new playlist</a>
<a class="btn btn-success" ng-show="!ctrl.isNew()"
......
<navbar model="ctrl.navModel"></navbar>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container">
<div class="page-header">
<page-h1 model="ctrl.navModel"></page-h1>
<a class="btn btn-primary pull-right" href="playlists/create">
<div class="page-container page-body">
<div class="page-action-bar">
<div class="page-action-bar__spacer"></div>
<a class="btn btn-success pull-right" href="playlists/create">
<i class="fa fa-plus"></i>
New Playlist
</a>
</div>
<table class="filter-table" style="margin-top: 20px">
<table class="filter-table">
<thead>
<th><strong>Name</strong></th>
<th><strong>Start url</strong></th>
......
///<reference path="../../headers/common.d.ts" />
import _ from 'lodash';
import coreModule from '../../core/core_module';
......@@ -11,10 +9,12 @@ export class PlaylistEditCtrl {
playlist: any = {
interval: '5m',
};
playlistItems: any = [];
dashboardresult: any = [];
tagresult: any = [];
navModel: any;
isNew: boolean;
/** @ngInject */
constructor(
......@@ -24,7 +24,9 @@ export class PlaylistEditCtrl {
$route,
navModelSrv
) {
this.navModel = navModelSrv.getNav('dashboards', 'playlists');
this.navModel = navModelSrv.getNav('dashboards', 'playlists', 0);
this.isNew = $route.current.params.id;
if ($route.current.params.id) {
var playlistId = $route.current.params.id;
......@@ -104,10 +106,6 @@ export class PlaylistEditCtrl {
});
}
isNew() {
return !this.playlist.id;
}
isPlaylistEmpty() {
return !this.playlistItems.length;
}
......
......@@ -9,7 +9,7 @@ export class PlaylistsCtrl {
/** @ngInject */
constructor(private $scope, private backendSrv, navModelSrv) {
this.navModel = navModelSrv.getNav('dashboards', 'playlists');
this.navModel = navModelSrv.getNav('dashboards', 'playlists', 0);
backendSrv.get('/api/playlists').then(result => {
this.playlists = result;
......
......@@ -41,7 +41,7 @@ export class DataSourceEditCtrl {
navModelSrv,
) {
this.navModel = navModelSrv.getNav('cfg', 'datasources');
this.navModel = navModelSrv.getNav('cfg', 'datasources', 0);
this.datasources = [];
this.tabIndex = 0;
......@@ -58,9 +58,7 @@ export class DataSourceEditCtrl {
this.isNew = true;
this.current = _.cloneDeep(defaults);
// add to nav & breadcrumbs
this.navModel.node = {text: 'New data source', icon: 'icon-gf icon-gf-fw icon-gf-datasources'};
this.navModel.breadcrumbs.push(this.navModel.node);
this.navModel.breadcrumbs.push({text: 'New'});
// We are coming from getting started
if (this.$location.search().gettingstarted) {
......@@ -87,7 +85,7 @@ export class DataSourceEditCtrl {
this.backendSrv.get('/api/datasources/' + id).then(ds => {
this.isNew = false;
this.current = ds;
this.navModel.node = {text: ds.name, icon: 'icon-gf icon-gf-fw icon-gf-datasources'};
this.navModel.node = {text: ds.name, icon: 'icon-gf icon-gf-fw icon-gf-datasources', id: 'ds-new'};
this.navModel.breadcrumbs.push(this.navModel.node);
if (datasourceCreated) {
......
......@@ -13,7 +13,7 @@ export class DataSourcesCtrl {
private datasourceSrv,
private navModelSrv) {
this.navModel = this.navModelSrv.getNav('cfg', 'datasources');
this.navModel = this.navModelSrv.getNav('cfg', 'datasources', 0);
backendSrv.get('/api/datasources').then(result => {
this.datasources = result;
......
......@@ -13,12 +13,6 @@
{{dash.title}}
</span>
</td>
<td>
<span>
Revision: {{dash.revision}}
<span ng-if="dash.imported" class="small">(Imported: {{dash.importedRevision}})</span>
<span>
</td>
<td style="text-align: right">
<button class="btn btn-secondary btn-small" ng-click="ctrl.import(dash, false)" ng-show="!dash.imported">
Import
......
<navbar model="ctrl.navModel"></navbar>
<div class="page-container">
<div class="page-header">
<page-h1 model="ctrl.navModel"></page-h1>
<page-header model="ctrl.navModel"></page-header>
<div ng-if="ctrl.current.readOnly" class="grafana-info-box span8">Disclaimer. This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource.</div>
<div class="page-container page-body">
<div class="page-header-tabs" ng-show="ctrl.hasDashboards">
<ul class="gf-tabs">
<li class="gf-tabs-item">
<a class="gf-tabs-link" ng-click="ctrl.tabIndex = 0" ng-class="{active: ctrl.tabIndex === 0}">
Config
</a>
</li>
<li class="gf-tabs-item">
<a class="gf-tabs-link" ng-click="ctrl.tabIndex = 1" ng-class="{active: ctrl.tabIndex === 1}">
Dashboards
</a>
</li>
</ul>
</div>
</div>
<div ng-if="ctrl.current.readOnly" class="page-action-bar">
<div class="grafana-info-box span8">
Disclaimer. This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource.
</div>
</div>
<div ng-if="ctrl.tabIndex === 0" class="tab-content">
<h3 class="page-sub-heading" ng-hide="ctrl.isNew">Edit Data Source</h3>
<h3 class="page-sub-heading" ng-show="ctrl.isNew">New Data Source</h3>
<form name="ctrl.editForm" ng-if="ctrl.current">
<div class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">Name</span>
<input class="gf-form-input max-width-23" type="text" ng-model="ctrl.current.name" placeholder="name" required>
<info-popover offset="0px -135px" mode="right-absolute">
The name is used when you select the data source in panels.
The <em>Default</em> data source is preselected in new
panels.
</info-popover>
</div>
<gf-form-switch class="gf-form" label="Default" checked="ctrl.current.isDefault" switch-class="max-width-6"></gf-form-switch>
</div>
<form name="ctrl.editForm" ng-if="ctrl.current">
<div class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">Name</span>
<input class="gf-form-input max-width-23" type="text" ng-model="ctrl.current.name" placeholder="name" required>
<info-popover offset="0px -135px" mode="right-absolute">
The name is used when you select the data source in panels.
The <em>Default</em> data source is preselected in new
panels.
</info-popover>
</div>
<gf-form-switch class="gf-form" label="Default" checked="ctrl.current.isDefault" switch-class="max-width-6"></gf-form-switch>
</div>
<div class="gf-form">
<span class="gf-form-label width-7">Type</span>
<div class="gf-form-select-wrapper max-width-23">
<select class="gf-form-input" ng-model="ctrl.current.type" ng-options="v.id as v.name for v in ctrl.types" ng-change="ctrl.userChangedType()"></select>
</div>
</div>
</div>
<div class="gf-form">
<span class="gf-form-label width-7">Type</span>
<div class="gf-form-select-wrapper max-width-23">
<select class="gf-form-input" ng-model="ctrl.current.type" ng-options="v.id as v.name for v in ctrl.types" ng-change="ctrl.userChangedType()"></select>
</div>
</div>
</div>
<div class="alert alert-info gf-form-group" ng-if="ctrl.datasourceMeta.state === 'alpha'">
This plugin is marked as being in alpha state, which means it is in early development phase and
updates will include breaking changes.
</div>
<div class="alert alert-info gf-form-group" ng-if="ctrl.datasourceMeta.state === 'alpha'">
This plugin is marked as being in alpha state, which means it is in early development phase and
updates will include breaking changes.
</div>
<rebuild-on-change property="ctrl.datasourceMeta.id">
<plugin-component type="datasource-config-ctrl">
</plugin-component>
</rebuild-on-change>
<rebuild-on-change property="ctrl.datasourceMeta.id">
<plugin-component type="datasource-config-ctrl">
</plugin-component>
</rebuild-on-change>
<div ng-if="ctrl.testing" class="gf-form-group section">
<h5 ng-show="!ctrl.testing.done">Testing.... <i class="fa fa-spiner fa-spin"></i></h5>
<div class="alert-{{ctrl.testing.status}} alert" ng-show="ctrl.testing.done">
<div class="alert-icon">
<i class="fa fa-exclamation-triangle" ng-show="ctrl.testing.status === 'error'"></i>
<i class="fa fa-check" ng-show="ctrl.testing.status !== 'error'"></i>
</div>
<div class="alert-body">
<div class="alert-title">{{ctrl.testing.message}}</div>
</div>
</div>
</div>
<div ng-if="ctrl.hasDashboards">
<h3 class="section-heading">Bundled Plugin Dashboards</h3>
<div class="section">
<dashboard-import-list plugin="ctrl.datasourceMeta" datasource="ctrl.current"></dashboard-import-list>
</div>
</div>
<div class="gf-form-button-row">
<button type="submit" class="btn btn-success" ng-disabled="ctrl.current.readOnly" ng-click="ctrl.saveChanges()">Save</button>
<button type="submit" class="btn btn-danger" ng-disabled="ctrl.current.readOnly" ng-show="!ctrl.isNew" ng-click="ctrl.delete()">
Delete
</button>
<a class="btn btn-link" href="datasources">Cancel</a>
</div>
<div ng-if="ctrl.testing" class="gf-form-group section">
<h5 ng-show="!ctrl.testing.done">Testing.... <i class="fa fa-spiner fa-spin"></i></h5>
<div class="alert-{{ctrl.testing.status}} alert" ng-show="ctrl.testing.done">
<div class="alert-icon">
<i class="fa fa-exclamation-triangle" ng-show="ctrl.testing.status === 'error'"></i>
<i class="fa fa-check" ng-show="ctrl.testing.status !== 'error'"></i>
</div>
<div class="alert-body">
<div class="alert-title">{{ctrl.testing.message}}</div>
</div>
</div>
</div>
<br />
<br />
<br />
<div class="gf-form-button-row">
<button type="submit" class="btn btn-success" ng-disabled="ctrl.current.readOnly" ng-click="ctrl.saveChanges()">Save</button>
<button type="submit" class="btn btn-danger" ng-disabled="ctrl.current.readOnly" ng-show="!ctrl.isNew" ng-click="ctrl.delete()">
Delete
</button>
<a class="btn btn-link" href="datasources">Cancel</a>
</div>
</form>
</div>
<div ng-if="ctrl.tabIndex === 1" class="tab-content">
<dashboard-import-list plugin="ctrl.datasourceMeta" datasource="ctrl.current"></dashboard-import-list>
</div>
<br />
<br />
<br />
</form>
</div>
<div class="gf-form-group">
<h3 class="page-heading">HTTP settings</h3>
<h3 class="section-heading">HTTP</h3>
<div class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form max-width-30">
......@@ -38,39 +38,38 @@
</div>
</div>
<h3 class="page-heading">HTTP Auth</h3>
<div class="gf-form-group">
<div class="gf-form-inline">
<gf-form-switch class="gf-form" label="Basic Auth" checked="current.basicAuth" label-class="width-8" switch-class="max-width-6"></gf-form-switch>
<gf-form-switch class="gf-form" label="With Credentials" tooltip="Whether credentials such as cookies or auth headers should be sent with cross-site requests." checked="current.withCredentials" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
</div>
<div class="gf-form-inline">
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="TLS Client Auth" label-class="width-8" checked="current.jsonData.tlsAuth" switch-class="max-width-6"></gf-form-switch>
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="With CA Cert" tooltip="Needed for verifing self-signed TLS Certs" checked="current.jsonData.tlsAuthWithCACert" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
</div>
<h3 class="section-heading">Auth</h3>
<div class="gf-form-group">
<div class="gf-form-inline">
<gf-form-switch class="gf-form" label="Basic Auth" checked="current.basicAuth" label-class="width-8" switch-class="max-width-6"></gf-form-switch>
<gf-form-switch class="gf-form" label="With Credentials" tooltip="Whether credentials such as cookies or auth headers should be sent with cross-site requests." checked="current.withCredentials" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
</div>
<div class="gf-form-inline">
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="Skip TLS Verification (Insecure)" label-class="width-16" checked="current.jsonData.tlsSkipVerify" switch-class="max-width-6"></gf-form-switch>
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="TLS Client Auth" label-class="width-8" checked="current.jsonData.tlsAuth" switch-class="max-width-6"></gf-form-switch>
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="With CA Cert" tooltip="Needed for verifing self-signed TLS Certs" checked="current.jsonData.tlsAuthWithCACert" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
</div>
</div>
<div class="gf-form-inline">
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="Skip TLS Verification (Insecure)" label-class="width-16" checked="current.jsonData.tlsSkipVerify" switch-class="max-width-6"></gf-form-switch>
</div>
</div>
<div class="gf-form-group" ng-if="current.basicAuth">
<h6>Basic Auth Details</h6>
<div class="gf-form" ng-if="current.basicAuth">
<span class="gf-form-label width-7">
User
</span>
<input class="gf-form-input max-width-21" type="text" ng-model='current.basicAuthUser' placeholder="user" required></input>
</div>
<div class="gf-form" ng-if="current.basicAuth">
<span class="gf-form-label width-7">
User
</span>
<input class="gf-form-input max-width-21" type="text" ng-model='current.basicAuthUser' placeholder="user" required></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-7">
Password
</span>
<input class="gf-form-input max-width-21" type="password" ng-model='current.basicAuthPassword' placeholder="password" required></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-7">
Password
</span>
<input class="gf-form-input max-width-21" type="password" ng-model='current.basicAuthPassword' placeholder="password" required></input>
</div>
</div>
<div class="gf-form-group" ng-if="(current.jsonData.tlsAuth || current.jsonData.tlsAuthWithCACert) && current.access=='proxy'">
......
<navbar model="ctrl.navModel"></navbar>
<div class="page-container">
<div class="page-header">
<page-h1 model="ctrl.navModel"></page-h1>
<page-header model="ctrl.navModel"></page-header>
<a class="page-header__cta btn btn-success" href="datasources/new">
Add data source
</a>
<div class="page-container page-body">
<div class="page-action-bar">
<div class="page-action-bar__spacer"></div>
<a class="page-header__cta btn btn-success" href="datasources/new">
<i class="fa fa-plus"></i>
Add data source
</a>
</div>
<section class="card-section" layout-mode>
<layout-selector></layout-selector>
<ol class="card-list">
<li class="card-item-wrapper" ng-repeat="ds in ctrl.datasources">
<a class="card-item" href="datasources/edit/{{ds.id}}/">
......@@ -43,4 +43,4 @@
<div ng-if="ctrl.datasources.length === 0">
<em>No data sources defined</em>
</div>
</div>
\ No newline at end of file
</div>
<navbar model="ctrl.navModel"></navbar>
<div class="page-container" ng-init="ctrl.init()">
<div class="page-header">
<div class="plugin-header">
<span class="plugin-header-logo">
<img ng-src="{{ctrl.model.info.logos.large}}">
</span>
<div class="plugin-header-info-block">
<h1 class="plugin-header-name">{{ctrl.model.name}}</h1>
<div class="plugin-header-author">By {{ctrl.model.info.author.name}}</div>
<div class="plugin-header-stamps">
<span class="plugin-header-stamps-type">
<i class="{{ctrl.pluginIcon}}"></i> {{ctrl.model.type}}
</span>
</div>
</div>
</div>
<ul class="gf-tabs">
<li class="gf-tabs-item" ng-repeat="tab in ctrl.tabs">
<a class="gf-tabs-link" ng-click="ctrl.tabIndex = $index" ng-class="{active: ctrl.tabIndex === $index}">
{{::tab}}
</a>
</li>
</ul>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container page-body" ng-init="ctrl.init()">
<div class="page-action-bar">
<button class="btn" ng-repeat="tab in ctrl.tabs" ng-class="{'btn-secondary': ctrl.tabIndex === $index, 'btn-inverse': ctrl.tabIndex !== $index}" ng-click="ctrl.tabIndex = $index">
{{tab}}
</button>
</div>
<div class="page-body">
<div class="tab-content page-content-with-sidebar" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Readme'">
<div class="sidebar-container">
<div class="tab-content sidebar-content" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Readme'">
<div ng-bind-html="ctrl.readmeHtml" class="markdown-html">
</div>
</div>
<div class="tab-content page-content-with-sidebar" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Config'">
<div class="tab-content sidebar-content" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Config'">
<div ng-if="ctrl.model.id">
<plugin-component type="app-config-ctrl"></plugin-component>
<div class="gf-form-button-row">
<button type="submit" class="btn btn-success" ng-click="ctrl.enable()" ng-show="!ctrl.model.enabled">Enable</button>
<button type="submit" class="btn btn-success" ng-click="ctrl.update()" ng-show="ctrl.model.enabled">Update</button>
<button type="submit" class="btn btn-danger" ng-click="ctrl.disable()" ng-show="ctrl.model.enabled">Disable</button>
</div>
<div class="gf-form-button-row">
<button type="submit" class="btn btn-success" ng-click="ctrl.enable()" ng-show="!ctrl.model.enabled">Enable</button>
<button type="submit" class="btn btn-success" ng-click="ctrl.update()" ng-show="ctrl.model.enabled">Update</button>
<button type="submit" class="btn btn-danger" ng-click="ctrl.disable()" ng-show="ctrl.model.enabled">Disable</button>
</div>
</div>
</div>
<div class="tab-content page-content-with-sidebar" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Dashboards'">
<dashboard-import-list plugin="ctrl.model"></dashboard-import-list>
<div class="tab-content sidebar.content" ng-if="ctrl.tabs[ctrl.tabIndex] === 'Dashboards'">
<dashboard-import-list plugin="ctrl.model"></dashboard-import-list>
</div>
<aside class="page-sidebar">
<section class="page-sidebar-section">
<h4>Version</h4>
<span>{{ctrl.model.info.version}}</span>
<div ng-show="ctrl.model.hasUpdate">
<div ng-show="ctrl.model.hasUpdate">
<a ng-click="ctrl.updateAvailable()" bs-tooltip="ctrl.model.latestVersion">Update Available!</a>
</div>
</div>
</section>
<section class="page-sidebar-section" ng-show="ctrl.model.type === 'app'">
<h5>Includes</h4>
......
<navbar model="ctrl.navModel"></navbar>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container">
<div class="page-header">
<h1>
<i class="icon-gf icon-gf-apps"></i>
Plugins <span class="muted small">(currently installed)</span>
</h1>
<!-- <div class="page&#45;header&#45;canvas"> -->
<!-- <div class="page&#45;container"> -->
<!-- <navbar model="ctrl.navModel"></navbar> -->
<!-- -->
<!-- <div class="page&#45;header"> -->
<!-- <page&#45;h1 model="ctrl.navModel"></page&#45;h1> -->
<!-- -->
<!-- <div class="page&#45;header&#45;tabs"> -->
<!-- <ul class="gf&#45;tabs"> -->
<!-- <li class="gf&#45;tabs&#45;item"> -->
<!-- <a class="gf&#45;tabs&#45;link" href="plugins?type=panel" ng&#45;class="{active: ctrl.tabIndex === 0}"> -->
<!-- <i class="icon&#45;gf icon&#45;gf&#45;panel"></i> -->
<!-- Panels -->
<!-- </a> -->
<!-- </li> -->
<!-- <li class="gf&#45;tabs&#45;item"> -->
<!-- <a class="gf&#45;tabs&#45;link" href="plugins?type=datasource" ng&#45;class="{active: ctrl.tabIndex === 1}"> -->
<!-- <i class="gicon gicon&#45;datasources"></i> -->
<!-- Data sources -->
<!-- </a> -->
<!-- </li> -->
<!-- <li class="gf&#45;tabs&#45;item"> -->
<!-- <a class="gf&#45;tabs&#45;link" href="plugins?type=app" ng&#45;class="{active: ctrl.tabIndex === 2}"> -->
<!-- <i class="icon&#45;gf icon&#45;gf&#45;apps"></i> -->
<!-- Apps -->
<!-- </a> -->
<!-- </li> -->
<!-- </ul> -->
<!-- -->
<!-- <a class="get&#45;more&#45;plugins&#45;link pull&#45;right" href="https://grafana.com/plugins?utm_source=grafana_plugin_list" target="_blank"> -->
<!-- Find more <img src="public/img/icn&#45;plugins&#45;tiny.svg" />plugins on Grafana.com -->
<!-- </a> -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<div class="page-header-tabs">
<ul class="gf-tabs">
<li class="gf-tabs-item">
<a class="gf-tabs-link" href="plugins?type=panel" ng-class="{active: ctrl.tabIndex === 0}">
Panels
</a>
</li>
<li class="gf-tabs-item">
<a class="gf-tabs-link" href="plugins?type=datasource" ng-class="{active: ctrl.tabIndex === 1}">
Data sources
</a>
</li>
<li class="gf-tabs-item">
<a class="gf-tabs-link" href="plugins?type=app" ng-class="{active: ctrl.tabIndex === 2}">
Apps
</a>
</li>
</ul>
<div class="page-container page-body">
<div class="page-action-bar">
<div class="gf-form">
<label class="gf-form-label">Search</label>
<input type="text" class="gf-form-input width-20" ng-model="ctrl.searchQuery" ng-change="ctrl.onQueryUpdated()" />
</div>
<a class="get-more-plugins-link" href="https://grafana.com/plugins?utm_source=grafana_plugin_list" target="_blank">
Find more <img src="public/img/icn-plugins-tiny.svg" />plugins on Grafana.com
</a>
</div>
<div class="page-action-bar__spacer"></div>
<a class="btn btn-success" href="https://grafana.com/plugins?utm_source=grafana_plugin_list" target="_blank">
Find more plugins on Grafana.com
</a>
</div>
<section class="card-section" layout-mode>
<layout-selector></layout-selector>
<section class="card-section" layout-mode>
<layout-selector></layout-selector>
<ol class="card-list" >
<li class="card-item-wrapper" ng-repeat="plugin in ctrl.plugins">
<a class="card-item" href="plugins/{{plugin.id}}/edit">
<div class="card-item-header">
<div class="card-item-type">
<i class="icon-gf icon-gf-{{plugin.type}}"></i>
{{plugin.type}}
</div>
<div class="card-item-notice" ng-show="plugin.hasUpdate">
<span bs-tooltip="plugin.latestVersion">Update available!</span>
</div>
</div>
<div class="card-item-body">
<figure class="card-item-figure">
<img ng-src="{{plugin.info.logos.small}}">
</figure>
<div class="card-item-details">
<div class="card-item-name">{{plugin.name}}</div>
<div class="card-item-sub-name">By {{plugin.info.author.name}}</div>
</div>
</div>
</a>
</li>
</ol>
</section>
<ol class="card-list" >
<li class="card-item-wrapper" ng-repeat="plugin in ctrl.plugins">
<a class="card-item" href="plugins/{{plugin.id}}/edit">
<div class="card-item-header">
<div class="card-item-type">
<i class="icon-gf icon-gf-{{plugin.type}}"></i>
{{plugin.type}}
</div>
<div class="card-item-notice" ng-show="plugin.hasUpdate">
<span bs-tooltip="plugin.latestVersion">Update available!</span>
</div>
</div>
<div class="card-item-body">
<figure class="card-item-figure">
<img ng-src="{{plugin.info.logos.small}}">
</figure>
<div class="card-item-details">
<div class="card-item-name">{{plugin.name}}</div>
<div class="card-item-sub-name">By {{plugin.info.author.name}}</div>
</div>
</div>
</a>
</li>
</ol>
</section>
</div>
......@@ -27,7 +27,7 @@ export class PluginEditCtrl {
$routeParams,
navModelSrv,
) {
this.navModel = navModelSrv.getNav('cfg', 'plugins');
this.navModel = navModelSrv.getNav('cfg', 'plugins', 0);
this.model = {};
this.pluginId = $routeParams.pluginId;
this.tabIndex = 0;
......
///<reference path="../../headers/common.d.ts" />
import angular from 'angular';
import _ from 'lodash';
export class PluginListCtrl {
plugins: any[];
tabIndex: number;
navModel: any;
searchQuery: string;
allPlugins: any[];
/** @ngInject */
constructor(private backendSrv: any, $location, navModelSrv) {
this.tabIndex = 0;
this.navModel = navModelSrv.getNav('cfg', 'plugins');
var pluginType = $location.search().type || 'panel';
switch (pluginType) {
case "datasource": {
this.tabIndex = 1;
break;
}
case "app": {
this.tabIndex = 2;
break;
}
case "panel":
default:
this.tabIndex = 0;
}
this.navModel = navModelSrv.getNav('cfg', 'plugins', 0);
this.backendSrv.get('api/plugins', {embedded: 0, type: pluginType}).then(plugins => {
this.backendSrv.get('api/plugins', {embedded: 0}).then(plugins => {
this.plugins = plugins;
this.allPlugins = plugins;
});
}
onQueryUpdated() {
let regex = new RegExp(this.searchQuery, 'ig');
this.plugins = _.filter(this.allPlugins, item => {
return regex.test(item.name) || regex.test(item.type);
});
}
}
......
<navbar model="ctrl.navModel"></navbar>
<page-header model="ctrl.navModel"></page-header>
<div class="page-container">
<div class="page-header">
<page-h1 model="ctrl.navModel"></page-h1>
</div>
<table class="filter-table" style="margin-top: 20px">
<div class="page-container page-body">
<table class="filter-table">
<thead>
<th><strong>Name</strong></th>
<th><strong>Snapshot url</strong></th>
......
......@@ -9,7 +9,7 @@ export class SnapshotsCtrl {
/** @ngInject */
constructor(private $rootScope, private backendSrv, navModelSrv) {
this.navModel = navModelSrv.getNav('dashboards', 'snapshots');
this.navModel = navModelSrv.getNav('dashboards', 'snapshots', 0);
this.backendSrv.get('/api/dashboard/snapshots').then(result => {
this.snapshots = result;
});
......
......@@ -3,7 +3,7 @@
suggest-url="http://localhost:8080">
</datasource-http-settings>
<h3 class="page-heading">Graphite details</h3>
<h3 class="section-heading">Graphite details</h3>
<div class="gf-form-group">
<div class="gf-form">
......
......@@ -85,6 +85,7 @@
@import "components/code_editor";
@import "components/dashboard_grid";
@import "components/dashboard_list";
@import "components/page_header";
// PAGES
......
......@@ -29,8 +29,9 @@
.dashnav-action-icons {
display: none;
}
.page-container {
padding: ($spacer * 1) ($spacer * 2);
padding: 0 $spacer * 2;
}
.dash-row-menu-container {
......
......@@ -52,6 +52,7 @@ $critical: #ed2e18;
// -------------------------
$body-bg: rgb(23,24,25);
$page-bg: rgb(22, 23, 25);
$body-color: $gray-4;
$text-color: $gray-4;
$text-color-strong: $white;
......
......@@ -227,7 +227,5 @@ $dashboard-padding: $panel-margin * 2;
$panel-padding: 0px 10px 5px 10px;
// tabs
$tabs-padding-top: 0.6rem;
$tabs-padding-bottom: 0.4rem;
$tabs-top-margin: 0.5rem;
$tabs-padding: 10px 15px 10px;
......@@ -43,5 +43,13 @@
background-image: url('../img/icons_#{$theme-name}_theme/icon_add_panel.svg');
}
.gicon-alert-notification-channel {
background-image: url('../img/icons_#{$theme-name}_theme/icon_notification_channels.svg');
}
.gicon-user-group {
background-image: url('../img/icons_#{$theme-name}_theme/icon_user_group.svg');
}
......@@ -5,7 +5,7 @@
.footer {
color: $footer-link-color;
padding: 5rem 0 1rem 0;
font-size: $font-size-xs;
font-size: $font-size-sm;
width: 98%; /* was causing horiz scrollbars - need to examine */
a {
......
.page-header-canvas {
background: linear-gradient(90deg, #292a2d, black);
box-shadow: inset 0px -4px 14px #2d2d2d;
border-bottom: 1px solid $dark-4;
}
.page-header {
padding: 2.5rem 0 0 0;
.btn {
float: right;
margin-left: 1rem;
// better align icons
.fa {
position: relative;
top: 1px;
}
}
}
.page-header__inner {
flex-grow: 1;
display: flex;
margin-bottom: 2.5rem;
}
.page-header__title {
font-size: $font-size-h2;
margin-bottom: 1px;
padding-top: $spacer;
}
.page-header__img {
border-radius: 50%;
position: relative;
top: -3px;
width: 50px;
height: 50px;
}
.page-header__icon {
font-size: 50px;
width: 50px;
height: 50px;
position: relative;
&.fa {
top: 8px;
}
&.gicon {
top: 9px;
}
&.icon-gf {
top: 3px;
}
}
.page-header__logo {
margin: 0 $spacer;
}
.page-header__sub-title {
color: $text-muted;
}
.page-header-stamps-type {
color: $link-color-disabled;
text-transform: uppercase;
}
.page-breadcrumbs {
display: flex;
padding: 10px 0;
line-height: 0.5;
}
.breadcrumb {
display: inline-block;
box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.35);
overflow: hidden;
border-radius: 5px;
counter-reset: flag;
}
.breadcrumb-item {
@include gradientBar($btn-inverse-bg, $btn-inverse-bg-hl, $btn-inverse-text-color);
text-decoration: none;
outline: none;
display: block;
float: left;
font-size: 12px;
line-height: 30px;
padding: 0 7px 0 37px;
position: relative;
box-shadow: $card-shadow;
&:first-child {
padding-left: 10px;
border-radius: 5px 0 0 5px; /*to match with the parent's radius*/
font-size: 18px;
}
&:first-child::before {
left: 14px;
}
&:last-child {
border-radius: 0 5px 5px 0; /*this was to prevent glitches on hover*/
padding-right: 20px;
}
&.active,
&:hover {
background: #333;
background: linear-gradient(#333, #000);
}
&.active::after,
&:hover::after {
background: #333;
background: linear-gradient(135deg, #333, #000);
}
&::after {
content: '';
position: absolute;
top: 0;
right: -14px; // half of square's length
// same dimension as the line-height of .breadcrumb-item
width: 30px;
height: 30px;
transform: scale(0.707) rotate(45deg);
// we need to prevent the arrows from getting buried under the next link
z-index: 1;
// background same as links but the gradient will be rotated to compensate with the transform applied
background: linear-gradient(135deg, $btn-inverse-bg, $btn-inverse-bg-hl);
// stylish arrow design using box shadow
box-shadow: 2px -2px 0 2px rgb(35, 31, 31), 3px -3px 0 2px rgba(255, 255, 255, 0.1);
// 5px - for rounded arrows and
// 50px - to prevent hover glitches on the border created using shadows*/
border-radius: 0 5px 0 50px;
}
// we dont need an arrow after the last link
&:last-child::after {
content: none;
}
}
......@@ -34,7 +34,7 @@
margin: 0;
background-color: transparent;
border: none;
padding: ($tabs-padding-top + $tabs-top-margin) $spacer $tabs-padding-bottom;
padding: $tabs-padding;
color: $text-color;
i {
font-size: 120%;
......
.nav-tabs-alt {
& > li > a {
color: darken($link-color, 20%);
}
li > a:hover {
border-bottom: none;
}
li.active > a,
li.active > a:focus,
li.active > a:hover {
@include border-radius(3px);
border: 1px solid $divider-border-color;
background-color: transparent;
border-bottom: 1px solid $page-bg;
color: $link-color;
}
li.disabled > a {
color: $text-color;
}
.open .dropdown-toggle {
background-color: #060606;
border-color: transparent;
}
.tab-content {
padding: 10px;
background-color: $panel-bg;
}
}
.gf-tabs {
@include clearfix();
float: left;
margin: $tabs-top-margin 0 0 0;
position: relative;
top: 1px;
}
.gf-tabs-item {
......@@ -44,13 +11,17 @@
}
.gf-tabs-link {
padding: $tabs-padding-top $spacer $tabs-padding-bottom $spacer;
padding: $tabs-padding;
margin-right: $spacer/2;
border: 1px solid transparent;
position: relative;
display: block;
border: solid transparent;
border-width: 2px 1px 1px;
border-radius: 3px 3px 0 0;
@include border-radius(2px 2px 0 0);
i {
margin-right: 5px;
}
&:hover,
&:focus {
......@@ -60,20 +31,9 @@
&.active,
&.active:hover,
&.active:focus {
@include border-radius(3px);
border-color: rgba(216, 131, 40, 0.77);
border-bottom: 1px solid $page-bg;
border-color: $orange $dark-4 transparent;
background: $page-bg;
color: $link-color;
position: relative;
top: 1px;
}
}
.form-tabs-wrapper {
@include brand-bottom-border();
@include clearfix();
}
.form-tabs-content {
padding: $spacer*2 $spacer;
}
......@@ -16,7 +16,7 @@
.page-container {
@extend .container;
padding: $spacer $spacer $spacer $spacer*3;
padding: 0 $spacer * 2;
}
.scroll-canvas {
......@@ -31,80 +31,53 @@
}
.page-body {
@include media-breakpoint-up(md) {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
padding-top: $spacer*2;
}
.page-content-with-sidebar {
width: calc(100% - #{$page-sidebar-width + $page-sidebar-margin}); // sidebar width + margin
}
.page-sidebar {
@include media-breakpoint-up(md) {
width: $page-sidebar-width;
margin-left: $page-sidebar-margin;
}
.page-heading {
font-size: 1.25rem;
margin-top: 0;
margin-bottom: $spacer * 0.7;
}
.page-header {
padding: 2rem 0 0 0;
margin-bottom: 2rem;
@include brand-bottom-border();
@include clearfix();
h1 {
font-size: $font-size-h2;
flex-grow: 1;
display: inline-block;
margin-bottom: 1rem;
img {
width: 30px;
height: 30px;
border-radius: 50%;
margin-right: 0.5rem;
position: relative;
top: -3px;
}
}
.page-action-bar {
margin-bottom: $spacer * 2;
display: flex;
align-items: flex-start;
a, button {
float: right;
> a, > button {
margin-left: $spacer;
// better align icons
.fa {
position: relative;
top: 1px;
}
}
}
.page-action-bar__spacer {
width: $spacer * 2;
flex-grow: 1;
}
.sidebar-content {
width: calc(100% - #{$page-sidebar-width + $page-sidebar-margin}); // sidebar width + margin
}
.page-heading {
font-size: 1.25rem;
margin-top: 0;
margin-bottom: $spacer * 0.7;
.sidebar-container {
@include media-breakpoint-up(md) {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
}
.admin-page {
max-width: 800px;
margin-left: 10px;
h2 {
margin-left: 15px;
margin-bottom: 0px;
font-size: $font-size-lg;
color: $text-color;
i {
padding-right: 6px;
}
.page-sidebar {
@include media-breakpoint-up(md) {
width: $page-sidebar-width;
margin-left: $page-sidebar-margin;
}
}
.page-sub-heading {
margin-bottom: $spacer;
}
.page-sidebar {
color: $text-color-weak;
h4 {
......@@ -120,89 +93,3 @@
.page-sidebar-section {
margin-bottom: $spacer*2;
}
.page-breadcrumbs {
display: flex;
padding: 10px 25px;
line-height: 0.5;
}
.breadcrumb {
display: inline-block;
box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.35);
overflow: hidden;
border-radius: 5px;
counter-reset: flag;
}
.breadcrumb-item {
text-decoration: none;
outline: none;
display: block;
float: left;
font-size: 12px;
line-height: 30px;
padding: 0 7px 0 37px;
@include gradientBar($btn-inverse-bg, $btn-inverse-bg-hl, $btn-inverse-text-color);
position: relative;
box-shadow: $card-shadow;
&:first-child {
padding-left: 10px;
border-radius: 5px 0 0 5px; /*to match with the parent's radius*/
font-size: 18px;
}
&:first-child:before {
left: 14px;
}
&:last-child {
border-radius: 0 5px 5px 0; /*this was to prevent glitches on hover*/
padding-right: 20px;
}
&.active,
&:hover {
background: #333;
background: linear-gradient(#333, #000);
}
&.active:after,
&:hover:after {
background: #333;
background: linear-gradient(135deg, #333, #000);
}
&:after {
content: '';
position: absolute;
top: 0;
right: -14px; // half of square's length
// same dimension as the line-height of .breadcrumb-item
width: 30px;
height: 30px;
transform: scale(0.707) rotate(45deg);
// we need to prevent the arrows from getting buried under the next link
z-index: 1;
// background same as links but the gradient will be rotated to compensate with the transform applied
background: linear-gradient(135deg, $btn-inverse-bg, $btn-inverse-bg-hl);
// stylish arrow design using box shadow
box-shadow: 2px -2px 0 2px rgb(35, 31, 31), 3px -3px 0 2px rgba(255, 255, 255, 0.1);
// 5px - for rounded arrows and
// 50px - to prevent hover glitches on the border created using shadows*/
border-radius: 0 5px 0 50px;
}
// we dont need an arrow after the last link
&:last-child:after {
content: none;
}
}
.plugin-header {
@include clearfix();
padding: $spacer 0 $spacer/2 0;
margin-bottom: 2rem;
}
.plugin-header-logo {
float: left;
width: 7rem;
img {
width: 7rem;
}
margin-right: $spacer;
}
.plugin-header-info-block {
float: left;
}
.plugin-header-author {
}
.plugin-header-stamps-type {
color: $link-color-disabled;
text-transform: uppercase;
}
.plugin-info-list-item {
img {
width: 16px;
}
white-space: nowrap;
max-width: $page-sidebar-width;
text-overflow: ellipsis;
overflow: hidden;
}
.get-more-plugins-link {
color: $gray-3;
......@@ -55,3 +17,15 @@
display: none;
}
}
.plugin-info-list-item {
img {
width: 16px;
}
white-space: nowrap;
max-width: $page-sidebar-width;
text-overflow: ellipsis;
overflow: hidden;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment