Events.vue (4924B)
1 <template> 2 <div class="events-wrapper"> 3 <div v-for="e in events" :key="e.id"> 4 <div class="event" 5 style="display:flex;cursor:pointer;" 6 :style="e.style" 7 @click="eventClicked(e, $event)"> 8 <div class="event-field">{{ e.service }}</div> 9 <!-- TODO: Include VueMQ 10 <!--<mq-layout mq="md+">--> 11 <div class="event-field">{{ simplifyDate(e.timestamp) }}</div> 12 <!--</mq-layout>--> 13 <div class="event-field">{{ e.title }}</div> 14 <button v-show="e.id > 0" class="delete-button">×</button> 15 </div> 16 <div v-show="e.open" style="padding: 5px; border: 1px solid rgba(0,0,0,.125); border-top: 0; overflow: auto"> 17 <code style="white-space:pre;">{{e.details}}</code> 18 </div> 19 </div> 20 </div> 21 </template> 22 23 <script> 24 import api from "./requests.js"; 25 export default { 26 name: "Events", 27 data() { 28 return { 29 events: [], 30 statusStyling: { 31 "ok": { color: "black", backgroundColor: "#c3e6cb" }, 32 "warning": { color: "black", backgroundColor: "#ffeeba" }, 33 "error": { color: "black", backgroundColor: "#f5c6cb" }, 34 "info": { color: "black", backgroundColor: "#fff" }, 35 "late":{ color: "black", backgroundColor: "#d6d8d9" }, 36 }, 37 eventSorter: (e1, e2) => e2.timestamp - e1.timestamp 38 }; 39 }, 40 methods: { 41 statusStyle(status) { 42 const style = this.statusStyling[status]; 43 if (style) { 44 return style; 45 } else { 46 return { color: "#000", backgroundColor: "#fff" }; 47 } 48 }, 49 eventClicked(e, clickEvent) { 50 if (clickEvent.target.className === "delete-button") { 51 // Element clicked is the delete button 52 this.deleteEvent(e.id); 53 } else { 54 // Not the delete button - toggle details 55 e.open = !e.open; 56 } 57 }, 58 deleteEvent(id) { 59 api.deleteEvent(id, 60 success => { 61 this.events = this.events.filter( 62 e => e.id !== id 63 ); 64 }, 65 error => { 66 console.error(error); 67 this.$emit("error"); 68 } 69 ); 70 }, 71 simplifyDate(eventUTC) { 72 let diffUTC = Date.now() - eventUTC; 73 let inFuture = false; 74 if (diffUTC < 0) { 75 inFuture = true; 76 diffUTC = -diffUTC; 77 } 78 let unitStrings = ["year", "week", "day", "hour", "minute"]; 79 let units = [31536000000, 604800000, 86400000, 3600000, 60000]; 80 let numOfUnits = 0; 81 for (let i = 0; i < units.length; i++) { 82 numOfUnits = Math.floor(diffUTC / units[i]); 83 if (numOfUnits === 0) { 84 continue; 85 } 86 if (inFuture) { 87 return "in " + numOfUnits + " " + unitStrings[i] + (numOfUnits > 1 ? "s" : ""); 88 } 89 return numOfUnits + " " + unitStrings[i] + (numOfUnits > 1 ? "s" : "") + " ago"; 90 } 91 return inFuture ? "now" : "just now"; 92 } 93 }, 94 mounted() { 95 api.getEvents( 96 successData => { 97 let lateId = 0; 98 this.events = successData.map(e => { 99 return { 100 ...e, 101 id: e.id ? e.id : lateId--, 102 style: this.statusStyle(e.status), 103 open: false 104 } 105 }).sort(this.eventSorter); 106 }, 107 error => { 108 console.error(error); 109 this.$emit("error"); 110 } 111 ); 112 } 113 } 114 115 </script> 116 117 <style scoped> 118 .event { 119 height: 3em; 120 /* 121 margin-bottom: 0.5em; 122 -webkit-box-shadow: 0 0 10px rgba(0,0,0,.1); 123 box-shadow: 0 0 10px rgba(0,0,0,.1); 124 */ 125 padding: .75rem; 126 border: 1px solid rgba(0,0,0,.125); 127 box-sizing: border-box; 128 white-space: nowrap; 129 } 130 .event-field { 131 flex: 1; 132 } 133 .events-wrapper { 134 margin: 0; 135 padding: 0; 136 } 137 button { 138 cursor: pointer; 139 background-color: inherit; 140 border: none; 141 text-align: center; 142 font-size: 16px; 143 } 144 </style>