Merge remote-tracking branch 'grafana/master' into all-data-as-table

* grafana/master:
  fix(explore/logs) not collapsing whitespace (#15737)
  Refactoring / fixing password hint PR #15868
  chore: Move sidemenu out of context service and use the logic we have in the router already for hiding the sidemenu
  Fix deduplication results displaying wrong data (#15755)
  Revert "Fix Datasource Update to no User/Password"
  fix imageurl in notification test
  changed all rems to pixels in defaults and template, changed back root font size
  Make password hint configurable from settings/defaults.ini
  changed root font to 100%(default 16px), changed font-size from px to rem, updated rem sizes in template and default.ts files, removed display classes and variables since not used, removed lead class and variables since not usedremoved serif font since not used and probably never should be used
  fix: Update test snapshot
  fix: Logo goes Home instead of toggling side menu #15482
  Fix: #14706 Incorrect index pattern padding in alerting queries
  Removed commented code
  Fixed alias in Cloudwatch Expressions
This commit is contained in:
ryan
2019-03-11 09:06:08 -07:00
35 changed files with 332 additions and 265 deletions
+1
View File
@@ -231,6 +231,7 @@ verify_email_enabled = false
# Background text for the user field on the login page # Background text for the user field on the login page
login_hint = email or username login_hint = email or username
password_hint = password
# Default UI theme ("dark" or "light") # Default UI theme ("dark" or "light")
default_theme = dark default_theme = dark
+1
View File
@@ -211,6 +211,7 @@ log_queries =
# Background text for the user field on the login page # Background text for the user field on the login page
;login_hint = email or username ;login_hint = email or username
;password_hint = password
# Default UI theme ("dark" or "light") # Default UI theme ("dark" or "light")
;default_theme = dark ;default_theme = dark
+11 -3
View File
@@ -162,9 +162,9 @@ executed with working directory set to the installation path.
### enable_gzip ### enable_gzip
Set this option to `true` to enable HTTP compression, this can improve Set this option to `true` to enable HTTP compression, this can improve
transfer speed and bandwidth utilization. It is recommended that most transfer speed and bandwidth utilization. It is recommended that most
users set it to `true`. By default it is set to `false` for compatibility users set it to `true`. By default it is set to `false` for compatibility
reasons. reasons.
### cert_file ### cert_file
@@ -342,6 +342,14 @@ options are `Admin` and `Editor`. e.g. :
Viewers can edit/inspect dashboard settings in the browser. But not save the dashboard. Viewers can edit/inspect dashboard settings in the browser. But not save the dashboard.
Defaults to `false`. Defaults to `false`.
### login_hint
Text used as placeholder text on login page for login/username input.
### password_hint
Text used as placeholder text on login page for password input.
<hr> <hr>
## [auth] ## [auth]
@@ -53,7 +53,7 @@
} }
.panel-options-group__title { .panel-options-group__title {
font-size: 1.1rem; font-size: 16px;
position: relative; position: relative;
top: 1px; top: 1px;
} }
@@ -17,7 +17,7 @@ $enable-hover-media-query: false !default;
// Control the default styling of most Bootstrap elements by modifying these // Control the default styling of most Bootstrap elements by modifying these
// variables. Mostly focused on spacing. // variables. Mostly focused on spacing.
$spacer: 1rem !default; $spacer: ${theme.spacing.m} !default;
$spacer-x: $spacer !default; $spacer-x: $spacer !default;
$spacer-y: $spacer !default; $spacer-y: $spacer !default;
$spacers: ( $spacers: (
@@ -46,7 +46,7 @@ $spacers: (
), ),
), ),
) !default; ) !default;
$border-width: 1px !default; $border-width: ${theme.border.width.s} !default;
// Grid breakpoints // Grid breakpoints
// //
@@ -54,11 +54,11 @@ $border-width: 1px !default;
// adapting to different screen sizes, for use in media queries. // adapting to different screen sizes, for use in media queries.
$grid-breakpoints: ( $grid-breakpoints: (
xs: 0, xs: ${theme.breakpoints.xs},
sm: 544px, sm: ${theme.breakpoints.s},
md: 768px, md: ${theme.breakpoints.m},
lg: 992px, lg: ${theme.breakpoints.l},
xl: 1200px, xl: ${theme.breakpoints.xl},
) !default; ) !default;
// Grid containers // Grid containers
@@ -84,46 +84,32 @@ $enable-flex: true;
// Typography // Typography
// ------------------------- // -------------------------
$font-family-sans-serif: 'Roboto', Helvetica, Arial, sans-serif; $font-family-sans-serif: ${theme.typography.fontFamily.sansSerif};
$font-family-serif: Georgia, 'Times New Roman', Times, serif; $font-family-monospace: ${theme.typography.fontFamily.monospace};
$font-family-monospace: Menlo, Monaco, Consolas, 'Courier New', monospace;
$font-family-base: $font-family-sans-serif !default; $font-family-base: $font-family-sans-serif !default;
$font-size-root: 14px !default; $font-size-root: ${theme.typography.size.root} !default;
$font-size-base: 13px !default; $font-size-base: ${theme.typography.size.base} !default;
$font-size-lg: 18px !default; $font-size-lg: ${theme.typography.size.l} !default;
$font-size-md: 14px !default; $font-size-md: ${theme.typography.size.m} !default;
$font-size-sm: 12px !default; $font-size-sm: ${theme.typography.size.s} !default;
$font-size-xs: 10px !default; $font-size-xs: ${theme.typography.size.xs} !default;
$line-height-base: 1.5 !default; $line-height-base: ${theme.typography.lineHeight.l} !default;
$font-weight-semi-bold: 500; $font-weight-semi-bold: ${theme.typography.weight.semibold};
$font-size-h1: 2rem !default; $font-size-h1: ${theme.typography.heading.h1} !default;
$font-size-h2: 1.75rem !default; $font-size-h2: ${theme.typography.heading.h2} !default;
$font-size-h3: 1.5rem !default; $font-size-h3: ${theme.typography.heading.h3} !default;
$font-size-h4: 1.3rem !default; $font-size-h4: ${theme.typography.heading.h4} !default;
$font-size-h5: 1.2rem !default; $font-size-h5: ${theme.typography.heading.h5} !default;
$font-size-h6: 1rem !default; $font-size-h6: ${theme.typography.heading.h6} !default;
$display1-size: 6rem !default;
$display2-size: 5.5rem !default;
$display3-size: 4.5rem !default;
$display4-size: 3.5rem !default;
$display1-weight: 400 !default;
$display2-weight: 400 !default;
$display3-weight: 400 !default;
$display4-weight: 400 !default;
$lead-font-size: 1.25rem !default;
$lead-font-weight: 300 !default;
$headings-margin-bottom: ($spacer / 2) !default; $headings-margin-bottom: ($spacer / 2) !default;
$headings-font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif; $headings-font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif;
$headings-font-weight: 400 !default; $headings-font-weight: ${theme.typography.weight.normal} !default;
$headings-line-height: 1.1 !default; $headings-line-height: ${theme.typography.lineHeight.s} !default;
$hr-border-width: $border-width !default; $hr-border-width: $border-width !default;
$dt-font-weight: bold !default; $dt-font-weight: bold !default;
@@ -141,8 +127,8 @@ $border-radius-sm: 2px !default;
// Page // Page
$page-sidebar-width: 11rem; $page-sidebar-width: 154px;
$page-sidebar-margin: 4rem; $page-sidebar-margin: 56px;
// Links // Links
// ------------------------- // -------------------------
@@ -174,7 +160,7 @@ $input-padding-y-lg: 10px !default;
$input-height: 35px !default; $input-height: 35px !default;
$gf-form-margin: 0.2rem; $gf-form-margin: 3px;
$gf-form-input-height: 35px; $gf-form-input-height: 35px;
$cursor-disabled: not-allowed !default; $cursor-disabled: not-allowed !default;
@@ -199,13 +185,13 @@ $zindex-typeahead: 1060;
// Buttons // Buttons
// //
$btn-padding-x: 1rem !default; $btn-padding-x: 14px !default;
$btn-padding-y: 0.7rem !default; $btn-padding-y: 10px !default;
$btn-line-height: 1 !default; $btn-line-height: 1 !default;
$btn-font-weight: 500 !default; $btn-font-weight: ${theme.typography.weight.semibold} !default;
$btn-padding-x-sm: 0.5rem !default; $btn-padding-x-sm: 7px !default;
$btn-padding-y-sm: 0.25rem !default; $btn-padding-y-sm: 4px !default;
$btn-padding-x-lg: 21px !default; $btn-padding-x-lg: 21px !default;
$btn-padding-y-lg: 11px !default; $btn-padding-y-lg: 11px !default;
+14 -11
View File
@@ -5,10 +5,10 @@ const theme: GrafanaThemeCommons = {
typography: { typography: {
fontFamily: { fontFamily: {
sansSerif: "'Roboto', Helvetica, Arial, sans-serif", sansSerif: "'Roboto', Helvetica, Arial, sans-serif",
serif: "Georgia, 'Times New Roman', Times, serif",
monospace: "Menlo, Monaco, Consolas, 'Courier New', monospace", monospace: "Menlo, Monaco, Consolas, 'Courier New', monospace",
}, },
size: { size: {
root: '14px',
base: '13px', base: '13px',
xs: '10px', xs: '10px',
s: '12px', s: '12px',
@@ -16,12 +16,12 @@ const theme: GrafanaThemeCommons = {
l: '18px', l: '18px',
}, },
heading: { heading: {
h1: '2rem', h1: '28px',
h2: '1.75rem', h2: '24px',
h3: '1.5rem', h3: '21px',
h4: '1.3rem', h4: '18px',
h5: '1.2rem', h5: '16px',
h6: '1rem', h6: '14px',
}, },
weight: { weight: {
light: 300, light: 300,
@@ -35,7 +35,7 @@ const theme: GrafanaThemeCommons = {
l: 1.5, l: 1.5,
}, },
}, },
brakpoints: { breakpoints: {
xs: '0', xs: '0',
s: '544px', s: '544px',
m: '768px', m: '768px',
@@ -44,9 +44,9 @@ const theme: GrafanaThemeCommons = {
}, },
spacing: { spacing: {
xs: '0', xs: '0',
s: '0.2rem', s: '3px',
m: '1rem', m: '14px',
l: '1.5rem', l: '21px',
gutter: '30px', gutter: '30px',
}, },
border: { border: {
@@ -55,6 +55,9 @@ const theme: GrafanaThemeCommons = {
s: '3px', s: '3px',
m: '5px', m: '5px',
}, },
width: {
s: '1px',
},
}, },
}; };
+5 -2
View File
@@ -6,7 +6,7 @@ export enum GrafanaThemeType {
export interface GrafanaThemeCommons { export interface GrafanaThemeCommons {
name: string; name: string;
// TODO: not sure if should be a part of theme // TODO: not sure if should be a part of theme
brakpoints: { breakpoints: {
xs: string; xs: string;
s: string; s: string;
m: string; m: string;
@@ -16,10 +16,10 @@ export interface GrafanaThemeCommons {
typography: { typography: {
fontFamily: { fontFamily: {
sansSerif: string; sansSerif: string;
serif: string;
monospace: string; monospace: string;
}; };
size: { size: {
root: string;
base: string; base: string;
xs: string; xs: string;
s: string; s: string;
@@ -60,6 +60,9 @@ export interface GrafanaThemeCommons {
s: string; s: string;
m: string; m: string;
}; };
width: {
s: string;
};
}; };
} }
+1
View File
@@ -36,6 +36,7 @@ func (hs *HTTPServer) LoginView(c *m.ReqContext) {
viewData.Settings["oauth"] = enabledOAuths viewData.Settings["oauth"] = enabledOAuths
viewData.Settings["disableUserSignUp"] = !setting.AllowUserSignUp viewData.Settings["disableUserSignUp"] = !setting.AllowUserSignUp
viewData.Settings["loginHint"] = setting.LoginHint viewData.Settings["loginHint"] = setting.LoginHint
viewData.Settings["passwordHint"] = setting.PasswordHint
viewData.Settings["disableLoginForm"] = setting.DisableLoginForm viewData.Settings["disableLoginForm"] = setting.DisableLoginForm
if loginError, ok := tryGetEncryptedCookie(c, LoginErrorCookieName); ok { if loginError, ok := tryGetEncryptedCookie(c, LoginErrorCookieName); ok {
+1 -1
View File
@@ -56,7 +56,7 @@ func createTestEvalContext(cmd *NotificationTestCommand) *EvalContext {
ctx := NewEvalContext(context.Background(), testRule) ctx := NewEvalContext(context.Background(), testRule)
if cmd.Settings.Get("uploadImage").MustBool(true) { if cmd.Settings.Get("uploadImage").MustBool(true) {
ctx.ImagePublicUrl = "http://grafana.org/assets/img/blog/mixed_styles.png" ctx.ImagePublicUrl = "https://grafana.com/assets/img/blog/mixed_styles.png"
} }
ctx.IsTestRun = true ctx.IsTestRun = true
ctx.Firing = true ctx.Firing = true
+6 -1
View File
@@ -174,6 +174,11 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error {
Version: cmd.Version + 1, Version: cmd.Version + 1,
} }
sess.UseBool("is_default")
sess.UseBool("basic_auth")
sess.UseBool("with_credentials")
sess.UseBool("read_only")
var updateSession *xorm.Session var updateSession *xorm.Session
if cmd.Version != 0 { if cmd.Version != 0 {
// the reason we allow cmd.version > db.version is make it possible for people to force // the reason we allow cmd.version > db.version is make it possible for people to force
@@ -185,7 +190,7 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error {
updateSession = sess.Where("id=? and org_id=?", ds.Id, ds.OrgId) updateSession = sess.Where("id=? and org_id=?", ds.Id, ds.OrgId)
} }
affected, err := updateSession.AllCols().Omit("created").Update(ds) affected, err := updateSession.Update(ds)
if err != nil { if err != nil {
return err return err
} }
+2
View File
@@ -109,6 +109,7 @@ var (
AutoAssignOrgRole string AutoAssignOrgRole string
VerifyEmailEnabled bool VerifyEmailEnabled bool
LoginHint string LoginHint string
PasswordHint string
DefaultTheme string DefaultTheme string
DisableLoginForm bool DisableLoginForm bool
DisableSignoutMenu bool DisableSignoutMenu bool
@@ -656,6 +657,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Viewer"}) AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Viewer"})
VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false) VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false)
LoginHint = users.Key("login_hint").String() LoginHint = users.Key("login_hint").String()
PasswordHint = users.Key("password_hint").String()
DefaultTheme = users.Key("default_theme").String() DefaultTheme = users.Key("default_theme").String()
ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String() ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String()
ExternalUserMngLinkName = users.Key("external_manage_link_name").String() ExternalUserMngLinkName = users.Key("external_manage_link_name").String()
+5 -4
View File
@@ -496,9 +496,6 @@ func parseQuery(model *simplejson.Json) (*CloudWatchQuery, error) {
} }
alias := model.Get("alias").MustString() alias := model.Get("alias").MustString()
if alias == "" {
alias = "{{metric}}_{{stat}}"
}
returnData := model.Get("returnData").MustBool(false) returnData := model.Get("returnData").MustBool(false)
highResolution := model.Get("highResolution").MustBool(false) highResolution := model.Get("highResolution").MustBool(false)
@@ -521,7 +518,11 @@ func parseQuery(model *simplejson.Json) (*CloudWatchQuery, error) {
func formatAlias(query *CloudWatchQuery, stat string, dimensions map[string]string) string { func formatAlias(query *CloudWatchQuery, stat string, dimensions map[string]string) string {
if len(query.Id) > 0 && len(query.Expression) > 0 { if len(query.Id) > 0 && len(query.Expression) > 0 {
return query.Id if len(query.Alias) > 0 {
return query.Alias
} else {
return query.Id
}
} }
data := map[string]string{} data := map[string]string{}
@@ -279,7 +279,7 @@ func formatDate(t time.Time, pattern string) string {
isoYearShort := fmt.Sprintf("%d", isoYear)[2:4] isoYearShort := fmt.Sprintf("%d", isoYear)[2:4]
formatted = strings.Replace(formatted, "<stdIsoYear>", fmt.Sprintf("%d", isoYear), -1) formatted = strings.Replace(formatted, "<stdIsoYear>", fmt.Sprintf("%d", isoYear), -1)
formatted = strings.Replace(formatted, "<stdIsoYearShort>", isoYearShort, -1) formatted = strings.Replace(formatted, "<stdIsoYearShort>", isoYearShort, -1)
formatted = strings.Replace(formatted, "<stdWeekOfYear>", fmt.Sprintf("%d", isoWeek), -1) formatted = strings.Replace(formatted, "<stdWeekOfYear>", fmt.Sprintf("%02d", isoWeek), -1)
formatted = strings.Replace(formatted, "<stdUnix>", fmt.Sprintf("%d", t.Unix()), -1) formatted = strings.Replace(formatted, "<stdUnix>", fmt.Sprintf("%d", t.Unix()), -1)
@@ -76,6 +76,15 @@ func TestIndexPattern(t *testing.T) {
So(indices, ShouldHaveLength, 1) So(indices, ShouldHaveLength, 1)
So(indices[0], ShouldEqual, "2018-data") So(indices[0], ShouldEqual, "2018-data")
}) })
Convey("Should return 01 week", func() {
from = fmt.Sprintf("%d", time.Date(2018, 1, 15, 17, 50, 0, 0, time.UTC).UnixNano()/int64(time.Millisecond))
to = fmt.Sprintf("%d", time.Date(2018, 1, 15, 17, 55, 0, 0, time.UTC).UnixNano()/int64(time.Millisecond))
indexPatternScenario(intervalWeekly, "[data-]GGGG.WW", tsdb.NewTimeRange(from, to), func(indices []string) {
So(indices, ShouldHaveLength, 1)
So(indices[0], ShouldEqual, "data-2018.03")
})
})
}) })
Convey("Hourly interval", t, func() { Convey("Hourly interval", t, func() {
@@ -2,7 +2,6 @@ import React from 'react';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import { SideMenu } from './SideMenu'; import { SideMenu } from './SideMenu';
import appEvents from '../../app_events'; import appEvents from '../../app_events';
import { contextSrv } from 'app/core/services/context_srv';
jest.mock('../../app_events', () => ({ jest.mock('../../app_events', () => ({
emit: jest.fn(), emit: jest.fn(),
@@ -26,7 +25,6 @@ jest.mock('app/core/services/context_srv', () => ({
isGrafanaAdmin: false, isGrafanaAdmin: false,
isEditor: false, isEditor: false,
hasEditPermissionFolders: false, hasEditPermissionFolders: false,
toggleSideMenu: jest.fn(),
}, },
})); }));
@@ -54,20 +52,6 @@ describe('Render', () => {
}); });
describe('Functions', () => { describe('Functions', () => {
describe('toggle side menu', () => {
const wrapper = setup();
const instance = wrapper.instance() as SideMenu;
instance.toggleSideMenu();
it('should call contextSrv.toggleSideMenu', () => {
expect(contextSrv.toggleSideMenu).toHaveBeenCalled();
});
it('should emit toggle sidemenu event', () => {
expect(appEvents.emit).toHaveBeenCalledWith('toggle-sidemenu');
});
});
describe('toggle side menu on mobile', () => { describe('toggle side menu on mobile', () => {
const wrapper = setup(); const wrapper = setup();
const instance = wrapper.instance() as SideMenu; const instance = wrapper.instance() as SideMenu;
@@ -1,31 +1,21 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import appEvents from '../../app_events'; import appEvents from '../../app_events';
import { contextSrv } from 'app/core/services/context_srv';
import TopSection from './TopSection'; import TopSection from './TopSection';
import BottomSection from './BottomSection'; import BottomSection from './BottomSection';
import { store } from 'app/store/store'; import config from 'app/core/config';
const homeUrl = config.appSubUrl || '/';
export class SideMenu extends PureComponent { export class SideMenu extends PureComponent {
toggleSideMenu = () => {
// ignore if we just made a location change, stops hiding sidemenu on double clicks of back button
const timeSinceLocationChanged = new Date().getTime() - store.getState().location.lastUpdated;
if (timeSinceLocationChanged < 1000) {
return;
}
contextSrv.toggleSideMenu();
appEvents.emit('toggle-sidemenu');
};
toggleSideMenuSmallBreakpoint = () => { toggleSideMenuSmallBreakpoint = () => {
appEvents.emit('toggle-sidemenu-mobile'); appEvents.emit('toggle-sidemenu-mobile');
}; };
render() { render() {
return [ return [
<div className="sidemenu__logo" onClick={this.toggleSideMenu} key="logo"> <a href={homeUrl} className="sidemenu__logo" key="logo">
<img src="public/img/grafana_icon.svg" alt="Grafana" /> <img src="public/img/grafana_icon.svg" alt="Grafana" />
</div>, </a>,
<div className="sidemenu__logo_small_breakpoint" onClick={this.toggleSideMenuSmallBreakpoint} key="hamburger"> <div className="sidemenu__logo_small_breakpoint" onClick={this.toggleSideMenuSmallBreakpoint} key="hamburger">
<i className="fa fa-bars" /> <i className="fa fa-bars" />
<span className="sidemenu__close"> <span className="sidemenu__close">
@@ -2,16 +2,16 @@
exports[`Render should render component 1`] = ` exports[`Render should render component 1`] = `
Array [ Array [
<div <a
className="sidemenu__logo" className="sidemenu__logo"
href="/"
key="logo" key="logo"
onClick={[Function]}
> >
<img <img
alt="Grafana" alt="Grafana"
src="public/img/grafana_icon.svg" src="public/img/grafana_icon.svg"
/> />
</div>, </a>,
<div <div
className="sidemenu__logo_small_breakpoint" className="sidemenu__logo_small_breakpoint"
key="hamburger" key="hamburger"
+1
View File
@@ -34,6 +34,7 @@ export class Settings {
oauth: any; oauth: any;
disableUserSignUp: boolean; disableUserSignUp: boolean;
loginHint: any; loginHint: any;
passwordHint: any;
loginError: any; loginError: any;
viewersCanEdit: boolean; viewersCanEdit: boolean;
editorsCanOwn: boolean; editorsCanOwn: boolean;
@@ -25,6 +25,7 @@ export class LoginCtrl {
$scope.disableLoginForm = config.disableLoginForm; $scope.disableLoginForm = config.disableLoginForm;
$scope.disableUserSignUp = config.disableUserSignUp; $scope.disableUserSignUp = config.disableUserSignUp;
$scope.loginHint = config.loginHint; $scope.loginHint = config.loginHint;
$scope.passwordHint = config.passwordHint;
$scope.loginMode = true; $scope.loginMode = true;
$scope.submitBtnText = 'Log in'; $scope.submitBtnText = 'Log in';
+3 -2
View File
@@ -245,12 +245,13 @@ export function dedupLogRows(logs: LogsModel, strategy: LogsDedupStrategy): Logs
} }
const dedupedRows = logs.rows.reduce((result: LogRowModel[], row: LogRowModel, index, list) => { const dedupedRows = logs.rows.reduce((result: LogRowModel[], row: LogRowModel, index, list) => {
const rowCopy = { ...row };
const previous = result[result.length - 1]; const previous = result[result.length - 1];
if (index > 0 && isDuplicateRow(row, previous, strategy)) { if (index > 0 && isDuplicateRow(row, previous, strategy)) {
previous.duplicates++; previous.duplicates++;
} else { } else {
row.duplicates = 0; rowCopy.duplicates = 0;
result.push(row); result.push(rowCopy);
} }
return result; return result;
}, []); }, []);
-9
View File
@@ -1,7 +1,6 @@
import config from 'app/core/config'; import config from 'app/core/config';
import _ from 'lodash'; import _ from 'lodash';
import coreModule from 'app/core/core_module'; import coreModule from 'app/core/core_module';
import store from 'app/core/store';
export class User { export class User {
isGrafanaAdmin: any; isGrafanaAdmin: any;
@@ -29,13 +28,10 @@ export class ContextSrv {
isSignedIn: any; isSignedIn: any;
isGrafanaAdmin: any; isGrafanaAdmin: any;
isEditor: any; isEditor: any;
sidemenu: any;
sidemenuSmallBreakpoint = false; sidemenuSmallBreakpoint = false;
hasEditPermissionInFolders: boolean; hasEditPermissionInFolders: boolean;
constructor() { constructor() {
this.sidemenu = store.getBool('grafana.sidemenu', true);
if (!config.bootData) { if (!config.bootData) {
config.bootData = { user: {}, settings: {} }; config.bootData = { user: {}, settings: {} };
} }
@@ -55,11 +51,6 @@ export class ContextSrv {
return !!(document.visibilityState === undefined || document.visibilityState === 'visible'); return !!(document.visibilityState === undefined || document.visibilityState === 'visible');
} }
toggleSideMenu() {
this.sidemenu = !this.sidemenu;
store.set('grafana.sidemenu', this.sidemenu);
}
hasAccessToExplore() { hasAccessToExplore() {
return (this.isEditor || config.viewersCanEdit) && config.exploreEnabled; return (this.isEditor || config.viewersCanEdit) && config.exploreEnabled;
} }
+28
View File
@@ -113,6 +113,34 @@ describe('dedupLogRows()', () => {
}, },
]); ]);
}); });
test('should return to non-deduped state on same log result', () => {
const logs = {
rows: [
{
entry: 'INFO 123',
},
{
entry: 'WARN 123',
},
{
entry: 'WARN 123',
},
],
};
expect(dedupLogRows(logs as LogsModel, LogsDedupStrategy.exact).rows).toEqual([
{
duplicates: 0,
entry: 'INFO 123',
},
{
duplicates: 1,
entry: 'WARN 123',
},
]);
expect(dedupLogRows(logs as LogsModel, LogsDedupStrategy.none).rows).toEqual(logs.rows);
});
}); });
describe('calculateFieldStats()', () => { describe('calculateFieldStats()', () => {
+14 -3
View File
@@ -13,8 +13,19 @@ interface Props {
export class LogLabels extends PureComponent<Props> { export class LogLabels extends PureComponent<Props> {
render() { render() {
const { getRows, labels, onClickLabel, plain } = this.props; const { getRows, labels, onClickLabel, plain } = this.props;
return Object.keys(labels).map(key => ( return (
<LogLabel key={key} getRows={getRows} label={key} value={labels[key]} plain={plain} onClickLabel={onClickLabel} /> <span className="logs-labels">
)); {Object.keys(labels).map(key => (
<LogLabel
key={key}
getRows={getRows}
label={key}
value={labels[key]}
plain={plain}
onClickLabel={onClickLabel}
/>
))}
</span>
);
} }
} }
+1 -1
View File
@@ -150,7 +150,7 @@ export class LogRow extends PureComponent<Props, State> {
</div> </div>
)} )}
{showLocalTime && ( {showLocalTime && (
<div className="logs-row__time" title={`${row.timestamp} (${row.timeFromNow})`}> <div className="logs-row__localtime" title={`${row.timestamp} (${row.timeFromNow})`}>
{row.timeLocal} {row.timeLocal}
</div> </div>
)} )}
@@ -0,0 +1,108 @@
import { deduplicatedLogsSelector } from './selectors';
import { LogsDedupStrategy } from 'app/core/logs_model';
import { ExploreItemState } from 'app/types';
const state = {
logsResult: {
rows: [
{
entry: '2019-03-05T11:00:56Z sntpc sntpc[1]: offset=-0.033938, delay=0.000649',
},
{
entry: '2019-03-05T11:00:26Z sntpc sntpc[1]: offset=-0.033730, delay=0.000581',
},
{
entry: '2019-03-05T10:59:56Z sntpc sntpc[1]: offset=-0.034184, delay=0.001089',
},
{
entry: '2019-03-05T10:59:26Z sntpc sntpc[1]: offset=-0.033972, delay=0.000582',
},
{
entry: '2019-03-05T10:58:56Z sntpc sntpc[1]: offset=-0.033955, delay=0.000606',
},
{
entry: '2019-03-05T10:58:26Z sntpc sntpc[1]: offset=-0.034067, delay=0.000616',
},
{
entry: '2019-03-05T10:57:56Z sntpc sntpc[1]: offset=-0.034155, delay=0.001021',
},
{
entry: '2019-03-05T10:57:26Z sntpc sntpc[1]: offset=-0.035797, delay=0.000883',
},
{
entry: '2019-03-05T10:56:56Z sntpc sntpc[1]: offset=-0.046818, delay=0.000605',
},
{
entry: '2019-03-05T10:56:26Z sntpc sntpc[1]: offset=-0.049200, delay=0.000584',
},
],
},
hiddenLogLevels: undefined,
dedupStrategy: LogsDedupStrategy.none,
};
describe('Deduplication selector', () => {
it('should correctly deduplicate log rows when changing strategy multiple times', () => {
// Simulating sequence of UI actions that was causing a problem with deduplication counter being visible when unnecessary.
// The sequence was changing dedup strategy: (none -> exact -> numbers -> signature -> none) *2 -> exact. After that the first
// row contained information that was deduped, while it shouldn't be.
// Problem was caused by mutating the log results entries in redux state. The memoisation hash for deduplicatedLogsSelector
// was changing depending on duplicates information from log row state, while should be dependand on log row only.
let dedups = deduplicatedLogsSelector(state as ExploreItemState);
expect(dedups.rows.length).toBe(10);
deduplicatedLogsSelector({
...state,
dedupStrategy: LogsDedupStrategy.none,
} as ExploreItemState);
deduplicatedLogsSelector({
...state,
dedupStrategy: LogsDedupStrategy.exact,
} as ExploreItemState);
deduplicatedLogsSelector({
...state,
dedupStrategy: LogsDedupStrategy.numbers,
} as ExploreItemState);
deduplicatedLogsSelector({
...state,
dedupStrategy: LogsDedupStrategy.signature,
} as ExploreItemState);
deduplicatedLogsSelector({
...state,
dedupStrategy: LogsDedupStrategy.none,
} as ExploreItemState);
deduplicatedLogsSelector({
...state,
dedupStrategy: LogsDedupStrategy.exact,
} as ExploreItemState);
deduplicatedLogsSelector({
...state,
dedupStrategy: LogsDedupStrategy.numbers,
} as ExploreItemState);
deduplicatedLogsSelector({
...state,
dedupStrategy: LogsDedupStrategy.signature,
} as ExploreItemState);
deduplicatedLogsSelector({
...state,
dedupStrategy: LogsDedupStrategy.none,
} as ExploreItemState);
dedups = deduplicatedLogsSelector({
...state,
dedupStrategy: LogsDedupStrategy.exact,
} as ExploreItemState);
// Expecting that no row has duplicates now
expect(dedups.rows.reduce((acc, row) => acc + row.duplicates, 0)).toBe(0);
});
});
+1 -1
View File
@@ -13,7 +13,7 @@
</div> </div>
<div class="login-form"> <div class="login-form">
<input type="password" name="password" class="gf-form-input login-form-input" required ng-model="formModel.password" id="inputPassword" <input type="password" name="password" class="gf-form-input login-form-input" required ng-model="formModel.password" id="inputPassword"
placeholder="password"> placeholder="{{passwordHint}}">
</div> </div>
<div class="login-button-group"> <div class="login-button-group">
<button type="submit" class="btn btn-large p-x-2" ng-if="!loggingIn" ng-click="submit();" ng-class="{'btn-inverse': !loginForm.$valid, 'btn-primary': loginForm.$valid}"> <button type="submit" class="btn btn-large p-x-2" ng-if="!loggingIn" ng-click="submit();" ng-class="{'btn-inverse': !loginForm.$valid, 'btn-primary': loginForm.$valid}">
+3 -19
View File
@@ -75,27 +75,22 @@ export class GrafanaCtrl {
} }
} }
function setViewModeBodyClass(body: JQuery, mode: KioskUrlValue, sidemenuOpen: boolean) { function setViewModeBodyClass(body: JQuery, mode: KioskUrlValue) {
body.removeClass('view-mode--tv'); body.removeClass('view-mode--tv');
body.removeClass('view-mode--kiosk'); body.removeClass('view-mode--kiosk');
body.removeClass('view-mode--inactive'); body.removeClass('view-mode--inactive');
switch (mode) { switch (mode) {
case 'tv': { case 'tv': {
body.removeClass('sidemenu-open');
body.addClass('view-mode--tv'); body.addClass('view-mode--tv');
break; break;
} }
// 1 & true for legacy states // 1 & true for legacy states
case '1': case '1':
case true: { case true: {
body.removeClass('sidemenu-open');
body.addClass('view-mode--kiosk'); body.addClass('view-mode--kiosk');
break; break;
} }
default: {
body.toggleClass('sidemenu-open', sidemenuOpen);
}
} }
} }
@@ -105,7 +100,6 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
restrict: 'E', restrict: 'E',
controller: GrafanaCtrl, controller: GrafanaCtrl,
link: (scope, elem) => { link: (scope, elem) => {
let sidemenuOpen;
const body = $('body'); const body = $('body');
// see https://github.com/zenorocha/clipboard.js/issues/155 // see https://github.com/zenorocha/clipboard.js/issues/155
@@ -113,14 +107,6 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
$('.preloader').remove(); $('.preloader').remove();
sidemenuOpen = scope.contextSrv.sidemenu;
body.toggleClass('sidemenu-open', sidemenuOpen);
appEvents.on('toggle-sidemenu', () => {
sidemenuOpen = scope.contextSrv.sidemenu;
body.toggleClass('sidemenu-open');
});
appEvents.on('toggle-sidemenu-mobile', () => { appEvents.on('toggle-sidemenu-mobile', () => {
body.toggleClass('sidemenu-open--xs'); body.toggleClass('sidemenu-open--xs');
}); });
@@ -163,7 +149,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
$('#tooltip, .tooltip').remove(); $('#tooltip, .tooltip').remove();
// check for kiosk url param // check for kiosk url param
setViewModeBodyClass(body, data.params.kiosk, sidemenuOpen); setViewModeBodyClass(body, data.params.kiosk);
// close all drops // close all drops
for (const drop of Drop.drops) { for (const drop of Drop.drops) {
@@ -198,7 +184,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
} }
$timeout(() => $location.search(search)); $timeout(() => $location.search(search));
setViewModeBodyClass(body, search.kiosk, sidemenuOpen); setViewModeBodyClass(body, search.kiosk);
}); });
// handle in active view state class // handle in active view state class
@@ -218,7 +204,6 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
if (new Date().getTime() - lastActivity > inActiveTimeLimit) { if (new Date().getTime() - lastActivity > inActiveTimeLimit) {
activeUser = false; activeUser = false;
body.addClass('view-mode--inactive'); body.addClass('view-mode--inactive');
body.removeClass('sidemenu-open');
} }
} }
@@ -227,7 +212,6 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
if (!activeUser) { if (!activeUser) {
activeUser = true; activeUser = true;
body.removeClass('view-mode--inactive'); body.removeClass('view-mode--inactive');
body.toggleClass('sidemenu-open', sidemenuOpen);
} }
} }
+14 -28
View File
@@ -20,7 +20,7 @@ $enable-hover-media-query: false !default;
// Control the default styling of most Bootstrap elements by modifying these // Control the default styling of most Bootstrap elements by modifying these
// variables. Mostly focused on spacing. // variables. Mostly focused on spacing.
$spacer: 1rem !default; $spacer: 14px !default;
$spacer-x: $spacer !default; $spacer-x: $spacer !default;
$spacer-y: $spacer !default; $spacer-y: $spacer !default;
$spacers: ( $spacers: (
@@ -88,7 +88,6 @@ $enable-flex: true;
// ------------------------- // -------------------------
$font-family-sans-serif: 'Roboto', Helvetica, Arial, sans-serif; $font-family-sans-serif: 'Roboto', Helvetica, Arial, sans-serif;
$font-family-serif: Georgia, 'Times New Roman', Times, serif;
$font-family-monospace: Menlo, Monaco, Consolas, 'Courier New', monospace; $font-family-monospace: Menlo, Monaco, Consolas, 'Courier New', monospace;
$font-family-base: $font-family-sans-serif !default; $font-family-base: $font-family-sans-serif !default;
@@ -103,25 +102,12 @@ $font-size-xs: 10px !default;
$line-height-base: 1.5 !default; $line-height-base: 1.5 !default;
$font-weight-semi-bold: 500; $font-weight-semi-bold: 500;
$font-size-h1: 2rem !default; $font-size-h1: 28px !default;
$font-size-h2: 1.75rem !default; $font-size-h2: 24px !default;
$font-size-h3: 1.5rem !default; $font-size-h3: 21px !default;
$font-size-h4: 1.3rem !default; $font-size-h4: 18px !default;
$font-size-h5: 1.2rem !default; $font-size-h5: 16px !default;
$font-size-h6: 1rem !default; $font-size-h6: 14px !default;
$display1-size: 6rem !default;
$display2-size: 5.5rem !default;
$display3-size: 4.5rem !default;
$display4-size: 3.5rem !default;
$display1-weight: 400 !default;
$display2-weight: 400 !default;
$display3-weight: 400 !default;
$display4-weight: 400 !default;
$lead-font-size: 1.25rem !default;
$lead-font-weight: 300 !default;
$headings-margin-bottom: ($spacer / 2) !default; $headings-margin-bottom: ($spacer / 2) !default;
$headings-font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif; $headings-font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif;
@@ -144,8 +130,8 @@ $border-radius-sm: 2px !default;
// Page // Page
$page-sidebar-width: 11rem; $page-sidebar-width: 154px;
$page-sidebar-margin: 4rem; $page-sidebar-margin: 56px;
// Links // Links
// ------------------------- // -------------------------
@@ -177,7 +163,7 @@ $input-padding-y-lg: 10px !default;
$input-height: 35px !default; $input-height: 35px !default;
$gf-form-margin: 0.2rem; $gf-form-margin: 3px;
$gf-form-input-height: 35px; $gf-form-input-height: 35px;
$cursor-disabled: not-allowed !default; $cursor-disabled: not-allowed !default;
@@ -202,13 +188,13 @@ $zindex-typeahead: 1060;
// Buttons // Buttons
// //
$btn-padding-x: 1rem !default; $btn-padding-x: 14px !default;
$btn-padding-y: 0.7rem !default; $btn-padding-y: 10px !default;
$btn-line-height: 1 !default; $btn-line-height: 1 !default;
$btn-font-weight: 500 !default; $btn-font-weight: 500 !default;
$btn-padding-x-sm: 0.5rem !default; $btn-padding-x-sm: 7px !default;
$btn-padding-y-sm: 0.25rem !default; $btn-padding-y-sm: 4px !default;
$btn-padding-x-lg: 21px !default; $btn-padding-x-lg: 21px !default;
$btn-padding-y-lg: 11px !default; $btn-padding-y-lg: 11px !default;
-23
View File
@@ -141,29 +141,6 @@ h6,
font-size: $font-size-h6; font-size: $font-size-h6;
} }
.lead {
font-size: $lead-font-size;
font-weight: $lead-font-weight;
}
// Type display classes
.display-1 {
font-size: $display1-size;
font-weight: $display1-weight;
}
.display-2 {
font-size: $display2-size;
font-weight: $display2-weight;
}
.display-3 {
font-size: $display3-size;
font-weight: $display3-weight;
}
.display-4 {
font-size: $display4-size;
font-weight: $display4-weight;
}
// //
// Horizontal rules // Horizontal rules
// //
+2 -8
View File
@@ -157,14 +157,8 @@
@include media-breakpoint-up(sm) { @include media-breakpoint-up(sm) {
.navbar { .navbar {
padding-left: 60px; padding-left: 20px;
} margin-left: 0;
.sidemenu-open {
.navbar {
padding-left: 25px;
margin-left: 0;
}
} }
.navbar-page-btn { .navbar-page-btn {
+25 -4
View File
@@ -63,6 +63,7 @@ $column-horizontal-spacing: 10px;
font-size: $font-size-sm; font-size: $font-size-sm;
display: table; display: table;
table-layout: fixed; table-layout: fixed;
width: 100%;
} }
.logs-row { .logs-row {
@@ -83,16 +84,22 @@ $column-horizontal-spacing: 10px;
.logs-row__time { .logs-row__time {
white-space: nowrap; white-space: nowrap;
width: 19em;
}
.logs-row__localtime {
white-space: nowrap;
width: 12.5em;
} }
.logs-row__labels { .logs-row__labels {
max-width: 20%; width: 20%;
line-height: 1.2; line-height: 1.2;
position: relative;
} }
.logs-row__message { .logs-row__message {
word-break: break-all; word-break: break-all;
min-width: 80%;
} }
.logs-row__match-highlight { .logs-row__match-highlight {
@@ -112,6 +119,7 @@ $column-horizontal-spacing: 10px;
.logs-row__level { .logs-row__level {
position: relative; position: relative;
width: 10px;
&::after { &::after {
content: ''; content: '';
@@ -165,6 +173,7 @@ $column-horizontal-spacing: 10px;
.logs-row__duplicates { .logs-row__duplicates {
text-align: right; text-align: right;
width: 4.5em;
} }
.logs-row__field-highlight { .logs-row__field-highlight {
@@ -193,15 +202,20 @@ $column-horizontal-spacing: 10px;
} }
} }
.logs-labels {
display: flex;
flex-wrap: wrap;
}
.logs-label { .logs-label {
display: inline-block; display: flex;
padding: 0 2px; padding: 0 2px;
background-color: $btn-inverse-bg; background-color: $btn-inverse-bg;
border-radius: $border-radius; border-radius: $border-radius;
margin: 0 4px 2px 0; margin: 0 4px 2px 0;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
position: relative; overflow: hidden;
} }
.logs-label__icon { .logs-label__icon {
@@ -211,6 +225,13 @@ $column-horizontal-spacing: 10px;
margin-left: 2px; margin-left: 2px;
} }
.logs-label__value {
display: inline-block;
max-width: 20em;
text-overflow: ellipsis;
overflow: hidden;
}
.logs-label__stats { .logs-label__stats {
position: absolute; position: absolute;
top: 1.25em; top: 1.25em;
+16 -18
View File
@@ -16,6 +16,14 @@
.sidemenu__close { .sidemenu__close {
display: none; display: none;
} }
@include media-breakpoint-up(sm) {
background: $side-menu-bg;
height: auto;
box-shadow: $side-menu-shadow;
position: relative;
z-index: $zindex-sidemenu;
}
} }
// body class that hides sidemenu // body class that hides sidemenu
@@ -25,32 +33,22 @@
} }
} }
@include media-breakpoint-up(sm) {
.sidemenu-open {
.sidemenu {
background: $side-menu-bg;
height: auto;
box-shadow: $side-menu-shadow;
position: relative;
z-index: $zindex-sidemenu;
}
.sidemenu__top,
.sidemenu__bottom {
display: block;
}
}
}
.sidemenu__top { .sidemenu__top {
padding-top: 3rem; padding-top: 3rem;
flex-grow: 1; flex-grow: 1;
display: none;
} }
.sidemenu__bottom { .sidemenu__bottom {
padding-bottom: $spacer; padding-bottom: $spacer;
}
.sidemenu__top,
.sidemenu__bottom {
display: none; display: none;
@include media-breakpoint-up(sm) {
display: block;
}
} }
.sidemenu-item { .sidemenu-item {
+15
View File
@@ -29,6 +29,21 @@
.view-mode--tv { .view-mode--tv {
@extend .view-mode--inactive; @extend .view-mode--inactive;
.sidemenu {
position: fixed;
background-color: transparent;
box-shadow: none;
.sidemenu__top,
.sidemenu__bottom {
display: none;
}
}
.navbar {
padding-left: $side-menu-width;
}
.submenu-controls { .submenu-controls {
display: none; display: none;
} }
-9
View File
@@ -79,10 +79,6 @@
// FONTS // FONTS
// -------------------------------------------------- // --------------------------------------------------
@mixin font-family-serif() {
font-family: $font-family-serif;
}
@mixin font-family-sans-serif() { @mixin font-family-sans-serif() {
font-family: $font-family-sans-serif; font-family: $font-family-sans-serif;
} }
@@ -97,11 +93,6 @@
line-height: $lineHeight; line-height: $lineHeight;
} }
@mixin font-serif($size: $font-size-base, $weight: normal, $lineHeight: $line-height-base) {
@include font-family-serif();
@include font-shorthand($size, $weight, $lineHeight);
}
@mixin font-sans-serif($size: $font-size-base, $weight: normal, $lineHeight: $line-height-base) { @mixin font-sans-serif($size: $font-size-base, $weight: normal, $lineHeight: $line-height-base) {
@include font-family-sans-serif(); @include font-family-sans-serif();
@include font-shorthand($size, $weight, $lineHeight); @include font-shorthand($size, $weight, $lineHeight);
+1 -35
View File
@@ -25,20 +25,13 @@
} }
} }
.sidemenu-open {
.explore-toolbar-header {
padding: 0;
margin-left: 0;
}
}
.explore-toolbar { .explore-toolbar {
background: inherit; background: inherit;
display: flex; display: flex;
flex-flow: row wrap; flex-flow: row wrap;
justify-content: flex-start; justify-content: flex-start;
height: auto; height: auto;
padding: 0px $dashboard-padding 0 25px; padding: 0 $dashboard-padding;
border-bottom: 1px solid #0000; border-bottom: 1px solid #0000;
transition-duration: 0.35s; transition-duration: 0.35s;
transition-timing-function: ease-in-out; transition-timing-function: ease-in-out;
@@ -72,11 +65,6 @@
font-size: 18px; font-size: 18px;
min-height: 55px; min-height: 55px;
line-height: 55px; line-height: 55px;
justify-content: space-between;
margin-left: $panel-margin * 3;
}
.explore-toolbar-header {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
@@ -134,20 +122,6 @@
} }
@media only screen and (max-width: 803px) { @media only screen and (max-width: 803px) {
.sidemenu-open {
.explore-toolbar-header-title {
.navbar-page-btn {
margin-left: 0;
}
}
}
.explore-toolbar-header-title {
.navbar-page-btn {
margin-left: $dashboard-padding;
}
}
.btn-title { .btn-title {
display: none; display: none;
} }
@@ -161,14 +135,6 @@
} }
@media only screen and (max-width: 544px) { @media only screen and (max-width: 544px) {
.sidemenu-open {
.explore-toolbar-header-title {
.navbar-page-btn {
margin-left: $dashboard-padding;
}
}
}
.explore-toolbar-header-title { .explore-toolbar-header-title {
.navbar-page-btn { .navbar-page-btn {
margin-left: $dashboard-padding; margin-left: $dashboard-padding;