Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
91843003
Unverified
Commit
91843003
authored
Dec 19, 2017
by
Marcus Efraimsson
Committed by
GitHub
Dec 19, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #10278 from grafana/10197_new_folder
Create new folder from the folder picker component
parents
908b6c8d
1ddcaf5b
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
311 additions
and
133 deletions
+311
-133
public/app/core/routes/routes.ts
+1
-1
public/app/core/services/backend_srv.ts
+1
-1
public/app/features/dashboard/all.ts
+29
-28
public/app/features/dashboard/create_folder_ctrl.ts
+15
-17
public/app/features/dashboard/dashboard_import_ctrl.ts
+18
-15
public/app/features/dashboard/folder_picker/folder_picker.html
+46
-0
public/app/features/dashboard/folder_picker/folder_picker.ts
+104
-37
public/app/features/dashboard/move_to_folder_modal/move_to_folder.html
+4
-1
public/app/features/dashboard/move_to_folder_modal/move_to_folder.ts
+9
-0
public/app/features/dashboard/partials/create_folder.html
+6
-15
public/app/features/dashboard/partials/dashboard_import.html
+3
-12
public/app/features/dashboard/save_as_modal.ts
+14
-2
public/app/features/dashboard/settings/settings.html
+5
-3
public/app/features/dashboard/specs/dashboard_import_ctrl.jest.ts
+6
-1
public/app/features/dashboard/validation_srv.ts
+46
-0
public/sass/components/_gf-form.scss
+4
-0
No files found.
public/app/core/routes/routes.ts
View file @
91843003
...
...
@@ -65,7 +65,7 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
})
.
when
(
"/dashboard/import"
,
{
templateUrl
:
"public/app/features/dashboard/partials/dashboard
I
mport.html"
,
"public/app/features/dashboard/partials/dashboard
_i
mport.html"
,
controller
:
"DashboardImportCtrl"
,
controllerAs
:
"ctrl"
})
...
...
public/app/core/services/backend_srv.ts
View file @
91843003
...
...
@@ -251,7 +251,7 @@ export class BackendSrv {
createDashboardFolder
(
name
)
{
const
dash
=
{
schemaVersion
:
16
,
title
:
name
,
title
:
name
.
trim
()
,
editable
:
true
,
panels
:
[]
};
...
...
public/app/features/dashboard/all.ts
View file @
91843003
import
"./dashboard_ctrl"
;
import
"./alerting_srv"
;
import
"./history/history"
;
import
"./dashboardLoaderSrv"
;
import
"./dashnav/dashnav"
;
import
"./submenu/submenu"
;
import
"./save_as_modal"
;
import
"./save_modal"
;
import
"./shareModalCtrl"
;
import
"./shareSnapshotCtrl"
;
import
"./dashboard_srv"
;
import
"./view_state_srv"
;
import
"./time_srv"
;
import
"./unsavedChangesSrv"
;
import
"./unsaved_changes_modal"
;
import
"./timepicker/timepicker"
;
import
"./upload"
;
import
"./export/export_modal"
;
import
"./export_data/export_data_modal"
;
import
"./ad_hoc_filters"
;
import
"./repeat_option/repeat_option"
;
import
"./dashgrid/DashboardGridDirective"
;
import
"./dashgrid/PanelLoader"
;
import
"./dashgrid/RowOptions"
;
import
"./acl/acl"
;
import
"./folder_picker/picker"
;
import
"./move_to_folder_modal/move_to_folder"
;
import
"./settings/settings"
;
import
'./dashboard_ctrl'
;
import
'./alerting_srv'
;
import
'./history/history'
;
import
'./dashboardLoaderSrv'
;
import
'./dashnav/dashnav'
;
import
'./submenu/submenu'
;
import
'./save_as_modal'
;
import
'./save_modal'
;
import
'./shareModalCtrl'
;
import
'./shareSnapshotCtrl'
;
import
'./dashboard_srv'
;
import
'./view_state_srv'
;
import
'./validation_srv'
;
import
'./time_srv'
;
import
'./unsavedChangesSrv'
;
import
'./unsaved_changes_modal'
;
import
'./timepicker/timepicker'
;
import
'./upload'
;
import
'./export/export_modal'
;
import
'./export_data/export_data_modal'
;
import
'./ad_hoc_filters'
;
import
'./repeat_option/repeat_option'
;
import
'./dashgrid/DashboardGridDirective'
;
import
'./dashgrid/PanelLoader'
;
import
'./dashgrid/RowOptions'
;
import
'./acl/acl'
;
import
'./folder_picker/folder_picker'
;
import
'./move_to_folder_modal/move_to_folder'
;
import
'./settings/settings'
;
import
coreModule
from
"app/core/core_module"
;
import
{
DashboardListCtrl
}
from
"./dashboard_list_ctrl"
;
...
...
public/app/features/dashboard/create_folder_ctrl.ts
View file @
91843003
...
...
@@ -3,23 +3,22 @@ import appEvents from "app/core/app_events";
export
class
CreateFolderCtrl
{
title
=
""
;
navModel
:
any
;
nameExists
=
false
;
titleTouched
=
false
;
hasValidationError
:
boolean
;
validationError
:
any
;
/** @ngInject **/
constructor
(
private
backendSrv
,
private
$location
,
navModelSrv
)
{
this
.
navModel
=
navModelSrv
.
getNav
(
"dashboards"
,
"manage-dashboards"
,
0
);
constructor
(
private
backendSrv
,
private
$location
,
private
validationSrv
,
navModelSrv
)
{
this
.
navModel
=
navModelSrv
.
getNav
(
'dashboards'
,
'manage-dashboards'
,
0
);
}
create
()
{
if
(
!
this
.
title
||
this
.
title
.
trim
().
length
===
0
)
{
if
(
this
.
hasValidationError
)
{
return
;
}
const
title
=
this
.
title
.
trim
();
return
this
.
backendSrv
.
createDashboardFolder
(
title
).
then
(
result
=>
{
appEvents
.
emit
(
"alert-success"
,
[
"Folder Created"
,
"OK"
]);
return
this
.
backendSrv
.
createDashboardFolder
(
this
.
title
).
then
(
result
=>
{
appEvents
.
emit
(
'alert-success'
,
[
'Folder Created'
,
'OK'
]);
var
folderUrl
=
`/dashboards/folder/
${
result
.
dashboard
.
id
}
/
${
result
.
meta
.
slug
...
...
@@ -31,14 +30,13 @@ export class CreateFolderCtrl {
titleChanged
()
{
this
.
titleTouched
=
true
;
this
.
backendSrv
.
search
({
query
:
this
.
title
}).
then
(
res
=>
{
this
.
nameExists
=
false
;
for
(
let
hit
of
res
)
{
if
(
this
.
title
===
hit
.
title
)
{
this
.
nameExists
=
true
;
break
;
}
}
});
this
.
validationSrv
.
validateNewDashboardOrFolderName
(
this
.
title
)
.
then
(()
=>
{
this
.
hasValidationError
=
false
;
})
.
catch
(
err
=>
{
this
.
hasValidationError
=
true
;
this
.
validationError
=
err
.
message
;
});
}
}
public/app/features/dashboard/dashboard_import_ctrl.ts
View file @
91843003
...
...
@@ -13,16 +13,13 @@ export class DashboardImportCtrl {
gnetUrl
:
string
;
gnetError
:
string
;
gnetInfo
:
any
;
titleTouched
:
boolean
;
hasNameValidationError
:
boolean
;
nameValidationError
:
any
;
/** @ngInject */
constructor
(
private
backendSrv
,
navModelSrv
,
private
$location
,
private
$scope
,
$routeParams
)
{
this
.
navModel
=
navModelSrv
.
getNav
(
"create"
,
"import"
);
constructor
(
private
backendSrv
,
private
validationSrv
,
navModelSrv
,
private
$location
,
private
$scope
,
$routeParams
)
{
this
.
navModel
=
navModelSrv
.
getNav
(
'create'
,
'import'
);
this
.
step
=
1
;
this
.
nameExists
=
false
;
...
...
@@ -93,15 +90,21 @@ export class DashboardImportCtrl {
}
titleChanged
()
{
this
.
backendSrv
.
search
({
query
:
this
.
dash
.
title
}).
then
(
res
=>
{
this
.
nameExists
=
false
;
for
(
let
hit
of
res
)
{
if
(
this
.
dash
.
title
===
hit
.
title
)
{
this
.
titleTouched
=
true
;
this
.
nameExists
=
false
;
this
.
validationSrv
.
validateNewDashboardOrFolderName
(
this
.
dash
.
title
)
.
then
(()
=>
{
this
.
hasNameValidationError
=
false
;
})
.
catch
(
err
=>
{
if
(
err
.
type
===
'EXISTING'
)
{
this
.
nameExists
=
true
;
break
;
}
}
});
this
.
hasNameValidationError
=
true
;
this
.
nameValidationError
=
err
.
message
;
});
}
saveDashboard
()
{
...
...
public/app/features/dashboard/folder_picker/folder_picker.html
0 → 100644
View file @
91843003
<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>
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>
public/app/features/dashboard/folder_picker/picker.ts
→
public/app/features/dashboard/folder_picker/
folder_
picker.ts
View file @
91843003
///<reference path="../../../headers/common.d.ts" />
import
coreModule
from
"app/core/core_module"
;
import
_
from
"lodash"
;
import
coreModule
from
"app/core/core_module"
;
import
appEvents
from
"app/core/app_events"
;
export
class
FolderPickerCtrl
{
initialTitle
:
string
;
...
...
@@ -9,29 +8,25 @@ export class FolderPickerCtrl {
labelClass
:
string
;
onChange
:
any
;
onLoad
:
any
;
onCreateFolder
:
any
;
enterFolderCreation
:
any
;
exitFolderCreation
:
any
;
enableCreateNew
:
boolean
;
rootName
=
"Root"
;
folder
:
any
;
createNewFolder
:
boolean
;
newFolderName
:
string
;
newFolderNameTouched
:
boolean
;
hasValidationError
:
boolean
;
validationError
:
any
;
/** @ngInject */
constructor
(
private
backendSrv
)
{
constructor
(
private
backendSrv
,
private
validationSrv
)
{
if
(
!
this
.
labelClass
)
{
this
.
labelClass
=
"width-7"
;
}
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
();
}
this
.
loadInitialValue
();
}
getOptions
(
query
)
{
...
...
@@ -51,41 +46,109 @@ export class FolderPickerCtrl {
result
.
unshift
({
title
:
this
.
rootName
,
id
:
0
});
}
if
(
this
.
enableCreateNew
&&
query
===
""
)
{
result
.
unshift
({
title
:
"-- New Folder --"
,
id
:
-
1
});
}
return
_
.
map
(
result
,
item
=>
{
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
)
{
this
.
onLoad
({
$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
()
{
return
{
restrict
:
"E"
,
template
:
template
,
templateUrl
:
"public/app/features/dashboard/folder_picker/folder_picker.html"
,
controller
:
FolderPickerCtrl
,
bindToController
:
true
,
controllerAs
:
"ctrl"
,
...
...
@@ -95,7 +158,11 @@ export function folderPicker() {
labelClass
:
"@"
,
rootName
:
"@"
,
onChange
:
"&"
,
onLoad
:
"&"
onLoad
:
"&"
,
onCreateFolder
:
"&"
,
enterFolderCreation
:
"&"
,
exitFolderCreation
:
"&"
,
enableCreateNew
:
"@"
}
};
}
...
...
public/app/features/dashboard/move_to_folder_modal/move_to_folder.html
View file @
91843003
...
...
@@ -18,12 +18,15 @@
<folder-picker
on-load=
"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"
>
</folder-picker>
</div>
</div>
<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>
</div>
</form>
...
...
public/app/features/dashboard/move_to_folder_modal/move_to_folder.ts
View file @
91843003
...
...
@@ -6,6 +6,7 @@ export class MoveToFolderCtrl {
folder
:
any
;
dismiss
:
any
;
afterSave
:
any
;
isValidFolderSelection
=
true
;
/** @ngInject */
constructor
(
private
backendSrv
)
{}
...
...
@@ -39,6 +40,14 @@ export class MoveToFolderCtrl {
return
this
.
afterSave
();
});
}
onEnterFolderCreation
()
{
this
.
isValidFolderSelection
=
false
;
}
onExitFolderCreation
()
{
this
.
isValidFolderSelection
=
true
;
}
}
export
function
moveToFolderModal
()
{
...
...
public/app/features/dashboard/partials/create_folder.html
View file @
91843003
...
...
@@ -7,34 +7,25 @@
<form
name=
"ctrl.saveForm"
ng-submit=
"ctrl.create()"
novalidate
>
<div
class=
"gf-form-inline"
>
<div
class=
"gf-form gf-form--grow"
>
<label
class=
"gf-form-label width-10"
>
Folder n
ame
</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}"
>
<label
class=
"gf-form-label text-success"
ng-if=
"
!ctrl.nameExists && ctrl.title
"
>
<label
class=
"gf-form-label width-10"
>
N
ame
</label>
<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.titleTouched && !ctrl.hasValidationError
"
>
<i
class=
"fa fa-check"
></i>
</label>
</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"
>
<label
class=
"gf-form-label text-warning gf-form-label--grow"
>
<i
class=
"fa fa-warning"
></i>
A Folder or Dashboard with the same name already exists
</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
{{ctrl.validationError}}
</label>
</div>
</div>
<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
</button>
</div>
...
...
public/app/features/dashboard/partials/dashboard
I
mport.html
→
public/app/features/dashboard/partials/dashboard
_i
mport.html
View file @
91843003
...
...
@@ -65,26 +65,17 @@
<div
class=
"gf-form gf-form--grow"
>
<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}"
>
<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>
</label>
</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"
>
<label
class=
"gf-form-label text-warning gf-form-label--grow"
>
<i
class=
"fa fa-warning"
></i>
A Dashboard with the same name already exists
</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
{{ctrl.nameValidationError}}
</label>
</div>
</div>
...
...
public/app/features/dashboard/save_as_modal.ts
View file @
91843003
...
...
@@ -22,13 +22,16 @@ const template = `
<div class="gf-form">
<folder-picker initial-folder-id="ctrl.folderId"
on-change="ctrl.onFolderChange($folder)"
enter-folder-creation="ctrl.onEnterFolderCreation()"
exit-folder-creation="ctrl.onExitFolderCreation()"
enable-create-new="true"
label-class="width-7">
</folder-picker>
</div>
</div>
<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>
</div>
</form>
...
...
@@ -38,6 +41,7 @@ const template = `
export
class
SaveDashboardAsModalCtrl
{
clone
:
any
;
folderId
:
any
;
isValidFolderSelection
=
true
;
dismiss
:
()
=>
void
;
/** @ngInject */
...
...
@@ -68,8 +72,16 @@ export class SaveDashboardAsModalCtrl {
return
this
.
dashboardSrv
.
save
(
this
.
clone
).
then
(
this
.
dismiss
);
}
onEnterFolderCreation
()
{
this
.
isValidFolderSelection
=
false
;
}
onExitFolderCreation
()
{
this
.
isValidFolderSelection
=
true
;
}
keyDown
(
evt
)
{
if
(
evt
.
keyCode
===
13
)
{
if
(
this
.
isValidFolderSelection
&&
evt
.
keyCode
===
13
)
{
this
.
save
();
}
}
...
...
public/app/features/dashboard/settings/settings.html
View file @
91843003
...
...
@@ -45,9 +45,11 @@
</bootstrap-tagsinput>
</div>
<folder-picker
initial-title=
"ctrl.dashboard.meta.folderTitle"
initial-folder-id=
"ctrl.dashboard.meta.folderId"
on-change=
"ctrl.onFolderChange($folder)"
label-class=
"width-7"
>
initial-folder-id=
"ctrl.dashboard.meta.folderId"
on-change=
"ctrl.onFolderChange($folder)"
enable-create-new=
"true"
is-valid-selection=
"true"
label-class=
"width-7"
>
</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>
...
...
public/app/features/dashboard/specs/dashboard_import_ctrl.jest.ts
View file @
91843003
...
...
@@ -6,6 +6,7 @@ describe("DashboardImportCtrl", function() {
let
navModelSrv
;
let
backendSrv
;
let
validationSrv
;
beforeEach
(()
=>
{
navModelSrv
=
{
...
...
@@ -17,7 +18,11 @@ describe("DashboardImportCtrl", function() {
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
()
{
...
...
public/app/features/dashboard/validation_srv.ts
0 → 100644
View file @
91843003
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
);
public/sass/components/_gf-form.scss
View file @
91843003
...
...
@@ -109,6 +109,10 @@ $input-border: 1px solid $input-border-color;
&
--error
{
color
:
$critical
;
}
&
:disabled
{
color
:
$text-color-weak
}
}
.gf-form-label
+
.gf-form-label
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment