Massive frontend overhaul
This commit is contained in:
		@ -1,5 +1,5 @@
 | 
			
		||||
before_script:
 | 
			
		||||
 - export VERSION=1.0.1
 | 
			
		||||
 - export VERSION=1.1.0
 | 
			
		||||
 - chmod +x packaging/build-package.sh packaging/package-upload.sh
 | 
			
		||||
 | 
			
		||||
stages:
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								package.json
									
									
									
									
									
								
							@ -10,10 +10,15 @@
 | 
			
		||||
    "build": "node build/build.js"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "bootstrap": "^4.0.0-beta.2",
 | 
			
		||||
    "bootstrap-vue": "^1.3.0",
 | 
			
		||||
    "@fortawesome/fontawesome": "^1.1.5",
 | 
			
		||||
    "@fortawesome/fontawesome-free-regular": "^5.0.9",
 | 
			
		||||
    "@fortawesome/fontawesome-free-solid": "^5.0.9",
 | 
			
		||||
    "@fortawesome/vue-fontawesome": "0.0.22",
 | 
			
		||||
    "bootstrap": "^4.0.0",
 | 
			
		||||
    "bootstrap-vue": "^1.5.1",
 | 
			
		||||
    "event-emitter": "^0.3.5",
 | 
			
		||||
    "jquery": "^3.2.1",
 | 
			
		||||
    "moment": "^2.22.0",
 | 
			
		||||
    "tiny-emitter": "^2.0.2",
 | 
			
		||||
    "util.inherits": "^1.0.3",
 | 
			
		||||
    "vue": "^2.4.2",
 | 
			
		||||
@ -39,18 +44,20 @@
 | 
			
		||||
    "friendly-errors-webpack-plugin": "^1.1.3",
 | 
			
		||||
    "html-webpack-plugin": "^2.28.0",
 | 
			
		||||
    "http-proxy-middleware": "^0.17.3",
 | 
			
		||||
    "webpack-bundle-analyzer": "^2.2.1",
 | 
			
		||||
    "semver": "^5.3.0",
 | 
			
		||||
    "shelljs": "^0.7.6",
 | 
			
		||||
    "node-sass": "^4.8.3",
 | 
			
		||||
    "opn": "^5.1.0",
 | 
			
		||||
    "optimize-css-assets-webpack-plugin": "^2.0.0",
 | 
			
		||||
    "ora": "^1.2.0",
 | 
			
		||||
    "rimraf": "^2.6.0",
 | 
			
		||||
    "sass-loader": "^6.0.7",
 | 
			
		||||
    "semver": "^5.3.0",
 | 
			
		||||
    "shelljs": "^0.7.6",
 | 
			
		||||
    "url-loader": "^0.5.8",
 | 
			
		||||
    "vue-loader": "^13.0.4",
 | 
			
		||||
    "vue-style-loader": "^3.0.1",
 | 
			
		||||
    "vue-template-compiler": "^2.4.2",
 | 
			
		||||
    "webpack": "^2.6.1",
 | 
			
		||||
    "webpack": "^2.7.0",
 | 
			
		||||
    "webpack-bundle-analyzer": "^2.2.1",
 | 
			
		||||
    "webpack-dev-middleware": "^1.10.0",
 | 
			
		||||
    "webpack-hot-middleware": "^2.18.0",
 | 
			
		||||
    "webpack-merge": "^4.1.0"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								src/App.vue
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/App.vue
									
									
									
									
									
								
							@ -1,21 +1,23 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div id="app" class="container">
 | 
			
		||||
    <div class="row" style="padding-bottom: 10px;">
 | 
			
		||||
      <div class="col-sm">
 | 
			
		||||
        <h1>Ripper</h1>
 | 
			
		||||
  <div id="app">
 | 
			
		||||
    <n :sensors="sensors" />
 | 
			
		||||
    <div class="container">
 | 
			
		||||
      <div class="row">
 | 
			
		||||
        <main role="main" class="col-md-12 ml-sm-auto col-lg-12 pt-3 px-4">
 | 
			
		||||
        <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom">
 | 
			
		||||
          <h1 class="h2">Jobs</h1>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <status :sensors="sensors"></status>
 | 
			
		||||
    <temperatures :temperatures="sensors.temperatures"></temperatures>
 | 
			
		||||
        <job v-for="(job, id) in jobs" :job="job" :key="job.id"></job>
 | 
			
		||||
        </main>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
