diff --git a/.bra.toml b/.bra.toml index 5be42ceebbf08..01d50e8c92882 100644 --- a/.bra.toml +++ b/.bra.toml @@ -1,6 +1,7 @@ [run] init_cmds = [ - ["go", "run", "build.go", "-dev", "build-server"], + ["go", "run", "build.go", "-dev", "build-cli"], + ["go", "run", "build.go", "-dev", "build-server"], ["./bin/grafana-server", "-packaging=dev", "cfg:app_mode=development"] ] watch_all = true diff --git a/.circleci/config.yml b/.circleci/config.yml index a783c8641a9f5..7b71800a2e5b8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -114,7 +114,7 @@ jobs: name: check documentation spelling errors command: 'codespell -I ./words_to_ignore.txt docs/' - backend-lint: + lint-go: docker: - image: circleci/golang:1.12.6 environment: @@ -124,8 +124,8 @@ jobs: steps: - checkout - run: - name: backend lint - command: './scripts/backend-lint.sh' + name: Lint Go + command: 'make lint-go' test-frontend: docker: @@ -633,7 +633,7 @@ workflows: filters: *filter-only-master - codespell: filters: *filter-only-master - - backend-lint: + - lint-go: filters: *filter-only-master - test-frontend: filters: *filter-only-master @@ -649,7 +649,7 @@ workflows: - test-backend - test-frontend - codespell - - backend-lint + - lint-go - mysql-integration-test - postgres-integration-test - build-oss-msi @@ -661,7 +661,7 @@ workflows: - test-backend - test-frontend - codespell - - backend-lint + - lint-go - mysql-integration-test - postgres-integration-test filters: *filter-only-master @@ -671,7 +671,7 @@ workflows: - test-backend - test-frontend - codespell - - backend-lint + - lint-go - mysql-integration-test - postgres-integration-test - build-all-enterprise @@ -682,7 +682,7 @@ workflows: - test-backend - test-frontend - codespell - - backend-lint + - lint-go - mysql-integration-test - postgres-integration-test filters: *filter-only-master @@ -702,7 +702,7 @@ workflows: filters: *filter-only-release - codespell: filters: *filter-only-release - - backend-lint: + - lint-go: filters: *filter-only-release - test-frontend: filters: *filter-only-release @@ -718,7 +718,7 @@ workflows: - test-backend - test-frontend - codespell - - backend-lint + - lint-go - mysql-integration-test - postgres-integration-test - build-oss-msi @@ -730,7 +730,7 @@ workflows: - test-backend - test-frontend - codespell - - backend-lint + - lint-go - mysql-integration-test - postgres-integration-test filters: *filter-only-release @@ -741,7 +741,7 @@ workflows: - test-backend - test-frontend - codespell - - backend-lint + - lint-go - mysql-integration-test - postgres-integration-test filters: *filter-only-release @@ -751,7 +751,7 @@ workflows: - test-backend - test-frontend - codespell - - backend-lint + - lint-go - mysql-integration-test - postgres-integration-test filters: *filter-only-release @@ -769,7 +769,7 @@ workflows: - build-fast-frontend - codespell: filters: *filter-not-release-or-master - - backend-lint: + - lint-go: filters: *filter-not-release-or-master - test-frontend: filters: *filter-not-release-or-master @@ -787,7 +787,7 @@ workflows: - test-backend - test-frontend - codespell - - backend-lint + - lint-go - mysql-integration-test - postgres-integration-test - cache-server-test @@ -798,7 +798,7 @@ workflows: - test-backend - test-frontend - codespell - - backend-lint + - lint-go - mysql-integration-test - postgres-integration-test - cache-server-test diff --git a/Makefile b/Makefile index 88c57a84ed5bd..9347d8647b975 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -include local/Makefile -.PHONY: all deps-go deps-js deps build-go build-server build-cli build-js build build-docker-dev build-docker-full lint-go test-go test-js test run clean gosec revive devenv devenv-down revive-alerting +.PHONY: all deps-go deps-js deps build-go build-server build-cli build-js build build-docker-dev build-docker-full lint-go gosec revive golangci-lint go-vet test-go test-js test run clean devenv devenv-down revive-alerting GO := GO111MODULE=on go GO_FILES := ./pkg/... @@ -43,10 +43,6 @@ build-docker-full: @echo "build docker container" docker build --tag grafana/grafana:dev . -lint-go: - @echo "lint go source" - scripts/backend-lint.sh - test-go: @echo "test backend" GO111MODULE=on go test -v ./pkg/... @@ -78,27 +74,46 @@ scripts/go/bin/bra: scripts/go/go.mod @cd scripts/go; \ $(GO) build -o ./bin/bra github.com/Unknwon/bra +scripts/go/bin/golangci-lint: scripts/go/go.mod + @cd scripts/go; \ + $(GO) build -o ./bin/golangci-lint github.com/golangci/golangci-lint/cmd/golangci-lint + revive: scripts/go/bin/revive + @echo "lint via revive" @scripts/go/bin/revive \ -formatter stylish \ -config ./scripts/go/configs/revive.toml \ $(GO_FILES) revive-alerting: scripts/go/bin/revive + @echo "lint alerting via revive" @scripts/go/bin/revive \ -formatter stylish \ ./pkg/services/alerting/... -run: scripts/go/bin/bra - @scripts/go/bin/bra run - # TODO recheck the rules and leave only necessary exclusions gosec: scripts/go/bin/gosec + @echo "lint via gosec" @scripts/go/bin/gosec -quiet \ -exclude=G104,G107,G201,G202,G204,G301,G304,G401,G402,G501 \ -conf=./scripts/go/configs/gosec.json \ $(GO_FILES) +golangci-lint: scripts/go/bin/golangci-lint + @echo "lint via golangci-lint" + @scripts/go/bin/golangci-lint run \ + --config ./scripts/go/configs/.golangci.yml \ + $(GO_FILES) + +go-vet: + @echo "lint via go vet" + @go vet $(GO_FILES) + +lint-go: go-vet golangci-lint revive revive-alerting gosec + +run: scripts/go/bin/bra + @scripts/go/bin/bra run + # create docker-compose file with provided sources and start them # example: make devenv sources=postgres,openldap ifeq ($(sources),) diff --git a/UPGRADING_DEPENDENCIES.md b/UPGRADING_DEPENDENCIES.md index 16e6ce9ad4459..17321043426ad 100644 --- a/UPGRADING_DEPENDENCIES.md +++ b/UPGRADING_DEPENDENCIES.md @@ -22,18 +22,30 @@ The Grafana project uses [Go modules](https://golang.org/cmd/go/#hdr-Modules__mo All dependencies are vendored in the `vendor/` directory. +_Note:_ Since most developers of Grafana still use the `GOPATH` we need to specify `GO111MODULE=on` to make `go mod` and `got get` work as intended. If you have setup Grafana outside of the `GOPATH` on your machine you can skip `GO111MODULE=on` when running the commands below. + To add or update a new dependency, use the `go get` command: ```bash +# The GO111MODULE variable can be omitted when the code isn't located in GOPATH. # Pick the latest tagged release. -go get example.com/some/module/pkg +GO111MODULE=on go get example.com/some/module/pkg # Pick a specific version. -go get example.com/some/module/pkg@vX.Y.Z +GO111MODULE=on go get example.com/some/module/pkg@vX.Y.Z ``` Tidy up the `go.mod` and `go.sum` files and copy the new/updated dependency to the `vendor/` directory: +```bash +# The GO111MODULE variable can be omitted when the code isn't located in GOPATH. +GO111MODULE=on go mod tidy + +GO111MODULE=on go mod vendor +``` + +You have to commit the changes to `go.mod`, `go.sum` and the `vendor/` directory before submitting the pull request. + ## Node.js Dependencies Updated using `yarn`. @@ -60,7 +72,7 @@ Our builds run on CircleCI through our build script. The main build step (in CircleCI) is built using a custom build container that comes pre-baked with some of the necessary dependencies. -Link: [grafana-build-container](https://github.com/grafana/grafana-build-container) +Link: [grafana/build-container](https://github.com/grafana/grafana/tree/master/scripts/build/ci-build) #### Dependencies diff --git a/docs/sources/plugins/developing/index.md b/docs/sources/plugins/developing/_index.md similarity index 100% rename from docs/sources/plugins/developing/index.md rename to docs/sources/plugins/developing/_index.md diff --git a/packages/grafana-ui/src/components/Select/_Select.scss b/packages/grafana-ui/src/components/Select/_Select.scss index f9c635053dda7..5814b2aaa6f50 100644 --- a/packages/grafana-ui/src/components/Select/_Select.scss +++ b/packages/grafana-ui/src/components/Select/_Select.scss @@ -58,6 +58,10 @@ $select-input-bg-disabled: $input-bg-disabled; position: absolute; z-index: $zindex-dropdown; min-width: 100%; + &-notice--no-options { + background-color: $input-bg; + padding: 10px; + } } .gf-form-select-box__menu-list { @@ -75,6 +79,21 @@ $select-input-bg-disabled: $input-bg-disabled; .gf-form-select-box__multi-value { display: inline; + margin: 0 6px 0 0; + cursor: pointer; +} + +.gf-form-select-box__multi-value__remove { + text-align: center; + display: inline-block; + height: 14px; + vertical-align: middle; + margin-left: 2px; +} + +.gf-form-select-box__multi-value__label { + display: inline; + vertical-align: middle; } .gf-form-select-box__option { @@ -105,6 +124,7 @@ $select-input-bg-disabled: $input-bg-disabled; vertical-align: middle; > div { display: inline-block; + vertical-align: middle; } } diff --git a/pkg/ARCHITECTURE.md b/pkg/ARCHITECTURE.md index 330f60d0c80c8..612d82ea549c4 100644 --- a/pkg/ARCHITECTURE.md +++ b/pkg/ARCHITECTURE.md @@ -31,6 +31,10 @@ We value clean & readable code that is loosely coupled and covered by unit tests The majority of our tests uses go convey but thats something we want to avoid going forward. For new tests we want to use standard library and `testify/assert`. +## Import aliases +Currently there are import aliases for `/pkg/models` package but thats something we want to avoid going forward. +Newly introduced code should refer explicitly to the `models` instead of using the alias `m`. Whenever changing existing code it's desired to remove the import aliases as well. + ## The Bus The bus is our way to introduce indirection between the HTTP handlers and sqlstore (responsible for fetching data from the database). Http handlers and sqlstore don't depend on each other. They only depend on the bus and the domain model(pkg/models). This makes it easier to test the code and avoids coupling. More about this under `current rewrite/refactorings` diff --git a/pkg/README.md b/pkg/README.md index bcf14b420b70b..3226cec056353 100644 --- a/pkg/README.md +++ b/pkg/README.md @@ -34,32 +34,4 @@ Newly introduced date columns in the database should be stored as epochs if date # Dependency management -The Grafana project uses [Go modules](https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more) to manage dependencies on external packages. This requires a working Go environment with version 1.11 or greater installed. - -All dependencies are vendored in the `vendor/` directory. - -_Note:_ Since most developers of Grafana still use the `GOPATH` we need to specify `GO111MODULE=on` to make `go mod` and `got get` work as intended. If you have setup Grafana outside of the `GOPATH` on your machine you can skip `GO111MODULE=on` when running the commands below. - -To add or update a new dependency, use the `go get` command: - -```bash -# The GO111MODULE variable can be omitted when the code isn't located in GOPATH. -# Pick the latest tagged release. -GO111MODULE=on go get example.com/some/module/pkg - -# Pick a specific version. -GO111MODULE=on go get example.com/some/module/pkg@vX.Y.Z -``` - -Tidy up the `go.mod` and `go.sum` files and copy the new/updated dependency to the `vendor/` directory: - -```bash -# The GO111MODULE variable can be omitted when the code isn't located in GOPATH. -GO111MODULE=on go mod tidy - -GO111MODULE=on go mod vendor -``` - -You have to commit the changes to `go.mod`, `go.sum` and the `vendor/` directory before submitting the pull request. - - +Documented in [UPDRAGING_DEPENDENCIES.md](https://github.com/grafana/grafana/blob/master/UPGRADING_DEPENDENCIES.md). diff --git a/pkg/STYLEGUIDE.md b/pkg/STYLEGUIDE.md index 8fce578cfad76..3d162b61100a2 100644 --- a/pkg/STYLEGUIDE.md +++ b/pkg/STYLEGUIDE.md @@ -5,7 +5,10 @@ Grafanas backend has been developed for a long time with a mix of code styles. This style guide is a guide for how we want to write Go code in the future. Generally, we want to follow the style guides used in Go [Code Review Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) and Peter Bourgon's [Go: Best Practices for Production Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style) ## Linting and formatting -We enforce strict `gofmt` formating and use some linters on our codebase. You can find the current list of linters at https://github.com/grafana/grafana/blob/master/scripts/backend-lint.sh +We enforce strict `gofmt` formating and use some linters on our codebase. You can lint the codebase with { +export class LogsContainer extends PureComponent { onChangeTime = (absoluteRange: AbsoluteTimeRange) => { const { exploreId, updateTimeRange } = this.props; @@ -86,19 +86,6 @@ export class LogsContainer extends Component { return []; }; - // Limit re-rendering to when a query is finished executing or when the deduplication strategy changes - // for performance reasons. - shouldComponentUpdate(nextProps: LogsContainerProps): boolean { - return ( - nextProps.loading !== this.props.loading || - nextProps.dedupStrategy !== this.props.dedupStrategy || - nextProps.logsHighlighterExpressions !== this.props.logsHighlighterExpressions || - nextProps.hiddenLogLevels !== this.props.hiddenLogLevels || - nextProps.scanning !== this.props.scanning || - nextProps.isLive !== this.props.isLive - ); - } - render() { const { exploreId, diff --git a/public/app/features/explore/QueryEditor.tsx b/public/app/features/explore/QueryEditor.tsx index d29e8a0e89254..53212c4d76e56 100644 --- a/public/app/features/explore/QueryEditor.tsx +++ b/public/app/features/explore/QueryEditor.tsx @@ -19,11 +19,13 @@ interface QueryEditorProps { initialQuery: DataQuery; exploreEvents: Emitter; range: TimeRange; + textEditModeEnabled?: boolean; } export default class QueryEditor extends PureComponent { element: any; component: AngularComponent; + angularScope: any; async componentDidMount() { if (!this.element) { @@ -58,6 +60,7 @@ export default class QueryEditor extends PureComponent { }; this.component = loader.load(this.element, scopeProps, template); + this.angularScope = scopeProps.ctrl; setTimeout(() => { this.props.onQueryChange(target); this.props.onExecuteQuery(); @@ -65,10 +68,19 @@ export default class QueryEditor extends PureComponent { } componentDidUpdate(prevProps: QueryEditorProps) { - if (prevProps.error !== this.props.error && this.component) { - // Some query controllers listen to data error events and need a digest - // for some reason this needs to be done in next tick - setTimeout(this.component.digest); + const hasToggledEditorMode = prevProps.textEditModeEnabled !== this.props.textEditModeEnabled; + const hasNewError = prevProps.error !== this.props.error; + + if (this.component) { + if (hasToggledEditorMode) { + this.angularScope.toggleEditorMode(); + } + + if (hasNewError || hasToggledEditorMode) { + // Some query controllers listen to data error events and need a digest + // for some reason this needs to be done in next tick + setTimeout(this.component.digest); + } } } diff --git a/public/app/features/explore/QueryField.tsx b/public/app/features/explore/QueryField.tsx index aded4cf029ada..93b6c075092c0 100644 --- a/public/app/features/explore/QueryField.tsx +++ b/public/app/features/explore/QueryField.tsx @@ -19,6 +19,7 @@ import { makeFragment, makeValue } from '@grafana/ui'; import PlaceholdersBuffer from './PlaceholdersBuffer'; export const TYPEAHEAD_DEBOUNCE = 100; +export const HIGHLIGHT_WAIT = 500; function getSuggestionByIndex(suggestions: CompletionItemGroup[], index: number): CompletionItem { // Flatten suggestion groups @@ -77,11 +78,13 @@ export class QueryField extends React.PureComponent) { super(props, context); this.placeholdersBuffer = new PlaceholdersBuffer(props.initialQuery || ''); + this.updateHighlightsTimer = _.debounce(this.updateLogsHighlights, HIGHLIGHT_WAIT); // Base plugins this.plugins = [ClearPlugin(), NewlinePlugin(), ...(props.additionalPlugins || [])].filter(p => p); @@ -152,7 +155,7 @@ export class QueryField extends React.PureComponent { const { onChange } = this.props; + if (onChange) { onChange(Plain.serialize(this.state.value)); } diff --git a/public/app/features/explore/QueryRow.tsx b/public/app/features/explore/QueryRow.tsx index 03d066ce5a362..54b0162c5521f 100644 --- a/public/app/features/explore/QueryRow.tsx +++ b/public/app/features/explore/QueryRow.tsx @@ -53,7 +53,15 @@ interface QueryRowProps extends PropsFromParent { mode: ExploreMode; } -export class QueryRow extends PureComponent { +interface QueryRowState { + textEditModeEnabled: boolean; +} + +export class QueryRow extends PureComponent { + state: QueryRowState = { + textEditModeEnabled: false, + }; + onRunQuery = () => { const { exploreId } = this.props; this.props.runQueries(exploreId); @@ -95,6 +103,10 @@ export class QueryRow extends PureComponent { this.props.runQueries(exploreId); }; + onClickToggleEditorMode = () => { + this.setState({ textEditModeEnabled: !this.state.textEditModeEnabled }); + }; + updateLogsHighlights = _.debounce((value: DataQuery) => { const { datasourceInstance } = this.props; if (datasourceInstance.getHighlighterExpression) { @@ -117,6 +129,7 @@ export class QueryRow extends PureComponent { queryErrors, mode, } = this.props; + const canToggleEditorModes = _.has(datasourceInstance, 'components.QueryCtrl.prototype.toggleEditorMode'); let QueryField; if (mode === ExploreMode.Metrics && datasourceInstance.components.ExploreMetricsQueryField) { @@ -129,9 +142,6 @@ export class QueryRow extends PureComponent { return (
-
- -
{QueryField ? ( { initialQuery={query} exploreEvents={exploreEvents} range={range} + textEditModeEnabled={this.state.textEditModeEnabled} /> )}
+
+ +
+ {canToggleEditorModes && ( +
+ +
+ )}