From ca6dd7392312fb05c15a18d71aba4df09133ab1c Mon Sep 17 00:00:00 2001 From: Athurg Feng Date: Thu, 25 Oct 2018 18:17:05 +0800 Subject: [PATCH 01/24] Add match values into Dingding notification message --- pkg/services/alerting/notifiers/dingding.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/services/alerting/notifiers/dingding.go b/pkg/services/alerting/notifiers/dingding.go index 1ef085c82f1..9ad85d55004 100644 --- a/pkg/services/alerting/notifiers/dingding.go +++ b/pkg/services/alerting/notifiers/dingding.go @@ -1,6 +1,8 @@ package notifiers import ( + "fmt" + "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/log" @@ -61,6 +63,10 @@ func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { message = title } + for i, match := range evalContext.EvalMatches { + message += fmt.Sprintf("\\n%2d. %s value %s", i+1, match.Metric, match.Value) + } + bodyJSON, err := simplejson.NewJson([]byte(`{ "msgtype": "link", "link": { From 7f45afac63b93bacd73d6ada811b5db0178b1723 Mon Sep 17 00:00:00 2001 From: Athurg Feng Date: Thu, 25 Oct 2018 18:24:04 +0800 Subject: [PATCH 02/24] Split text template into variable --- pkg/services/alerting/notifiers/dingding.go | 23 ++++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/pkg/services/alerting/notifiers/dingding.go b/pkg/services/alerting/notifiers/dingding.go index 9ad85d55004..bf1b721f753 100644 --- a/pkg/services/alerting/notifiers/dingding.go +++ b/pkg/services/alerting/notifiers/dingding.go @@ -10,19 +10,21 @@ import ( "github.com/grafana/grafana/pkg/services/alerting" ) -func init() { - alerting.RegisterNotifier(&alerting.NotifierPlugin{ - Type: "dingding", - Name: "DingDing", - Description: "Sends HTTP POST request to DingDing", - Factory: NewDingDingNotifier, - OptionsTemplate: ` +const DingdingOptionsTemplate = `

DingDing settings

Url
- `, +` + +func init() { + alerting.RegisterNotifier(&alerting.NotifierPlugin{ + Type: "dingding", + Name: "DingDing", + Description: "Sends HTTP POST request to DingDing", + Factory: NewDingDingNotifier, + OptionsTemplate: DingdingOptionsTemplate, }) } @@ -67,7 +69,7 @@ func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { message += fmt.Sprintf("\\n%2d. %s value %s", i+1, match.Metric, match.Value) } - bodyJSON, err := simplejson.NewJson([]byte(`{ + bodyStr := `{ "msgtype": "link", "link": { "text": "` + message + `", @@ -75,7 +77,8 @@ func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { "picUrl": "` + picUrl + `", "messageUrl": "` + messageUrl + `" } - }`)) + }` + bodyJSON, err := simplejson.NewJson([]byte(bodyStr)) if err != nil { this.log.Error("Failed to create Json data", "error", err, "dingding", this.Name) From cb86e386289a02f1a8638b2e84030b36c697efa9 Mon Sep 17 00:00:00 2001 From: Athurg Feng Date: Thu, 25 Oct 2018 18:29:47 +0800 Subject: [PATCH 03/24] Add Dingding message type to support mass text notification --- pkg/services/alerting/notifiers/dingding.go | 45 ++++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/pkg/services/alerting/notifiers/dingding.go b/pkg/services/alerting/notifiers/dingding.go index bf1b721f753..ce932b7a799 100644 --- a/pkg/services/alerting/notifiers/dingding.go +++ b/pkg/services/alerting/notifiers/dingding.go @@ -10,12 +10,17 @@ import ( "github.com/grafana/grafana/pkg/services/alerting" ) +const DefaultDingdingMsgType = "link" const DingdingOptionsTemplate = `

DingDing settings

Url
+
+ MessageType + +
` func init() { @@ -35,8 +40,11 @@ func NewDingDingNotifier(model *m.AlertNotification) (alerting.Notifier, error) return nil, alerting.ValidationError{Reason: "Could not find url property in settings"} } + msgType := model.Settings.Get("msgType").MustString(DefaultDingdingMsgType) + return &DingDingNotifier{ NotifierBase: NewNotifierBase(model), + MsgType: msgType, Url: url, log: log.New("alerting.notifier.dingding"), }, nil @@ -44,8 +52,9 @@ func NewDingDingNotifier(model *m.AlertNotification) (alerting.Notifier, error) type DingDingNotifier struct { NotifierBase - Url string - log log.Logger + MsgType string + Url string + log log.Logger } func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { @@ -69,15 +78,29 @@ func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { message += fmt.Sprintf("\\n%2d. %s value %s", i+1, match.Metric, match.Value) } - bodyStr := `{ - "msgtype": "link", - "link": { - "text": "` + message + `", - "title": "` + title + `", - "picUrl": "` + picUrl + `", - "messageUrl": "` + messageUrl + `" - } - }` + var bodyStr string + if this.MsgType == "actionCard" { + bodyStr = `{ + "msgtype": "actionCard", + "actionCard": { + "text": "` + message + `", + "title": "` + title + `", + "singleTitle": "More", + "singleURL": "` + messageUrl + `" + } + }` + } else { + bodyStr = `{ + "msgtype": "link", + "link": { + "text": "` + message + `", + "title": "` + title + `", + "picUrl": "` + picUrl + `", + "messageUrl": "` + messageUrl + `" + } + }` + } + bodyJSON, err := simplejson.NewJson([]byte(bodyStr)) if err != nil { From 201dd6bf658501782180ce90111390d4970b16c8 Mon Sep 17 00:00:00 2001 From: Athurg Feng Date: Thu, 25 Oct 2018 18:53:45 +0800 Subject: [PATCH 04/24] Optimize the Dingding match values format --- pkg/services/alerting/notifiers/dingding.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/alerting/notifiers/dingding.go b/pkg/services/alerting/notifiers/dingding.go index ce932b7a799..94961e82025 100644 --- a/pkg/services/alerting/notifiers/dingding.go +++ b/pkg/services/alerting/notifiers/dingding.go @@ -75,7 +75,7 @@ func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { } for i, match := range evalContext.EvalMatches { - message += fmt.Sprintf("\\n%2d. %s value %s", i+1, match.Metric, match.Value) + message += fmt.Sprintf("\\n%2d. %s: %s", i+1, match.Metric, match.Value) } var bodyStr string From b7787db34e2b71cdc59aef829ea1a3d69b0a1e3c Mon Sep 17 00:00:00 2001 From: Athurg Feng Date: Thu, 8 Nov 2018 18:44:00 +0800 Subject: [PATCH 05/24] Add new option to set where to open the message url --- pkg/services/alerting/notifiers/dingding.go | 37 ++++++++++++++++----- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/pkg/services/alerting/notifiers/dingding.go b/pkg/services/alerting/notifiers/dingding.go index 94961e82025..af1063a4c70 100644 --- a/pkg/services/alerting/notifiers/dingding.go +++ b/pkg/services/alerting/notifiers/dingding.go @@ -2,6 +2,7 @@ package notifiers import ( "fmt" + "net/url" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" @@ -15,12 +16,17 @@ const DingdingOptionsTemplate = `

DingDing settings

Url - +
MessageType
+
+ OpenInBrowser + + Open the message url in browser instead of inside of Dingding +
` func init() { @@ -41,20 +47,23 @@ func NewDingDingNotifier(model *m.AlertNotification) (alerting.Notifier, error) } msgType := model.Settings.Get("msgType").MustString(DefaultDingdingMsgType) + openInBrowser := model.Settings.Get("openInBrowser").MustBool(true) return &DingDingNotifier{ - NotifierBase: NewNotifierBase(model), - MsgType: msgType, - Url: url, - log: log.New("alerting.notifier.dingding"), + NotifierBase: NewNotifierBase(model), + OpenInBrowser: openInBrowser, + MsgType: msgType, + Url: url, + log: log.New("alerting.notifier.dingding"), }, nil } type DingDingNotifier struct { NotifierBase - MsgType string - Url string - log log.Logger + MsgType string + OpenInBrowser bool //Set whether the message url will open outside of Dingding + Url string + log log.Logger } func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { @@ -65,6 +74,18 @@ func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { this.log.Error("Failed to get messageUrl", "error", err, "dingding", this.Name) messageUrl = "" } + + if this.OpenInBrowser { + q := url.Values{ + "pc_slide": {"false"}, + "url": {messageUrl}, + } + + // Use special link to auto open the message url outside of Dingding + // Refer: https://open-doc.dingtalk.com/docs/doc.htm?treeId=385&articleId=104972&docType=1#s9 + messageUrl = "dingtalk://dingtalkclient/page/link?" + q.Encode() + } + this.log.Info("messageUrl:" + messageUrl) message := evalContext.Rule.Message From 919d00437e21944d5feea3c6ac175a2d85736784 Mon Sep 17 00:00:00 2001 From: Athurg Feng Date: Mon, 12 Nov 2018 11:18:53 +0800 Subject: [PATCH 06/24] Add pic into actionCard message --- pkg/services/alerting/notifiers/dingding.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/services/alerting/notifiers/dingding.go b/pkg/services/alerting/notifiers/dingding.go index af1063a4c70..3514554a1db 100644 --- a/pkg/services/alerting/notifiers/dingding.go +++ b/pkg/services/alerting/notifiers/dingding.go @@ -101,6 +101,11 @@ func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { var bodyStr string if this.MsgType == "actionCard" { + // Embed the pic into the markdown directly because actionCard doesn't have a picUrl field + if picUrl != "" { + message = "![](" + picUrl + ")\\n\\n" + message + } + bodyStr = `{ "msgtype": "actionCard", "actionCard": { From bba92c0746e3bbbb53833dd222cb4f38cca8a2d5 Mon Sep 17 00:00:00 2001 From: Athurg Feng Date: Sat, 2 Feb 2019 13:35:17 +0800 Subject: [PATCH 07/24] Remove option used to control within browser --- pkg/services/alerting/notifiers/dingding.go | 38 ++++++++------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/pkg/services/alerting/notifiers/dingding.go b/pkg/services/alerting/notifiers/dingding.go index 3514554a1db..a3934903bd6 100644 --- a/pkg/services/alerting/notifiers/dingding.go +++ b/pkg/services/alerting/notifiers/dingding.go @@ -22,11 +22,6 @@ const DingdingOptionsTemplate = ` MessageType -
- OpenInBrowser - - Open the message url in browser instead of inside of Dingding -
` func init() { @@ -47,23 +42,20 @@ func NewDingDingNotifier(model *m.AlertNotification) (alerting.Notifier, error) } msgType := model.Settings.Get("msgType").MustString(DefaultDingdingMsgType) - openInBrowser := model.Settings.Get("openInBrowser").MustBool(true) return &DingDingNotifier{ - NotifierBase: NewNotifierBase(model), - OpenInBrowser: openInBrowser, - MsgType: msgType, - Url: url, - log: log.New("alerting.notifier.dingding"), + NotifierBase: NewNotifierBase(model), + MsgType: msgType, + Url: url, + log: log.New("alerting.notifier.dingding"), }, nil } type DingDingNotifier struct { NotifierBase - MsgType string - OpenInBrowser bool //Set whether the message url will open outside of Dingding - Url string - log log.Logger + MsgType string + Url string + log log.Logger } func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { @@ -75,17 +67,15 @@ func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { messageUrl = "" } - if this.OpenInBrowser { - q := url.Values{ - "pc_slide": {"false"}, - "url": {messageUrl}, - } - - // Use special link to auto open the message url outside of Dingding - // Refer: https://open-doc.dingtalk.com/docs/doc.htm?treeId=385&articleId=104972&docType=1#s9 - messageUrl = "dingtalk://dingtalkclient/page/link?" + q.Encode() + q := url.Values{ + "pc_slide": {"false"}, + "url": {messageUrl}, } + // Use special link to auto open the message url outside of Dingding + // Refer: https://open-doc.dingtalk.com/docs/doc.htm?treeId=385&articleId=104972&docType=1#s9 + messageUrl = "dingtalk://dingtalkclient/page/link?" + q.Encode() + this.log.Info("messageUrl:" + messageUrl) message := evalContext.Rule.Message From 70b23ab73bfbf364c97da23fe9a829ae9099731c Mon Sep 17 00:00:00 2001 From: Athurg Feng Date: Sat, 2 Feb 2019 13:36:10 +0800 Subject: [PATCH 08/24] Add string quote func --- pkg/services/alerting/notifiers/dingding.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/services/alerting/notifiers/dingding.go b/pkg/services/alerting/notifiers/dingding.go index a3934903bd6..3e3496622b7 100644 --- a/pkg/services/alerting/notifiers/dingding.go +++ b/pkg/services/alerting/notifiers/dingding.go @@ -3,6 +3,7 @@ package notifiers import ( "fmt" "net/url" + "strings" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" @@ -99,8 +100,8 @@ func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error { bodyStr = `{ "msgtype": "actionCard", "actionCard": { - "text": "` + message + `", - "title": "` + title + `", + "text": "` + strings.Replace(message, `"`, "'", -1) + `", + "title": "` + strings.Replace(title, `"`, "'", -1) + `", "singleTitle": "More", "singleURL": "` + messageUrl + `" } From e5ce7591677976768fa3877eac240a4a3f94d9be Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 23 Feb 2019 21:53:20 -0800 Subject: [PATCH 09/24] update --- public/app/plugins/panel/text2/TextPanel.tsx | 100 ++++++++++++++++++ .../plugins/panel/text2/TextPanelEditor.tsx | 32 ++++++ public/app/plugins/panel/text2/module.tsx | 18 ++-- public/app/plugins/panel/text2/types.ts | 14 +++ 4 files changed, 153 insertions(+), 11 deletions(-) create mode 100644 public/app/plugins/panel/text2/TextPanel.tsx create mode 100644 public/app/plugins/panel/text2/TextPanelEditor.tsx create mode 100644 public/app/plugins/panel/text2/types.ts diff --git a/public/app/plugins/panel/text2/TextPanel.tsx b/public/app/plugins/panel/text2/TextPanel.tsx new file mode 100644 index 00000000000..9e9210df119 --- /dev/null +++ b/public/app/plugins/panel/text2/TextPanel.tsx @@ -0,0 +1,100 @@ +import React, { Component } from 'react'; + +import Remarkable from 'remarkable'; +import { sanitize } from 'app/core/utils/text'; +import config from 'app/core/config'; +import templateSrv from 'app/features/templating/template_srv'; +import { debounce } from 'lodash'; + +// Types +import { TextOptions } from './types'; +import { PanelProps } from '@grafana/ui/src/types'; + +interface Props extends PanelProps {} +interface State { + html: string; +} + +export class TextPanel extends Component { + remarkable: Remarkable; + + constructor(props) { + super(props); + + // TODO thre must be some better way to start with defualt options! + let opts = props.options; + if (opts && opts['options']) { + opts = opts['options']; + console.log('WEIRD!', opts); + } + + this.state = { + html: this.processContent(opts), + }; + } + + updateHTML = debounce(() => { + const html = this.processContent(this.props.options); + if (html !== this.state.html) { + this.setState({ html }); + } + }, 100); + + componentDidUpdate(prevProps: Props) { + // Since any change could be referenced in a template variable, + // This needs to process everything + this.updateHTML(); + } + + prepareHTML(html: string): string { + const scopedVars = {}; // TODO?? = this.props.; + html = config.disableSanitizeHtml ? html : sanitize(html); + try { + return templateSrv.replace(html, scopedVars); + } catch (e) { + // TODO -- put the error in the header window + console.log('Text panel error: ', e); + return html; + } + } + + prepareText(content: string): string { + return this.prepareHTML( + content + .replace(/&/g, '&') + .replace(/>/g, '>') + .replace(/') + ); + } + + prepareMarkdown(content: string): string { + if (!this.remarkable) { + this.remarkable = new Remarkable(); + } + return this.prepareHTML(this.remarkable.render(content)); + } + + processContent(options: TextOptions): string { + const { mode, content } = options; + + if (!content) { + return ''; + } + + if (mode === 'markdown') { + return this.prepareMarkdown(content); + } + if (mode === 'html') { + return this.prepareHTML(content); + } + + return this.prepareText(content); + } + + render() { + const { html } = this.state; + + return
; + } +} diff --git a/public/app/plugins/panel/text2/TextPanelEditor.tsx b/public/app/plugins/panel/text2/TextPanelEditor.tsx new file mode 100644 index 00000000000..2581384af9a --- /dev/null +++ b/public/app/plugins/panel/text2/TextPanelEditor.tsx @@ -0,0 +1,32 @@ +import React, { PureComponent } from 'react'; +import { PanelEditorProps, PanelOptionsGroup, Select, SelectOptionItem } from '@grafana/ui'; + +import { TextOptions } from './types'; + +export class TextPanelEditor extends PureComponent> { + modes: SelectOptionItem[] = [ + { value: 'markdown', label: 'Markdown' }, + { value: 'text', label: 'Text' }, + { value: 'html', label: 'HTML' }, + ]; + + onModeChange = (item: SelectOptionItem) => this.props.onChange({ ...this.props.options, mode: item.value }); + + onContentChange = evt => this.props.onChange({ ...this.props.options, content: (event.target as any).value }); + + render() { + const { mode, content } = this.props.options; + + return ( + +
+ Mode + mode === e.value)} options={this.modes} /> +
+
+ Mode +
-
- -
+ +
@@ -44,6 +44,7 @@ export class SaveDashboardAsModalCtrl { folderId: any; dismiss: () => void; isValidFolderSelection = true; + preseveTags: boolean; /** @ngInject */ constructor(private dashboardSrv) { @@ -55,6 +56,7 @@ export class SaveDashboardAsModalCtrl { this.clone.editable = true; this.clone.hideControls = false; this.folderId = dashboard.meta.folderId; + this.preseveTags = false; // remove alerts if source dashboard is already persisted // do not want to create alert dupes @@ -71,6 +73,10 @@ export class SaveDashboardAsModalCtrl { } save() { + if (!this.preseveTags) { + this.clone.tags = []; + } + return this.dashboardSrv.save(this.clone, { folderId: this.folderId }).then(this.dismiss); } From 04c88a226b1d36355fb92cd12a515d58ac88e76d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 8 Mar 2019 14:24:45 +0100 Subject: [PATCH 21/24] Minor refactoring of copy tags when saving feature, #15446 --- .../SaveModals/SaveDashboardAsModalCtrl.ts | 14 ++++++++------ public/sass/components/_tags.scss | 6 ++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/public/app/features/dashboard/components/SaveModals/SaveDashboardAsModalCtrl.ts b/public/app/features/dashboard/components/SaveModals/SaveDashboardAsModalCtrl.ts index 59cfa22e468..23ad97708b4 100644 --- a/public/app/features/dashboard/components/SaveModals/SaveDashboardAsModalCtrl.ts +++ b/public/app/features/dashboard/components/SaveModals/SaveDashboardAsModalCtrl.ts @@ -26,9 +26,11 @@ const template = ` enable-create-new="true" label-class="width-8" dashboard-id="ctrl.clone.id"> - - - + +
+ + +
@@ -44,7 +46,7 @@ export class SaveDashboardAsModalCtrl { folderId: any; dismiss: () => void; isValidFolderSelection = true; - preseveTags: boolean; + copyTags: boolean; /** @ngInject */ constructor(private dashboardSrv) { @@ -56,7 +58,7 @@ export class SaveDashboardAsModalCtrl { this.clone.editable = true; this.clone.hideControls = false; this.folderId = dashboard.meta.folderId; - this.preseveTags = false; + this.copyTags = false; // remove alerts if source dashboard is already persisted // do not want to create alert dupes @@ -73,7 +75,7 @@ export class SaveDashboardAsModalCtrl { } save() { - if (!this.preseveTags) { + if (!this.copyTags) { this.clone.tags = []; } diff --git a/public/sass/components/_tags.scss b/public/sass/components/_tags.scss index 692259facb3..4451f2ee8a6 100644 --- a/public/sass/components/_tags.scss +++ b/public/sass/components/_tags.scss @@ -21,10 +21,8 @@ border-radius: 3px; text-shadow: none; font-size: 13px; - padding: 3px 6px 1px 6px; - border-width: 1px; - border-style: solid; - box-shadow: 0 0 1px rgba($white, 0.2); + padding: 2px 6px 2px 6px; + border: 1px solid lighten($purple, 10%); .icon-tag { position: relative; From d104ee1c150b502d0b28bcc0062c1fadc5c9fcf3 Mon Sep 17 00:00:00 2001 From: Dominik Prokop Date: Fri, 8 Mar 2019 14:42:19 +0100 Subject: [PATCH 22/24] @grafana/ui - release docs v1 (#15835) * Readme update * Update @grafana/ui Readme qith release process description. Allow version commit creation during release * Run tests and checks for grafana/core before releasing grafana/ui * Post review Readme updates --- package.json | 2 +- packages/grafana-ui/README.md | 30 ++++++++++++++++++++++++++ scripts/cli/index.ts | 2 ++ scripts/cli/tasks/grafanaui.release.ts | 30 +++++++++++++++++++++++--- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index a937ba6f717..d2760bbad02 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "gui:build": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts gui:build", "gui:releasePrepare": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts gui:release", "gui:publish": "cd packages/grafana-ui/dist && npm publish --access public", - "gui:release": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts gui:release -p", + "gui:release": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts gui:release -p --createVersionCommit", "cli": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts" }, "husky": { diff --git a/packages/grafana-ui/README.md b/packages/grafana-ui/README.md index fa482003253..935124e99ba 100644 --- a/packages/grafana-ui/README.md +++ b/packages/grafana-ui/README.md @@ -12,6 +12,36 @@ See [package source](https://github.com/grafana/grafana/tree/master/packages/gra `npm install @grafana/ui` +## Development + +For development purposes we suggest using `yarn link` that will create symlink to @grafana/ui lib. To do so navigate to `packages/grafana-ui` and run `yarn link`. Then, navigate to your project and run `yarn link @grafana/ui` to use the linked version of the lib. To unlink follow the same procedure, but use `yarn unlink` instead. + +## Building @grafana/ui +To build @grafana/ui run `npm run gui:build` script *from Grafana repository root*. The build will be created in `packages/grafana-ui/dist` directory. Following steps from [Development](#development) you can test built package. + +## Releasing new version +To release new version run `npm run gui:release` script *from Grafana repository root*. The script will prepare the distribution package as well as prompt you to bump library version and publish it to the NPM registry. + +### Automatic version bump +When running `npm run gui:release` package.json file will be automatically updated. Also, package.json file will be commited and pushed to upstream branch. + +### Manual version bump +To use `package.json` defined version run `npm run gui:release --usePackageJsonVersion` *from Grafana repository root*. + +### Preparing release package without publishing to NPM registry +For testing purposes there is `npm run gui:releasePrepare` task that prepares distribution package without publishing it to the NPM registry. + +### V1 release process overview +1. Package is compiled with TSC. Typings are created in `/dist` directory, and the compiled js lands in `/compiled` dir +2. Rollup creates a CommonJS package based on compiled sources, and outputs it to `/dist` directory +3. Readme, changelog and index.js files are moved to `/dist` directory +4. Package version is bumped in both `@grafana/ui` package dir and in dist directory. +5. Version commit is created and pushed to master branch +5. Package is published to npm + + ## Versioning To limit the confusion related to @grafana/ui and Grafana versioning we decided to keep the major version in sync between those two. This means, that first version of @grafana/ui is taged with 6.0.0-alpha.0 to keep version in sync with Grafana 6.0 release. + + diff --git a/scripts/cli/index.ts b/scripts/cli/index.ts index 301592315bc..27d1ab71c26 100644 --- a/scripts/cli/index.ts +++ b/scripts/cli/index.ts @@ -33,10 +33,12 @@ program .description('Prepares @grafana/ui release (and publishes to npm on demand)') .option('-p, --publish', 'Publish @grafana/ui to npm registry') .option('-u, --usePackageJsonVersion', 'Use version specified in package.json') + .option('--createVersionCommit', 'Create and push version commit') .action(async cmd => { await execTask(releaseTask)({ publishToNpm: !!cmd.publish, usePackageJsonVersion: !!cmd.usePackageJsonVersion, + createVersionCommit: !!cmd.createVersionCommit, }); }); diff --git a/scripts/cli/tasks/grafanaui.release.ts b/scripts/cli/tasks/grafanaui.release.ts index a7fb8e4d6ea..f0e53a4e7ba 100644 --- a/scripts/cli/tasks/grafanaui.release.ts +++ b/scripts/cli/tasks/grafanaui.release.ts @@ -9,10 +9,10 @@ import { savePackage, buildTask } from './grafanaui.build'; import { TaskRunner, Task } from './task'; type VersionBumpType = 'prerelease' | 'patch' | 'minor' | 'major'; - interface ReleaseTaskOptions { publishToNpm: boolean; usePackageJsonVersion: boolean; + createVersionCommit: boolean; } const promptBumpType = async () => { @@ -62,6 +62,12 @@ const promptConfirm = async (message?: string) => { ]); }; +// Since Grafana core depends on @grafana/ui highly, we run full check before release +const runChecksAndTests = async () => + useSpinner(`Running checks and tests`, async () => { + await execa('npm', ['run', 'test']); + })(); + const bumpVersion = (version: string) => useSpinner(`Saving version ${version} to package.json`, async () => { changeCwdToGrafanaUi(); @@ -94,8 +100,21 @@ const ensureMasterBranch = async () => { } }; -const releaseTaskRunner: TaskRunner = async ({ publishToNpm, usePackageJsonVersion }) => { +const prepareVersionCommitAndPush = async (version: string) => + useSpinner('Commiting and pushing @grafana/ui version update', async () => { + await execa.stdout('git', ['commit', '-a', '-m', `Upgrade @grafana/ui version to v${version}`]); + await execa.stdout('git', ['push']); + })(); + +const releaseTaskRunner: TaskRunner = async ({ + publishToNpm, + usePackageJsonVersion, + createVersionCommit, +}) => { + await runChecksAndTests(); if (publishToNpm) { + // TODO: Ensure release branch + // When need to update this when we star keeping @grafana/ui releases in sync with core await ensureMasterBranch(); } @@ -145,10 +164,15 @@ const releaseTaskRunner: TaskRunner = async ({ publishToNpm, await bumpVersion(nextVersion); } + if (createVersionCommit) { + await prepareVersionCommitAndPush(nextVersion); + } + if (publishToNpm) { await publishPackage(pkg.name, nextVersion); console.log(chalk.green(`\nVersion ${nextVersion} of ${pkg.name} succesfully released!`)); - console.log(chalk.yellow(`\nUpdated @grafana/ui/package.json with version bump created - COMMIT THIS FILE!`)); + console.log(chalk.yellow(`\nUpdated @grafana/ui/package.json with version bump created.`)); + process.exit(); } else { console.log( From e08d8eb55d95a2d62be949ba4020a55916552f1d Mon Sep 17 00:00:00 2001 From: zhulongcheng Date: Sat, 9 Mar 2019 00:27:39 +0800 Subject: [PATCH 23/24] docs: update CONTRIBUTING.md --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 677a12831dc..d21ef5232d6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,10 +34,10 @@ To setup a local development environment we recommend reading [Building Grafana ### Pull requests with new features Commits should be as small as possible, while ensuring that each commit is correct independently (i.e., each commit should compile and pass tests). -Make sure to include `closes #` or `fixes #` in the pull request description. +Make sure to include `Closes #` or `Fixes #` in the pull request description. ### Pull requests with bug fixes -Please make all changes in one commit if possible. Include `closes #12345` in bottom of the commit message. +Please make all changes in one commit if possible. Include `Closes #` in bottom of the commit message. A commit message for a bug fix should look something like this. ``` @@ -48,7 +48,7 @@ provsioners each provisioner overwrite each other. filling up dashboard_versions quite fast if using default settings. -closes #12864 +Closes #12864 ``` -If the pull request needs changes before its merged the new commits should be rebased into one commit before its merged. \ No newline at end of file +If the pull request needs changes before its merged the new commits should be rebased into one commit before its merged. From ccdc82b9214893f6a5f0ed7df1ead06377543e4a Mon Sep 17 00:00:00 2001 From: Navaneesh Kumar Date: Fri, 8 Mar 2019 22:38:50 +0530 Subject: [PATCH 24/24] docs: Fix indentation level for OAuth2 config --- docs/sources/auth/generic-oauth.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sources/auth/generic-oauth.md b/docs/sources/auth/generic-oauth.md index 1a83432b8f7..510776750f3 100644 --- a/docs/sources/auth/generic-oauth.md +++ b/docs/sources/auth/generic-oauth.md @@ -217,10 +217,10 @@ Some OAuth2 providers might not support `client_id` and `client_secret` passed v results in `invalid_client` error. To allow Grafana to authenticate via these type of providers, the client identifiers must be send via POST body, which can be enabled via the following settings: - ```bash - [auth.generic_oauth] - send_client_credentials_via_post = true - ``` +```bash +[auth.generic_oauth] +send_client_credentials_via_post = true +```