Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
spring-boot-admin
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
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
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
openSource
spring-boot-admin
Commits
6e3a6c00
Commit
6e3a6c00
authored
Jun 01, 2016
by
Johannes Edmeier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add ui for managing notification filters
parent
46e319ee
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
202 additions
and
28 deletions
+202
-28
.gitignore
.gitignore
+3
-0
notificationSettings.js
...i/modules/applications/components/notificationSettings.js
+73
-0
notificationSettings.tpl.html
...les/applications/components/notificationSettings.tpl.html
+41
-0
popover.js
...dmin-server-ui/modules/applications/components/popover.js
+18
-13
popover.tpl.html
...erver-ui/modules/applications/components/popover.tpl.html
+6
-0
applicationsCtrl.js
...r-ui/modules/applications/controllers/applicationsCtrl.js
+8
-3
module.css
...-boot-admin-server-ui/modules/applications/css/module.css
+6
-0
module.js
spring-boot-admin-server-ui/modules/applications/module.js
+2
-1
notificationFilters.js
...r-ui/modules/applications/services/notificationFilters.js
+23
-6
applications-list.html
...rver-ui/modules/applications/views/applications-list.html
+2
-2
NotificationFilterController.java
...admin/notify/filter/web/NotificationFilterController.java
+6
-2
NotificationFilterControllerTest.java
...n/notify/filter/web/NotificationFilterControllerTest.java
+14
-1
No files found.
.gitignore
View file @
6e3a6c00
...
...
@@ -11,5 +11,8 @@ target/
*.iml
*.iws
#vscode
.vscode/
# gnupg keyring
/.gnupg
spring-boot-admin-server-ui/modules/applications/components/notificationSettings.js
0 → 100644
View file @
6e3a6c00
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
;
var
angular
=
require
(
'angular'
);
module
.
exports
=
{
bindings
:
{
application
:
'<application'
,
filters
:
'<filters'
,
refreshFilters
:
'&refreshCallback'
},
controller
:
function
(
NotificationFilters
)
{
'ngInject'
;
var
ctrl
=
this
;
ctrl
.
$onInit
=
function
()
{
ctrl
.
ttl
=
'-1'
;
ctrl
.
filterType
=
'by-name'
;
};
ctrl
.
$onChanges
=
function
()
{
ctrl
.
activeFilters
=
NotificationFilters
.
getActiveFilters
(
ctrl
.
filters
,
ctrl
.
application
);
ctrl
.
hasActiveFilter
=
!
angular
.
equals
({},
ctrl
.
activeFilters
);
if
(
!
ctrl
.
hasActiveFilter
)
{
ctrl
.
showPopover
=
false
;
}
};
ctrl
.
removeFilter
=
function
(
filterId
)
{
return
NotificationFilters
.
removeFilter
(
filterId
).
then
(
function
()
{
ctrl
.
refreshFilters
();
});
};
ctrl
.
addFilter
=
function
()
{
var
ttl
=
parseInt
(
ctrl
.
ttl
);
if
(
ttl
>=
0
)
{
ttl
=
ttl
*
60000
;
}
var
promise
=
null
;
switch
(
ctrl
.
filterType
)
{
case
'by-name'
:
promise
=
NotificationFilters
.
addFilterByName
(
ctrl
.
application
.
name
,
ttl
);
break
;
case
'by-id'
:
promise
=
NotificationFilters
.
addFilterById
(
ctrl
.
application
.
id
,
ttl
);
break
;
default
:
return
;
}
return
promise
.
then
(
function
()
{
ctrl
.
showPopover
=
false
;
ctrl
.
refreshFilters
();
});
};
},
template
:
require
(
'./notificationSettings.tpl.html'
)
};
\ No newline at end of file
spring-boot-admin-server-ui/modules/applications/components/notificationSettings.tpl.html
0 → 100644
View file @
6e3a6c00
<button
class=
"btn"
ng-click=
"$ctrl.showPopover = !$ctrl.showPopover"
>
<i
class=
"fa fa-fw {{$ctrl.hasActiveFilter ? 'fa-bell-slash' : 'fa-bell muted'}}"
></i>
</button>
<sba-popover
popover-title=
"Notification Filters"
popover-toggle=
"$ctrl.showPopover"
>
<button
class=
"btn btn-link pull-right"
ng-click=
"$ctrl.refreshFilters()"
><i
class=
"fa fa-fw fa-repeat"
></i></button>
<table
class=
"table"
>
<tr>
<th>
Type
</th>
<th>
Expiry
</th>
<th>
remove
</th>
</tr>
<tr
ng-repeat=
"(key, value) in $ctrl.activeFilters"
>
<td
ng-if=
"value.name"
>
by name ({{value.name}})
</td>
<td
ng-if=
"value.id"
>
by id ({{value.id}})
</td>
<td
ng-if=
"value.expiry >=0"
ng-bind=
"value.expiry | date:'HH:mm:ss'"
></td>
<td
ng-if=
"value.expiry <0"
>
unlimited
</td>
<td><button
class=
"btn btn-danger btn-small"
ng-click=
"$ctrl.removeFilter(key)"
><i
class=
"fa fa-times"
></i></button>
</tr>
<tr>
<td>
<select
class=
"input-xlarge"
ng-model=
"$ctrl.filterType"
>
<option
value=
"{{'by-name'}}"
>
by name ({{$ctrl.application.name}})
</option>
<option
value=
"{{'by-id'}}"
>
by id ({{$ctrl.application.id}})
</option>
</select>
</td>
<td>
<select
class=
"input-small"
ng-model=
"$ctrl.ttl"
>
<option
value=
"{{'5'}}"
>
5 min
</option>
<option
value=
"{{'15'}}"
>
15 min
</option>
<option
value=
"{{'30'}}"
>
30 min
</option>
<option
value=
"{{'60'}}"
>
1 hr
</option>
<option
value=
"{{'-1'}}"
>
unlimited
</option>
</select>
</td>
<td>
<button
class=
"btn btn-success btn-small"
value=
"Add filter"
ng-click=
"$ctrl.addFilter()"
><i
class=
"fa fa-plus"
></i></button>
</td>
</tr>
</table>
</sba-popover>
\ No newline at end of file
spring-boot-admin-server-ui/modules/applications/components/
notificationFilt
er.js
→
spring-boot-admin-server-ui/modules/applications/components/
popov
er.js
View file @
6e3a6c00
...
...
@@ -14,26 +14,31 @@
* limitations under the License.
*/
'use strict'
;
var
angular
=
require
(
'angular'
);
module
.
exports
=
{
transclude
:
true
,
bindings
:
{
application
:
'<application
'
,
filters
:
'<filters
'
title
:
'@popoverTitle
'
,
toggle
:
'<popoverToggle
'
},
controller
:
function
()
{
controllerAs
:
'$popover'
,
controller
:
function
(
$element
)
{
'ngInject'
;
var
ctrl
=
this
;
ctrl
.
offset
=
null
;
var
notificationActive
=
function
(
)
{
var
active
=
true
;
angular
.
forEach
(
ctrl
.
filters
,
function
(
value
)
{
active
=
active
&&
(
value
.
id
!==
ctrl
.
application
.
id
&&
value
.
name
!==
ctrl
.
application
.
name
||
value
.
expired
);
}
);
return
active
;
ctrl
.
$onChanges
=
function
(
changes
)
{
if
(
changes
.
toggle
.
currentValue
)
{
ctrl
.
offset
=
$element
.
parent
().
offset
();
ctrl
.
offset
.
left
-=
((
$element
.
children
().
first
().
outerWidth
()
-
$element
.
parent
().
outerWidth
())
/
2
);
ctrl
.
offset
.
top
+=
+
((
$element
.
parent
().
outerHeight
())
);
}
};
ctrl
.
getCssClass
=
function
()
{
return
notificationActive
()
?
'fa-bell muted'
:
'fa-bell-slash '
;
ctrl
.
isVisible
=
function
()
{
return
ctrl
.
toggle
;
};
},
template
:
'<i class="fa {{$ctrl.getCssClass()}}"></i>'
template
:
require
(
'./popover.tpl.html'
)
};
spring-boot-admin-server-ui/modules/applications/components/popover.tpl.html
0 → 100644
View file @
6e3a6c00
<div
class=
"popover fade bottom"
ng-class=
"{'in' : $popover.isVisible()}"
style=
"display: {{$popover.isVisible() ? 'block' : 'none'}}; top: {{$popover.offset.top}}px; left: {{$popover.offset.left}}px; "
>
<div
class=
"arrow"
></div>
<h3
class=
"popover-title"
ng-bind=
"$popover.title"
ng-if=
"$popover.title"
></h3>
<div
class=
"popover-content"
ng-transclude
></div>
</div>
\ No newline at end of file
spring-boot-admin-server-ui/modules/applications/controllers/applicationsCtrl.js
View file @
6e3a6c00
...
...
@@ -18,8 +18,10 @@
module
.
exports
=
function
(
$rootScope
,
$scope
,
$state
,
ApplicationViews
,
NotificationFilters
)
{
'ngInject'
;
$scope
.
applications
=
$rootScope
.
applications
;
$scope
.
notificationFilters
=
{};
$scope
.
notificationFilters
=
null
;
$scope
.
notificationFiltersSupported
=
false
;
$scope
.
remove
=
function
(
application
)
{
application
.
$remove
();
...
...
@@ -51,7 +53,10 @@ module.exports = function ($rootScope, $scope, $state, ApplicationViews, Notific
}
};
NotificationFilters
.
getFilters
().
then
(
function
(
filters
)
{
$scope
.
notificationFilters
=
filters
.
data
;
$scope
.
loadFilters
=
function
()
{
return
NotificationFilters
.
getFilters
().
then
(
function
(
filters
)
{
$scope
.
notificationFilters
=
filters
;
});
};
$scope
.
loadFilters
();
};
spring-boot-admin-server-ui/modules/applications/css/module.css
View file @
6e3a6c00
...
...
@@ -133,3 +133,9 @@
.accordion-group
{
border
:
1px
solid
#34302D
;
}
/* ---------- */
.popover
{
max-width
:
none
!important
;
}
spring-boot-admin-server-ui/modules/applications/module.js
View file @
6e3a6c00
...
...
@@ -34,7 +34,8 @@ module.filter('limitLines', require('./filters/limitLines.js'));
module
.
component
(
'sbaInfoPanel'
,
require
(
'./components/infoPanel.js'
));
module
.
component
(
'sbaAccordion'
,
require
(
'./components/accordion.js'
));
module
.
component
(
'sbaAccordionGroup'
,
require
(
'./components/accordionGroup.js'
));
module
.
component
(
'sbaNotificationFilter'
,
require
(
'./components/notificationFilter.js'
));
module
.
component
(
'sbaNotificationSettings'
,
require
(
'./components/notificationSettings.js'
));
module
.
component
(
'sbaPopover'
,
require
(
'./components/popover.js'
));
require
(
'./css/module.css'
);
...
...
spring-boot-admin-server-ui/modules/applications/services/notificationFilters.js
View file @
6e3a6c00
...
...
@@ -15,30 +15,47 @@
*/
'use strict'
;
var
angular
=
require
(
'angular'
);
module
.
exports
=
function
(
$http
)
{
'ngInject'
;
this
.
getFilters
=
function
()
{
return
$http
.
get
(
'api/notifications/filters'
);
return
$http
.
get
(
'api/notifications/filters'
).
then
(
function
(
response
)
{
return
response
.
data
;
}).
catch
(
function
()
{
return
null
;
});
};
this
.
getActiveFilters
=
function
(
filters
,
application
)
{
var
appFilters
=
{};
angular
.
forEach
(
filters
,
function
(
value
,
key
)
{
if
((
value
.
expired
===
false
||
value
.
expired
===
undefined
)
&&
(
value
.
id
===
application
.
id
||
value
.
name
===
application
.
name
))
{
appFilters
[
key
]
=
value
;
}
});
return
appFilters
;
};
this
.
addFilterByName
=
function
(
name
,
ttl
)
{
return
$http
.
post
(
'api/notifications/filters'
,
{
return
$http
.
post
(
'api/notifications/filters'
,
null
,
{
params
:
{
name
:
name
,
ttl
:
ttl
}
});
};
this
.
addFilterById
=
function
(
id
,
ttl
)
{
return
$http
.
post
(
'api/notifications/filters'
,
{
return
$http
.
post
(
'api/notifications/filters'
,
null
,
{
params
:
{
id
:
id
,
ttl
:
ttl
}
});
};
this
.
removeFilter
=
function
(
id
)
{
return
$http
.
delete
(
'api/notifications/filters'
,
{
id
:
id
});
return
$http
.
delete
(
'api/notifications/filters/'
+
id
);
};
};
spring-boot-admin-server-ui/modules/applications/views/applications-list.html
View file @
6e3a6c00
...
...
@@ -34,13 +34,13 @@
<span
ng-show=
"application.refreshing"
><i
class=
"fa fa-spinner fa-pulse fa-lg"
></i></span>
</td>
<td>
<sba-notification-
filter
application=
"application"
filters=
"notificationFilters"
></sba-notification-filter
>
<sba-notification-
settings
ng-if=
"notificationFilters"
application=
"application"
filters=
"notificationFilters"
refresh-callback=
"loadFilters()"
></sba-notification-settings
>
</td>
<td>
<div
class=
"pull-right"
>
<div
class=
"btn-group"
>
<a
ng-if=
"application.capabilities.logfile && application.managementUrl && application.statusInfo.status != null && application.statusInfo.status != 'OFFLINE'"
target=
"_blank"
class=
"btn btn-success"
ng-href=
"{{application.capabilities.logfile ? 'api/applications/' + application.id + '/logfile' :''}}"
><i
class=
"fa fa-file-text-o"
></i>
Log
</a>
<a
ng-if=
"views.length > 0"
ng-href=
"{{views[0].href}}"
class=
"btn btn-success"
ng-bind-html=
"views[0].title"
>
/a>
<a
ng-if=
"views.length > 0"
ng-href=
"{{views[0].href}}"
class=
"btn btn-success"
ng-bind-html=
"views[0].title"
>
<
/a>
<a
class=
"btn btn-success dropdown-toggle"
data-toggle=
"dropdown"
ng-if=
"views.length > 1"
>
<i
class=
"fa fa-caret-down"
></i>
</a>
...
...
spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/notify/filter/web/NotificationFilterController.java
View file @
6e3a6c00
...
...
@@ -17,6 +17,7 @@ package de.codecentric.boot.admin.notify.filter.web;
import
static
org
.
springframework
.
util
.
StringUtils
.
hasText
;
import
java.util.Collections
;
import
java.util.Map
;
import
org.springframework.http.ResponseEntity
;
...
...
@@ -53,11 +54,13 @@ public class NotificationFilterController {
@RequestMapping
(
path
=
"/api/notifications/filters"
,
method
=
{
RequestMethod
.
POST
},
produces
=
MimeTypeUtils
.
APPLICATION_JSON_VALUE
)
public
ResponseEntity
<
String
>
addFilter
(
@RequestParam
(
name
=
"id"
,
required
=
false
)
String
id
,
public
ResponseEntity
<
?
>
addFilter
(
@RequestParam
(
name
=
"id"
,
required
=
false
)
String
id
,
@RequestParam
(
name
=
"name"
,
required
=
false
)
String
name
,
@RequestParam
(
name
=
"ttl"
,
required
=
false
,
defaultValue
=
"-1"
)
long
ttl
)
{
if
(
hasText
(
id
)
||
hasText
(
name
))
{
return
ResponseEntity
.
ok
(
filteringNotifier
.
addFilter
(
createFilter
(
id
,
name
,
ttl
)));
NotificationFilter
filter
=
createFilter
(
id
,
name
,
ttl
);
String
filterId
=
filteringNotifier
.
addFilter
(
filter
);
return
ResponseEntity
.
ok
(
Collections
.
singletonMap
(
filterId
,
filter
));
}
else
{
return
ResponseEntity
.
badRequest
().
body
(
"Either 'id' or 'name' must be set"
);
}
...
...
@@ -78,6 +81,7 @@ public class NotificationFilterController {
NotificationFilter
filter
=
hasText
(
id
)
?
new
ApplicationIdNotificationFilter
(
id
,
expiry
)
:
new
ApplicationNameNotificationFilter
(
name
,
expiry
);
return
filter
;
}
}
spring-boot-admin-server/src/test/java/de/codecentric/boot/admin/notify/filter/web/NotificationFilterControllerTest.java
View file @
6e3a6c00
...
...
@@ -9,10 +9,16 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
jsonPath
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
status
;
import
java.io.IOException
;
import
java.util.Map
;
import
org.junit.Test
;
import
org.springframework.test.web.servlet.MockMvc
;
import
org.springframework.test.web.servlet.setup.MockMvcBuilders
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
de.codecentric.boot.admin.notify.LoggingNotifier
;
import
de.codecentric.boot.admin.notify.filter.FilteringNotifier
;
...
...
@@ -35,10 +41,12 @@ public class NotificationFilterControllerTest {
@Test
public
void
test_post_delete
()
throws
Exception
{
String
id
=
mvc
.
perform
(
post
(
"/api/notifications/filters?id=1337&ttl=10000"
))
String
response
=
mvc
.
perform
(
post
(
"/api/notifications/filters?id=1337&ttl=10000"
))
.
andExpect
(
status
().
isOk
()).
andExpect
(
content
().
string
(
not
(
isEmptyString
())))
.
andReturn
().
getResponse
().
getContentAsString
();
String
id
=
extractId
(
response
);
mvc
.
perform
(
get
(
"/api/notifications/filters"
)).
andExpect
(
status
().
isOk
())
.
andExpect
(
jsonPath
(
"$..id"
).
value
(
"1337"
));
...
...
@@ -47,4 +55,9 @@ public class NotificationFilterControllerTest {
mvc
.
perform
(
get
(
"/api/notifications/filters"
)).
andExpect
(
status
().
isOk
())
.
andExpect
(
jsonPath
(
"$"
).
isEmpty
());
}
private
String
extractId
(
String
response
)
throws
JsonProcessingException
,
IOException
{
Map
<?,
?>
map
=
new
ObjectMapper
().
readerFor
(
Map
.
class
).
readValue
(
response
);
return
map
.
keySet
().
iterator
().
next
().
toString
();
}
}
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