Skip to content

Commit

Permalink
feat(web2): add sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
fiftin committed Oct 3, 2020
1 parent 08ac853 commit c855bf1
Show file tree
Hide file tree
Showing 19 changed files with 997 additions and 49 deletions.
37 changes: 37 additions & 0 deletions web2/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions web2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.18.0",
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
Expand Down
236 changes: 197 additions & 39 deletions web2/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,60 +1,218 @@
<template>
<v-app>
<v-app-bar
app
color="primary"
dark
<v-app v-if="state === 'success'" style="background: white;">
<v-snackbar
v-model="snackbar"
:color="snackbarColor"
:timeout="3000"
top
>
<div class="d-flex align-center">
<v-img
alt="Vuetify Logo"
class="shrink mr-2"
contain
src="https://cdn.vuetifyjs.com/images/logos/vuetify-logo-dark.png"
transition="scale-transition"
width="40"
/>

<v-img
alt="Vuetify Name"
class="shrink mt-1 hidden-sm-and-down"
contain
min-width="100"
src="https://cdn.vuetifyjs.com/images/logos/vuetify-name-dark.png"
width="100"
/>
</div>

<v-spacer></v-spacer>

{{ snackbarText }}
<v-btn
href="https://github.com/vuetifyjs/vuetify/releases/latest"
target="_blank"
text
@click="snackbar = false"
>
<span class="mr-2">Latest Release dd</span>
<v-icon>mdi-open-in-new</v-icon>
Close
</v-btn>
</v-app-bar>
</v-snackbar>

<v-navigation-drawer
app
permanent
v-if="$route.path.startsWith('/project/')"
>
<v-toolbar flat class="white">
<v-toolbar-title>
<v-icon large style="position: absolute; left: 10px; top: 13px;">
mdi-play-circle-outline
</v-icon>
<router-link to="/" style="color: black; text-decoration: none; margin-left: 46px;">
{{ project.name }}
</router-link>
</v-toolbar-title>
</v-toolbar>
<v-divider></v-divider>

<div style="padding: 10px 15px;">
<v-select
solo-inverted
flat
hide-details
:items="projects"
item-value="id"
item-text="name"
v-model="projectId"
></v-select>
</div>

<v-list class="pt-0" rounded>
<v-list-item key="templates" :to="`/project/${projectId}/templates`">
<v-list-item-icon>
<v-icon>mdi-check-all</v-icon>
</v-list-item-icon>

<v-list-item-content>
<v-list-item-title>Task Templates</v-list-item-title>
</v-list-item-content>
</v-list-item>

<v-list-item key="inventory" :to="`/project/${projectId}/inventory`">
<v-list-item-icon>
<v-icon>mdi-monitor-multiple</v-icon>
</v-list-item-icon>

<v-list-item-content>
<v-list-item-title>Inventory</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>

<v-main>
<router-view v-bind:projectId="projectId"></router-view>
</v-main>

</v-app>

<v-app v-else-if="state === 'loading'">
<v-main>
<HelloWorld/>
<v-container
fluid
fill-height
align-center
justify-center
class="pa-0"
>
<v-progress-circular
:size="70"
color="primary"
indeterminate
></v-progress-circular>
</v-container>
</v-main>
</v-app>

<v-app v-else></v-app>
</template>
<style lang="scss">
.site-select {
& > .v-input__control > .v-input__slot {
border-radius: 0 !important;
}
}
</style>

<script>
import HelloWorld from './components/HelloWorld.vue';
import axios from 'axios';
import EventBus from './event-bus';
export default {
name: 'App',
data() {
return {
user: null,
components: {
HelloWorld,
state: 'loading',
snackbar: false,
snackbarText: '',
snackbarColor: '',
projects: null,
projectId: null,
};
},
computed: {
project() {
return this.projects.find((x) => x.id === this.projectId);
},
},
watch: {
async projectId(val) {
if (val == null) {
return;
}
const projectId = parseInt(this.$route.params.projectId, 10) || null;
if (val === projectId) {
return;
}
await this.$router.push({ path: `/project/${val}` });
},
},
async created() {
if (!this.isAuthenticated()) {
await this.$router.push({ path: '/auth/login' });
return;
}
try {
await this.loadUserInfo();
await this.loadProjects();
if (!this.projectId) {
if (this.projects.length > 0) {
this.projectId = this.projects[0].id;
} else {
// TODO: create project page
this.projectId = parseInt(this.$route.params.projectId, 10) || null;
}
}
this.state = 'success';
} catch (err) {
EventBus.$emit('i-session-end');
}
},
mounted() {
EventBus.$on('i-snackbar', (e) => {
this.snackbar = true;
this.snackbarColor = e.color;
this.snackbarText = e.text;
});
EventBus.$on('i-session-end', async () => {
this.snackbar = false;
this.snackbarColor = '';
this.snackbarText = '';
await this.$router.push({ path: '/auth/login' });
});
EventBus.$on('i-account-changed', async () => {
await this.loadUserInfo();
});
EventBus.$on('i-site-changed', async () => {
await this.loadProjects();
});
},
data: () => ({
//
}),
methods: {
isAuthenticated() {
return document.cookie.includes('semaphore=');
},
async loadProjects() {
this.projects = (await axios({
method: 'get',
url: '/api/projects',
responseType: 'json',
})).data;
},
async loadUserInfo() {
if (!this.isAuthenticated()) {
return;
}
this.user = (await axios({
method: 'get',
url: '/api/user',
responseType: 'json',
})).data;
},
},
};
</script>
Binary file modified web2/src/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web2/src/event-bus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Vue from 'vue';

export default new Vue();
3 changes: 3 additions & 0 deletions web2/src/lib/delay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function delay(milliseconds = 100) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}
7 changes: 7 additions & 0 deletions web2/src/lib/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// eslint-disable-next-line import/prefer-default-export
export function getErrorMessage(err) {
if (err.response && err.response.data) {
return err.response.data.error || err.message;
}
return err.message;
}
56 changes: 46 additions & 10 deletions web2/src/router/index.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,58 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import Dashboard from '../views/project/Dashboard.vue';
import Templates from '../views/project/Templates.vue';
import Environment from '../views/project/Environment.vue';
import Inventory from '../views/project/Inventory.vue';
import Keys from '../views/project/Keys.vue';
import Repositories from '../views/project/Repositories.vue';
import Team from '../views/project/Team.vue';
import Users from '../views/Users.vue';
import Auth from '../views/Auth.vue';
import ChangePassword from '../views/ChangePassword.vue';

Vue.use(VueRouter);

const routes = [
{
path: '/',
name: 'Home',
component: Home,
path: '/project/:projectId/',
component: Dashboard,
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
path: '/project/:projectId/templates',
component: Templates,
},
{
path: '/project/:projectId/environment',
component: Environment,
},
{
path: '/project/:projectId/inventory',
component: Inventory,
},
{
path: '/project/:projectId/repositories',
component: Repositories,
},
{
path: '/project/:projectId/keys',
component: Keys,
},
{
path: '/project/:projectId/team',
component: Team,
},
{
path: '/auth/login',
component: Auth,
},
{
path: '/users',
component: Users,
},
{
path: '/change-password',
component: ChangePassword,
},
];

Expand Down
Loading

0 comments on commit c855bf1

Please sign in to comment.