Commit ec47ac0f by Johannes Edmeier

Apply new style to application list and add scroll into view

parent 3e53030f
...@@ -16,68 +16,68 @@ ...@@ -16,68 +16,68 @@
<template> <template>
<div class="applications-list"> <div class="applications-list">
<template v-for="application in applications"> <div class="application-list__item card" :class="{'is-active': selected === application.name}"
<div v-if="selected !== application.name" :key="application.name" v-for="application in applications" :key="application.name" :id=" application.name"
@click.stop="select(application.name)" v-on-clickaway="(event) => selected === application.name && deselect(event)">
class="applications-list-item applications-list-item--collapsed"> <header class="hero application-list__item__header"
:class="getHeaderClass(application)"
@click.stop="select(application.name)">
<template v-if="selected !== application.name">
<sba-status :status="application.status" <sba-status :status="application.status"
:date="application.statusTimestamp" :date="application.statusTimestamp"
class="applications-list-item__status"/> class="application-list__item__header__status"/>
<span class="applications-list-item__text"> <p class="application-list__item__header__name">
<span v-text="application.name"/> <span v-text="application.name"/><br>
<span class="applications-list-item__secondary"> <span class="is-muted">
<a v-if="application.instances.length === 1" <a v-if="application.instances.length === 1"
v-text="application.instances[0].registration.serviceUrl || application.instances[0].registration.healthUrl" v-text="application.instances[0].registration.serviceUrl || application.instances[0].registration.healthUrl"
:href="application.instances[0].registration.serviceUrl || application.instances[0].registration.healthUrl"/> :href="application.instances[0].registration.serviceUrl || application.instances[0].registration.healthUrl"/>
<span v-else <span v-else
v-text="`${application.instances.length} instances`"/> v-text="`${application.instances.length} instances`"/>
</span> </span>
</span> </p>
<div class="applications-list-item__text" <p class="application-list__item__header__version" v-text="application.version"/>
v-text="application.version"/> <div class="application-list__item__header__actions">
<div class="applications-list-item__actions">
<sba-icon-button icon="trash" <sba-icon-button icon="trash"
v-if="application.isUnregisterable" v-if="application.isUnregisterable"
@click.native.stop="unregister(application)"/> @click.native.stop="unregister(application)"/>
</div> </div>
</div> </template>
<div v-else :key="application.name" <template v-else>
v-on-clickaway="deselect" <h1 class="title is-size-5 application-list__item__header__name" v-text="application.name"/>
class="applications-list-item applications-list-item--detailed"> <div class="application-list__item__header__actions">
<div class="applications-list-item__header"
@click.stop="deselect()">
<div class="applications-list-item__header-text" v-text="application.name"/>
<div class="applications-list-item__header-actions">
<sba-icon-button icon="trash" <sba-icon-button icon="trash"
v-if="application.isUnregisterable" v-if="application.isUnregisterable"
@click.native.stop="unregister(application)"/> @click.native.stop="unregister(application)"/>
</div> </div>
</div> </template>
<ul class="applications-list-item__instance-list"> </header>
<li v-for="instance in application.instances" :key="instance.id" <div class="card-content" v-if="selected === application.name">
class="applications-list-item__instance" <table class="table is-hoverable is-selectable is-fullwidth application__instances">
@click.stop="showDetails(instance)"> <tbody>
<sba-status :status="instance.statusInfo.status" <tr v-for="instance in application.instances" :key="instance.id" @click.stop="showDetails(instance)">
:date="instance.statusTimestamp" <td class="instance__status">
class="applications-list-item__status"/> <sba-status :status="instance.statusInfo.status" :date="instance.statusTimestamp"/>
<span class="applications-list-item__text"> </td>
<td>
<a v-text="instance.registration.serviceUrl || instance.registration.healthUrl" <a v-text="instance.registration.serviceUrl || instance.registration.healthUrl"
:href="instance.registration.serviceUrl || instance.registration.healthUrl" :href="instance.registration.serviceUrl || instance.registration.healthUrl"
@click.stop/> @click.stop/><br>
<span v-text="instance.id" <span class="is-muted" v-text="instance.id"/>
class="applications-list-item__secondary"/> </td>
</span> <td>
<span v-text="instance.info.version" <span v-text="instance.info.version"/>
class="applications-list-item__text"/> </td>
<div class="applications-list-item__actions"> <td class="instance__actions">
<sba-icon-button icon="trash" <sba-icon-button icon="trash"
v-if="instance.isUnregisterable" v-if="instance.isUnregisterable"
@click.native.stop="unregister(instance)"/> @click.native.stop="unregister(instance)"/>
</td>
</tr>
</tbody>
</table>
</div> </div>
</li>
</ul>
</div> </div>
</template>
</div> </div>
</template> </template>
...@@ -112,6 +112,22 @@ ...@@ -112,6 +112,22 @@
showDetails(instance) { showDetails(instance) {
this.$router.push({name: 'instance/details', params: {instanceId: instance.id}}); this.$router.push({name: 'instance/details', params: {instanceId: instance.id}});
}, },
async scrollIntoView(id, behavior) {
if (id) {
await this.$nextTick();
const el = document.getElementById(id);
if (el) {
const top = el.getBoundingClientRect().top + window.scrollY - 100;
window.scroll({top, left: window.scrollX, behavior: behavior || 'smooth'});
}
}
},
getHeaderClass(application) {
if (this.selected !== application.name) {
return 'is-selectable';
}
return (application.status === 'UP' ? 'is-primary' : (application.status === 'RESTRICTED' ? 'is-warning' : 'is-danger'));
},
async unregister(item) { async unregister(item) {
try { try {
item.unregister(); item.unregister();
...@@ -119,6 +135,14 @@ ...@@ -119,6 +135,14 @@
this.errors.push(e); this.errors.push(e);
} }
} }
},
mounted() {
return this.scrollIntoView(this.selected, 'instant');
},
watch: {
selected(newVal) {
return this.scrollIntoView(newVal);
}
} }
} }
</script> </script>
...@@ -126,104 +150,77 @@ ...@@ -126,104 +150,77 @@
<style lang="scss"> <style lang="scss">
@import "~@/assets/css/utilities"; @import "~@/assets/css/utilities";
$list-background-color: $white !default; .application-list__item {
$list-shadow: 0 2px 3px rgba($black, 0.1), 0 0 0 1px rgba($black, 0.1) !default; transition: all $easing $speed;
$list-color: $text !default;
.applications-list-item { &.is-active {
background-color: $list-background-color; margin: 0.75rem -0.75rem;
box-shadow: $list-shadow; max-width: unset;
color: $list-color; }
max-width: 100%;
&--collapsed { &__header {
display: flex; display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center; align-items: center;
overflow: hidden;
cursor: pointer; *:not(.is-active) > &:hover {
&:hover {
background-color: $white-bis; background-color: $white-bis;
} }
}
&--detailed { & > *:not(:first-child) {
display: flex; margin-left: 12px;
flex-direction: column;
margin: ($gap / 2) 0;
} }
&__status { &__status {
width: 40px; width: $gap;
padding-left: ($gap / 2);
} }
&__text { &__name,
padding-left: ($gap / 2); &__version {
display: inline-flex;
align-items: flex-start;
flex-direction: column;
flex-grow: 1; flex-grow: 1;
flex-basis: 0; flex-basis: 50%;
} }
&__secondary { &__name.title {
color: $grey-light; margin: 0.75rem 0;
font-size: $size-6;
} }
&__actions { &__actions {
justify-self: end; justify-self: end;
padding-right: ($gap / 2);
opacity: 0; opacity: 0;
transition: all $easing $speed; transition: all $easing $speed;
will-change: opacity; will-change: opacity;
} margin-right: ($gap / 2);
*:hover > &__actions { *:hover > &,
*.is-active & {
opacity: 1; opacity: 1;
} }
&__header {
display: flex;
height: 48px;
align-items: center;
overflow: hidden;
cursor: pointer;
&-text {
color: $grey-darker;
font-weight: $weight-semibold;
padding-left: $gap;
flex-grow: 1;
} }
&-actions {
justify-self: end;
padding-right: $gap;
} }
} }
&__instance-list { .application__instances td {
list-style: none; vertical-align: middle;
margin: 0 ($gap / 2) ($gap / 2) ($gap / 2);
padding: 0;
} }
&__instance { .instance {
display: flex; &__status {
height: 48px; width: $gap;
overflow: hidden;
background-color: #fff;
align-items: center;
cursor: pointer;
&:hover {
background-color: $white-bis;
} }
& + & { &__actions {
border-top: 1px solid rgba(0, 0, 0, .12); text-align: right;
margin-top: 0; opacity: 0;
transition: all $easing $speed;
will-change: opacity;
margin-right: $gap;
*:hover > & {
opacity: 1;
} }
} }
} }
</style> </style>
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
<p v-text="error.message"/> <p v-text="error.message"/>
</div> </div>
</div> </div>
<div class="level"> <div class="level applications-stats">
<div class="level-item has-text-centered"> <div class="level-item has-text-centered">
<div> <div>
<p class="heading">Applications</p> <p class="heading">Applications</p>
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</div> </div>
</div> </div>
</div> </div>
<div v-for="group in statusGroups" :key="group.status"> <div class="application-group" v-for="group in statusGroups" :key="group.status">
<p class="heading" v-text="group.status"/> <p class="heading" v-text="group.status"/>
<applications-list :applications="group.applications" :selected="selected"/> <applications-list :applications="group.applications" :selected="selected"/>
</div> </div>
...@@ -117,3 +117,13 @@ ...@@ -117,3 +117,13 @@
component: component component: component
}; };
</script> </script>
<style lang="scss">
@import "~@/assets/css/utilities";
.application-group {
margin: $gap 0;
}
</style>
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