diff --git a/.gitignore b/.gitignore
index 3aa23b45149..3fdbcac5734 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,5 +31,5 @@ public/css/*.min.css
conf/custom.ini
fig.yml
profile.cov
-grafana
+/grafana
.notouch
diff --git a/CHANGELOG.md b/CHANGELOG.md
index acf60b77689..1b39e7cb589 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
# 3.0.0 (unrelased master branch)
+### New Features ###
+* **Playlists**: Playlists can now be persisted and started from urls, closes [#3655](https://github.com/grafana/grafana/pull/3655)
+
### Breaking changes
**InfluxDB 0.8.x** The data source for the old version of influxdb (0.8.x) is no longer included in default builds. Can easily be installed via improved plugin system, closes #3523
**KairosDB** The data source is no longer included in default builds. Can easily be installed via improved plugin system, closes #3524
diff --git a/pkg/api/api.go b/pkg/api/api.go
index ec256bb5c52..a893ffd72e1 100644
--- a/pkg/api/api.go
+++ b/pkg/api/api.go
@@ -147,6 +147,11 @@ func Register(r *macaron.Macaron) {
r.Put("/quotas/:target", bind(m.UpdateOrgQuotaCmd{}), wrap(UpdateOrgQuota))
}, reqGrafanaAdmin)
+ // orgs (admin routes)
+ r.Group("/orgs/name/:name", func() {
+ r.Get("/", wrap(GetOrgByName))
+ }, reqGrafanaAdmin)
+
// auth api keys
r.Group("/auth/keys", func() {
r.Get("/", wrap(GetApiKeys))
diff --git a/pkg/api/org.go b/pkg/api/org.go
index 6ed4a7c4a14..a64c6134eba 100644
--- a/pkg/api/org.go
+++ b/pkg/api/org.go
@@ -20,6 +20,33 @@ func GetOrgById(c *middleware.Context) Response {
return getOrgHelper(c.ParamsInt64(":orgId"))
}
+// Get /api/orgs/:name
+func GetOrgByName(c *middleware.Context) Response {
+ query := m.GetOrgByNameQuery{Name: c.Params(":name")}
+ if err := bus.Dispatch(&query); err != nil {
+ if err == m.ErrOrgNotFound {
+ return ApiError(404, "Organization not found", err)
+ }
+
+ return ApiError(500, "Failed to get organization", err)
+ }
+ org := query.Result
+ result := m.OrgDetailsDTO{
+ Id: org.Id,
+ Name: org.Name,
+ Address: m.Address{
+ Address1: org.Address1,
+ Address2: org.Address2,
+ City: org.City,
+ ZipCode: org.ZipCode,
+ State: org.State,
+ Country: org.Country,
+ },
+ }
+
+ return Json(200, &result)
+}
+
func getOrgHelper(orgId int64) Response {
query := m.GetOrgByIdQuery{Id: orgId}
diff --git a/public/app/plugins/datasource/grafana/datasource.ts b/public/app/plugins/datasource/grafana/datasource.ts
new file mode 100644
index 00000000000..afac499cdb1
--- /dev/null
+++ b/public/app/plugins/datasource/grafana/datasource.ts
@@ -0,0 +1,16 @@
+///
+
+class GrafanaDatasource {
+
+ constructor(private backendSrv) {}
+
+ query(options) {
+ return this.backendSrv.get('/api/metrics/test', {
+ from: options.range.from.valueOf(),
+ to: options.range.to.valueOf(),
+ maxDataPoints: options.maxDataPoints
+ });
+ }
+}
+
+export {GrafanaDatasource};
diff --git a/public/app/plugins/datasource/grafana/module.ts b/public/app/plugins/datasource/grafana/module.ts
new file mode 100644
index 00000000000..bfe2b041fb1
--- /dev/null
+++ b/public/app/plugins/datasource/grafana/module.ts
@@ -0,0 +1,14 @@
+///
+
+import angular from 'angular';
+import {GrafanaDatasource} from './datasource';
+
+var module = angular.module('grafana.directives');
+
+module.directive('metricQueryEditorGrafana', function() {
+ return {templateUrl: 'app/plugins/datasource/grafana/partials/query.editor.html'};
+});
+
+
+export {GrafanaDatasource, GrafanaDatasource as Datasource};
+
diff --git a/public/app/plugins/datasource/mixed/module.ts b/public/app/plugins/datasource/mixed/module.ts
new file mode 100644
index 00000000000..1f29e1e80f4
--- /dev/null
+++ b/public/app/plugins/datasource/mixed/module.ts
@@ -0,0 +1,14 @@
+///
+
+import angular from 'angular';
+import {MixedDatasource} from './datasource';
+
+var module = angular.module('grafana.directives');
+
+module.directive('metricQueryEditorMixed', function() {
+ return {templateUrl: 'app/plugins/datasource/mixed/partials/query.editor.html'};
+});
+
+
+export {MixedDatasource, MixedDatasource as Datasource};
+