Compare commits

...

29 Commits

Author SHA1 Message Date
Torkel Ödegaard
9504db83bf Graph: Fixed auto decimals in legend values (#16455)
Fixes #16448

(cherry picked from commit 52c3990412)
2019-04-09 15:26:42 +02:00
Torkel Ödegaard
0992fbc4be Build: Updated version to v6.1.3 2019-04-09 15:23:19 +02:00
Torkel Ödegaard
1f35ce691c Graph: fixed png rendering with legend to the right (#16463)
(cherry picked from commit fed75695a1)
2019-04-09 15:22:52 +02:00
Torkel Ödegaard
be84bffa57 Singlestat: Use decimal override when manually specified (#16451)
Fixes #16373

(cherry picked from commit b46b84f156)
2019-04-09 15:22:18 +02:00
Dominik Prokop
a2236de67f Fix: Bring back styles on Switch components when checked
Fixed bug introduced by replacing native input with @grafana/ui/Input component.

Switch's styling relies on native input checked attribute used in adjacent sibling selector. Because React based Input is wrapped in div, there was no chance for styling to work

(cherry picked from commit 6b2c81bcf2)
2019-04-09 15:22:10 +02:00
Torkel Ödegaard
de8f6ac4b1 Bumped version to 6.1.2 2019-04-08 11:16:37 +02:00
Patrick O'Carroll
0c7d43b999 Graph: Fixed series legend color for hidden series (#16438)
* replaced colors for headingColor, link and linkDisabled with colors from grayscale, replaced colors for linkDisabled and linkHover with colors from grayscale, changed color for sha-modal-in-text to text-color-empahises

* fixed snapshot

(cherry picked from commit 70dcb6a22a)
2019-04-08 11:15:58 +02:00
Torkel Ödegaard
0974663079 Styles: Fixed left menu highlight (#16431)
Upgrades to webpack & css optimization caused changes
in production build that removed the left brand
gradient.

Fixes #16430

(cherry picked from commit 0968fbed49)
2019-04-08 11:15:51 +02:00
Torkel Ödegaard
9eba279b8d Graph: Fixed tooltip highlight on white theme (#16429)
Fixes #16359

(cherry picked from commit 9b39dbc2fb)
2019-04-08 11:15:41 +02:00
Torkel Ödegaard
da0302f15e Units: Correctly use the override decimals (#16413)
Fixes bugs introduced in PR #14716 and #15146 also restores unit tests that where lost in the
move from kbn units to @grafana/ui units

Fixes #16068
Fixes #16373

(cherry picked from commit 8a4a6b4dc1)
2019-04-08 11:15:31 +02:00
Torkel Ödegaard
eff01d2b54 Updated version to 6.1.1 2019-04-05 11:42:24 +02:00
Torkel Ödegaard
cbc515b22c Fix: Graphite query rendering fix (#16390)
Only interpolate string parameters

Fixes #16367

(cherry picked from commit 173e7fd839)
2019-04-05 11:42:03 +02:00
Torkel Ödegaard
638d49dd6e Fix: align panel padding between sass & js theme (#16404)
(cherry picked from commit 35e68b868e)
2019-04-05 11:37:24 +02:00
Torkel Ödegaard
9d452256bf Fix: playlist now preserve the correct url query params (#16403)
Fixes #16377

(cherry picked from commit 6d3b6f3c2f)
2019-04-05 11:37:15 +02:00
Sean Lafferty
f941f25831 Fix: Query editor toggle edit mode fix (#16394)
Increase timeout when waiting for datasource toggleEditorMode check 

Fixes  #16393

(cherry picked from commit c2d399b059)
2019-04-05 11:37:07 +02:00
Marcus Efraimsson
b585fdec6f Alerting: Notification channel http api fixes (#16379)
Fixes so it's possible to create new notification channel and providing uid.
Fixes better error/result handling when updating a notifcation channel.

Fixes #16372
Ref #16219 #16012

(cherry picked from commit 5da1faf454)
2019-04-05 11:36:58 +02:00
Leonard Gram
e6c639f6f0 build: Fixed incorrect permissions for repo folders in ci-deploy. (#16360)
(cherry picked from commit 6baba64935)
2019-04-05 11:36:51 +02:00
Torkel Ödegaard
03346b6f6f Build: updated version to 6.1.0 2019-04-03 10:08:03 +02:00
Mitsuhiro Tanda
9a575f93ad Fix: Cloudwatch fix for dimension value (#16356)
Fixes autocomplete suggestion after changing dimension key

Fixes #15984

(cherry picked from commit 58eb74660d)
2019-04-03 09:57:28 +02:00
Torkel Ödegaard
21957ad515 Fix: Autoprefixer is now working (#16351)
The autoprefixer not working broke the phantomjs backend png rendering

Fixes #16345

(cherry picked from commit 2e59166daa)
2019-04-03 09:57:16 +02:00
Leonard Gram
bd93aad63d build: Fix for renamed package for armv6.
(cherry picked from commit b48c18a1c5)
2019-04-03 09:57:07 +02:00
Torkel Ödegaard
8ae5980c23 Fix: Graphite query ast to string fix (#16297)
Fixes #16291

(cherry picked from commit 74ae756d02)
2019-04-03 09:56:55 +02:00
Torkel Ödegaard
eb38581dc1 Fix: Template query editor this bind exception fix (#16299)
Also fixes the default 100% width of inputs.
Fixes #16298

(cherry picked from commit 5c3a0a624a)
2019-04-03 09:56:43 +02:00
Marcus Efraimsson
be217d8c0e Fix: Alerting Notification channel http api fixes (#16288)
Fix so that uid can be changed when updating notification
channels through the http api.
Update documentation

(cherry picked from commit 79b86466fd)
2019-04-03 09:56:11 +02:00
Floyd May
dfbc3bfb1f InfluxDB: Fix tag names with periods in alerting (#16255)
Updates regex to match tag names with periods when generating
series names in alerting evaluation (backend).

Fixes #9148

(cherry picked from commit 33d1d427bc)
2019-04-03 09:56:01 +02:00
Torkel Ödegaard
a6c8cd7f3a Automation: Updates to yarn cli cherrypick & changelog tasks (#16357)
* Automation: Updated cherrypick task to show merge sha

* Fixed changelog milestone filtering

(cherry picked from commit 5aea77fc95)
2019-04-03 09:55:19 +02:00
Daniel Lee
56e4032db3 Chore: docs whats new article for the 6.1 release (#16251)
(cherry picked from commit 0e2d279e3a)
2019-03-27 13:49:01 +01:00
Daniel Lee
944e526eb9 release 6.1.0-beta1 2019-03-27 12:06:23 +01:00
Daniel Lee
0d6db7e6b8 Chore: scripts update publish script before 6.1 release
(cherry picked from commit cbe2543717894ace2a8347859bff22dfbbf57a73)
2019-03-27 12:02:59 +01:00
49 changed files with 308 additions and 132 deletions

4
.browserslistrc Normal file
View File

@@ -0,0 +1,4 @@
>1%,
Chrome > 20
last 4 versions,
Firefox ESR

View File

@@ -322,7 +322,7 @@ jobs:
deploy-enterprise-master: deploy-enterprise-master:
docker: docker:
- image: grafana/grafana-ci-deploy:1.2.1 - image: grafana/grafana-ci-deploy:1.2.2
steps: steps:
- attach_workspace: - attach_workspace:
at: . at: .
@@ -347,7 +347,7 @@ jobs:
deploy-enterprise-release: deploy-enterprise-release:
docker: docker:
- image: grafana/grafana-ci-deploy:1.2.1 - image: grafana/grafana-ci-deploy:1.2.2
steps: steps:
- checkout - checkout
- attach_workspace: - attach_workspace:
@@ -380,7 +380,7 @@ jobs:
deploy-master: deploy-master:
docker: docker:
- image: grafana/grafana-ci-deploy:1.2.1 - image: grafana/grafana-ci-deploy:1.2.2
steps: steps:
- attach_workspace: - attach_workspace:
at: . at: .
@@ -411,7 +411,7 @@ jobs:
deploy-release: deploy-release:
docker: docker:
- image: grafana/grafana-ci-deploy:1.2.1 - image: grafana/grafana-ci-deploy:1.2.2
steps: steps:
- checkout - checkout
- attach_workspace: - attach_workspace:

View File

@@ -361,6 +361,7 @@ func createPackage(options linuxPackageOptions) {
fmt.Printf("pkgArch is set to '%s', generated arch is '%s'\n", pkgArch, options.packageArch) fmt.Printf("pkgArch is set to '%s', generated arch is '%s'\n", pkgArch, options.packageArch)
if pkgArch == "armv6" { if pkgArch == "armv6" {
name += "-rpi" name += "-rpi"
args = append(args, "--replaces", "grafana")
} }
args = append(args, "--name", name) args = append(args, "--name", name)

View File

@@ -0,0 +1,55 @@
+++
title = "What's New in Grafana v6.1"
description = "Feature & improvement highlights for Grafana v6.1"
keywords = ["grafana", "new", "documentation", "6.1"]
type = "docs"
[menu.docs]
name = "Version 6.1"
identifier = "v6.1"
parent = "whatsnew"
weight = -12
+++
# What's New in Grafana v6.1
## Highlights
### Ad hoc Filtering for Prometheus
{{< imgbox max-width="30%" img="/img/docs/v61/prometheus-ad-hoc.gif" caption="Ad-hoc filters variable for Prometheus" >}}
The ad hoc filter feature allows you to create new key/value filters on the fly with autocomplete for both key and values. The filter condition is then automatically applied to all queries on the dashboard. This makes it easier to explore your data in a dashboard without changing queries and without having to add new template variables.
Other timeseries databases with label-based query languages have had this feature for a while. Recently Prometheus added support for fetching label names from their API and thanks to [Mitsuhiro Tanda](https://github.com/mtanda) implementing it in Grafana, the Prometheus datasource finally supports ad hoc filtering.
Support for fetching a list of label names was released in Prometheus v2.6.0 so that is a requirement for this feature to work in Grafana.
### Permissions: Editors can own dashboards, folders and teams they create
When the dashboard folders feature and permissions system was released in Grafana 5.0, users with the editor role were not allowed to administrate dashboards, folders or teams. In the 6.1 release, we have added a config option so that by default editors are admins for any Dashboard, Folder or Team they create.
This feature also adds a new Team permission that can be assigned to any user with the editor or viewer role and lets that user add other users to the Team.
We believe that this is more in line with the Grafana philosophy, as it will allow teams to be more self-organizing. This option will be made permanent if it gets positive feedback from the community so let us know what you think in the [issue on GitHub](https://github.com/grafana/grafana/issues/15590).
To turn this feature on add the following [config option](/installation/configuration/#editors-can-admin) to your Grafana ini file in the `users` section and then restart the Grafana server:
```ini
[users]
editors_can_admin = true
```
### Minor Features and Fixes
This release contains a lot of small features and fixes:
- A new keyboard shortcut `d l` toggles all Graph legends in a dashboard.
- A small bug fix for Elasticsearch - template variables in the alias field now work properly.
- Some new capabilities have been added for datasource plugins that will be of interest to plugin authors:
- a new oauth pass-through option.
- it is now possible to add user details to requests sent to the dataproxy.
- Heatmap and Explore fixes.
Checkout the [CHANGELOG.md](https://github.com/grafana/grafana/blob/master/CHANGELOG.md) file for a complete list of new features, changes, and bug fixes.
A huge thanks to our community for all the reported issues, bug fixes and feedback.

View File

@@ -152,6 +152,7 @@ Content-Type: application/json
PUT /api/alert-notifications/1 HTTP/1.1 PUT /api/alert-notifications/1 HTTP/1.1
Accept: application/json Accept: application/json
Content-Type: application/json Content-Type: application/json
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
``` ```
@@ -170,7 +171,7 @@ Content-Type: application/json
Deletes an existing notification channel identified by uid. Deletes an existing notification channel identified by uid.
**Example Request**: **Example Request**:
**Example Request**:
```http ```http
DELETE /api/alert-notifications/uid/team-a-email-notifier HTTP/1.1 DELETE /api/alert-notifications/uid/team-a-email-notifier HTTP/1.1
Accept: application/json Accept: application/json
@@ -198,6 +199,7 @@ Content-Type: application/json
DELETE /api/alert-notifications/1 HTTP/1.1 DELETE /api/alert-notifications/1 HTTP/1.1
Accept: application/json Accept: application/json
Content-Type: application/json Content-Type: application/json
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
``` ```
**Example Response**: **Example Response**:
@@ -217,7 +219,7 @@ Content-Type: application/json
**Example Request**: **Example Request**:
**Example Request**: ```http
POST /api/alert-notifications/test HTTP/1.1 POST /api/alert-notifications/test HTTP/1.1
Accept: application/json Accept: application/json
Content-Type: application/json Content-Type: application/json
@@ -247,7 +249,7 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
{ {
"id": 1, "id": 1,
"uid": "cIBgcSjkk", "uid": "new-alert-notification", // optional
"name": "new alert notification", //Required "name": "new alert notification", //Required
"type": "email", //Required "type": "email", //Required
"isDefault": false, "isDefault": false,
@@ -267,7 +269,7 @@ Content-Type: application/json
{ {
"id": 1, "id": 1,
"uid": "cIBgcSjkk", "uid": "new-alert-notification",
"name": "new alert notification", "name": "new alert notification",
"type": "email", "type": "email",
"isDefault": false, "isDefault": false,

View File

@@ -5,7 +5,7 @@
"company": "Grafana Labs" "company": "Grafana Labs"
}, },
"name": "grafana", "name": "grafana",
"version": "6.1.0-pre", "version": "6.1.3",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://github.com/grafana/grafana.git" "url": "http://github.com/grafana/grafana.git"

View File

@@ -72,7 +72,7 @@ export class Input extends PureComponent<Props> {
const inputElementProps = this.populateEventPropsWithStatus(restProps, validationEvents); const inputElementProps = this.populateEventPropsWithStatus(restProps, validationEvents);
return ( return (
<div> <div style={{ flexGrow: 1 }}>
<input {...inputElementProps} className={inputClassName} /> <input {...inputElementProps} className={inputClassName} />
{error && !hideErrorMessage && <span>{error}</span>} {error && !hideErrorMessage && <span>{error}</span>}
</div> </div>

View File

@@ -1,7 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Input renders correctly 1`] = ` exports[`Input renders correctly 1`] = `
<div> <div
style={
Object {
"flexGrow": 1,
}
}
>
<input <input
className="gf-form-input" className="gf-form-input"
/> />

View File

@@ -1,6 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import uniqueId from 'lodash/uniqueId'; import uniqueId from 'lodash/uniqueId';
import { Input } from '@grafana/ui';
export interface Props { export interface Props {
label: string; label: string;
@@ -39,7 +38,7 @@ export class Switch extends PureComponent<Props, State> {
<label htmlFor={labelId} className={`gf-form gf-form-switch-container ${className || ''}`}> <label htmlFor={labelId} className={`gf-form gf-form-switch-container ${className || ''}`}>
{label && <div className={labelClassName}>{label}</div>} {label && <div className={labelClassName}>{label}</div>}
<div className={switchClassName}> <div className={switchClassName}>
<Input id={labelId} type="checkbox" checked={checked} onChange={this.internalOnChange} /> <input id={labelId} type="checkbox" checked={checked} onChange={this.internalOnChange} />
<span className="gf-form-switch__slider" /> <span className="gf-form-switch__slider" />
</div> </div>
</label> </label>

View File

@@ -148,10 +148,10 @@ exports[`Render should render with base threshold 1`] = `
"grayBlue": "#212327", "grayBlue": "#212327",
"greenBase": "#299c46", "greenBase": "#299c46",
"greenShade": "#23843b", "greenShade": "#23843b",
"headingColor": "#e3e3e3", "headingColor": "#d8d9da",
"inputBlack": "#09090b", "inputBlack": "#09090b",
"link": "#e3e3e3", "link": "#d8d9da",
"linkDisabled": "#e3e3e3", "linkDisabled": "#8e8e8e",
"linkExternal": "#33b5e5", "linkExternal": "#33b5e5",
"linkHover": "#ffffff", "linkHover": "#ffffff",
"online": "#299c46", "online": "#299c46",
@@ -178,8 +178,8 @@ exports[`Render should render with base threshold 1`] = `
}, },
"name": "Grafana Dark", "name": "Grafana Dark",
"panelPadding": Object { "panelPadding": Object {
"horizontal": 10, "horizontal": 16,
"vertical": 5, "vertical": 8,
}, },
"spacing": Object { "spacing": Object {
"d": "14px", "d": "14px",
@@ -305,10 +305,10 @@ exports[`Render should render with base threshold 1`] = `
"grayBlue": "#212327", "grayBlue": "#212327",
"greenBase": "#299c46", "greenBase": "#299c46",
"greenShade": "#23843b", "greenShade": "#23843b",
"headingColor": "#e3e3e3", "headingColor": "#d8d9da",
"inputBlack": "#09090b", "inputBlack": "#09090b",
"link": "#e3e3e3", "link": "#d8d9da",
"linkDisabled": "#e3e3e3", "linkDisabled": "#8e8e8e",
"linkExternal": "#33b5e5", "linkExternal": "#33b5e5",
"linkHover": "#ffffff", "linkHover": "#ffffff",
"online": "#299c46", "online": "#299c46",
@@ -335,8 +335,8 @@ exports[`Render should render with base threshold 1`] = `
}, },
"name": "Grafana Dark", "name": "Grafana Dark",
"panelPadding": Object { "panelPadding": Object {
"horizontal": 10, "horizontal": 16,
"vertical": 5, "vertical": 8,
}, },
"spacing": Object { "spacing": Object {
"d": "14px", "d": "14px",
@@ -465,7 +465,13 @@ exports[`Render should render with base threshold 1`] = `
type="text" type="text"
value="Base" value="Base"
> >
<div> <div
style={
Object {
"flexGrow": 1,
}
}
>
<input <input
className="gf-form-input" className="gf-form-input"
readOnly={true} readOnly={true}

View File

@@ -197,7 +197,9 @@ $side-menu-width: 60px;
// dashboard // dashboard
$dashboard-padding: $space-md; $dashboard-padding: $space-md;
$panel-padding: 0 $space-md $space-sm $space-md; $panel-padding: 0 ${theme.panelPadding.horizontal}px ${theme.panelPadding.vertical}px ${
theme.panelPadding.horizontal
}px;
// tabs // tabs
$tabs-padding: 10px 15px 9px; $tabs-padding: 10px 15px 9px;

View File

@@ -1,4 +1,3 @@
import tinycolor from 'tinycolor2';
import defaultTheme from './default'; import defaultTheme from './default';
import { GrafanaTheme, GrafanaThemeType } from '../types/theme'; import { GrafanaTheme, GrafanaThemeType } from '../types/theme';
@@ -66,11 +65,11 @@ const darkTheme: GrafanaTheme = {
textWeak: basicColors.gray2, textWeak: basicColors.gray2,
textEmphasis: basicColors.gray5, textEmphasis: basicColors.gray5,
textFaint: basicColors.dark5, textFaint: basicColors.dark5,
link: new tinycolor(basicColors.white).darken(11).toString(), link: basicColors.gray4,
linkDisabled: new tinycolor(basicColors.white).darken(11).toString(), linkDisabled: basicColors.gray2,
linkHover: basicColors.white, linkHover: basicColors.white,
linkExternal: basicColors.blue, linkExternal: basicColors.blue,
headingColor: new tinycolor(basicColors.white).darken(11).toString(), headingColor: basicColors.gray4,
}, },
background: { background: {
dropdown: basicColors.dark3, dropdown: basicColors.dark3,

View File

@@ -67,8 +67,8 @@ const theme: GrafanaThemeCommons = {
}, },
}, },
panelPadding: { panelPadding: {
horizontal: 10, horizontal: 16,
vertical: 5, vertical: 8,
}, },
zIndex: { zIndex: {
dropdown: '1000', dropdown: '1000',

View File

@@ -1,4 +1,3 @@
import tinycolor from 'tinycolor2';
import defaultTheme from './default'; import defaultTheme from './default';
import { GrafanaTheme, GrafanaThemeType } from '../types/theme'; import { GrafanaTheme, GrafanaThemeType } from '../types/theme';
@@ -65,11 +64,11 @@ const lightTheme: GrafanaTheme = {
text: basicColors.gray1, text: basicColors.gray1,
textStrong: basicColors.dark2, textStrong: basicColors.dark2,
textWeak: basicColors.gray2, textWeak: basicColors.gray2,
textEmphasis: basicColors.gray5, textEmphasis: basicColors.dark5,
textFaint: basicColors.dark4, textFaint: basicColors.dark4,
link: basicColors.gray1, link: basicColors.gray1,
linkDisabled: new tinycolor(basicColors.gray1).lighten(30).toString(), linkDisabled: basicColors.gray3,
linkHover: new tinycolor(basicColors.gray1).darken(20).toString(), linkHover: basicColors.dark1,
linkExternal: basicColors.blueLight, linkExternal: basicColors.blueLight,
headingColor: basicColors.gray1, headingColor: basicColors.gray1,
}, },

View File

@@ -5,7 +5,9 @@ export interface DisplayValue {
title?: string; title?: string;
} }
export type DecimalCount = number | null | undefined;
export interface DecimalInfo { export interface DecimalInfo {
decimals: number; decimals: DecimalCount;
scaledDecimals: number; scaledDecimals: DecimalCount;
} }

View File

@@ -158,6 +158,12 @@ describe('Format value', () => {
expect(instance(value).text).toEqual('0.02'); expect(instance(value).text).toEqual('0.02');
}); });
it('should use override decimals', () => {
const value = 100030303;
const instance = getDisplayProcessor({ decimals: 2, unit: 'bytes' });
expect(instance(value).text).toEqual('95.40 MiB');
});
it('should return mapped value if there are matching value mappings', () => { it('should return mapped value if there are matching value mappings', () => {
const valueMappings: ValueMapping[] = [ const valueMappings: ValueMapping[] = [
{ id: 0, operator: '', text: '1-20', type: MappingType.RangeToText, from: '1', to: '20' }, { id: 0, operator: '', text: '1-20', type: MappingType.RangeToText, from: '1', to: '20' },
@@ -182,5 +188,6 @@ describe('getDecimalsForValue()', () => {
expect(getDecimalsForValue(20000)).toEqual({ decimals: 0, scaledDecimals: -2 }); expect(getDecimalsForValue(20000)).toEqual({ decimals: 0, scaledDecimals: -2 });
expect(getDecimalsForValue(200000)).toEqual({ decimals: 0, scaledDecimals: -3 }); expect(getDecimalsForValue(200000)).toEqual({ decimals: 0, scaledDecimals: -3 });
expect(getDecimalsForValue(200000000)).toEqual({ decimals: 0, scaledDecimals: -6 }); expect(getDecimalsForValue(200000000)).toEqual({ decimals: 0, scaledDecimals: -6 });
expect(getDecimalsForValue(100, 2)).toEqual({ decimals: 2, scaledDecimals: null });
}); });
}); });

View File

@@ -8,8 +8,15 @@ import { getMappedValue } from './valueMappings';
import { getColorFromHexRgbOrName } from './namedColorsPalette'; import { getColorFromHexRgbOrName } from './namedColorsPalette';
// Types // Types
import { Threshold, ValueMapping, DecimalInfo, DisplayValue, GrafanaTheme, GrafanaThemeType } from '../types'; import {
import { DecimalCount } from './valueFormats/valueFormats'; Threshold,
ValueMapping,
DecimalInfo,
DisplayValue,
GrafanaTheme,
GrafanaThemeType,
DecimalCount,
} from '../types';
export type DisplayProcessor = (value: any) => DisplayValue; export type DisplayProcessor = (value: any) => DisplayValue;
@@ -69,18 +76,7 @@ export function getDisplayProcessor(options?: DisplayValueOptions): DisplayProce
if (!isNaN(numeric)) { if (!isNaN(numeric)) {
if (shouldFormat && !_.isBoolean(value)) { if (shouldFormat && !_.isBoolean(value)) {
let decimals; const { decimals, scaledDecimals } = getDecimalsForValue(value, options.decimals);
let scaledDecimals = 0;
if (!options.decimals) {
const decimalInfo = getDecimalsForValue(value);
decimals = decimalInfo.decimals;
scaledDecimals = decimalInfo.scaledDecimals;
} else {
decimals = options.decimals;
}
text = formatFunc(numeric, decimals, scaledDecimals, options.isUtc); text = formatFunc(numeric, decimals, scaledDecimals, options.isUtc);
} }
if (thresholds && thresholds.length > 0) { if (thresholds && thresholds.length > 0) {
@@ -159,7 +155,12 @@ export function getColorFromThreshold(value: number, thresholds: Threshold[], th
return getColorFromHexRgbOrName(thresholds[0].color, themeType); return getColorFromHexRgbOrName(thresholds[0].color, themeType);
} }
export function getDecimalsForValue(value: number): DecimalInfo { export function getDecimalsForValue(value: number, decimalOverride?: DecimalCount): DecimalInfo {
if (_.isNumber(decimalOverride)) {
// It's important that scaledDecimals is null here
return { decimals: decimalOverride, scaledDecimals: null };
}
const delta = value / 2; const delta = value / 2;
let dec = -Math.floor(Math.log(delta) / Math.LN10); let dec = -Math.floor(Math.log(delta) / Math.LN10);

View File

@@ -1,4 +1,5 @@
import { toFixed, DecimalCount } from './valueFormats'; import { toFixed } from './valueFormats';
import { DecimalCount } from '../../types';
export function toPercent(size: number, decimals: DecimalCount) { export function toPercent(size: number, decimals: DecimalCount) {
if (size === null) { if (size === null) {

View File

@@ -1,4 +1,5 @@
import { toFixed, toFixedScaled, DecimalCount } from './valueFormats'; import { toFixed, toFixedScaled } from './valueFormats';
import { DecimalCount } from '../../types';
import moment from 'moment'; import moment from 'moment';
interface IntervalsInSeconds { interface IntervalsInSeconds {

View File

@@ -1,4 +1,5 @@
import { scaledUnits, DecimalCount } from './valueFormats'; import { scaledUnits } from './valueFormats';
import { DecimalCount } from '../../types';
export function currency(symbol: string) { export function currency(symbol: string) {
const units = ['', 'K', 'M', 'B', 'T']; const units = ['', 'K', 'M', 'B', 'T'];

View File

@@ -0,0 +1,38 @@
import { toFixed, getValueFormat } from './valueFormats';
describe('valueFormats', () => {
describe('toFixed and negative decimals', () => {
it('should treat as zero decimals', () => {
const str = toFixed(186.123, -2);
expect(str).toBe('186');
});
});
describe('ms format when scaled decimals is null do not use it', () => {
it('should use specified decimals', () => {
const str = getValueFormat('ms')(10000086.123, 1, null);
expect(str).toBe('2.8 hour');
});
});
describe('kbytes format when scaled decimals is null do not use it', () => {
it('should use specified decimals', () => {
const str = getValueFormat('kbytes')(10000000, 3, null);
expect(str).toBe('9.537 GiB');
});
});
describe('deckbytes format when scaled decimals is null do not use it', () => {
it('should use specified decimals', () => {
const str = getValueFormat('deckbytes')(10000000, 3, null);
expect(str).toBe('10.000 GB');
});
});
describe('ms format when scaled decimals is 0', () => {
it('should use scaledDecimals and add 3', () => {
const str = getValueFormat('ms')(1200, 0, 0);
expect(str).toBe('1.200 s');
});
});
});

View File

@@ -1,6 +1,5 @@
import { getCategories } from './categories'; import { getCategories } from './categories';
import { DecimalCount } from '../../types';
export type DecimalCount = number | null | undefined;
export type ValueFormatter = ( export type ValueFormatter = (
value: number, value: number,
@@ -57,17 +56,15 @@ export function toFixed(value: number, decimals?: DecimalCount): string {
export function toFixedScaled( export function toFixedScaled(
value: number, value: number,
decimals?: DecimalCount, decimals: DecimalCount,
scaledDecimals?: DecimalCount, scaledDecimals: DecimalCount,
additionalDecimals?: DecimalCount, additionalDecimals: number,
ext?: string ext?: string
) { ) {
if (scaledDecimals) { if (scaledDecimals === null || scaledDecimals === undefined) {
if (additionalDecimals) { return toFixed(value, decimals) + ext;
return toFixed(value, scaledDecimals + additionalDecimals) + ext; } else {
} else { return toFixed(value, scaledDecimals + additionalDecimals) + ext;
return toFixed(value, scaledDecimals) + ext;
}
} }
return toFixed(value, decimals) + ext; return toFixed(value, decimals) + ext;

View File

@@ -261,6 +261,10 @@ func UpdateAlertNotification(c *m.ReqContext, cmd m.UpdateAlertNotificationComma
return Error(500, "Failed to update alert notification", err) return Error(500, "Failed to update alert notification", err)
} }
if cmd.Result == nil {
return Error(404, "Alert notification not found", nil)
}
return JSON(200, dtos.NewAlertNotification(cmd.Result)) return JSON(200, dtos.NewAlertNotification(cmd.Result))
} }
@@ -272,6 +276,10 @@ func UpdateAlertNotificationByUID(c *m.ReqContext, cmd m.UpdateAlertNotification
return Error(500, "Failed to update alert notification", err) return Error(500, "Failed to update alert notification", err)
} }
if cmd.Result == nil {
return Error(404, "Alert notification not found", nil)
}
return JSON(200, dtos.NewAlertNotification(cmd.Result)) return JSON(200, dtos.NewAlertNotification(cmd.Result))
} }

View File

@@ -39,7 +39,7 @@ type AlertNotification struct {
} }
type CreateAlertNotificationCommand struct { type CreateAlertNotificationCommand struct {
Uid string `json:"-"` Uid string `json:"uid"`
Name string `json:"name" binding:"Required"` Name string `json:"name" binding:"Required"`
Type string `json:"type" binding:"Required"` Type string `json:"type" binding:"Required"`
SendReminder bool `json:"sendReminder"` SendReminder bool `json:"sendReminder"`
@@ -54,6 +54,7 @@ type CreateAlertNotificationCommand struct {
type UpdateAlertNotificationCommand struct { type UpdateAlertNotificationCommand struct {
Id int64 `json:"id" binding:"Required"` Id int64 `json:"id" binding:"Required"`
Uid string `json:"uid"`
Name string `json:"name" binding:"Required"` Name string `json:"name" binding:"Required"`
Type string `json:"type" binding:"Required"` Type string `json:"type" binding:"Required"`
SendReminder bool `json:"sendReminder"` SendReminder bool `json:"sendReminder"`
@@ -68,6 +69,7 @@ type UpdateAlertNotificationCommand struct {
type UpdateAlertNotificationWithUidCommand struct { type UpdateAlertNotificationWithUidCommand struct {
Uid string `json:"-"` Uid string `json:"-"`
NewUid string `json:"uid"`
Name string `json:"name" binding:"Required"` Name string `json:"name" binding:"Required"`
Type string `json:"type" binding:"Required"` Type string `json:"type" binding:"Required"`
SendReminder bool `json:"sendReminder"` SendReminder bool `json:"sendReminder"`

View File

@@ -317,6 +317,10 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error {
current.SendReminder = cmd.SendReminder current.SendReminder = cmd.SendReminder
current.DisableResolveMessage = cmd.DisableResolveMessage current.DisableResolveMessage = cmd.DisableResolveMessage
if cmd.Uid != "" {
current.Uid = cmd.Uid
}
if current.SendReminder { if current.SendReminder {
if cmd.Frequency == "" { if cmd.Frequency == "" {
return m.ErrNotificationFrequencyNotFound return m.ErrNotificationFrequencyNotFound
@@ -356,8 +360,13 @@ func UpdateAlertNotificationWithUid(cmd *m.UpdateAlertNotificationWithUidCommand
return fmt.Errorf("Cannot update, alert notification uid %s doesn't exist", cmd.Uid) return fmt.Errorf("Cannot update, alert notification uid %s doesn't exist", cmd.Uid)
} }
if cmd.NewUid == "" {
cmd.NewUid = cmd.Uid
}
updateNotification := &m.UpdateAlertNotificationCommand{ updateNotification := &m.UpdateAlertNotificationCommand{
Id: current.Id, Id: current.Id,
Uid: cmd.NewUid,
Name: cmd.Name, Name: cmd.Name,
Type: cmd.Type, Type: cmd.Type,
SendReminder: cmd.SendReminder, SendReminder: cmd.SendReminder,
@@ -373,6 +382,8 @@ func UpdateAlertNotificationWithUid(cmd *m.UpdateAlertNotificationWithUidCommand
return err return err
} }
cmd.Result = updateNotification.Result
return nil return nil
} }

View File

@@ -18,7 +18,7 @@ var (
) )
func init() { func init() {
legendFormat = regexp.MustCompile(`\[\[(\w+?)*\]\]*|\$\s*(\w+?)*`) legendFormat = regexp.MustCompile(`\[\[(\w+)(\.\w+)*\]\]*|\$\s*(\w+?)*`)
} }
func (rp *ResponseParser) Parse(response *Response, query *Query) *tsdb.QueryResult { func (rp *ResponseParser) Parse(response *Response, query *Query) *tsdb.QueryResult {

View File

@@ -75,7 +75,10 @@ func TestInfluxdbResponseParser(t *testing.T) {
{ {
Name: "cpu.upc", Name: "cpu.upc",
Columns: []string{"time", "mean", "sum"}, Columns: []string{"time", "mean", "sum"},
Tags: map[string]string{"datacenter": "America"}, Tags: map[string]string{
"datacenter": "America",
"dc.region.name": "Northeast",
},
Values: [][]interface{}{ Values: [][]interface{}{
{json.Number("111"), json.Number("222"), json.Number("333")}, {json.Number("111"), json.Number("222"), json.Number("333")},
}, },
@@ -159,6 +162,13 @@ func TestInfluxdbResponseParser(t *testing.T) {
So(result.Series[0].Name, ShouldEqual, "alias America") So(result.Series[0].Name, ShouldEqual, "alias America")
}) })
Convey("tag alias with periods", func() {
query := &Query{Alias: "alias [[tag_dc.region.name]]"}
result := parser.Parse(response, query)
So(result.Series[0].Name, ShouldEqual, "alias Northeast")
})
}) })
}) })
}) })

View File

@@ -139,7 +139,7 @@ export class QueryEditorRow extends PureComponent<Props, State> {
// give angular time to compile // give angular time to compile
setTimeout(() => { setTimeout(() => {
this.setState({ hasTextEditMode: !!this.angularScope.toggleEditorMode }); this.setState({ hasTextEditMode: !!this.angularScope.toggleEditorMode });
}, 10); }, 100);
} }
onToggleCollapse = () => { onToggleCollapse = () => {

View File

@@ -9,6 +9,12 @@ import locationUtil from 'app/core/utils/location_util';
import kbn from 'app/core/utils/kbn'; import kbn from 'app/core/utils/kbn';
import { store } from 'app/store/store'; import { store } from 'app/store/store';
export const queryParamsToPreserve: { [key: string]: boolean } = {
kiosk: true,
autofitpanels: true,
orgId: true,
};
export class PlaylistSrv { export class PlaylistSrv {
private cancelPromise: any; private cancelPromise: any;
private dashboards: Array<{ url: string }>; private dashboards: Array<{ url: string }>;
@@ -41,9 +47,7 @@ export class PlaylistSrv {
const dash = this.dashboards[this.index]; const dash = this.dashboards[this.index];
const queryParams = this.$location.search(); const queryParams = this.$location.search();
const filteredParams = _.pickBy(queryParams, key => { const filteredParams = _.pickBy(queryParams, (value: any, key: string) => queryParamsToPreserve[key]);
return key === 'kiosk' || key === 'autofitpanels' || key === 'orgId';
});
const nextDashboardUrl = locationUtil.stripBaseFromUrl(dash.url); const nextDashboardUrl = locationUtil.stripBaseFromUrl(dash.url);
// this is done inside timeout to make sure digest happens after // this is done inside timeout to make sure digest happens after

View File

@@ -8,13 +8,13 @@ export default class DefaultVariableQueryEditor extends PureComponent<VariableQu
this.state = { value: props.query }; this.state = { value: props.query };
} }
handleChange(event) { onChange = (event: React.FormEvent<HTMLInputElement>) => {
this.setState({ value: event.target.value }); this.setState({ value: event.currentTarget.value });
} };
handleBlur(event) { onBlur = (event: React.FormEvent<HTMLInputElement>) => {
this.props.onChange(event.target.value, event.target.value); this.props.onChange(event.currentTarget.value, event.currentTarget.value);
} };
render() { render() {
return ( return (
@@ -24,8 +24,8 @@ export default class DefaultVariableQueryEditor extends PureComponent<VariableQu
type="text" type="text"
className="gf-form-input" className="gf-form-input"
value={this.state.value} value={this.state.value}
onChange={this.handleChange} onChange={this.onChange}
onBlur={this.handleBlur} onBlur={this.onBlur}
placeholder="metric name or tags query" placeholder="metric name or tags query"
required required
/> />

View File

@@ -112,6 +112,7 @@ export class CloudWatchQueryParameterCtrl {
query = $scope.datasource.getDimensionKeys($scope.target.namespace, $scope.target.region); query = $scope.datasource.getDimensionKeys($scope.target.namespace, $scope.target.region);
} else if (segment.type === 'value') { } else if (segment.type === 'value') {
const dimensionKey = $scope.dimSegments[$index - 2].value; const dimensionKey = $scope.dimSegments[$index - 2].value;
delete target.dimensions[dimensionKey];
query = $scope.datasource.getDimensionValues( query = $scope.datasource.getDimensionValues(
target.region, target.region,
target.namespace, target.namespace,

View File

@@ -966,7 +966,6 @@ export class FuncInstance {
const str = this.def.name + '('; const str = this.def.name + '(';
const parameters = _.map(this.params, (value, index) => { const parameters = _.map(this.params, (value, index) => {
const valueInterpolated = replaceVariables(value);
let paramType; let paramType;
if (index < this.def.params.length) { if (index < this.def.params.length) {
@@ -980,6 +979,8 @@ export class FuncInstance {
return value; return value;
} }
const valueInterpolated = _.isString(value) ? replaceVariables(value) : value;
// param types that might be quoted // param types that might be quoted
// To quote variables correctly we need to interpolate it to check if it contains a numeric or string value // To quote variables correctly we need to interpolate it to check if it contains a numeric or string value
if (_.includes(['int_or_interval', 'node_or_tag'], paramType) && _.isFinite(+valueInterpolated)) { if (_.includes(['int_or_interval', 'node_or_tag'], paramType) && _.isFinite(+valueInterpolated)) {

View File

@@ -19,6 +19,7 @@ export default class GraphiteQuery {
this.datasource = datasource; this.datasource = datasource;
this.target = target; this.target = target;
this.templateSrv = templateSrv; this.templateSrv = templateSrv;
this.scopedVars = scopedVars;
this.parseTarget(); this.parseTarget();
this.removeTagValue = '-- remove tag --'; this.removeTagValue = '-- remove tag --';
@@ -162,7 +163,9 @@ export default class GraphiteQuery {
updateModelTarget(targets) { updateModelTarget(targets) {
const wrapFunction = (target: string, func: any) => { const wrapFunction = (target: string, func: any) => {
return func.render(target, this.templateSrv.replace); return func.render(target, (value: string) => {
return this.templateSrv.replace(value, this.scopedVars);
});
}; };
if (!this.target.textEditor) { if (!this.target.textEditor) {

View File

@@ -31,7 +31,8 @@ describe('when creating func instance from func names', () => {
}); });
function replaceVariablesDummy(str: string) { function replaceVariablesDummy(str: string) {
return str; // important that this does replace
return str.replace('asdasdas', 'asdsad');
} }
describe('when rendering func instance', () => { describe('when rendering func instance', () => {

View File

@@ -398,7 +398,13 @@ Array [
> >
Alias By Alias By
</label> </label>
<div> <div
style={
Object {
"flexGrow": 1,
}
}
>
<input <input
className="gf-form-input gf-form-input width-24" className="gf-form-input gf-form-input width-24"
onChange={[Function]} onChange={[Function]}
@@ -426,7 +432,13 @@ Array [
> >
Project Project
</span> </span>
<div> <div
style={
Object {
"flexGrow": 1,
}
}
>
<input <input
className="gf-form-input gf-form-input width-15" className="gf-form-input gf-form-input width-15"
disabled={true} disabled={true}

View File

@@ -191,7 +191,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
data.value = 0; data.value = 0;
data.valueRounded = 0; data.valueRounded = 0;
} else { } else {
const decimalInfo = getDecimalsForValue(data.value); const decimalInfo = getDecimalsForValue(data.value, this.panel.decimals);
const formatFunc = getValueFormat(this.panel.format); const formatFunc = getValueFormat(this.panel.format);
data.valueFormatted = formatFunc( data.valueFormatted = formatFunc(
@@ -199,7 +199,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
decimalInfo.decimals, decimalInfo.decimals,
decimalInfo.scaledDecimals decimalInfo.scaledDecimals
); );
data.valueRounded = kbn.roundValue(data.value, this.panel.decimals || 0); data.valueRounded = kbn.roundValue(data.value, decimalInfo.decimals);
} }
this.setValueMapping(data); this.setValueMapping(data);
@@ -279,17 +279,15 @@ class SingleStatCtrl extends MetricsPanelCtrl {
data.value = this.series[0].stats[this.panel.valueName]; data.value = this.series[0].stats[this.panel.valueName];
data.flotpairs = this.series[0].flotpairs; data.flotpairs = this.series[0].flotpairs;
let decimals = this.panel.decimals; const decimalInfo = getDecimalsForValue(data.value, this.panel.decimals);
let scaledDecimals = 0;
if (!this.panel.decimals) { data.valueFormatted = formatFunc(
const decimalInfo = getDecimalsForValue(data.value); data.value,
decimals = decimalInfo.decimals; decimalInfo.decimals,
scaledDecimals = decimalInfo.scaledDecimals; decimalInfo.scaledDecimals,
} this.dashboard.isTimezoneUtc()
);
data.valueFormatted = formatFunc(data.value, decimals, scaledDecimals, this.dashboard.isTimezoneUtc()); data.valueRounded = kbn.roundValue(data.value, decimalInfo.decimals);
data.valueRounded = kbn.roundValue(data.value, decimals);
} }
// Add $__name variable for using in prefix or postfix // Add $__name variable for using in prefix or postfix

View File

@@ -102,14 +102,14 @@ $edit-gradient: linear-gradient(180deg, $dark-2 50%, $input-black);
// Links // Links
// ------------------------- // -------------------------
$link-color: #e3e3e3; $link-color: #d8d9da;
$link-color-disabled: #e3e3e3; $link-color-disabled: #8e8e8e;
$link-hover-color: #ffffff; $link-hover-color: #ffffff;
$external-link-color: #33b5e5; $external-link-color: #33b5e5;
// Typography // Typography
// ------------------------- // -------------------------
$headings-color: #e3e3e3; $headings-color: #d8d9da;
$abbr-border-color: $gray-2 !default; $abbr-border-color: $gray-2 !default;
$text-muted: $text-color-weak; $text-muted: $text-color-weak;

View File

@@ -200,7 +200,7 @@ $side-menu-width: 60px;
// dashboard // dashboard
$dashboard-padding: $space-md; $dashboard-padding: $space-md;
$panel-padding: 0 $space-md $space-sm $space-md; $panel-padding: 0 16px 8px 16px;
// tabs // tabs
$tabs-padding: 10px 15px 9px; $tabs-padding: 10px 15px 9px;

View File

@@ -76,7 +76,7 @@ $text-color: #52545c;
$text-color-strong: #41444b; $text-color-strong: #41444b;
$text-color-weak: #767980; $text-color-weak: #767980;
$text-color-faint: #35373f; $text-color-faint: #35373f;
$text-color-emphasis: #dde4ed; $text-color-emphasis: #41444b;
$text-shadow-faint: none; $text-shadow-faint: none;
@@ -89,8 +89,8 @@ $edit-gradient: linear-gradient(-60deg, $gray-7, #f5f6f9 70%, $gray-7 98%);
// Links // Links
// ------------------------- // -------------------------
$link-color: #52545c; $link-color: #52545c;
$link-color-disabled: #9ea0a9; $link-color-disabled: #acb6bf;
$link-hover-color: #222326; $link-hover-color: #1e2028;
$external-link-color: #5794f2; $external-link-color: #5794f2;
// Typography // Typography

View File

@@ -153,7 +153,7 @@
.share-modal-info-text { .share-modal-info-text {
margin-top: 5px; margin-top: 5px;
strong { strong {
color: $headings-color; color: $text-color-emphasis;
font-weight: 500; font-weight: 500;
} }
} }

View File

@@ -120,6 +120,10 @@
// fix for phantomjs // fix for phantomjs
.body--phantomjs { .body--phantomjs {
.graph-panel {
display: -webkit-box;
}
.graph-panel--legend-right { .graph-panel--legend-right {
.graph-legend { .graph-legend {
display: block; display: block;

View File

@@ -335,7 +335,6 @@
} }
@mixin left-brand-border-gradient() { @mixin left-brand-border-gradient() {
border: none;
border-image: linear-gradient(rgba(255, 213, 0, 1) 0%, rgba(255, 68, 0, 1) 99%, rgba(255, 68, 0, 1) 100%); border-image: linear-gradient(rgba(255, 213, 0, 1) 0%, rgba(255, 68, 0, 1) 99%, rgba(255, 68, 0, 1) 100%);
border-image-slice: 1; border-image-slice: 1;
border-style: solid; border-style: solid;

View File

@@ -18,7 +18,9 @@ RUN pip install -U awscli crcmod && \
apt-get autoremove -y && \ apt-get autoremove -y && \
rm -rf /var/lib/apt/lists/* && \ rm -rf /var/lib/apt/lists/* && \
ln -s /opt/google-cloud-sdk/bin/gsutil /usr/bin/gsutil && \ ln -s /opt/google-cloud-sdk/bin/gsutil /usr/bin/gsutil && \
ln -s /opt/google-cloud-sdk/bin/gcloud /usr/bin/gcloud ln -s /opt/google-cloud-sdk/bin/gcloud /usr/bin/gcloud && \
mkdir -p /deb-repo /rpm-repo && \
chown circleci:circleci /deb-repo /rpm-repo
COPY --from=0 /go/bin/aptly /usr/local/bin/aptly COPY --from=0 /go/bin/aptly /usr/local/bin/aptly

View File

@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
_version="1.2.1" _version="1.2.2"
_tag="grafana/grafana-ci-deploy:${_version}" _tag="grafana/grafana-ci-deploy:${_version}"
docker build -t $_tag . docker build -t $_tag .

View File

@@ -6,8 +6,8 @@ EXTRA_OPTS="$@"
# Right now we hack this in into the publish script. # Right now we hack this in into the publish script.
# Eventually we might want to keep a list of all previous releases somewhere. # Eventually we might want to keep a list of all previous releases somewhere.
_releaseNoteUrl="https://community.grafana.com/t/release-notes-v6-0-x/14010" _releaseNoteUrl="https://community.grafana.com/t/release-notes-v6-1-x/15772"
_whatsNewUrl="http://docs.grafana.org/guides/whats-new-in-v6-0/" _whatsNewUrl="http://docs.grafana.org/guides/whats-new-in-v6-1/"
./scripts/build/release_publisher/release_publisher \ ./scripts/build/release_publisher/release_publisher \
--wn ${_whatsNewUrl} \ --wn ${_whatsNewUrl} \

View File

@@ -14,21 +14,21 @@ const changelogTaskRunner: TaskRunner<ChangelogOptions> = async ({ milestone })
timeout: 10000, timeout: 10000,
}); });
if (!/^\d+$/.test(milestone)) {
console.log('Use milestone number not title, find number in milestone url');
return;
}
const res = await client.get('/issues', { const res = await client.get('/issues', {
params: { params: {
state: 'closed', state: 'closed',
per_page: 100, per_page: 100,
labels: 'add to changelog', labels: 'add to changelog',
milestone: milestone,
}, },
}); });
const issues = res.data.filter(item => { const issues = res.data;
if (!item.milestone) {
console.log('Item missing milestone', item.number);
return false;
}
return item.milestone.title === milestone;
});
const bugs = _.sortBy( const bugs = _.sortBy(
issues.filter(item => { issues.filter(item => {

View File

@@ -27,13 +27,10 @@ const cherryPickRunner: TaskRunner<CherryPickOptions> = async () => {
continue; continue;
} }
console.log(item.number + ' closed_at ' + item.closed_at + ' ' + item.html_url); console.log(`${item.title} (${item.number}) closed_at ${item.closed_at}`);
console.log(`\tURL: ${item.closed_at} ${item.html_url}`);
const issueDetails = await client.get(item.pull_request.url); const issueDetails = await client.get(item.pull_request.url);
const commits = await client.get(issueDetails.data.commits_url); console.log(`\tMerge sha: ${issueDetails.data.merge_commit_sha}`);
for (const commit of commits.data) {
console.log(commit.commit.message + ' sha: ' + commit.sha);
}
} }
}; };

View File

@@ -1,7 +1,9 @@
module.exports = { module.exports = () => {
plugins: { return {
'autoprefixer': {}, plugins: {
'postcss-reporter': {}, autoprefixer: {},
'postcss-browser-reporter': {}, 'postcss-reporter': {},
} 'postcss-browser-reporter': {},
} }
};
};

View File

@@ -19,7 +19,7 @@ module.exports = function(options) {
loader: 'postcss-loader', loader: 'postcss-loader',
options: { options: {
sourceMap: options.sourceMap, sourceMap: options.sourceMap,
config: { path: __dirname + '/postcss.config.js' }, config: { path: __dirname },
}, },
}, },
{ {