Commit c69096ac by Johannes Edmeier

Add session endpoint

parent 52f4849c
......@@ -41,7 +41,7 @@
}
}
.section.is-loading {
.is-loading {
&::after {
@include loader;
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';
import sbaInstancesLiquibase from './views/instances/liquibase';
import sbaInstancesLogfile from './views/instances/logfile';
import sbaInstancesLoggers from './views/instances/loggers';
import sbaInstancesSessions from './views/instances/sessions';
import sbaInstancesShell from './views/instances/shell';
import sbaInstancesThreaddump from './views/instances/threaddump';
import sbaInstancesTrace from './views/instances/trace';
......@@ -88,6 +89,8 @@ views.register({
}, {
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: 'flyway', component: sbaInstancesFlyway, props: true, name: 'instance/flyway',
......@@ -128,29 +131,37 @@ views.register({
name: 'instance/trace',
template: 'Traces',
order: 500,
isActive: ({instance}) => instance.hasEndpoint('traces')
});
views.register({
name: 'instance/auditevents',
template: 'Audit Log',
order: 600,
isActive: ({instance}) => instance.hasEndpoint('auditevents')
});
views.register({
name: 'instance/sessions',
template: 'Sessions',
order: 700,
isActive: ({instance}) => instance.hasEndpoint('sessions')
});
views.register({
name: 'instance/heapdump',
href: params => `instances/${params.instanceId}/actuator/heapdump`,
template: 'Heapdump',
order: 700,
order: 800,
isActive: ({instance}) => instance.hasEndpoint('heapdump')
});
views.register({
name: 'instance/liquibase',
template: 'Liquibase',
order: 800,
order: 900,
isActive: ({instance}) => instance.hasEndpoint('liquibase')
});
views.register({
name: 'instance/flyway',
template: 'Flyway',
order: 800,
order: 900,
isActive: ({instance}) => instance.hasEndpoint('flyway')
});
......
......@@ -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) {
return logtail(`instances/${this.id}/actuator/logfile`, interval);
}
......
......@@ -17,9 +17,12 @@ export {Observable} from 'rxjs/Observable';
export {animationFrame} from 'rxjs/scheduler/animationFrame';
import 'rxjs/add/observable/empty';
import 'rxjs/add/observable/from';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/timer';
import 'rxjs/add/operator/concatAll';
import 'rxjs/add/operator/concatMap';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
\ No newline at end of file
import 'rxjs/add/operator/finally';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
\ No newline at end of file
......@@ -15,14 +15,14 @@
-->
<template>
<table class="table is-fullwidth is-hoverable">
<table class="table is-hoverable">
<thead>
<tr>
<th>Timestamp</th>
<th>Event</th>
<th>Principal</th>
<th>Remote address</th>
<th>Session id</th>
<th>Session Id</th>
</tr>
</thead>
<template v-for="event in events">
......@@ -45,6 +45,9 @@
</td>
</tr>
</template>
<tr v-if="events.length === 0">
<td class="is-muted" colspan="5">No auditevents found.</td>
</tr>
</table>
</template>
......
......@@ -17,12 +17,9 @@
<template>
<section class="section" :class="{ 'is-loading' : !events}">
<div class="container" v-if="events">
<div class="content" v-if="events.length > 0">
<div class="content">
<auditevents-list :events="events"></auditevents-list>
</div>
<div class="content" v-else>
<p class="is-muted">No audit events recorded.</p>
</div>
</div>
</section>
</template>
......
......@@ -51,23 +51,29 @@
</div>
</div>
</div>
<table class="table is-hoverable is-fullwidth">
<tbody>
<tr v-for="logger in limitedLoggers" :key="logger.name">
<td>
<span class="is-breakable" v-text="logger.name"></span>
<sba-logger-control class="is-pulled-right"
:level-options="levels"
:effective-level="logger.effectiveLevel"
:configured-level="logger.configuredLevel"
:is-loading="loading[logger.name]"
:allow-reset="logger.name !== 'ROOT'"
@input="level => configureLogger(logger, level)">
</sba-logger-control>
</td>
</tr>
</tbody>
</table>
<div class="content">
<table class="table is-hoverable">
<tbody>
<tr v-for="logger in limitedLoggers" :key="logger.name">
<td>
<span class="is-breakable" v-text="logger.name"></span>
<sba-logger-control class="is-pulled-right"
:level-options="levels"
:effective-level="logger.effectiveLevel"
:configured-level="logger.configuredLevel"
:is-loading="loading[logger.name]"
:allow-reset="logger.name !== 'ROOT'"
@input="level => configureLogger(logger, level)">
</sba-logger-control>
</td>
</tr>
<tr v-if="limitedLoggers.length === 0">
<td class="is-muted" colspan="5">No loggers found.
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</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 @@
<template>
<section class="section" :class="{ 'is-loading' : !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 has-addons">
<p class="control is-expanded">
......@@ -69,9 +69,6 @@
<sba-traces-chart :traces="filteredTraces" @selected="(d) => selection = d"></sba-traces-chart>
<sba-traces-list :traces="selectedTraces"></sba-traces-list>
</div>
<div class="content" v-else>
<p class="is-muted">No traces recorded.</p>
</div>
</div>
</section>
</template>
......
......@@ -15,7 +15,7 @@
-->
<template>
<table class="table is-fullwidth is-hoverable">
<table class="table is-hoverable">
<thead>
<tr>
<th>Timestamp</th>
......@@ -49,6 +49,9 @@
</td>
</tr>
</template>
<tr v-if="traces.length === 0">
<td class="is-muted" colspan="5">No traces found.</td>
</tr>
</table>
</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