import job from './components/Job';
 | 
			
		||||
import status from './components/Status';
 | 
			
		||||
import temperatures from './components/TempStatus';
 | 
			
		||||
import navbar from './components/Nav';
 | 
			
		||||
import EventWebSocket from './websocket';
 | 
			
		||||
 | 
			
		||||
let d = {
 | 
			
		||||
@ -70,8 +72,7 @@ export default {
 | 
			
		||||
  name: 'app',
 | 
			
		||||
  components: {
 | 
			
		||||
    job: job,
 | 
			
		||||
    status: status,
 | 
			
		||||
    temperatures: temperatures,
 | 
			
		||||
    n: navbar,
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return d;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										93
									
								
								src/assets/scss/_sidebar.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/assets/scss/_sidebar.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,93 @@
 | 
			
		||||
body {
 | 
			
		||||
  font-size: .875rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.feather {
 | 
			
		||||
  width: 16px;
 | 
			
		||||
  height: 16px;
 | 
			
		||||
  vertical-align: text-bottom;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Sidebar
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
.sidebar {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  z-index: 100; /* Behind the navbar */
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-sticky {
 | 
			
		||||
  position: -webkit-sticky;
 | 
			
		||||
  position: sticky;
 | 
			
		||||
  top: 48px; /* Height of navbar */
 | 
			
		||||
  height: calc(100vh - 48px);
 | 
			
		||||
  padding-top: .5rem;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
  overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar .nav-link {
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  color: #333;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar .nav-link .feather {
 | 
			
		||||
  margin-right: 4px;
 | 
			
		||||
  color: #999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar .nav-link.active {
 | 
			
		||||
  color: #007bff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar .nav-link:hover .feather,
 | 
			
		||||
.sidebar .nav-link.active .feather {
 | 
			
		||||
  color: inherit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-heading {
 | 
			
		||||
  font-size: .75rem;
 | 
			
		||||
  text-transform: uppercase;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Navbar
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
.navbar-brand {
 | 
			
		||||
  padding-top: .75rem;
 | 
			
		||||
  padding-bottom: .75rem;
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
  background-color: rgba(0, 0, 0, .25);
 | 
			
		||||
  box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbar .form-control {
 | 
			
		||||
  padding: .75rem 1rem;
 | 
			
		||||
  border-width: 0;
 | 
			
		||||
  border-radius: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-control-dark {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  background-color: rgba(255, 255, 255, .1);
 | 
			
		||||
  border-color: rgba(255, 255, 255, .1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-control-dark:focus {
 | 
			
		||||
  border-color: transparent;
 | 
			
		||||
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .25);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Utilities
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
.border-top { border-top: 1px solid #e5e5e5; }
 | 
			
		||||
.border-bottom { border-bottom: 1px solid #e5e5e5; }
 | 
			
		||||
							
								
								
									
										23
									
								
								src/assets/scss/_variables.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/assets/scss/_variables.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
$cold: #6CA6CD;
 | 
			
		||||
$cool: #79CDCD;
 | 
			
		||||
$info: #4F94CD;
 | 
			
		||||
$acceptable: #66CDAA;
 | 
			
		||||
$success: #A2CD5A;
 | 
			
		||||
$high: #EEE685;
 | 
			
		||||
$warning: #E3A869;
 | 
			
		||||
$danger: #EE8262;
 | 
			
		||||
 | 
			
		||||
$badge-color: #545454;
 | 
			
		||||
 | 
			
		||||
$theme-colors: (
 | 
			
		||||
  "cold": $cold,
 | 
			
		||||
  "cool": $cool,
 | 
			
		||||
  "acceptable": $acceptable,
 | 
			
		||||
  "high": $high
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@each $color, $value in $theme-colors {
 | 
			
		||||
  .badge-#{$color} {
 | 
			
		||||
    color: $badge-color !important;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/assets/scss/app.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/assets/scss/app.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
@import '_variables.scss';
 | 
			
		||||
@import '~bootstrap/scss/bootstrap';
 | 
			
		||||
@import '~bootstrap-vue/dist/bootstrap-vue.css';
 | 
			
		||||
@import '_sidebar.scss';
 | 
			
		||||
 | 
			
		||||
.margin-top-10 {
 | 
			
		||||
  margin-top: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.margin-bottom-10 {
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.margin-bottom-20 {
 | 
			
		||||
  margin-bottom: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.badge-success {
 | 
			
		||||
  color: #454545;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.nav-item .progress {
 | 
			
		||||
  width: 70px;
 | 
			
		||||
}
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <job v-for="(job, index) in jobs" :job="job" :key="job_id"></job>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import job from '@/components/Job';
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'hello',
 | 
			
		||||
  components: {
 | 
			
		||||
    job: job
 | 
			
		||||
  },
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      msg: 'Welcome to Your Vue.js App'
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
@ -1,11 +1,19 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <div class="col-sm">
 | 
			
		||||
      <h3>{{ job.title }} - {{ stageValue }}</h3>
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-header">
 | 
			
		||||
          <div class="row">
 | 
			
		||||
            <div class="col-md">{{ job.title }}</div>
 | 
			
		||||
            <div class="col-md text-center badge">{{ stageValue }}</div>
 | 
			
		||||
            <div class="col-md text-right">Remaining: {{ eta }}</div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <template v-if="job.progress">
 | 
			
		||||
            <span class="text-center">{{ job.progress.name }} ({{ job.progress.percentage }}%)</span>
 | 
			
		||||
            <div class="progress">
 | 
			
		||||
          <div class="progress-bar bg-success" role="progressbar" :style="'width: ' + job.progress.percentage + '%'" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">{{ job.progress.percentage }}%</div>
 | 
			
		||||
              <div class="progress-bar bg-success" role="progressbar" :style="'width: ' + job.progress.percentage + '%'" :aria-valuenow=job.progress.percentage aria-valuemin="0" aria-valuemax="100">{{ job.progress.percentage }}%</div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <template v-if="job.progress.totalPercentage">
 | 
			
		||||
              <span class="text-center">Total Progress ({{ job.progress.totalPercentage }}%)</span>
 | 
			
		||||
@ -16,6 +24,8 @@
 | 
			
		||||
          </template>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
@ -28,8 +38,20 @@
 | 
			
		||||
          return 'Ripping';
 | 
			
		||||
        } else if (this.job.stage === 'transcode') {
 | 
			
		||||
          return 'Transcoding';
 | 
			
		||||
        } else if (this.job.stage === 'copy') {
 | 
			
		||||
          return 'Copying';
 | 
			
		||||
        }
 | 
			
		||||
        return 'Unknown: ' + this.job.stage;
 | 
			
		||||
      },
 | 
			
		||||
      eta: function() {
 | 
			
		||||
        if (this.job.eta == 0) {
 | 
			
		||||
          return 'Unknown';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Job is in nanoseconds because of Go's time.Duration
 | 
			
		||||
        let eta = moment.duration(this.job.eta / 1000);
 | 
			
		||||
 | 
			
		||||
        return eta.humanize();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								src/components/Nav.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/components/Nav.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="navbar navbar-expand-lg navbar-dark bg-dark sticky-top p-0">
 | 
			
		||||
    <div class="container d-flex flex-column flex-md-row">
 | 
			
		||||
      <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#">ARM</a>
 | 
			
		||||
      <div class="collapse navbar-collapse">
 | 
			
		||||
        <status :sensors="sensors" v-if="sensors"></status>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import status from './Status';
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'navbar',
 | 
			
		||||
    props: [ 'sensors' ],
 | 
			
		||||
    components: {
 | 
			
		||||
      status: status,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="row" v-if="sensors.cpu || sensors.memory || sensors.storage">
 | 
			
		||||
    <cpu_status :status="sensors.cpu"></cpu_status>
 | 
			
		||||
  <ul class="navbar-nav ml-auto" v-if="sensors.cpu || sensors.memory || sensors.disks">
 | 
			
		||||
    <cpu_status :status="sensors.cpu" :cpuName="sensors.cpuName" :temperatures="sensors.temperatures"></cpu_status>
 | 
			
		||||
    <memory_status :status="sensors.memory"></memory_status>
 | 
			
		||||
    <disk_status :status="sensors.disk"></disk_status>
 | 
			
		||||
  </div>
 | 
			
		||||
    <disk_status :status="sensors.disks"></disk_status>
 | 
			
		||||
  </ul>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div style="padding-top: 10px;">
 | 
			
		||||
    <template v-for="(temp, id) in temperatures">
 | 
			
		||||
      <span class="badge badge-info">{{ temp.name }}: {{ temp.temperature }}C</span> 
 | 
			
		||||
    </template>
 | 
			
		||||
  <div class="margin-top-10 margin-bottom-20 text-center">
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@ -10,6 +7,7 @@
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'temp_status',
 | 
			
		||||
    props: [ 'temperatures' ],
 | 
			
		||||
    components: {},
 | 
			
		||||
    methods: {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -1,21 +1,38 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="col">
 | 
			
		||||
    <h4>CPU <span :class="'badge badge-' + percentageClass">{{ formattedPercentage }}%</span></h4>
 | 
			
		||||
    <div class="progress">
 | 
			
		||||
      <div :class="'progress-bar bg-' + percentageClass" role="progressbar" :style="{ width : status.UserPct + '%' }" :aria-valuenow="status.UserPct" aria-valuemin="0" aria-valuemax="100"></div>
 | 
			
		||||
  <b-nav-item-dropdown no-caret right>
 | 
			
		||||
    <template slot="button-content">
 | 
			
		||||
      <font-awesome-icon icon="tachometer-alt" /> CPU
 | 
			
		||||
      <b-progress :value="status.UserPct" height=".5rem" :variant="percentageClass"></b-progress>
 | 
			
		||||
    </template>
 | 
			
		||||
    <b-dropdown-header class="text-center">CPU</b-dropdown-header>
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
      <small>{{ cpuName }}</small>
 | 
			
		||||
      <br />
 | 
			
		||||
      <span :class="'badge badge-' + percentageClass">{{ formattedPercentage }}%</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
      <template v-for="(temp, id) in temperatures">
 | 
			
		||||
        <span :class="'badge badge-' + badgeClass(temp.temperature)" :title="temp.name">{{ temp.temperature }}C</span> 
 | 
			
		||||
      </template>
 | 
			
		||||
    </div>
 | 
			
		||||
  </b-nav-item-dropdown>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'cpu_status',
 | 
			
		||||
    props: [ 'status' ],
 | 
			
		||||
    props: [ 'status', 'cpuName', 'temperatures' ],
 | 
			
		||||
    computed: {
 | 
			
		||||
      formattedPercentage: function() {
 | 
			
		||||
        if (!this.status) {
 | 
			
		||||
          return '0.00';
 | 
			
		||||
        }
 | 
			
		||||
        return parseFloat(this.status.UserPct).toFixed(2);
 | 
			
		||||
      },
 | 
			
		||||
      percentageClass: function() {
 | 
			
		||||
        if (!this.status) {
 | 
			
		||||
          return 'info';
 | 
			
		||||
        }
 | 
			
		||||
        if (this.status.UserPct >= 90) {
 | 
			
		||||
          return 'danger';
 | 
			
		||||
        } else if (this.status.UserPct >= 80) {
 | 
			
		||||
@ -23,6 +40,24 @@
 | 
			
		||||
        }
 | 
			
		||||
        return 'success'
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      badgeClass: function(temp) {
 | 
			
		||||
        if (temp >= 90) {
 | 
			
		||||
          return 'danger';
 | 
			
		||||
        } else if (temp >= 70) {
 | 
			
		||||
          return 'warning';
 | 
			
		||||
        } else if (temp >= 60) {
 | 
			
		||||
          return 'high';
 | 
			
		||||
        } else if (temp >= 50) {
 | 
			
		||||
          return 'success';
 | 
			
		||||
        } else if (temp >= 40) {
 | 
			
		||||
          return 'acceptable';
 | 
			
		||||
        } else if (temp >= 30) {
 | 
			
		||||
          return 'cool';
 | 
			
		||||
        }
 | 
			
		||||
        return 'cold';
 | 
			
		||||
      },
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,22 @@
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="col">
 | 
			
		||||
    <h4>Disk Space <span :class="'badge badge-' + percentageClass"><formatBytes :bytes="status.used"></formatBytes> of <formatBytes :bytes="status.total"></formatBytes></span></h4>
 | 
			
		||||
    <div class="progress">
 | 
			
		||||
      <div :class="'progress-bar bg-' + percentageClass" role="progressbar" :style="{ width : usedPercentage + '%' }" :aria-valuenow="usedPercentage" aria-valuemin="0" aria-valuemax="100"></div>
 | 
			
		||||
  <b-nav-item-dropdown no-caret right>
 | 
			
		||||
    <template slot="button-content">
 | 
			
		||||
      <font-awesome-icon icon="hdd" /> Disks
 | 
			
		||||
      <b-progress :value="totalUsedPercentage" height=".5rem" :variant="totalPercentageClass"></b-progress>
 | 
			
		||||
    </template>
 | 
			
		||||
    <b-dropdown-header class="text-center">Disks</b-dropdown-header>
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
      Total
 | 
			
		||||
      <br />
 | 
			
		||||
      <span :class="'badge badge-' + totalPercentageClass"><formatBytes :bytes="totalUsed" /> / <formatBytes :bytes="total" /></span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div v-for="(disk, index) in status" class="text-center">
 | 
			
		||||
      {{ disk.path }}
 | 
			
		||||
      <br />
 | 
			
		||||
      <span :class="'badge badge-' + individualPercentages[index]"><formatBytes :bytes="disk.used" /> / <formatBytes :bytes="disk.total" /></span>
 | 
			
		||||
    </div>
 | 
			
		||||
  </b-nav-item-dropdown>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
@ -12,14 +24,40 @@
 | 
			
		||||
    name: 'disk_status',
 | 
			
		||||
    props: [ 'status' ],
 | 
			
		||||
    computed: {
 | 
			
		||||
      usedPercentage: function() {
 | 
			
		||||
        if (!this.status) {
 | 
			
		||||
          return 0;
 | 
			
		||||
      totalUsed: function() {
 | 
			
		||||
        let used = 0;
 | 
			
		||||
 | 
			
		||||
        let i;
 | 
			
		||||
        for (i = 0; i < this.status.length; i++) {
 | 
			
		||||
          used += this.status[i].used;
 | 
			
		||||
        }
 | 
			
		||||
        return parseFloat((this.status.used / this.status.total) * 100).toFixed(1).toString();
 | 
			
		||||
 | 
			
		||||
        return used;
 | 
			
		||||
      },
 | 
			
		||||
      percentageClass: function() {
 | 
			
		||||
        let usedPercent = (this.status.used / this.status.total) * 100;
 | 
			
		||||
      total: function() {
 | 
			
		||||
        let total = 0;
 | 
			
		||||
 | 
			
		||||
        let i;
 | 
			
		||||
        for (i = 0; i < this.status.length; i++) {
 | 
			
		||||
          total += this.status[i].total;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return total;
 | 
			
		||||
      },
 | 
			
		||||
      totalUsedPercentage: function() {
 | 
			
		||||
        let used = 0;
 | 
			
		||||
        let total = 0;
 | 
			
		||||
 | 
			
		||||
        let i;
 | 
			
		||||
        for (i = 0; i < this.status.length; i++) {
 | 
			
		||||
          used += this.status[i].used;
 | 
			
		||||
          total += this.status[i].total;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (used / total) * 100;
 | 
			
		||||
      },
 | 
			
		||||
      totalPercentageClass: function() {
 | 
			
		||||
        let usedPercent = this.totalUsedPercentage;
 | 
			
		||||
        if (usedPercent >= 90) {
 | 
			
		||||
          return 'danger';
 | 
			
		||||
        } else if (usedPercent >= 75) {
 | 
			
		||||
@ -27,6 +65,24 @@
 | 
			
		||||
        }
 | 
			
		||||
        return 'success'
 | 
			
		||||
      },
 | 
			
		||||
      individualPercentages: function() {
 | 
			
		||||
        let percentages = [];
 | 
			
		||||
        let i, usedPercent;
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < this.status.length; i++) {
 | 
			
		||||
          usedPercent = (this.status[i].used / this.status[i].total) * 100;
 | 
			
		||||
 | 
			
		||||
          if (usedPercent >= 90) {
 | 
			
		||||
            percentages[i] = 'danger';
 | 
			
		||||
          } else if (usedPercent >= 75) {
 | 
			
		||||
            percentages[i] = 'warning';
 | 
			
		||||
          } else {
 | 
			
		||||
            percentages[i] = 'success';
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return percentages;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,15 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="col">
 | 
			
		||||
    <h4>Memory <span :class="'badge badge-' + percentageClass"><formatBytes :bytes="(status.MemUsed + status.Buffers + status.Cached) * 1024" /> / <formatBytes :bytes="status.MemTotal * 1024" /></span></h4>
 | 
			
		||||
    <div class="progress">
 | 
			
		||||
      <div class="progress-bar bg-success" role="progressbar" :style="{ width: memoryPercentage + '%' }" :aria-valuenow="memoryPercentage" aria-valuemin="0" aria-valuemax="100"></div>
 | 
			
		||||
      <div class="progress-bar bg-warning" role="progressbar" :style="{ width: memoryBufCachePercentage + '%' }" :aria-valuenow="memoryBufCachePercentage" aria-valuemin="0" aria-valuemax="100"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
  <b-nav-item-dropdown no-caret right>
 | 
			
		||||
    <template slot="button-content">
 | 
			
		||||
      <font-awesome-icon icon="microchip" /> Memory
 | 
			
		||||
      <b-progress :value="memoryPercentage" height=".5rem" :variant="percentageClass"></b-progress>
 | 
			
		||||
    </template>
 | 
			
		||||
    <b-dropdown-header class="text-center">Memory</b-dropdown-header>
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
      <span :class="'badge badge-' + percentageClass"><formatBytes :bytes="status.MemUsed * 1024" /> / <formatBytes :bytes="status.MemTotal * 1024" /></span>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
  </b-nav-item-dropdown>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
@ -14,16 +18,10 @@
 | 
			
		||||
    props: [ 'status' ],
 | 
			
		||||
    computed: {
 | 
			
		||||
      memoryPercentage: function() {
 | 
			
		||||
        if (!this.status) {
 | 
			
		||||
          return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return parseFloat((this.status.MemUsed / this.status.MemTotal) * 100).toFixed(1).toString();
 | 
			
		||||
        return (this.status.MemUsed / this.status.MemTotal) * 100;
 | 
			
		||||
      },
 | 
			
		||||
      memoryBufCachePercentage: function() {
 | 
			
		||||
        if (!this.status) {
 | 
			
		||||
          return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return parseFloat(((this.status.Buffers + this.status.Cached) / this.status.MemTotal) * 100).toFixed(1).toString();
 | 
			
		||||
        return ((this.status.Buffers + this.status.Cached) / this.status.MemTotal) * 100;
 | 
			
		||||
      },
 | 
			
		||||
      percentageClass: function() {
 | 
			
		||||
        let usedPercent = (this.status.MemUsed / this.status.MemTotal) * 100;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								src/main.js
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/main.js
									
									
									
									
									
								
							@ -1,14 +1,20 @@
 | 
			
		||||
// The Vue build version to load with the `import` command
 | 
			
		||||
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
import 'bootstrap/dist/css/bootstrap.css'
 | 
			
		||||
import 'bootstrap-vue/dist/bootstrap-vue.css'
 | 
			
		||||
import './assets/scss/app.scss'
 | 
			
		||||
import App from './App'
 | 
			
		||||
import fontawesome from '@fortawesome/fontawesome'
 | 
			
		||||
import FontAwesomeIcon from '@fortawesome/vue-fontawesome'
 | 
			
		||||
import solid from '@fortawesome/fontawesome-free-solid'
 | 
			
		||||
 | 
			
		||||
import BootstrapVue from 'bootstrap-vue'
 | 
			
		||||
 | 
			
		||||
Vue.use(BootstrapVue);
 | 
			
		||||
 | 
			
		||||
fontawesome.library.add(solid);
 | 
			
		||||
 | 
			
		||||
Vue.component('font-awesome-icon', FontAwesomeIcon);
 | 
			
		||||
 | 
			
		||||
Vue.component('formatBytes', {
 | 
			
		||||
  render: function (createElement) {
 | 
			
		||||
    return createElement(
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,3 @@
 | 
			
		||||
window.arm_config = {
 | 
			
		||||
  url: 'ws://127.0.0.1:8080/ws'
 | 
			
		||||
  url: 'ws://192.168.2.85:8080/ws'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user