Skip to content

feat(ui): general ui improvements #215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/go/web/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ func Start(opts ...ServerOption) error {
http.FileServer(assets),
)

router.Handle("/favicon.ico", http.FileServer(assets))

router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch a := assets.(type) {
case *assetfs.AssetFS:
Expand Down
2 changes: 1 addition & 1 deletion src/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@fortawesome/fontawesome-free": "^6.4.0",
"@fortawesome/fontawesome-svg-core": "^6.4.0",
"@fortawesome/vue-fontawesome": "^2.0.6",
"buefy": "^0.9.22",
"buefy": "^0.9.29",
"d3": "^6.2.0",
"file-saver": "^2.0.5",
"js-yaml": "^4.1.0",
Expand Down
35 changes: 30 additions & 5 deletions src/js/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ login and returns a user to Experiments component if successful.
-->

<template>
<div class="container">
<div>
<app-header></app-header>
<div class="row">
<div class="row container is-fullhd px-4">
<div class="col-xs-12">
<router-view></router-view>
</div>
<app-footer></app-footer>
</div>
<app-footer></app-footer>
</div>
</template>

Expand Down Expand Up @@ -75,13 +75,19 @@ login and returns a user to Experiments component if successful.
wsConnect () {
let path = `${process.env.BASE_URL}api/v1/ws`;

if (this.$route.path === "/signin" || this.$route.path === "/login") {
console.log("skipping websocket connect until login")
return
}

if (this.$store.getters.token) {
path += `?token=${this.$store.getters.token}`;
}

let proto = location.protocol == "https:" ? "wss://" : "ws://";
let url = proto + location.host + path;

console.log("connect websocket")
this.$connect(url);

// Separate, stand-alone websocket connection to handle app-wide
Expand Down Expand Up @@ -118,6 +124,12 @@ login and returns a user to Experiments component if successful.
}
});
}
},
watch: {
'$route': function(to, _) {
if (!this.socket && !(to.path === "/signin" || to.path === "/login"))
this.wsConnect();
}
}
}
</script>
Expand Down Expand Up @@ -257,6 +269,14 @@ clue what this stuff does.
transform: rotate( 0deg );
}

.b-table {
.table {
td {
vertical-align: middle;
}
}
}

// Import Bulma's core
@import "~bulma/sass/utilities/_all";

Expand All @@ -274,6 +294,8 @@ clue what this stuff does.

$progress-text-color: black;

$fullhd: 1536px + (2 * $gap);

$colors: (
"light": ( $light, $light-invert ),
"dark": ( $dark, $dark-invert ),
Expand All @@ -285,13 +307,16 @@ clue what this stuff does.
"warning": ( $warning, $warning-invert ),
"danger": ( $danger, $danger-invert )
);

$navbar-background-color: $light;
$navbar-item-img-max-height: 2.5rem;

// Import Bulma and Buefy styles
@import "~bulma";
@import "~buefy/src/scss/buefy";

