Skip to content

Commit

Permalink
Feat/mbeans app groups (#2153)
Browse files Browse the repository at this point in the history
* refactor: remove export as only internal usage (#2152)

* feat: group results by instance for application scope (#2152)

* fix: handle non existing body at HTTP errors (#2152)

* refactor: use template in section to remove doubled footer (#2152)

* feat: sort response first by state then by instanceId (#2152)

* feat: prefix id with instance (#2152)

Co-authored-by: Thomas Zub <t.zub@lvm.de>
Co-authored-by: Thomas Zub <thomas.zub@codecentric.de>
  • Loading branch information
3 people committed Oct 29, 2022
1 parent ab485ed commit 85ec2b7
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 90 deletions.
Expand Up @@ -53,44 +53,83 @@
</section>
</template>

<template v-else-if="state === 'completed'">
<template v-else-if="scope === 'instance'">
<section class="modal-card-body">
<div class="message is-success">
<div class="message-body">
<strong v-text="$t('instances.jolokia.execution_successful')" />
<template v-if="state === 'completed'">
<div class="message is-success">
<div class="message-body">
<strong v-text="$t('instances.jolokia.execution_successful')" />
</div>
</div>
</div>
<pre v-if="descriptor.ret !== 'void'" v-text="prettyPrintedResult" />
<pre v-if="descriptor.ret !== 'void'" v-text="prettyPrinted(result)" />
</template>

<template v-else-if="state === 'failed'">
<div class="message is-danger">
<div class="message-body">
<strong>
<font-awesome-icon class="has-text-danger"
icon="exclamation-triangle"
/>
<span v-text="$t('instances.jolokia.execution_failed')" />
</strong>
<p v-text="error.message" />
</div>
</div>
<pre v-if="error.stacktrace"
v-text="error.stacktrace"
/>
<pre v-if="error.response && error.response.data"
v-text="error.response.data"
/>
</template>
</section>
<footer class="modal-card-foot">
<div class="field is-grouped is-grouped-right">
<div class="control">
<button class="button is-light" @click="abort" v-text="$t('term.close')" />
<button class="button is-light" @click="abort" v-text="$t('instances.jolokia.close')" />
</div>
</div>
</footer>
</template>

<template v-else-if="state === 'failed'">
<template v-else-if="scope === 'application'">
<section class="modal-card-body">
<div class="message is-danger">
<div class="message-body">
<strong>
<font-awesome-icon class="has-text-danger"
icon="exclamation-triangle"
/>
<span v-text="$t('instances.jolokia.execution_failed')" />
</strong>
<p v-text="error.message" />
</div>
<div v-for="(instanceId, idx) in instanceIds" :key="instanceId">
<template v-if="state[idx] === 'completed'">
<div class="message is-success instance">
<div :class="{'is-selectable': descriptor.ret !== 'void'}"
class="message-body"
@click="select(instanceId)"
>
<strong v-text="$t('term.instance') + ': ' + instanceId" />
</div>
<pre v-if="selectedInstance === instanceId && descriptor.ret !== 'void'" v-text="prettyPrinted(result[idx])" />
</div>
</template>

<template v-else-if="state[idx] === 'failed'">
<div class="message is-danger">
<div class="message-body">
<strong>
<font-awesome-icon class="has-text-danger"
icon="exclamation-triangle"
/>
<span v-text="$t('term.instance') + ': ' + instanceId" />
</strong>
<p v-text="error[idx].message" />
</div>
</div>
<pre v-if="error[idx].stacktrace"
v-text="error[idx].stacktrace"
/>
<pre v-if="error[idx].response && error[idx].response.data"
v-text="error[idx].response.data"
/>
</template>
</div>
<pre v-if="error.stacktrace"
v-text="error.stacktrace"
/>
<pre v-if="error.response && error.response.data"
v-text="error.response.data"
/>
</section>

<footer class="modal-card-foot">
<div class="field is-grouped is-grouped-right">
<div class="control">
Expand All @@ -111,6 +150,7 @@ import {
STATE_INPUT_ARGS,
STATE_PREPARED
} from '@/views/instances/jolokia/responseHandler.js';
import {sortBy} from 'lodash'
export default {
props: {
Expand All @@ -133,29 +173,20 @@ export default {
onExecute: {
type: Function,
required: true
},
scope: {
type: String,
required: true
}
},
data: () => ({
state: null,
error: null,
args: null,
result: null
result: null,
instanceIds: null,
selectedInstance: null
}),
computed: {
prettyPrintedResult() {
if (this.result && typeof this.result === 'string') {
try {
const o = JSON.parse(this.result);
return JSON.stringify(o, undefined, 4);
} catch (e) {
return this.result;
}
} else if (typeof result === 'object') {
return JSON.stringify(this.result, undefined, 4);
}
return this.result;
}
},
methods: {
abort() {
this.onClose();
Expand All @@ -174,10 +205,21 @@ export default {
this.state = STATE_EXECUTING;
try {
const response = await this.onExecute(this.args);
const {result, state, error} = responseHandler(response);
this.result = result;
this.state = state;
this.error = error;
if (this.scope === 'instance') {
const {result, state, error} = responseHandler(response);
this.result = result;
this.state = state;
this.error = error;
} else {
const handledResponse = sortBy(responseHandler(response), [
r => (r.state === STATE_FAILED) ? -1 : 1,
r => r.instanceId
]);
this.instanceIds = handledResponse.map(r => r.instanceId);
this.result = handledResponse.map(r => r.result);
this.state = handledResponse.map(r => r.state);
this.error = handledResponse.map(r => r.error);
}
} catch (error) {
this.state = STATE_FAILED;
this.error = error;
Expand All @@ -189,6 +231,22 @@ export default {
this.abort()
}
},
prettyPrinted(result) {
if (result && typeof result === 'string') {
try {
const o = JSON.parse(result);
return JSON.stringify(o, undefined, 4);
} catch (e) {
return result;
}
} else if (typeof result === 'object') {
return JSON.stringify(result, undefined, 4);
}
return result;
},
select(instanceId) {
this.selectedInstance = (this.selectedInstance !== instanceId) ? instanceId : null;
}
},
created() {
this.invoke();
Expand All @@ -202,8 +260,19 @@ export default {
}
</script>

<style scoped>
<style scoped lang="scss">
@import "~@/assets/css/utilities";
.modal-card-title {
word-break: break-all;
}
.is-selectable {
&:hover {
background-color: $white-bis;
}
}
</style>
Expand Up @@ -24,7 +24,7 @@
:name="name" :descriptor="operation" @click="invoke(name, operation)"
/>
<m-bean-operation-invocation v-if="invocation" :name="invocation.name" :descriptor="invocation.descriptor"
:on-execute="execute" :on-close="closeInvocation"
:scope="scope" :on-execute="execute" :on-close="closeInvocation"
/>
</div>
</template>
Expand Down
Expand Up @@ -4,42 +4,13 @@ export const STATE_EXECUTING = 'executing';
export const STATE_FAILED = 'failed';
export const STATE_COMPLETED = 'completed';

export function resultContainsErrorStatus(result) {
if (result.status >= 400) {
return true;
}

const parsedResponse = parseValue(result.data);
if (Array.isArray(parsedResponse)) {
return parsedResponse.some(r => r.status >= 400);
} else {
return result.data.status >= 400;
}
}

export function parseValue(data) {
if (Array.isArray(data)) {
return data.map(elem => {
const parsedBody = JSON.parse(elem['body']);
return {
instanceId: elem['instanceId'],
...parsedBody
};
});
} else {
return data.value;
}
function resultContainsErrorStatus(data) {
return data.status >= 400;
}

export function responseHandler(result) {
if (resultContainsErrorStatus(result)) {
const parsedResult = parseValue(result.data);
let failedRequest = result.data;

// Show first failed request
if (Array.isArray(result.data)) {
failedRequest = parsedResult[0];
}
function responseDataHandler(data) {
if (resultContainsErrorStatus(data)) {
let failedRequest = data;

const error = new Error(`Execution failed: ${failedRequest.error}`);
error.stacktrace = failedRequest.stacktrace;
Expand All @@ -51,8 +22,32 @@ export function responseHandler(result) {
}
} else {
return {
result: parseValue(result.data),
result: data.value,
state: STATE_COMPLETED
}
}
}

function handleInstanceData(data) {
if ('body' in data) {
return responseDataHandler(JSON.parse(data.body));
} else {
const error = new Error(`Execution failed with HTTP error: ${data.status}`);
console.warn('Invocation failed', error);
return {
state: STATE_FAILED,
error
};
}
}

export function responseHandler(result) {
if (Array.isArray(result.data)) {
return result.data.map(d => ({
instanceId: d.instanceId,
...handleInstanceData(d)
}));
} else {
return responseDataHandler(result.data);
}
}

0 comments on commit 85ec2b7

Please sign in to comment.