Commit 91843003 by Marcus Efraimsson Committed by GitHub

Merge pull request #10278 from grafana/10197_new_folder

Create new folder from the folder picker component
parents 908b6c8d 1ddcaf5b
...@@ -65,7 +65,7 @@ function setupAngularRoutes($routeProvider, $locationProvider) { ...@@ -65,7 +65,7 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
}) })
.when("/dashboard/import", { .when("/dashboard/import", {
templateUrl: templateUrl:
"public/app/features/dashboard/partials/dashboardImport.html", "public/app/features/dashboard/partials/dashboard_import.html",
controller: "DashboardImportCtrl", controller: "DashboardImportCtrl",
controllerAs: "ctrl" controllerAs: "ctrl"
}) })
......
...@@ -251,7 +251,7 @@ export class BackendSrv { ...@@ -251,7 +251,7 @@ export class BackendSrv {
createDashboardFolder(name) { createDashboardFolder(name) {
const dash = { const dash = {
schemaVersion: 16, schemaVersion: 16,
title: name, title: name.trim(),
editable: true, editable: true,
panels: [] panels: []
}; };
......
import "./dashboard_ctrl"; import './dashboard_ctrl';
import "./alerting_srv"; import './alerting_srv';
import "./history/history"; import './history/history';
import "./dashboardLoaderSrv"; import './dashboardLoaderSrv';
import "./dashnav/dashnav"; import './dashnav/dashnav';
import "./submenu/submenu"; import './submenu/submenu';
import "./save_as_modal"; import './save_as_modal';
import "./save_modal"; import './save_modal';
import "./shareModalCtrl"; import './shareModalCtrl';
import "./shareSnapshotCtrl"; import './shareSnapshotCtrl';
import "./dashboard_srv"; import './dashboard_srv';
import "./view_state_srv"; import './view_state_srv';
import "./time_srv"; import './validation_srv';
import "./unsavedChangesSrv"; import './time_srv';
import "./unsaved_changes_modal"; import './unsavedChangesSrv';
import "./timepicker/timepicker"; import './unsaved_changes_modal';
import "./upload"; import './timepicker/timepicker';
import "./export/export_modal"; import './upload';
import "./export_data/export_data_modal"; import './export/export_modal';
import "./ad_hoc_filters"; import './export_data/export_data_modal';
import "./repeat_option/repeat_option"; import './ad_hoc_filters';
import "./dashgrid/DashboardGridDirective"; import './repeat_option/repeat_option';
import "./dashgrid/PanelLoader"; import './dashgrid/DashboardGridDirective';
import "./dashgrid/RowOptions"; import './dashgrid/PanelLoader';
import "./acl/acl"; import './dashgrid/RowOptions';
import "./folder_picker/picker"; import './acl/acl';
import "./move_to_folder_modal/move_to_folder"; import './folder_picker/folder_picker';
import "./settings/settings"; import './move_to_folder_modal/move_to_folder';
import './settings/settings';
import coreModule from "app/core/core_module"; import coreModule from "app/core/core_module";
import { DashboardListCtrl } from "./dashboard_list_ctrl"; import { DashboardListCtrl } from "./dashboard_list_ctrl";
......
...@@ -3,23 +3,22 @@ import appEvents from "app/core/app_events"; ...@@ -3,23 +3,22 @@ import appEvents from "app/core/app_events";
export class CreateFolderCtrl { export class CreateFolderCtrl {
title = ""; title = "";
navModel: any; navModel: any;
nameExists = false;
titleTouched = false; titleTouched = false;
hasValidationError: boolean;
validationError: any;
/** @ngInject **/ /** @ngInject **/
constructor(private backendSrv, private $location, navModelSrv) { constructor(private backendSrv, private $location, private validationSrv, navModelSrv) {
this.navModel = navModelSrv.getNav("dashboards", "manage-dashboards", 0); this.navModel = navModelSrv.getNav('dashboards', 'manage-dashboards', 0);
} }
create() { create() {
if (!this.title || this.title.trim().length === 0) { if (this.hasValidationError) {
return; return;
} }
const title = this.title.trim(); return this.backendSrv.createDashboardFolder(this.title).then(result => {
appEvents.emit('alert-success', ['Folder Created', 'OK']);
return this.backendSrv.createDashboardFolder(title).then(result => {
appEvents.emit("alert-success", ["Folder Created", "OK"]);
var folderUrl = `/dashboards/folder/${result.dashboard.id}/${ var folderUrl = `/dashboards/folder/${result.dashboard.id}/${
result.meta.slug result.meta.slug
...@@ -31,14 +30,13 @@ export class CreateFolderCtrl { ...@@ -31,14 +30,13 @@ export class CreateFolderCtrl {
titleChanged() { titleChanged() {
this.titleTouched = true; this.titleTouched = true;
this.backendSrv.search({ query: this.title }).then(res => { this.validationSrv.validateNewDashboardOrFolderName(this.title)
this.nameExists = false; .then(() => {
for (let hit of res) { this.hasValidationError = false;
if (this.title === hit.title) { })
this.nameExists = true; .catch(err => {
break; this.hasValidationError = true;
} this.validationError = err.message;
} });
});
} }
} }
...@@ -13,16 +13,13 @@ export class DashboardImportCtrl { ...@@ -13,16 +13,13 @@ export class DashboardImportCtrl {
gnetUrl: string; gnetUrl: string;
gnetError: string; gnetError: string;
gnetInfo: any; gnetInfo: any;
titleTouched: boolean;
hasNameValidationError: boolean;
nameValidationError: any;
/** @ngInject */ /** @ngInject */
constructor( constructor(private backendSrv, private validationSrv, navModelSrv, private $location, private $scope, $routeParams) {
private backendSrv, this.navModel = navModelSrv.getNav('create', 'import');
navModelSrv,
private $location,
private $scope,
$routeParams
) {
this.navModel = navModelSrv.getNav("create", "import");
this.step = 1; this.step = 1;
this.nameExists = false; this.nameExists = false;
...@@ -93,15 +90,21 @@ export class DashboardImportCtrl { ...@@ -93,15 +90,21 @@ export class DashboardImportCtrl {
} }
titleChanged() { titleChanged() {
this.backendSrv.search({ query: this.dash.title }).then(res => { this.titleTouched = true;
this.nameExists = false; this.nameExists = false;
for (let hit of res) {
if (this.dash.title === hit.title) { this.validationSrv.validateNewDashboardOrFolderName(this.dash.title)
.then(() => {
this.hasNameValidationError = false;
})
.catch(err => {
if (err.type === 'EXISTING') {
this.nameExists = true; this.nameExists = true;
break;
} }
}
}); this.hasNameValidationError = true;
this.nameValidationError = err.message;
});
} }
saveDashboard() { saveDashboard() {
......
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label {{ctrl.labelClass}}">Folder</label>
<div class="dropdown" ng-hide="ctrl.createNewFolder">
<gf-form-dropdown model="ctrl.folder"
get-options="ctrl.getOptions($query)"
on-change="ctrl.onFolderChange($option)">
</gf-form-dropdown>
</div>
<input type="text"
class="gf-form-input max-width-10"
ng-show="ctrl.createNewFolder"
give-focus="ctrl.createNewFolder"
ng-model="ctrl.newFolderName"
ng-model-options="{ debounce: 400 }"
ng-class="{'validation-error': !ctrl.isNewFolderNameValid()}"
ng-change="ctrl.newFolderNameChanged()" />
</div>
<div class="gf-form" ng-show="ctrl.createNewFolder">
<label class="gf-form-label text-success"
ng-show="ctrl.newFolderNameTouched && !ctrl.hasValidationError">
<i class="fa fa-check"></i>
</label>
</div>
<div class="gf-form" ng-show="ctrl.createNewFolder">
<button class="gf-form-label"
ng-click="ctrl.createFolder($event)"
ng-disabled="!ctrl.newFolderNameTouched || ctrl.hasValidationError">
<i class="fa fa-fw fa-save"></i>&nbsp;Create
</button>
</div>
<div class="gf-form" ng-show="ctrl.createNewFolder">
<button class="gf-form-label"
ng-click="ctrl.cancelCreateFolder($event)">
Cancel
</button>
</div>
</div>
<div class="gf-form-inline" ng-if="ctrl.newFolderNameTouched && ctrl.hasValidationError">
<div class="gf-form gf-form--grow">
<label class="gf-form-label text-warning gf-form-label--grow">
<i class="fa fa-warning"></i>
{{ctrl.validationError}}
</label>
</div>
</div>
///<reference path="../../../headers/common.d.ts" />
import coreModule from "app/core/core_module";
import _ from "lodash"; import _ from "lodash";
import coreModule from "app/core/core_module";
import appEvents from "app/core/app_events";
export class FolderPickerCtrl { export class FolderPickerCtrl {
initialTitle: string; initialTitle: string;
...@@ -9,29 +8,25 @@ export class FolderPickerCtrl { ...@@ -9,29 +8,25 @@ export class FolderPickerCtrl {
labelClass: string; labelClass: string;
onChange: any; onChange: any;
onLoad: any; onLoad: any;
onCreateFolder: any;
enterFolderCreation: any;
exitFolderCreation: any;
enableCreateNew: boolean;
rootName = "Root"; rootName = "Root";
folder: any; folder: any;
createNewFolder: boolean;
newFolderName: string;
newFolderNameTouched: boolean;
hasValidationError: boolean;
validationError: any;
/** @ngInject */ /** @ngInject */
constructor(private backendSrv) { constructor(private backendSrv, private validationSrv) {
if (!this.labelClass) { if (!this.labelClass) {
this.labelClass = "width-7"; this.labelClass = "width-7";
} }
if (this.initialFolderId && this.initialFolderId > 0) { this.loadInitialValue();
this.getOptions("").then(result => {
this.folder = _.find(result, { value: this.initialFolderId });
this.onFolderLoad();
});
} else {
if (this.initialTitle) {
this.folder = { text: this.initialTitle, value: null };
} else {
this.folder = { text: this.rootName, value: 0 };
}
this.onFolderLoad();
}
} }
getOptions(query) { getOptions(query) {
...@@ -51,41 +46,109 @@ export class FolderPickerCtrl { ...@@ -51,41 +46,109 @@ export class FolderPickerCtrl {
result.unshift({ title: this.rootName, id: 0 }); result.unshift({ title: this.rootName, id: 0 });
} }
if (this.enableCreateNew && query === "") {
result.unshift({ title: "-- New Folder --", id: -1 });
}
return _.map(result, item => { return _.map(result, item => {
return { text: item.title, value: item.id }; return { text: item.title, value: item.id };
}); });
}); });
} }
onFolderLoad() { onFolderChange(option) {
if (option.value === -1) {
this.createNewFolder = true;
this.enterFolderCreation();
return;
}
this.onChange({ $folder: { id: option.value, title: option.text } });
}
newFolderNameChanged() {
this.newFolderNameTouched = true;
this.validationSrv
.validateNewDashboardOrFolderName(this.newFolderName)
.then(() => {
this.hasValidationError = false;
})
.catch(err => {
this.hasValidationError = true;
this.validationError = err.message;
});
}
createFolder(evt) {
if (evt) {
evt.stopPropagation();
evt.preventDefault();
}
return this.backendSrv
.createDashboardFolder(this.newFolderName)
.then(result => {
appEvents.emit("alert-success", ["Folder Created", "OK"]);
this.closeCreateFolder();
this.folder = {
text: result.dashboard.title,
value: result.dashboard.id
};
this.onFolderChange(this.folder);
});
}
cancelCreateFolder(evt) {
if (evt) {
evt.stopPropagation();
evt.preventDefault();
}
this.closeCreateFolder();
this.loadInitialValue();
}
private closeCreateFolder() {
this.exitFolderCreation();
this.createNewFolder = false;
this.hasValidationError = false;
this.validationError = null;
this.newFolderName = "";
this.newFolderNameTouched = false;
}
private loadInitialValue() {
if (this.initialFolderId && this.initialFolderId > 0) {
this.getOptions("").then(result => {
this.folder = _.find(result, { value: this.initialFolderId });
this.onFolderLoad();
});
} else {
if (this.initialTitle) {
this.folder = { text: this.initialTitle, value: null };
} else {
this.folder = { text: this.rootName, value: 0 };
}
this.onFolderLoad();
}
}
private onFolderLoad() {
if (this.onLoad) { if (this.onLoad) {
this.onLoad({ this.onLoad({
$folder: { id: this.folder.value, title: this.folder.text } $folder: { id: this.folder.value, title: this.folder.text }
}); });
} }
} }
onFolderChange(option) {
this.onChange({ $folder: { id: option.value, title: option.text } });
}
} }
const template = `
<div class="gf-form">
<label class="gf-form-label {{ctrl.labelClass}}">Folder</label>
<div class="dropdown">
<gf-form-dropdown model="ctrl.folder"
get-options="ctrl.getOptions($query)"
on-change="ctrl.onFolderChange($option)">
</gf-form-dropdown>
</div>
</div>
`;
export function folderPicker() { export function folderPicker() {
return { return {
restrict: "E", restrict: "E",
template: template, templateUrl:
"public/app/features/dashboard/folder_picker/folder_picker.html",
controller: FolderPickerCtrl, controller: FolderPickerCtrl,
bindToController: true, bindToController: true,
controllerAs: "ctrl", controllerAs: "ctrl",
...@@ -95,7 +158,11 @@ export function folderPicker() { ...@@ -95,7 +158,11 @@ export function folderPicker() {
labelClass: "@", labelClass: "@",
rootName: "@", rootName: "@",
onChange: "&", onChange: "&",
onLoad: "&" onLoad: "&",
onCreateFolder: "&",
enterFolderCreation: "&",
exitFolderCreation: "&",
enableCreateNew: "@"
} }
}; };
} }
......
...@@ -18,12 +18,15 @@ ...@@ -18,12 +18,15 @@
<folder-picker <folder-picker
on-load="ctrl.onFolderChange($folder)" on-load="ctrl.onFolderChange($folder)"
on-change="ctrl.onFolderChange($folder)" on-change="ctrl.onFolderChange($folder)"
enter-folder-creation="ctrl.onEnterFolderCreation()"
exit-folder-creation="ctrl.onExitFolderCreation()"
enable-create-new="true"
label-class="width-7"> label-class="width-7">
</folder-picker> </folder-picker>
</div> </div>
</div> </div>
<div class="gf-form-button-row text-center"> <div class="gf-form-button-row text-center">
<button type="submit" class="btn btn-success" ng-disabled="ctrl.saveForm.$invalid">Move</button> <button type="submit" class="btn btn-success" ng-disabled="ctrl.saveForm.$invalid || !ctrl.isValidFolderSelection">Move</button>
<a class="btn-text" ng-click="ctrl.dismiss();">Cancel</a> <a class="btn-text" ng-click="ctrl.dismiss();">Cancel</a>
</div> </div>
</form> </form>
......
...@@ -6,6 +6,7 @@ export class MoveToFolderCtrl { ...@@ -6,6 +6,7 @@ export class MoveToFolderCtrl {
folder: any; folder: any;
dismiss: any; dismiss: any;
afterSave: any; afterSave: any;
isValidFolderSelection = true;
/** @ngInject */ /** @ngInject */
constructor(private backendSrv) {} constructor(private backendSrv) {}
...@@ -39,6 +40,14 @@ export class MoveToFolderCtrl { ...@@ -39,6 +40,14 @@ export class MoveToFolderCtrl {
return this.afterSave(); return this.afterSave();
}); });
} }
onEnterFolderCreation() {
this.isValidFolderSelection = false;
}
onExitFolderCreation() {
this.isValidFolderSelection = true;
}
} }
export function moveToFolderModal() { export function moveToFolderModal() {
......
...@@ -7,34 +7,25 @@ ...@@ -7,34 +7,25 @@
<form name="ctrl.saveForm" ng-submit="ctrl.create()" novalidate> <form name="ctrl.saveForm" ng-submit="ctrl.create()" novalidate>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<label class="gf-form-label width-10">Folder name</label> <label class="gf-form-label width-10">Name</label>
<input type="text" class="gf-form-input max-width-25" ng-model="ctrl.title" give-focus="true" ng-change="ctrl.titleChanged()" ng-model-options="{ debounce: 400 }" ng-class="{'validation-error': ctrl.nameExists || !ctrl.dash.title}"> <input type="text" class="gf-form-input" ng-model="ctrl.title" give-focus="true" ng-change="ctrl.titleChanged()" ng-model-options="{ debounce: 400 }" ng-class="{'validation-error': ctrl.nameExists || !ctrl.dash.title}">
<label class="gf-form-label text-success" ng-if="!ctrl.nameExists && ctrl.title"> <label class="gf-form-label text-success" ng-if="ctrl.titleTouched && !ctrl.hasValidationError">
<i class="fa fa-check"></i> <i class="fa fa-check"></i>
</label> </label>
</div> </div>
</div> </div>
<div class="gf-form-inline" ng-if="ctrl.nameExists"> <div class="gf-form-inline" ng-if="ctrl.hasValidationError">
<div class="gf-form offset-width-10 gf-form--grow"> <div class="gf-form offset-width-10 gf-form--grow">
<label class="gf-form-label text-warning gf-form-label--grow"> <label class="gf-form-label text-warning gf-form-label--grow">
<i class="fa fa-warning"></i> <i class="fa fa-warning"></i>
A Folder or Dashboard with the same name already exists {{ctrl.validationError}}
</label>
</div>
</div>
<div class="gf-form-inline" ng-if="!ctrl.title && ctrl.titleTouched">
<div class="gf-form offset-width-10 gf-form--grow">
<label class="gf-form-label text-warning gf-form-label--grow">
<i class="fa fa-warning"></i>
A Folder should have a name
</label> </label>
</div> </div>
</div> </div>
<div class="gf-form-button-row"> <div class="gf-form-button-row">
<button type="submit" class="btn btn-success width-12" ng-disabled="ctrl.nameExists || ctrl.title.length === 0"> <button type="submit" class="btn btn-success width-12" ng-disabled="!ctrl.titleTouched || ctrl.hasValidationError">
<i class="fa fa-save"></i> Create <i class="fa fa-save"></i> Create
</button> </button>
</div> </div>
......
...@@ -65,26 +65,17 @@ ...@@ -65,26 +65,17 @@
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<label class="gf-form-label width-15">Name</label> <label class="gf-form-label width-15">Name</label>
<input type="text" class="gf-form-input" ng-model="ctrl.dash.title" give-focus="true" ng-change="ctrl.titleChanged()" ng-class="{'validation-error': ctrl.nameExists || !ctrl.dash.title}"> <input type="text" class="gf-form-input" ng-model="ctrl.dash.title" give-focus="true" ng-change="ctrl.titleChanged()" ng-class="{'validation-error': ctrl.nameExists || !ctrl.dash.title}">
<label class="gf-form-label text-success" ng-if="!ctrl.nameExists && ctrl.dash.title"> <label class="gf-form-label text-success" ng-if="ctrl.titleTouched && !ctrl.hasNameValidationError">
<i class="fa fa-check"></i> <i class="fa fa-check"></i>
</label> </label>
</div> </div>
</div> </div>
<div class="gf-form-inline" ng-if="ctrl.nameExists"> <div class="gf-form-inline" ng-if="ctrl.hasNameValidationError">
<div class="gf-form offset-width-15 gf-form--grow"> <div class="gf-form offset-width-15 gf-form--grow">
<label class="gf-form-label text-warning gf-form-label--grow"> <label class="gf-form-label text-warning gf-form-label--grow">
<i class="fa fa-warning"></i> <i class="fa fa-warning"></i>
A Dashboard with the same name already exists {{ctrl.nameValidationError}}
</label>
</div>
</div>
<div class="gf-form-inline" ng-if="!ctrl.dash.title">
<div class="gf-form offset-width-15 gf-form--grow">
<label class="gf-form-label text-warning gf-form-label--grow">
<i class="fa fa-warning"></i>
A Dashboard should have a name
</label> </label>
</div> </div>
</div> </div>
......
...@@ -22,13 +22,16 @@ const template = ` ...@@ -22,13 +22,16 @@ const template = `
<div class="gf-form"> <div class="gf-form">
<folder-picker initial-folder-id="ctrl.folderId" <folder-picker initial-folder-id="ctrl.folderId"
on-change="ctrl.onFolderChange($folder)" on-change="ctrl.onFolderChange($folder)"
enter-folder-creation="ctrl.onEnterFolderCreation()"
exit-folder-creation="ctrl.onExitFolderCreation()"
enable-create-new="true"
label-class="width-7"> label-class="width-7">
</folder-picker> </folder-picker>
</div> </div>
</div> </div>
<div class="gf-form-button-row text-center"> <div class="gf-form-button-row text-center">
<button type="submit" class="btn btn-success" ng-disabled="ctrl.saveForm.$invalid">Save</button> <button type="submit" class="btn btn-success" ng-disabled="ctrl.saveForm.$invalid || !ctrl.isValidFolderSelection">Save</button>
<a class="btn-text" ng-click="ctrl.dismiss();">Cancel</a> <a class="btn-text" ng-click="ctrl.dismiss();">Cancel</a>
</div> </div>
</form> </form>
...@@ -38,6 +41,7 @@ const template = ` ...@@ -38,6 +41,7 @@ const template = `
export class SaveDashboardAsModalCtrl { export class SaveDashboardAsModalCtrl {
clone: any; clone: any;
folderId: any; folderId: any;
isValidFolderSelection = true;
dismiss: () => void; dismiss: () => void;
/** @ngInject */ /** @ngInject */
...@@ -68,8 +72,16 @@ export class SaveDashboardAsModalCtrl { ...@@ -68,8 +72,16 @@ export class SaveDashboardAsModalCtrl {
return this.dashboardSrv.save(this.clone).then(this.dismiss); return this.dashboardSrv.save(this.clone).then(this.dismiss);
} }
onEnterFolderCreation() {
this.isValidFolderSelection = false;
}
onExitFolderCreation() {
this.isValidFolderSelection = true;
}
keyDown(evt) { keyDown(evt) {
if (evt.keyCode === 13) { if (this.isValidFolderSelection && evt.keyCode === 13) {
this.save(); this.save();
} }
} }
......
...@@ -45,9 +45,11 @@ ...@@ -45,9 +45,11 @@
</bootstrap-tagsinput> </bootstrap-tagsinput>
</div> </div>
<folder-picker initial-title="ctrl.dashboard.meta.folderTitle" <folder-picker initial-title="ctrl.dashboard.meta.folderTitle"
initial-folder-id="ctrl.dashboard.meta.folderId" initial-folder-id="ctrl.dashboard.meta.folderId"
on-change="ctrl.onFolderChange($folder)" on-change="ctrl.onFolderChange($folder)"
label-class="width-7"> enable-create-new="true"
is-valid-selection="true"
label-class="width-7">
</folder-picker> </folder-picker>
<gf-form-switch class="gf-form" label="Editable" tooltip="Uncheck, then save and reload to disable all dashboard editing" checked="ctrl.dashboard.editable" label-class="width-7"> <gf-form-switch class="gf-form" label="Editable" tooltip="Uncheck, then save and reload to disable all dashboard editing" checked="ctrl.dashboard.editable" label-class="width-7">
</gf-form-switch> </gf-form-switch>
......
...@@ -6,6 +6,7 @@ describe("DashboardImportCtrl", function() { ...@@ -6,6 +6,7 @@ describe("DashboardImportCtrl", function() {
let navModelSrv; let navModelSrv;
let backendSrv; let backendSrv;
let validationSrv;
beforeEach(() => { beforeEach(() => {
navModelSrv = { navModelSrv = {
...@@ -17,7 +18,11 @@ describe("DashboardImportCtrl", function() { ...@@ -17,7 +18,11 @@ describe("DashboardImportCtrl", function() {
get: jest.fn() get: jest.fn()
}; };
ctx.ctrl = new DashboardImportCtrl(backendSrv, navModelSrv, {}, {}, {}); validationSrv = {
validateNewDashboardOrFolderName: jest.fn().mockReturnValue(Promise.resolve())
};
ctx.ctrl = new DashboardImportCtrl(backendSrv, validationSrv, navModelSrv, {}, {}, {});
}); });
describe("when uploading json", function() { describe("when uploading json", function() {
......
import coreModule from "app/core/core_module";
export class ValidationSrv {
rootName = "root";
/** @ngInject */
constructor(private $q, private backendSrv) {}
validateNewDashboardOrFolderName(name) {
name = (name || "").trim();
if (name.length === 0) {
return this.$q.reject({
type: "REQUIRED",
message: "Name is required"
});
}
if (name.toLowerCase() === this.rootName) {
return this.$q.reject({
type: "EXISTING",
message: "A folder or dashboard with the same name already exists"
});
}
let deferred = this.$q.defer();
this.backendSrv.search({ query: name }).then(res => {
for (let hit of res) {
if (name.toLowerCase() === hit.title.toLowerCase()) {
deferred.reject({
type: "EXISTING",
message: "A folder or dashboard with the same name already exists"
});
break;
}
}
deferred.resolve();
});
return deferred.promise;
}
}
coreModule.service("validationSrv", ValidationSrv);
...@@ -109,6 +109,10 @@ $input-border: 1px solid $input-border-color; ...@@ -109,6 +109,10 @@ $input-border: 1px solid $input-border-color;
&--error { &--error {
color: $critical; color: $critical;
} }
&:disabled {
color: $text-color-weak
}
} }
.gf-form-label + .gf-form-label { .gf-form-label + .gf-form-label {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment