Massive frontend overhaul
This commit is contained in:
		| @ -1,5 +1,5 @@ | |||||||
| before_script: | before_script: | ||||||
|  - export VERSION=1.0.1 |  - export VERSION=1.1.0 | ||||||
|  - chmod +x packaging/build-package.sh packaging/package-upload.sh |  - chmod +x packaging/build-package.sh packaging/package-upload.sh | ||||||
|  |  | ||||||
| stages: | stages: | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								package.json
									
									
									
									
									
								
							| @ -10,10 +10,15 @@ | |||||||
|     "build": "node build/build.js" |     "build": "node build/build.js" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "bootstrap": "^4.0.0-beta.2", |     "@fortawesome/fontawesome": "^1.1.5", | ||||||
|     "bootstrap-vue": "^1.3.0", |     "@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", |     "event-emitter": "^0.3.5", | ||||||
|     "jquery": "^3.2.1", |     "jquery": "^3.2.1", | ||||||
|  |     "moment": "^2.22.0", | ||||||
|     "tiny-emitter": "^2.0.2", |     "tiny-emitter": "^2.0.2", | ||||||
|     "util.inherits": "^1.0.3", |     "util.inherits": "^1.0.3", | ||||||
|     "vue": "^2.4.2", |     "vue": "^2.4.2", | ||||||
| @ -39,18 +44,20 @@ | |||||||
|     "friendly-errors-webpack-plugin": "^1.1.3", |     "friendly-errors-webpack-plugin": "^1.1.3", | ||||||
|     "html-webpack-plugin": "^2.28.0", |     "html-webpack-plugin": "^2.28.0", | ||||||
|     "http-proxy-middleware": "^0.17.3", |     "http-proxy-middleware": "^0.17.3", | ||||||
|     "webpack-bundle-analyzer": "^2.2.1", |     "node-sass": "^4.8.3", | ||||||
|     "semver": "^5.3.0", |  | ||||||
|     "shelljs": "^0.7.6", |  | ||||||
|     "opn": "^5.1.0", |     "opn": "^5.1.0", | ||||||
|     "optimize-css-assets-webpack-plugin": "^2.0.0", |     "optimize-css-assets-webpack-plugin": "^2.0.0", | ||||||
|     "ora": "^1.2.0", |     "ora": "^1.2.0", | ||||||
|     "rimraf": "^2.6.0", |     "rimraf": "^2.6.0", | ||||||
|  |     "sass-loader": "^6.0.7", | ||||||
|  |     "semver": "^5.3.0", | ||||||
|  |     "shelljs": "^0.7.6", | ||||||
|     "url-loader": "^0.5.8", |     "url-loader": "^0.5.8", | ||||||
|     "vue-loader": "^13.0.4", |     "vue-loader": "^13.0.4", | ||||||
|     "vue-style-loader": "^3.0.1", |     "vue-style-loader": "^3.0.1", | ||||||
|     "vue-template-compiler": "^2.4.2", |     "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-dev-middleware": "^1.10.0", | ||||||
|     "webpack-hot-middleware": "^2.18.0", |     "webpack-hot-middleware": "^2.18.0", | ||||||
|     "webpack-merge": "^4.1.0" |     "webpack-merge": "^4.1.0" | ||||||
|  | |||||||
							
								
								
									
										23
									
								
								src/App.vue
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/App.vue
									
									
									
									
									
								
							| @ -1,21 +1,23 @@ | |||||||
| <template> | <template> | ||||||
|   <div id="app" class="container"> |   <div id="app"> | ||||||
|     <div class="row" style="padding-bottom: 10px;"> |     <n :sensors="sensors" /> | ||||||
|       <div class="col-sm"> |     <div class="container"> | ||||||
|         <h1>Ripper</h1> |       <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> | ||||||
|  |         <job v-for="(job, id) in jobs" :job="job" :key="job.id"></job> | ||||||
|  |         </main> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|     <status :sensors="sensors"></status> |  | ||||||
|     <temperatures :temperatures="sensors.temperatures"></temperatures> |  | ||||||
|     <job v-for="(job, id) in jobs" :job="job" :key="job.id"></job> |  | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| import Vue from 'vue' | import Vue from 'vue' | ||||||
| import job from './components/Job'; | import job from './components/Job'; | ||||||
| import status from './components/Status'; | import navbar from './components/Nav'; | ||||||
| import temperatures from './components/TempStatus'; |  | ||||||
| import EventWebSocket from './websocket'; | import EventWebSocket from './websocket'; | ||||||
|  |  | ||||||
| let d = { | let d = { | ||||||
| @ -70,8 +72,7 @@ export default { | |||||||
|   name: 'app', |   name: 'app', | ||||||
|   components: { |   components: { | ||||||
|     job: job, |     job: job, | ||||||
|     status: status, |     n: navbar, | ||||||
|     temperatures: temperatures, |  | ||||||
|   }, |   }, | ||||||
|   data() { |   data() { | ||||||
|     return d; |     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,19 +1,29 @@ | |||||||
| <template> | <template> | ||||||
|   <div class="row"> |   <div class="row"> | ||||||
|     <div class="col-sm"> |     <div class="col-sm"> | ||||||
|       <h3>{{ job.title }} - {{ stageValue }}</h3> |       <div class="card"> | ||||||
|       <template v-if="job.progress"> |         <div class="card-header"> | ||||||
|         <span class="text-center">{{ job.progress.name }} ({{ job.progress.percentage }}%)</span> |           <div class="row"> | ||||||
|         <div class="progress"> |             <div class="col-md">{{ job.title }}</div> | ||||||
|           <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="col-md text-center badge">{{ stageValue }}</div> | ||||||
|         </div> |             <div class="col-md text-right">Remaining: {{ eta }}</div> | ||||||
|         <template v-if="job.progress.totalPercentage"> |  | ||||||
|           <span class="text-center">Total Progress ({{ job.progress.totalPercentage }}%)</span> |  | ||||||
|           <div class="progress" v-if="job.progress.totalPercentage > 0"> |  | ||||||
|             <div class="progress-bar bg-success" role="progressbar" :style="'width: ' + job.progress.totalPercentage + '%'" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">{{ job.progress.totalPercentage }}%</div> |  | ||||||
|           </div> |           </div> | ||||||
|         </template> |         </div> | ||||||
|       </template> |         <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=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> | ||||||
|  |               <div class="progress" v-if="job.progress.totalPercentage > 0"> | ||||||
|  |                 <div class="progress-bar bg-success" role="progressbar" :style="'width: ' + job.progress.totalPercentage + '%'" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">{{ job.progress.totalPercentage }}%</div> | ||||||
|  |               </div> | ||||||
|  |             </template> | ||||||
|  |           </template> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| @ -28,8 +38,20 @@ | |||||||
|           return 'Ripping'; |           return 'Ripping'; | ||||||
|         } else if (this.job.stage === 'transcode') { |         } else if (this.job.stage === 'transcode') { | ||||||
|           return 'Transcoding'; |           return 'Transcoding'; | ||||||
|  |         } else if (this.job.stage === 'copy') { | ||||||
|  |           return 'Copying'; | ||||||
|         } |         } | ||||||
|         return 'Unknown: ' + this.job.stage; |         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> | <template> | ||||||
|   <div class="row" v-if="sensors.cpu || sensors.memory || sensors.storage"> |   <ul class="navbar-nav ml-auto" v-if="sensors.cpu || sensors.memory || sensors.disks"> | ||||||
|     <cpu_status :status="sensors.cpu"></cpu_status> |     <cpu_status :status="sensors.cpu" :cpuName="sensors.cpuName" :temperatures="sensors.temperatures"></cpu_status> | ||||||
|     <memory_status :status="sensors.memory"></memory_status> |     <memory_status :status="sensors.memory"></memory_status> | ||||||
|     <disk_status :status="sensors.disk"></disk_status> |     <disk_status :status="sensors.disks"></disk_status> | ||||||
|   </div> |   </ul> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
|  | |||||||
| @ -1,8 +1,5 @@ | |||||||
| <template> | <template> | ||||||
|   <div style="padding-top: 10px;"> |   <div class="margin-top-10 margin-bottom-20 text-center"> | ||||||
|     <template v-for="(temp, id) in temperatures"> |  | ||||||
|       <span class="badge badge-info">{{ temp.name }}: {{ temp.temperature }}C</span>  |  | ||||||
|     </template> |  | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| @ -10,6 +7,7 @@ | |||||||
|   export default { |   export default { | ||||||
|     name: 'temp_status', |     name: 'temp_status', | ||||||
|     props: [ 'temperatures' ], |     props: [ 'temperatures' ], | ||||||
|     components: {}, |     methods: { | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| </script> | </script> | ||||||
|  | |||||||
| @ -1,21 +1,38 @@ | |||||||
| <template> | <template> | ||||||
|   <div class="col"> |   <b-nav-item-dropdown no-caret right> | ||||||
|     <h4>CPU <span :class="'badge badge-' + percentageClass">{{ formattedPercentage }}%</span></h4> |     <template slot="button-content"> | ||||||
|     <div class="progress"> |       <font-awesome-icon icon="tachometer-alt" /> CPU | ||||||
|       <div :class="'progress-bar bg-' + percentageClass" role="progressbar" :style="{ width : status.UserPct + '%' }" :aria-valuenow="status.UserPct" aria-valuemin="0" aria-valuemax="100"></div> |       <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> | ||||||
|   </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> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
|   export default { |   export default { | ||||||
|     name: 'cpu_status', |     name: 'cpu_status', | ||||||
|     props: [ 'status' ], |     props: [ 'status', 'cpuName', 'temperatures' ], | ||||||
|     computed: { |     computed: { | ||||||
|       formattedPercentage: function() { |       formattedPercentage: function() { | ||||||
|  |         if (!this.status) { | ||||||
|  |           return '0.00'; | ||||||
|  |         } | ||||||
|         return parseFloat(this.status.UserPct).toFixed(2); |         return parseFloat(this.status.UserPct).toFixed(2); | ||||||
|       }, |       }, | ||||||
|       percentageClass: function() { |       percentageClass: function() { | ||||||
|  |         if (!this.status) { | ||||||
|  |           return 'info'; | ||||||
|  |         } | ||||||
|         if (this.status.UserPct >= 90) { |         if (this.status.UserPct >= 90) { | ||||||
|           return 'danger'; |           return 'danger'; | ||||||
|         } else if (this.status.UserPct >= 80) { |         } else if (this.status.UserPct >= 80) { | ||||||
| @ -23,6 +40,24 @@ | |||||||
|         } |         } | ||||||
|         return 'success' |         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> | </script> | ||||||
|  | |||||||
| @ -1,10 +1,22 @@ | |||||||
|  |  | ||||||
| <template> | <template> | ||||||
|   <div class="col"> |   <b-nav-item-dropdown no-caret right> | ||||||
|     <h4>Disk Space <span :class="'badge badge-' + percentageClass"><formatBytes :bytes="status.used"></formatBytes> of <formatBytes :bytes="status.total"></formatBytes></span></h4> |     <template slot="button-content"> | ||||||
|     <div class="progress"> |       <font-awesome-icon icon="hdd" /> Disks | ||||||
|       <div :class="'progress-bar bg-' + percentageClass" role="progressbar" :style="{ width : usedPercentage + '%' }" :aria-valuenow="usedPercentage" aria-valuemin="0" aria-valuemax="100"></div> |       <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> | ||||||
|   </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> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| @ -12,14 +24,40 @@ | |||||||
|     name: 'disk_status', |     name: 'disk_status', | ||||||
|     props: [ 'status' ], |     props: [ 'status' ], | ||||||
|     computed: { |     computed: { | ||||||
|       usedPercentage: function() { |       totalUsed: function() { | ||||||
|         if (!this.status) { |         let used = 0; | ||||||
|           return 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() { |       total: function() { | ||||||
|         let usedPercent = (this.status.used / this.status.total) * 100; |         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) { |         if (usedPercent >= 90) { | ||||||
|           return 'danger'; |           return 'danger'; | ||||||
|         } else if (usedPercent >= 75) { |         } else if (usedPercent >= 75) { | ||||||
| @ -27,6 +65,24 @@ | |||||||
|         } |         } | ||||||
|         return 'success' |         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> | </script> | ||||||
|  | |||||||
| @ -1,11 +1,15 @@ | |||||||
| <template> | <template> | ||||||
|   <div class="col"> |   <b-nav-item-dropdown no-caret right> | ||||||
|     <h4>Memory <span :class="'badge badge-' + percentageClass"><formatBytes :bytes="(status.MemUsed + status.Buffers + status.Cached) * 1024" /> / <formatBytes :bytes="status.MemTotal * 1024" /></span></h4> |     <template slot="button-content"> | ||||||
|     <div class="progress"> |       <font-awesome-icon icon="microchip" /> Memory | ||||||
|       <div class="progress-bar bg-success" role="progressbar" :style="{ width: memoryPercentage + '%' }" :aria-valuenow="memoryPercentage" aria-valuemin="0" aria-valuemax="100"></div> |       <b-progress :value="memoryPercentage" height=".5rem" :variant="percentageClass"></b-progress> | ||||||
|       <div class="progress-bar bg-warning" role="progressbar" :style="{ width: memoryBufCachePercentage + '%' }" :aria-valuenow="memoryBufCachePercentage" aria-valuemin="0" aria-valuemax="100"></div> |     </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> |     </div> | ||||||
|   </div> |   </b-nav-item-dropdown> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| @ -14,16 +18,10 @@ | |||||||
|     props: [ 'status' ], |     props: [ 'status' ], | ||||||
|     computed: { |     computed: { | ||||||
|       memoryPercentage: function() { |       memoryPercentage: function() { | ||||||
|         if (!this.status) { |         return (this.status.MemUsed / this.status.MemTotal) * 100; | ||||||
|           return 0; |  | ||||||
|         } |  | ||||||
|         return parseFloat((this.status.MemUsed / this.status.MemTotal) * 100).toFixed(1).toString(); |  | ||||||
|       }, |       }, | ||||||
|       memoryBufCachePercentage: function() { |       memoryBufCachePercentage: function() { | ||||||
|         if (!this.status) { |         return ((this.status.Buffers + this.status.Cached) / this.status.MemTotal) * 100; | ||||||
|           return 0; |  | ||||||
|         } |  | ||||||
|         return parseFloat(((this.status.Buffers + this.status.Cached) / this.status.MemTotal) * 100).toFixed(1).toString(); |  | ||||||
|       }, |       }, | ||||||
|       percentageClass: function() { |       percentageClass: function() { | ||||||
|         let usedPercent = (this.status.MemUsed / this.status.MemTotal) * 100; |         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 | // The Vue build version to load with the `import` command | ||||||
| // (runtime-only or standalone) has been set in webpack.base.conf with an alias. | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. | ||||||
| import Vue from 'vue' | import Vue from 'vue' | ||||||
| import 'bootstrap/dist/css/bootstrap.css' | import './assets/scss/app.scss' | ||||||
| import 'bootstrap-vue/dist/bootstrap-vue.css' |  | ||||||
| import App from './App' | 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' | import BootstrapVue from 'bootstrap-vue' | ||||||
|  |  | ||||||
| Vue.use(BootstrapVue); | Vue.use(BootstrapVue); | ||||||
|  |  | ||||||
|  | fontawesome.library.add(solid); | ||||||
|  |  | ||||||
|  | Vue.component('font-awesome-icon', FontAwesomeIcon); | ||||||
|  |  | ||||||
| Vue.component('formatBytes', { | Vue.component('formatBytes', { | ||||||
|   render: function (createElement) { |   render: function (createElement) { | ||||||
|     return createElement( |     return createElement( | ||||||
|  | |||||||
| @ -1,3 +1,3 @@ | |||||||
| window.arm_config = { | 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