a.navbar-item:hover {
background: #404040;
a.navbar-item.router-link-exact-active, a.navbar-item:hover {
background: #5b5b5b;
}

div.is-success {
Expand Down
2 changes: 0 additions & 2 deletions src/js/src/components/Configs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
</div>
</b-modal>
<template v-if="editor.use">
<hr>
<section class="hero is-light is-bold is-small">
<div class="columns">
<div class="column is-1" />
Expand Down Expand Up @@ -126,7 +125,6 @@
</section>
</template>
<template v-else>
<hr>
<div class="level">
<div class="level-left" />
<div class="level-right">
Expand Down
15 changes: 7 additions & 8 deletions src/js/src/components/Experiments.vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@
</section>
</template>
<template v-else>
<hr>
<b-field position="is-right">
<b-autocomplete v-model="searchName"
placeholder="Find an Experiment"
Expand Down Expand Up @@ -138,7 +137,7 @@
</div>
</section>
</template>
<b-table-column field="name" label="Name" width="200" sortable v-slot="props">
<b-table-column field="name" label="Name" sortable v-slot="props">
<template v-if="updating( props.row.status )">
{{ props.row.name }}
</template>
Expand Down Expand Up @@ -171,22 +170,22 @@
</span>
</template>
</b-table-column>
<b-table-column field="topology" label="Topology" width="200" v-slot="props">
<b-table-column field="topology" label="Topology" v-slot="props">
{{ props.row.topology | lowercase }}
</b-table-column>
<b-table-column field="scenario" label="Scenario" width="200" v-slot="props">
<b-table-column field="scenario" label="Scenario" v-slot="props">
{{ props.row.scenario | lowercase }}
</b-table-column>
<b-table-column field="start_time" label="Start Time" width="250" sortable v-slot="props">
<b-table-column field="start_time" label="Start Time" sortable v-slot="props">
{{ props.row.start_time }}
</b-table-column>
<b-table-column field="vm_count" label="VMs" width="100" centered sortable v-slot="props">
<b-table-column field="vm_count" label="VMs" width="50" centered sortable v-slot="props">
{{ props.row.vm_count }}
</b-table-column>
<b-table-column field="vlan_range" label="VLANs" width="100" centered v-slot="props">
<b-table-column field="vlan_range" label="VLANs" centered v-slot="props">
{{ props.row.vlan_min }} - {{ props.row.vlan_max}} ({{ props.row.vlan_count }})
</b-table-column>
<b-table-column label="Actions" width="150" centered v-slot="props">
<b-table-column label="Actions" width="125" centered v-slot="props">
<button v-if="roleAllowed('experiments', 'delete', props.row.name)" class="button is-light is-small action" :disabled="updating( props.row.status )" @click="del( props.row.name, props.row.running )">
<b-icon icon="trash"></b-icon>
</button>
Expand Down
6 changes: 3 additions & 3 deletions src/js/src/components/Footer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ component.

<template>
<div>
<hr>
<div>
<hr class="mb-4">
<div class="container is-fluid">
<small>
<p style="float: left; color: whitesmoke">Copyright &copy; <b>2019-2022 Sandia National Laboratories</b>. All Rights Reserved.</p>
<p style="float: left; color: whitesmoke; padding-bottom: 16px;">Copyright &copy; <b>2019-2025 Sandia National Laboratories</b>. All Rights Reserved.</p>
<p style="float: right; color: whitesmoke">{{ version }}</p>
</small>
</div>
Expand Down
168 changes: 77 additions & 91 deletions src/js/src/components/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,112 +7,98 @@ are only available to Global Administrator or Global Viewer.
-->

<template>
<div>
<a :href="homeLoc()">
<img src="@/assets/phenix-banner.png" width="240">
</a>
<b-navbar class="mb-4">
<template #brand>
<b-navbar-item tag="router-link" :to="homeLoc()" :active="false">
<img src="@/assets/phenix-banner.png" alt="phenix">
</b-navbar-item>
</template>
<template #start>
<b-navbar-item v-if="auth && roleAllowed('experiments', 'list')" tag="router-link"
:to="{ name: 'experiments' }">Experiments</b-navbar-item>
<b-navbar-item v-if="auth && roleAllowed('configs', 'list')" tag="router-link"
:to="{ name: 'configs' }">Configs</b-navbar-item>
<b-navbar-item v-if="auth && roleAllowed('hosts', 'list')" tag="router-link"
:to="{ name: 'hosts' }">Hosts</b-navbar-item>
<b-navbar-item v-if="auth" tag="router-link"
:to="{ name: 'users' }">Users</b-navbar-item>
<b-navbar-item v-if="auth && roleAllowed('logs', 'list')" tag="router-link"
:to="{ name: 'log' }">Log</b-navbar-item>
<b-navbar-item v-if="auth && roleAllowed('experiments', 'list')" tag="router-link"
:to="{ name: 'scorch' }">Scorch</b-navbar-item>
<b-navbar-item v-if="auth && roleAllowed('experiments', 'list')" tag="router-link"
:to="builderLoc()" target="_blank">Builder</b-navbar-item>
<b-navbar-item v-if="auth && roleAllowed('miniconsole', 'post')" tag="router-link"
:to="{name: 'console'}">Console</b-navbar-item>
<b-navbar-item v-if="auth && tunneler" tag="router-link"
:to="{ name: 'tunneler' }">Tunneler</b-navbar-item>
</template>

<nav class="navbar is-light" role="navigation" aria-label="main navigation">
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<menu-link v-if="auth && roleAllowed('experiments', 'list')"
:to="{name: 'experiments'}"
class="navbar-item">Experiments</menu-link>
<menu-link v-if="auth && roleAllowed('configs', 'list')"
:to="{name: 'configs'}"
class="navbar-item">Configs</menu-link>
<menu-link v-if="auth && roleAllowed('hosts', 'list')"
:to="{name: 'hosts'}"
class="navbar-item">Hosts</menu-link>
<menu-link v-if="auth"
:to="{name: 'users'}"
class="navbar-item">Users</menu-link>
<menu-link v-if="auth && roleAllowed('logs', 'list')"
:to="{name: 'log'}"
class="navbar-item">Log</menu-link>
<menu-link v-if="auth && roleAllowed('experiments', 'list')"
:to="{name: 'scorch'}"
class="navbar-item">Scorch</menu-link>
<menu-link v-if="auth && roleAllowed('experiments', 'list')"
:to="builderLoc()"
external
class="navbar-item">Builder</menu-link>
<menu-link v-if="auth && roleAllowed('miniconsole', 'post')"
:to="{name: 'console'}"
class="navbar-item">Console</menu-link>
<menu-link v-if="auth && tunneler"
:to="{name: 'tunneler'}"
class="navbar-item">Tunneler</menu-link>
</div>
</div>
<template #end>
<b-navbar-item v-if="proxyAuth" class="navbar-item" @click="logout">Reauthorize
</b-navbar-item>
<b-navbar-item v-else-if="auth" class="navbar-item" @click="logout">Logout
</b-navbar-item>
</template>
</b-navbar>

<div class="navbar-end">
<div v-if="proxyAuth" class="navbar-item">
<a role="button" class="button navbar-item is-light" @click="logout">Reauthorize</a>
</div>
<div v-else-if="auth" class="navbar-item">
<a role="button" class="button navbar-item is-light" @click="logout">Logout</a>
</div>
</div>
</nav>
</div>
</template>

<script>
import MenuLink from '@/components/MenuLink.vue'
import MenuLink from '@/components/MenuLink.vue'

export default {
components: {
menuLink: MenuLink
export default {
components: {
menuLink: MenuLink
},

// The computed elements determine if the user is already logged
// in; if so, the routable links are available. If not, the sign
// in routable link is the only one available. The role getter
// determines what the role of the user is; this is used to present
// routable links in the header row.
computed: {
auth() {
return this.$store.getters.auth;
},

// The computed elements determine if the user is already logged
// in; if so, the routable links are available. If not, the sign
// in routable link is the only one available. The role getter
// determines what the role of the user is; this is used to present
// routable links in the header row.
computed: {
auth () {
return this.$store.getters.auth;
},
proxyAuth() {
return process.env.VUE_APP_AUTH === 'proxy';
},

proxyAuth () {
return process.env.VUE_APP_AUTH === 'proxy';
},
tunneler() {
return this.$store.getters.features.includes('tunneler-download');
}
},

tunneler () {
return this.$store.getters.features.includes('tunneler-download');
}
},

methods: {
// These methods are used to logout a user; or, present
// routable link based on a Global user role.
logout () {
this.$http.get( 'logout' ).then(
response => {
if ( response.status == 204 ) {
this.$store.commit( 'LOGOUT' );
methods: {
// These methods are used to logout a user; or, present
// routable link based on a Global user role.
logout() {
this.$http.get('logout').then(
response => {
if (response.status == 204) {
this.$store.commit('LOGOUT');

if ( this.proxyAuth ) {
this.$buefy.toast.open({
message: 'Your account has been reauthorized',
type: 'is-success',
duration: 4000
});
}
if (this.proxyAuth) {
this.$buefy.toast.open({
message: 'Your account has been reauthorized',
type: 'is-success',
duration: 4000
});
}
}
);
},
}
);
},

homeLoc () {
return this.$router.resolve({name: 'home'}).href
},
homeLoc() {
return this.$router.resolve({ name: 'home' }).href
},

builderLoc () {
return this.$router.resolve({name: 'builder', params: {token: this.$store.getters.token}}).href;
}
builderLoc() {
return this.$router.resolve({ name: 'builder', params: { token: this.$store.getters.token } }).href;
}
}
}
</script>
Loading