Commit c69096ac by Johannes Edmeier

Add session endpoint

parent 52f4849c
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
} }
} }
.section.is-loading { .is-loading {
&::after { &::after {
@include loader; @include loader;
height: 5rem; height: 5rem;
......
<!--
- Copyright 2014-2018 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.
-->
<template>
<button @click="click()">
<slot name="confirm" v-if="confirm">Confirm</slot>
<slot v-else></slot>
</button>
</template>
<script>
export default {
data: () => ({
confirm: false
}),
methods: {
click(event) {
if (this.confirm) {
this.$emit('click', event);
}
this.confirm = !this.confirm;
}
}
}
</script>
\ No newline at end of file
...@@ -30,6 +30,7 @@ import sbaInstancesFlyway from './views/instances/flyway'; ...@@ -30,6 +30,7 @@ import sbaInstancesFlyway from './views/instances/flyway';
import sbaInstancesLiquibase from './views/instances/liquibase'; import sbaInstancesLiquibase from './views/instances/liquibase';
import sbaInstancesLogfile from './views/instances/logfile'; import sbaInstancesLogfile from './views/instances/logfile';
import sbaInstancesLoggers from './views/instances/loggers'; import sbaInstancesLoggers from './views/instances/loggers';
import sbaInstancesSessions from './views/instances/sessions';
import sbaInstancesShell from './views/instances/shell'; import sbaInstancesShell from './views/instances/shell';
import sbaInstancesThreaddump from './views/instances/threaddump'; import sbaInstancesThreaddump from './views/instances/threaddump';
import sbaInstancesTrace from './views/instances/trace'; import sbaInstancesTrace from './views/instances/trace';
...@@ -88,6 +89,8 @@ views.register({ ...@@ -88,6 +89,8 @@ views.register({
}, { }, {
path: 'auditevents', component: sbaInstancesAuditevents, props: true, name: 'instance/auditevents', path: 'auditevents', component: sbaInstancesAuditevents, props: true, name: 'instance/auditevents',
}, { }, {
path: 'sessions', component: sbaInstancesSessions, props: true, name: 'instance/sessions',
}, {
path: 'liquibase', component: sbaInstancesLiquibase, props: true, name: 'instance/liquibase', path: 'liquibase', component: sbaInstancesLiquibase, props: true, name: 'instance/liquibase',
}, { }, {
path: 'flyway', component: sbaInstancesFlyway, props: true, name: 'instance/flyway', path: 'flyway', component: sbaInstancesFlyway, props: true, name: 'instance/flyway',
...@@ -128,29 +131,37 @@ views.register({ ...@@ -128,29 +131,37 @@ views.register({
name: 'instance/trace', name: 'instance/trace',
template: 'Traces', template: 'Traces',
order: 500, order: 500,
isActive: ({instance}) => instance.hasEndpoint('traces')
}); });
views.register({ views.register({
name: 'instance/auditevents', name: 'instance/auditevents',
template: 'Audit Log', template: 'Audit Log',
order: 600, order: 600,
isActive: ({instance}) => instance.hasEndpoint('auditevents')
});
views.register({
name: 'instance/sessions',
template: 'Sessions',
order: 700,
isActive: ({instance}) => instance.hasEndpoint('sessions')
}); });
views.register({ views.register({
name: 'instance/heapdump', name: 'instance/heapdump',
href: params => `instances/${params.instanceId}/actuator/heapdump`, href: params => `instances/${params.instanceId}/actuator/heapdump`,
template: 'Heapdump', template: 'Heapdump',
order: 700, order: 800,
isActive: ({instance}) => instance.hasEndpoint('heapdump') isActive: ({instance}) => instance.hasEndpoint('heapdump')
}); });
views.register({ views.register({
name: 'instance/liquibase', name: 'instance/liquibase',
template: 'Liquibase', template: 'Liquibase',
order: 800, order: 900,
isActive: ({instance}) => instance.hasEndpoint('liquibase') isActive: ({instance}) => instance.hasEndpoint('liquibase')
}); });
views.register({ views.register({
name: 'instance/flyway', name: 'instance/flyway',
template: 'Flyway', template: 'Flyway',
order: 800, order: 900,
isActive: ({instance}) => instance.hasEndpoint('flyway') isActive: ({instance}) => instance.hasEndpoint('flyway')
}); });
......
...@@ -117,6 +117,27 @@ class Instance { ...@@ -117,6 +117,27 @@ class Instance {
}); });
} }
async fetchSessions(username) {
return await axios.get(`instances/${this.id}/actuator/sessions`, {
headers: {'Accept': actuatorMimeTypes},
params: {
username
}
});
}
async fetchSession(sessionId) {
return await axios.get(`instances/${this.id}/actuator/sessions/${sessionId}`, {
headers: {'Accept': actuatorMimeTypes}
});
}
async deleteSession(sessionId) {
return await axios.delete(`instances/${this.id}/actuator/sessions/${sessionId}`, {
headers: {'Accept': actuatorMimeTypes}
});
}
streamLogfile(interval) { streamLogfile(interval) {
return logtail(`instances/${this.id}/actuator/logfile`, interval); return logtail(`instances/${this.id}/actuator/logfile`, interval);
} }
......
...@@ -17,9 +17,12 @@ export {Observable} from 'rxjs/Observable'; ...@@ -17,9 +17,12 @@ export {Observable} from 'rxjs/Observable';
export {animationFrame} from 'rxjs/scheduler/animationFrame'; export {animationFrame} from 'rxjs/scheduler/animationFrame';
import 'rxjs/add/observable/empty'; import 'rxjs/add/observable/empty';
import 'rxjs/add/observable/from';
import 'rxjs/add/observable/of'; import 'rxjs/add/observable/of';
import 'rxjs/add/observable/timer'; import 'rxjs/add/observable/timer';
import 'rxjs/add/operator/concatAll'; import 'rxjs/add/operator/concatAll';
import 'rxjs/add/operator/concatMap'; import 'rxjs/add/operator/concatMap';
import 'rxjs/add/operator/do'; import 'rxjs/add/operator/do';
import 'rxjs/add/operator/finally';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
\ No newline at end of file
...@@ -15,14 +15,14 @@ ...@@ -15,14 +15,14 @@
--> -->
<template> <template>
<table class="table is-fullwidth is-hoverable"> <table class="table is-hoverable">
<thead> <thead>
<tr> <tr>
<th>Timestamp</th> <th>Timestamp</th>
<th>Event</th> <th>Event</th>
<th>Principal</th> <th>Principal</th>
<th>Remote address</th> <th>Remote address</th>
<th>Session id</th> <th>Session Id</th>
</tr> </tr>
</thead> </thead>
<template v-for="event in events"> <template v-for="event in events">
...@@ -45,6 +45,9 @@ ...@@ -45,6 +45,9 @@
</td> </td>
</tr> </tr>
</template> </template>
<tr v-if="events.length === 0">
<td class="is-muted" colspan="5">No auditevents found.</td>
</tr>
</table> </table>
</template> </template>
......
...@@ -17,12 +17,9 @@ ...@@ -17,12 +17,9 @@
<template> <template>
<section class="section" :class="{ 'is-loading' : !events}"> <section class="section" :class="{ 'is-loading' : !events}">
<div class="container" v-if="events"> <div class="container" v-if="events">
<div class="content" v-if="events.length > 0"> <div class="content">
<auditevents-list :events="events"></auditevents-list> <auditevents-list :events="events"></auditevents-list>
</div> </div>
<div class="content" v-else>
<p class="is-muted">No audit events recorded.</p>
</div>
</div> </div>
</section> </section>
</template> </template>
......
...@@ -51,7 +51,8 @@ ...@@ -51,7 +51,8 @@
</div> </div>
</div> </div>
</div> </div>
<table class="table is-hoverable is-fullwidth"> <div class="content">
<table class="table is-hoverable">
<tbody> <tbody>
<tr v-for="logger in limitedLoggers" :key="logger.name"> <tr v-for="logger in limitedLoggers" :key="logger.name">
<td> <td>
...@@ -66,9 +67,14 @@ ...@@ -66,9 +67,14 @@
</sba-logger-control> </sba-logger-control>
</td> </td>
</tr> </tr>
<tr v-if="limitedLoggers.length === 0">
<td class="is-muted" colspan="5">No loggers found.
</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
</section> </section>
</template> </template>
......
<!--
- Copyright 2014-2018 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.
-->
<template>
<section class="section">
<div class="container">
<div class="content">
<div class="field has-addons">
<div class="control">
<span class="select">
<select v-model="filtertype">
<option value="username">Username</option>
<option value="sessionId">SessionId</option>
</select>
</span>
</div>
<div class="control is-expanded">
<input class="input" type="text" v-model="filter" @keyup.enter="fetchSessions()">
</div>
</div>
</div>
<div class="content" :class="{ 'is-loading' : isLoading }">
<sba-sessions-list :instance="instance" :sessions="sessions"
@deleted="fetchSessions()"></sba-sessions-list>
</div>
</div>
</section>
</template>
<script>
import _ from 'lodash';
import moment from 'moment';
import sbaSessionsList from './sessions-list';
class Session {
constructor({id, attributeNames, creationTime, lastAccessedTime, maxInactiveInterval, expired}) {
this.id = id;
this.attributeNames = attributeNames;
this.creationTime = moment(creationTime);
this.lastAccessedTime = moment(lastAccessedTime);
this.maxInactiveInterval = maxInactiveInterval;
this.expired = expired;
}
}
export default {
props: ['instance'],
components: {sbaSessionsList},
data: () => ({
filter: '',
filtertype: 'username',
sessions: [],
isLoading: false
}),
computed: {},
methods: {
fetchSessions: _.debounce(async function () {
if (!this.filter) {
this.sessions = [];
return;
}
this.isLoading = true;
if (this.filtertype === 'username') {
const response = await this.instance.fetchSessions(this.filter);
this.sessions = response.data.sessions.map(session => new Session(session));
} else {
const response = await this.instance.fetchSession(this.filter);
this.sessions = [new Session(response.data)];
}
this.isLoading = false;
}, 250)
},
watch: {
filtertype() {
this.fetchSessions();
},
filter() {
this.fetchSessions();
}
}
}
</script>
\ No newline at end of file
<!--
- Copyright 2014-2018 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.
-->
<template>
<table class="table">
<thead>
<tr>
<th></th>
<th>Session Id</th>
<th>Created at</th>
<th>Last accessed at</th>
<th>Max. inactive interval
</th>
<th>Attributes</th>
<th>
<sba-confirm-button class="button" :class="{ 'is-loading' : deletingAll }"
:disabled="sessions.length <= 0" @click="deleteAllSessions()">
<font-awesome-icon icon="trash"></font-awesome-icon>&nbsp;Delete
</sba-confirm-button>
</th>
</tr>
</thead>
<tr v-for="session in sessions" :key="session.id">
<td>
<span v-if="session.expired" class="tag is-info">Expired</span>
</td>
<td v-text="session.id"></td>
<td v-text="session.creationTime.format('L HH:mm:ss.SSS')"></td>
<td v-text="session.lastAccessedTime.format('L HH:mm:ss.SSS')"></td>
<td>
<span v-if="session.maxInactiveInterval >= 0" v-text="`${session.maxInactiveInterval}s`"></span>
<span v-else>unlimited</span>
</td>
<td>
<span class="tag" v-for="name in session.attributeNames" :key="`${session.id}-${name}`"
v-text="name"></span>
</td>
<td>
<button class="button" :class="{ 'is-loading' : deletingAll || deleting[session.id] }"
@click="deleteSession(session.id)">
<font-awesome-icon icon="trash"></font-awesome-icon>&nbsp;Delete
</button>
</td>
</tr>
<tr v-if="sessions.length=== 0">
<td class="is-muted" colspan="7 ">No sessions found.</td>
</tr>
</table>
</template>
<script>
import {Observable} from '@/utils/rxjs';
import prettyBytes from 'pretty-bytes';
export default {
props: ['sessions', 'instance'],
data: () => ({
deletingAll: false,
deleting: []
}),
methods: {
prettyBytes,
async deleteAllSessions() {
const vm = this;
vm.deletingAll = true;
this.subscription = Observable.from(vm.sessions)
.map(session => session.id)
.concatMap(async sessionId => {
await vm.instance.deleteSession(sessionId);
return sessionId;
})
.finally(() => {
vm.deletingAll = false;
vm.$emit('deleted');
})
.subscribe({
error: (err) => {
},
});
},
async deleteSession(sessionId) {
const vm = this;
vm.$set(vm.deleting, sessionId, true);
this.subscription = Observable.of(sessionId)
.concatMap(async sessionId => {
await vm.instance.deleteSession(sessionId);
return sessionId;
})
.finally(() => {
vm.$emit('deleted');
vm.$delete(vm.deleting, sessionId);
})
.subscribe({
error: (err) => {
},
});
}
}
}
</script>
\ No newline at end of file
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
<template> <template>
<section class="section" :class="{ 'is-loading' : !traces}"> <section class="section" :class="{ 'is-loading' : !traces}">
<div class="container" v-if="traces"> <div class="container" v-if="traces">
<div class="content" v-if="traces.length > 0"> <div class="content">
<div class="field-body"> <div class="field-body">
<div class="field has-addons"> <div class="field has-addons">
<p class="control is-expanded"> <p class="control is-expanded">
...@@ -69,9 +69,6 @@ ...@@ -69,9 +69,6 @@
<sba-traces-chart :traces="filteredTraces" @selected="(d) => selection = d"></sba-traces-chart> <sba-traces-chart :traces="filteredTraces" @selected="(d) => selection = d"></sba-traces-chart>
<sba-traces-list :traces="selectedTraces"></sba-traces-list> <sba-traces-list :traces="selectedTraces"></sba-traces-list>
</div> </div>
<div class="content" v-else>
<p class="is-muted">No traces recorded.</p>
</div>
</div> </div>
</section> </section>
</template> </template>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
--> -->
<template> <template>
<table class="table is-fullwidth is-hoverable"> <table class="table is-hoverable">
<thead> <thead>
<tr> <tr>
<th>Timestamp</th> <th>Timestamp</th>
...@@ -49,6 +49,9 @@ ...@@ -49,6 +49,9 @@
</td> </td>
</tr> </tr>
</template> </template>
<tr v-if="traces.length === 0">
<td class="is-muted" colspan="5">No traces found.</td>
</tr>
</table> </table>
</template> </template>
......
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