mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge pull request #12169 from alexanderzobnin/feat-10796
Import dashboard to folder
This commit is contained in:
commit
2288e01752
@ -57,4 +57,5 @@ type ImportDashboardCommand struct {
|
||||
Overwrite bool `json:"overwrite"`
|
||||
Dashboard *simplejson.Json `json:"dashboard"`
|
||||
Inputs []plugins.ImportDashboardInput `json:"inputs"`
|
||||
FolderId int64 `json:"folderId"`
|
||||
}
|
||||
|
@ -99,9 +99,10 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
|
||||
|
||||
if c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR {
|
||||
children = append(children, &dtos.NavLink{Text: "Folder", SubTitle: "Create a new folder to organize your dashboards", Id: "folder", Icon: "gicon gicon-folder-new", Url: setting.AppSubUrl + "/dashboards/folder/new"})
|
||||
children = append(children, &dtos.NavLink{Text: "Import", SubTitle: "Import dashboard from file or Grafana.com", Id: "import", Icon: "gicon gicon-dashboard-import", Url: setting.AppSubUrl + "/dashboard/import"})
|
||||
}
|
||||
|
||||
children = append(children, &dtos.NavLink{Text: "Import", SubTitle: "Import dashboard from file or Grafana.com", Id: "import", Icon: "gicon gicon-dashboard-import", Url: setting.AppSubUrl + "/dashboard/import"})
|
||||
|
||||
data.NavTree = append(data.NavTree, &dtos.NavLink{
|
||||
Text: "Create",
|
||||
Id: "create",
|
||||
|
@ -174,6 +174,7 @@ func ImportDashboard(c *m.ReqContext, apiCmd dtos.ImportDashboardCommand) Respon
|
||||
Path: apiCmd.Path,
|
||||
Inputs: apiCmd.Inputs,
|
||||
Overwrite: apiCmd.Overwrite,
|
||||
FolderId: apiCmd.FolderId,
|
||||
Dashboard: apiCmd.Dashboard,
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ type ImportDashboardCommand struct {
|
||||
Path string
|
||||
Inputs []ImportDashboardInput
|
||||
Overwrite bool
|
||||
FolderId int64
|
||||
|
||||
OrgId int64
|
||||
User *m.SignedInUser
|
||||
@ -70,7 +71,7 @@ func ImportDashboard(cmd *ImportDashboardCommand) error {
|
||||
UserId: cmd.User.UserId,
|
||||
Overwrite: cmd.Overwrite,
|
||||
PluginId: cmd.PluginId,
|
||||
FolderId: dashboard.FolderId,
|
||||
FolderId: cmd.FolderId,
|
||||
}
|
||||
|
||||
dto := &dashboards.SaveDashboardDTO{
|
||||
@ -91,6 +92,7 @@ func ImportDashboard(cmd *ImportDashboardCommand) error {
|
||||
Title: savedDash.Title,
|
||||
Path: cmd.Path,
|
||||
Revision: savedDash.Data.Get("revision").MustInt64(1),
|
||||
FolderId: savedDash.FolderId,
|
||||
ImportedUri: "db/" + savedDash.Slug,
|
||||
ImportedUrl: savedDash.GetUrl(),
|
||||
ImportedRevision: dashboard.Data.Get("revision").MustInt64(1),
|
||||
|
@ -17,6 +17,7 @@ type PluginDashboardInfoDTO struct {
|
||||
ImportedUrl string `json:"importedUrl"`
|
||||
Slug string `json:"slug"`
|
||||
DashboardId int64 `json:"dashboardId"`
|
||||
FolderId int64 `json:"folderId"`
|
||||
ImportedRevision int64 `json:"importedRevision"`
|
||||
Revision int64 `json:"revision"`
|
||||
Description string `json:"description"`
|
||||
|
@ -13,6 +13,10 @@
|
||||
<i class="fa fa-plus"></i>
|
||||
Folder
|
||||
</a>
|
||||
<a class="btn btn-success" href="{{ctrl.importDashboardUrl()}}" ng-if="ctrl.hasEditPermissionInFolders || ctrl.canSave">
|
||||
<i class="fa fa-plus"></i>
|
||||
Import
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="page-action-bar page-action-bar--narrow" ng-show="ctrl.hasFilters">
|
||||
|
@ -294,6 +294,16 @@ export class ManageDashboardsCtrl {
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
importDashboardUrl() {
|
||||
let url = 'dashboard/import';
|
||||
|
||||
if (this.folderId) {
|
||||
url += `?folderId=${this.folderId}`;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
export function manageDashboardsDirective() {
|
||||
|
@ -52,11 +52,11 @@
|
||||
<a href="dashboards/folder/new" class="search-filter-box-link" ng-if="ctrl.isEditor">
|
||||
<i class="gicon gicon-folder-new"></i> New folder
|
||||
</a>
|
||||
<a href="dashboard/import" class="search-filter-box-link" ng-if="ctrl.isEditor">
|
||||
<a href="dashboard/import" class="search-filter-box-link" ng-if="ctrl.isEditor || ctrl.hasEditPermissionInFolders">
|
||||
<i class="gicon gicon-dashboard-import"></i> Import dashboard
|
||||
</a>
|
||||
<a class="search-filter-box-link" target="_blank" href="https://grafana.com/dashboards?utm_source=grafana_search">
|
||||
<img src="public/img/icn-dashboard-tiny.svg" width="20" /> Find dashboards on Grafana.com
|
||||
<img src="public/img/icn-dashboard-tiny.svg" width="20" /> Find dashboards on Grafana.com
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -21,6 +21,9 @@ export class DashboardImportCtrl {
|
||||
uidValidationError: any;
|
||||
autoGenerateUid: boolean;
|
||||
autoGenerateUidValue: string;
|
||||
folderId: number;
|
||||
initialFolderTitle: string;
|
||||
isValidFolderSelection: boolean;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private backendSrv, private validationSrv, navModelSrv, private $location, $routeParams) {
|
||||
@ -31,6 +34,8 @@ export class DashboardImportCtrl {
|
||||
this.uidExists = false;
|
||||
this.autoGenerateUid = true;
|
||||
this.autoGenerateUidValue = 'auto-generated';
|
||||
this.folderId = $routeParams.folderId ? Number($routeParams.folderId) || 0 : null;
|
||||
this.initialFolderTitle = 'Select a folder';
|
||||
|
||||
// check gnetId in url
|
||||
if ($routeParams.gnetId) {
|
||||
@ -102,8 +107,9 @@ export class DashboardImportCtrl {
|
||||
this.nameExists = false;
|
||||
|
||||
this.validationSrv
|
||||
.validateNewDashboardName(0, this.dash.title)
|
||||
.validateNewDashboardName(this.folderId, this.dash.title)
|
||||
.then(() => {
|
||||
this.nameExists = false;
|
||||
this.hasNameValidationError = false;
|
||||
})
|
||||
.catch(err => {
|
||||
@ -138,6 +144,23 @@ export class DashboardImportCtrl {
|
||||
});
|
||||
}
|
||||
|
||||
onFolderChange(folder) {
|
||||
this.folderId = folder.id;
|
||||
this.titleChanged();
|
||||
}
|
||||
|
||||
onEnterFolderCreation() {
|
||||
this.inputsValid = false;
|
||||
}
|
||||
|
||||
onExitFolderCreation() {
|
||||
this.inputValueChanged();
|
||||
}
|
||||
|
||||
isValid() {
|
||||
return this.inputsValid && this.folderId !== null;
|
||||
}
|
||||
|
||||
saveDashboard() {
|
||||
var inputs = this.inputs.map(input => {
|
||||
return {
|
||||
@ -153,6 +176,7 @@ export class DashboardImportCtrl {
|
||||
dashboard: this.dash,
|
||||
overwrite: true,
|
||||
inputs: inputs,
|
||||
folderId: this.folderId,
|
||||
})
|
||||
.then(res => {
|
||||
this.$location.url(res.importedUrl);
|
||||
|
@ -132,23 +132,26 @@ export class FolderPickerCtrl {
|
||||
}
|
||||
|
||||
private loadInitialValue() {
|
||||
if (this.initialFolderId && this.initialFolderId > 0) {
|
||||
this.getOptions('').then(result => {
|
||||
this.folder = _.find(result, { value: this.initialFolderId });
|
||||
if (!this.folder) {
|
||||
this.folder = { text: this.initialTitle, value: this.initialFolderId };
|
||||
}
|
||||
this.onFolderLoad();
|
||||
});
|
||||
} else {
|
||||
if (this.initialTitle && this.initialFolderId === null) {
|
||||
this.folder = { text: this.initialTitle, value: null };
|
||||
} else {
|
||||
this.folder = { text: this.rootName, value: 0 };
|
||||
const resetFolder = { text: this.initialTitle, value: null };
|
||||
const rootFolder = { text: this.rootName, value: 0 };
|
||||
this.getOptions('').then(result => {
|
||||
let folder;
|
||||
if (this.initialFolderId) {
|
||||
folder = _.find(result, { value: this.initialFolderId });
|
||||
} else if (this.enableReset && this.initialTitle && this.initialFolderId === null) {
|
||||
folder = resetFolder;
|
||||
}
|
||||
|
||||
if (!folder) {
|
||||
if (this.isEditor) {
|
||||
folder = rootFolder;
|
||||
} else {
|
||||
folder = result.length > 0 ? result[0] : resetFolder;
|
||||
}
|
||||
}
|
||||
this.folder = folder;
|
||||
this.onFolderLoad();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onFolderLoad() {
|
||||
|
@ -80,6 +80,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form gf-form--grow">
|
||||
<folder-picker label-class="width-15"
|
||||
initial-folder-id="ctrl.folderId"
|
||||
initial-title="ctrl.initialFolderTitle"
|
||||
on-change="ctrl.onFolderChange($folder)"
|
||||
on-load="ctrl.onFolderChange($folder)"
|
||||
enter-folder-creation="ctrl.onEnterFolderCreation()"
|
||||
exit-folder-creation="ctrl.onExitFolderCreation()"
|
||||
enable-create-new="true">
|
||||
</folder-picker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form gf-form--grow">
|
||||
<span class="gf-form-label width-15">
|
||||
@ -132,10 +146,10 @@
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row">
|
||||
<button type="button" class="btn btn-success width-12" ng-click="ctrl.saveDashboard()" ng-hide="ctrl.nameExists || ctrl.uidExists" ng-disabled="!ctrl.inputsValid">
|
||||
<button type="button" class="btn btn-success width-12" ng-click="ctrl.saveDashboard()" ng-hide="ctrl.nameExists || ctrl.uidExists" ng-disabled="!ctrl.isValid()">
|
||||
<i class="fa fa-save"></i> Import
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger width-12" ng-click="ctrl.saveDashboard()" ng-show="ctrl.nameExists || ctrl.uidExists" ng-disabled="!ctrl.inputsValid">
|
||||
<button type="button" class="btn btn-danger width-12" ng-click="ctrl.saveDashboard()" ng-show="ctrl.nameExists || ctrl.uidExists" ng-disabled="!ctrl.isValid()">
|
||||
<i class="fa fa-save"></i> Import (Overwrite)
|
||||
</button>
|
||||
<a class="btn btn-link" ng-click="ctrl.back()">Cancel</a>
|
||||
|
Loading…
Reference in New Issue
Block a user