implemented basic ui
							
								
								
									
										7
									
								
								app/static/assets/css/bootstrap-icons.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										6
									
								
								app/static/assets/css/bootstrap.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										56
									
								
								app/static/assets/css/custom.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,56 @@
 | 
			
		||||
/*
 | 
			
		||||
    Original: #76b900
 | 
			
		||||
    Darken 1: #5DA000 (10%)
 | 
			
		||||
    Darken 2: #438600 (20%)
 | 
			
		||||
    Darken 3: #2A6D00 (30%)
 | 
			
		||||
    Darken 4: #105300 (40%)
 | 
			
		||||
    Darken 5: #003A00 (50%)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.text-primary {
 | 
			
		||||
    color: #76b900 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.lead {
 | 
			
		||||
    color: #105300 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbar-green {
 | 
			
		||||
    background-color: #76b900 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbar-brand {
 | 
			
		||||
    background-color: transparent;
 | 
			
		||||
    color: #ffffff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbar-brand:focus, .navbar-brand:hover {
 | 
			
		||||
    color: #fcfcfc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.btn-primary {
 | 
			
		||||
    background-color: #76b900 !important;
 | 
			
		||||
    border-color: #76b900 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.btn-primary:focus, .btn-primary:hover {
 | 
			
		||||
    background-color: #5DA000 !important;
 | 
			
		||||
    border-color: #5DA000 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
code {
 | 
			
		||||
    color: #105300 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar .nav-link.active {
 | 
			
		||||
    color: #76b900 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar .nav-link:focus, .sidebar .nav-link:hover {
 | 
			
		||||
    color: #105300 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbar-nav .nav-item .nav-link {
 | 
			
		||||
    color: white !important;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								app/static/assets/css/dashboard.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,101 @@
 | 
			
		||||
body {
 | 
			
		||||
  font-size: .875rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.feather {
 | 
			
		||||
  width: 16px;
 | 
			
		||||
  height: 16px;
 | 
			
		||||
  vertical-align: text-bottom;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Sidebar
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
.sidebar {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  /* rtl:raw:
 | 
			
		||||
  right: 0;
 | 
			
		||||
  */
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  /* rtl:remove */
 | 
			
		||||
  left: 0;
 | 
			
		||||
  z-index: 100; /* Behind the navbar */
 | 
			
		||||
  padding: 48px 0 0; /* Height of navbar */
 | 
			
		||||
  box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (max-width: 767.98px) {
 | 
			
		||||
  .sidebar {
 | 
			
		||||
    top: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-sticky {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  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: #727272;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar .nav-link.active {
 | 
			
		||||
  color: #2470dc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.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 .navbar-toggler {
 | 
			
		||||
  top: .25rem;
 | 
			
		||||
  right: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								app/static/assets/fonts/bootstrap-icons.woff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								app/static/assets/fonts/bootstrap-icons.woff2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								app/static/assets/img/favicons/android-chrome-192x192.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 27 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								app/static/assets/img/favicons/android-chrome-512x512.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 51 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								app/static/assets/img/favicons/apple-touch-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 25 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								app/static/assets/img/favicons/favicon-16x16.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 733 B  | 
							
								
								
									
										
											BIN
										
									
								
								app/static/assets/img/favicons/favicon-32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								app/static/assets/img/favicons/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 15 KiB  | 
							
								
								
									
										1
									
								
								app/static/assets/img/favicons/manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								app/static/assets/img/logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 73 KiB  | 
							
								
								
									
										6
									
								
								app/static/assets/js/bootstrap.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										94
									
								
								app/static/assets/js/helper.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,94 @@
 | 
			
		||||
async function fetchOriginsWithLeases(element) {
 | 
			
		||||
    let xhr = new XMLHttpRequest();
 | 
			
		||||
    xhr.open("GET", '/-/origins?leases=true', true);
 | 
			
		||||
    xhr.onreadystatechange = function () {
 | 
			
		||||
        if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
 | 
			
		||||
            const x = JSON.parse(xhr.response)
 | 
			
		||||
            console.debug(x)
 | 
			
		||||
 | 
			
		||||
            element.innerHTML = ''
 | 
			
		||||
            let table = document.createElement('table')
 | 
			
		||||
            table.classList.add('table', 'mt-4');
 | 
			
		||||
            let thead = document.createElement('thead');
 | 
			
		||||
            thead.innerHTML = `
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <th scope="col">origin</th>
 | 
			
		||||
                        <th scope="col">hostname</th>
 | 
			
		||||
                        <th scope="col">OS</th>
 | 
			
		||||
                        <th scope="col">driver version</th>
 | 
			
		||||
                        <th scope="col">leases</th>
 | 
			
		||||
                    </tr>`
 | 
			
		||||
            table.appendChild(thead)
 | 
			
		||||
            let tbody = document.createElement('thead');
 | 
			
		||||
            x.forEach((o) => {
 | 
			
		||||
                let row = document.createElement('tr');
 | 
			
		||||
                row.innerHTML = `
 | 
			
		||||
                        <td><code>${o.origin_ref}</code></td>
 | 
			
		||||
                        <td>${o.hostname}</td>
 | 
			
		||||
                        <td>${o.os_platform}</td>
 | 
			
		||||
                        <td>${o.os_version}</td>
 | 
			
		||||
                        <td>${o.leases.map(x => `<code title="expires: ${x.lease_expires}">${x.lease_ref}</code>`).join(', ')}</td>`
 | 
			
		||||
                tbody.appendChild(row);
 | 
			
		||||
            })
 | 
			
		||||
            table.appendChild(tbody)
 | 
			
		||||
            element.appendChild(table)
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    xhr.send();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function fetchLeases(element) {
 | 
			
		||||
    let xhr = new XMLHttpRequest();
 | 
			
		||||
    xhr.open("GET", '/-/leases?origin=true', true);
 | 
			
		||||
    xhr.onreadystatechange = function () {
 | 
			
		||||
        if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
 | 
			
		||||
            const x = JSON.parse(xhr.response)
 | 
			
		||||
            console.debug(x)
 | 
			
		||||
 | 
			
		||||
            element.innerHTML = ''
 | 
			
		||||
            let table = document.createElement('table')
 | 
			
		||||
            table.classList.add('table', 'mt-4');
 | 
			
		||||
            let thead = document.createElement('thead');
 | 
			
		||||
            thead.innerHTML = `
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <th scope="col">lease</th>
 | 
			
		||||
                        <th scope="col">created</th>
 | 
			
		||||
                        <th scope="col">updated</th>
 | 
			
		||||
                        <th scope="col">expires</th>
 | 
			
		||||
                        <th scope="col">origin</th>
 | 
			
		||||
                    </tr>`
 | 
			
		||||
            table.appendChild(thead)
 | 
			
		||||
            let tbody = document.createElement('thead');
 | 
			
		||||
            x.forEach((o) => {
 | 
			
		||||
                let row = document.createElement('tr');
 | 
			
		||||
                row.innerHTML = `
 | 
			
		||||
                        <td><code>${o.lease_ref}</code></td>
 | 
			
		||||
                        <td>${o.lease_created}</td>
 | 
			
		||||
                        <td>${o.lease_updated}</td>
 | 
			
		||||
                        <td>${o.lease_expires}</td>
 | 
			
		||||
                        <td><code>${o.origin_ref}</code></td>`
 | 
			
		||||
                tbody.appendChild(row);
 | 
			
		||||
            })
 | 
			
		||||
            table.appendChild(tbody)
 | 
			
		||||
            element.appendChild(table)
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    xhr.send();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function deleteOrigins() {
 | 
			
		||||
    let xhr = new XMLHttpRequest();
 | 
			
		||||
    xhr.open("DELETE", '/-/origins', true);
 | 
			
		||||
    xhr.send();
 | 
			
		||||
    await fetchOriginsWithLeases()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function deleteLease(lease_ref) {
 | 
			
		||||
    if (lease_ref === undefined)
 | 
			
		||||
        lease_ref = window.prompt("Please enter 'lease_ref' which should be deleted");
 | 
			
		||||
    if (lease_ref === null || lease_ref === "")
 | 
			
		||||
        return
 | 
			
		||||
    let xhr = new XMLHttpRequest();
 | 
			
		||||
    xhr.open("DELETE", `/-/lease/${{lease_ref}}`, true);
 | 
			
		||||
    xhr.send();
 | 
			
		||||
}
 | 
			
		||||