Interactive table, bind value of array to html content SUCESS

This commit is contained in:
infidel 2022-12-14 00:06:43 +07:00
parent ea9e7fb5d0
commit dd416e7758
13 changed files with 982 additions and 56 deletions

11
package-lock.json generated
View File

@ -15,6 +15,7 @@
"@tailwindcss/forms": "0.2.1",
"axios": "^1.1.3",
"chart.js": "2.9.4",
"papaparse": "^5.3.2",
"sirv-cli": "1.0.11",
"svelte-routing": "1.5.0",
"tailwindcss": "^2.2.19"
@ -1396,6 +1397,11 @@
"integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==",
"dev": true
},
"node_modules/papaparse": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.2.tgz",
"integrity": "sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw=="
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@ -3277,6 +3283,11 @@
"integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==",
"dev": true
},
"papaparse": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.2.tgz",
"integrity": "sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw=="
},
"parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",

View File

@ -31,6 +31,7 @@
"@tailwindcss/forms": "0.2.1",
"axios": "^1.1.3",
"chart.js": "2.9.4",
"papaparse": "^5.3.2",
"sirv-cli": "1.0.11",
"svelte-routing": "1.5.0",
"tailwindcss": "^2.2.19"

View File

@ -1375,6 +1375,10 @@ select {
clear: none;
}
.m-1 {
margin: 0.25rem;
}
.m-2 {
margin: 0.5rem;
}
@ -2235,6 +2239,12 @@ select {
gap: 1.5rem;
}
.space-x-0 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0px * var(--tw-space-x-reverse));
margin-left: calc(0px * calc(1 - var(--tw-space-x-reverse)));
}
.space-x-4 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(1rem * var(--tw-space-x-reverse));
@ -2609,6 +2619,21 @@ select {
border-style: none;
}
.border-teal-300 {
--tw-border-opacity: 1;
border-color: rgba(94, 234, 212, var(--tw-border-opacity));
}
.border-amber-500 {
--tw-border-opacity: 1;
border-color: rgba(245, 158, 11, var(--tw-border-opacity));
}
.border-amber-600 {
--tw-border-opacity: 1;
border-color: rgba(217, 119, 6, var(--tw-border-opacity));
}
.border-red-600 {
--tw-border-opacity: 1;
border-color: rgba(220, 38, 38, var(--tw-border-opacity));
@ -2654,6 +2679,11 @@ select {
border-color: rgba(71, 85, 105, var(--tw-border-opacity));
}
.hover\:border-teal-500:hover {
--tw-border-opacity: 1;
border-color: rgba(20, 184, 166, var(--tw-border-opacity));
}
.focus\:border-black:focus {
--tw-border-opacity: 1;
border-color: rgba(0, 0, 0, var(--tw-border-opacity));
@ -2769,6 +2799,16 @@ select {
background-color: rgba(245, 158, 11, var(--tw-bg-opacity));
}
.bg-amber-600 {
--tw-bg-opacity: 1;
background-color: rgba(217, 119, 6, var(--tw-bg-opacity));
}
.bg-amber-700 {
--tw-bg-opacity: 1;
background-color: rgba(180, 83, 9, var(--tw-bg-opacity));
}
.bg-orange-200 {
--tw-bg-opacity: 1;
background-color: rgba(254, 215, 170, var(--tw-bg-opacity));
@ -2864,11 +2904,21 @@ select {
background-color: rgba(30, 41, 59, var(--tw-bg-opacity));
}
.hover\:bg-teal-500:hover {
--tw-bg-opacity: 1;
background-color: rgba(20, 184, 166, var(--tw-bg-opacity));
}
.focus\:bg-white:focus {
--tw-bg-opacity: 1;
background-color: rgba(255, 255, 255, var(--tw-bg-opacity));
}
.focus\:bg-teal-400:focus {
--tw-bg-opacity: 1;
background-color: rgba(45, 212, 191, var(--tw-bg-opacity));
}
.focus\:bg-gray-200:focus {
--tw-bg-opacity: 1;
background-color: rgba(228, 228, 231, var(--tw-bg-opacity));
@ -3079,6 +3129,11 @@ select {
padding-right: 0.375rem;
}
.py-0 {
padding-top: 0px;
padding-bottom: 0px;
}
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
@ -3337,6 +3392,11 @@ select {
line-height: 1;
}
.focus\:text-base:focus {
font-size: 1rem;
line-height: 1.5rem;
}
.font-light {
font-weight: 300;
}
@ -3345,6 +3405,10 @@ select {
font-weight: 400;
}
.font-medium {
font-weight: 500;
}
.font-semibold {
font-weight: 600;
}
@ -3591,6 +3655,11 @@ select {
color: rgba(30, 41, 59, var(--tw-text-opacity));
}
.hover\:text-white:hover {
--tw-text-opacity: 1;
color: rgba(255, 255, 255, var(--tw-text-opacity));
}
.hover\:text-red-600:hover {
--tw-text-opacity: 1;
color: rgba(220, 38, 38, var(--tw-text-opacity));
@ -3616,6 +3685,11 @@ select {
color: rgba(30, 41, 59, var(--tw-text-opacity));
}
.focus\:text-white:focus {
--tw-text-opacity: 1;
color: rgba(255, 255, 255, var(--tw-text-opacity));
}
.underline {
text-decoration: underline;
}

View File

@ -1,10 +1,94 @@
<script>
import { getCookie } from "components/Utils/CookieHandler.js";
let user_ip = [];
let user_allowed_ip = [];
let user_ip_txt;
let user_allowed_ip_txt;
async function getwgIpRecs() {
let csrftoken = getCookie('csrftoken');
let authToken = getCookie('Token');
const wgResponse = await fetch(
'/api2/wgUserRecommendations', {
method: 'GET',
credentials: 'include',
mode: 'same-origin',
headers: {
'Authorization': "Token "+authToken,
'Accept': 'application/json',
'Content-Type': 'application/json',
}
});
return await wgResponse.json();
}
function validate() {
console.log("Validate user creation here...");
}
function select_ip(ip) {
if (!user_ip.includes(ip)) {
user_ip.push(ip);
window.document.getElementById(ip).classList.add('bg-amber-500');
} else {
// user_ip.splice(ip);
const index = user_ip.indexOf(ip);
if (index > -1) {
user_ip.splice(index, 1);
}
window.document.getElementById(ip).classList.remove('bg-amber-500');
}
user_ip_txt = user_ip.join(", ");
console.log(user_ip);
console.log(user_ip_txt);
}
function select_allowed_ip(ip) {
if (!user_allowed_ip.includes(ip)) {
user_allowed_ip.push(ip);
window.document.getElementById(ip).classList.add('bg-amber-500');
} else {
// user_allowed_ip.splice(ip);
const index = user_allowed_ip.indexOf(ip);
if (index > -1) {
user_allowed_ip.splice(index, 1);
}
window.document.getElementById(ip).classList.remove('bg-amber-500');
}
user_allowed_ip_txt = user_allowed_ip.join(", ");
console.log(user_allowed_ip);
console.log(user_allowed_ip_txt);
}
let promise_IPs = getwgIpRecs();
</script>
<div class="flex-auto px-4 lg:px-10 py-10 pt-0">
<form>
<form on:submit|preventDefault={validate}>
<h6 class="text-blueGray-400 text-sm mt-3 mb-6 font-bold uppercase">
User Information
</h6>
<div class="flex flex-wrap">
<div class="w-full lg:w-6/12 px-4">
<div class="relative w-full mb-3">
<label
class="block uppercase text-blueGray-600 text-xs font-bold mb-2"
@ -19,8 +103,6 @@
value="" placeholder="User Name"
/>
</div>
</div>
<div class="w-full lg:w-6/12 px-4">
<div class="relative w-full mb-3">
<label
class="block uppercase text-blueGray-600 text-xs font-bold mb-2"
@ -32,10 +114,32 @@
id="grid-email"
type="email"
class="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
value="jesse@example.com"
placeholder="jesse@example.com"
/>
</div>
<div class="relative w-full mb-3">
<label
class="block uppercase text-blueGray-600 text-xs font-bold mb-2"
for="grid-email"
>
Organization
</label>
<input
id="grid-email"
type="name"
class="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
placeholder="jesse@example.com"
/>
</div>
{#await promise_IPs }
<div class="relative pt-1">
<div class="flex mb-2 items-center justify-between">
<h6> Loading </h6>
</div>
<div class="overflow-hidden h-2 mb-4 text-xs flex rounded bg-teal-200">
</div>
</div>
{:then IPs}
<div class="relative w-full mb-3">
<label
class="block uppercase text-blueGray-600 text-xs font-bold mb-2"
@ -44,11 +148,26 @@
IP Allocation
</label>
<input
id="grid-address"
id="grid-email"
type="text"
class="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
value=""
class="border-0 px-3 py-2 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
bind:value={user_ip_txt}
/>
<div class="relative pt-1">
<div class="flex-wrap mt-2 mb-2 items-center">
{#each IPs.allocated_ips as ip_val}
<button
id="{ip_val}"
class="border-2 border-amber-500 px-4 py-1 text-xs font-bold text-blueGray-500 rounded mr-2 active:bg-red-500 hover:bg-teal-500 hover:border-teal-500 hover:text-white"
value="{ip_val}"
type="button"
on:click="{() => select_ip(ip_val)}"
>
{ip_val}
</button>
{/each}
</div>
</div>
</div>
<div class="relative w-full mb-3">
<label
@ -60,10 +179,33 @@
<input
id="grid-address"
type="text"
class="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
value=""
class="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150 "
bind:value={user_allowed_ip_txt}
/>
<div class="relative pt-1">
<div class="flex flex-wrap mt-2 mb-2 items-center">
{#each Object.entries(IPs.allowed_ips) as [key, ip_val]}
<div class="space-x-0">
<button
class="border-2 border-amber-600 bg-amber-600 px-1 py-1 text-xs font-bold text-blueGray-100 rounded-l"
>
{key}
</button>
<button
id="{ip_val}"
class="border-2 border-amber-600 px-1 py-1 text-xs font-bold text-blueGray-500 rounded-r mr-2 active:bg-red-500 hover:bg-teal-500 hover:border-teal-500 hover:text-white"
value="{ip_val}"
type="button"
on:click="{() => select_allowed_ip(ip_val)}"
>
{ip_val}
</button>
</div>
{/each}
</div>
</div>
</div>
{/await}
<div class="relative w-full mb-3">
<label
class="block uppercase text-blueGray-600 text-xs font-bold mb-2"
@ -80,8 +222,6 @@
</div>
</div>
<hr class="mt-6 border-b-1 border-blueGray-300" />
<h6 class="text-blueGray-400 text-sm mt-3 mb-6 font-bold uppercase">
Contact Information
</h6>

View File

@ -25,7 +25,6 @@
credentials: 'include',
mode: 'same-origin',
headers: {
'X-CSRFToken': csrftoken,
'Authorization': "Token "+authToken,
'Accept': 'application/json',
'Content-Type': 'application/json',
@ -138,47 +137,47 @@
{#each infTable as infRows}
<tr class="{infRows.wgDin < 1 ? 'bg-red-50 text-red-500 text-sm' : infRows.wgStatus == 'true' ? 'bg-teal-50 text-sm text-teal-700 ' : 'text-blueGray-500 bg-blueGray-50 text-sm'} ">
<td
class="border-t-8 px-4 align-middle border-l-0 border-r-0 whitespace-nowrap p-4 border-slate-700"
class="border-t-8 px-4 align-middle border-l-0 border-r-0 whitespace-nowrap p-2 border-slate-700"
>
{ infRows.wgName }
</td>
<td
class="border-t-8 px-4 align-middle border-l-0 border-r-0 whitespace-nowrap p-4"
class="border-t-8 px-4 align-middle border-l-0 border-r-0 whitespace-nowrap p-2"
>
{ infRows.wgMail }
</td>
<td
class="border-t-8 px-4 align-middle border-l-0 border-r-0 whitespace-nowrap p-4"
class="border-t-8 px-4 align-middle border-l-0 border-r-0 whitespace-nowrap p-2"
>
{ infRows.wgKey }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 whitespace-nowrap p-4"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 whitespace-nowrap p-2"
>
{ infRows.wgDin/1000000 } MBytes
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 whitespace-nowrap p-4"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 whitespace-nowrap p-2"
>
{ infRows.wgDout/1000000 } MBytes
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 font-bold whitespace-nowrap p-4"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 font-bold whitespace-nowrap p-2"
>
{ infRows.wgStatus == 'true' ? 'Connected Now': infRows.wgDin < 1 ? 'Never Connected' : 'Not Connected Now' }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 whitespace-nowrap p-4"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 whitespace-nowrap p-2"
>
{ infRows.wgTStamp }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 whitespace-nowrap p-4 text-right"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 whitespace-nowrap p-2 text-right"
>
<TableDropdown />
</td>

View File

@ -0,0 +1,289 @@
<script>
import PapaParse from 'papaparse';
import { getCookie } from "components/Utils/CookieHandler.js";
let onUpload;
let dataToCSV = [];
let prevDataToCSV;
let allowedFiledExtensions = ['csv']; let maxFileSize = 3145728;
let data = [];
let placeholder = [
"Name",
"Email",
"Code",
"Organization"
];
let headers = [
"Name",
"Email",
"Code",
"Organization"
];
let newRow = [...placeholder];
// bound to the uploaded file
let uploader;
async function postWGReg(data) {
let csrftoken = getCookie('csrftoken');
let authToken = getCookie('Token');
console.log(csrftoken);
console.log(authToken);
const wgResponse = await fetch(
'/api2/wgBulkReg?', {
method: 'POST',
credentials: 'include',
mode: 'same-origin',
headers: {
'Authorization': "Token "+authToken,
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
});
return await wgResponse.json();
}
$: {
// Monitor props
if (dataToCSV !== prevDataToCSV && dataToCSV.length !== 0) {
prevDataToCSV = dataToCSV;
const csvData = PapaParse.unparse(dataToCSV); // Change this to parser of yours <papaparse or django backed parser>
onUpload ? onUpload(csvData) : console.log("CSV Data: ", csvData);
}
}
function submitRegistration(){
console.log("I'm submitting registration data");
console.log(data);
}
function clearData(){
data = [];
}
function addRow(){
console.log("Should add row here...");
data = [...data, [...newRow]];
newRow = placeholder;
placeholder = ["", "", "", ""];
}
function checkData(){
console.log(data);
}
function deleteRow(rowTarget) {
data = data.filter(row => row != rowTarget);
console.log(data);
}
function uploadFile(event) {
event.preventDefault();
const file = uploader.files[0];
console.log(file);
const fileExtensionArray = file.type.split("/");
const fileExtension = fileExtensionArray[fileExtensionArray.length-1];
if (file.size > maxFileSize) {
console.log("Your stupid file is too big");
return;
}
if (fileExtension.includes('csv') && file.size < maxFileSize) {
console.log("Will proceed with your file after the infrastructure ready...");
const csvData = PapaParse.parse(
file,
{
complete: (results) => {
onUpload ? onUpload(results.data) : data = results.data;
}
}
);
} else if (allowedFiledExtensions.includes(fileExtension)) {
onUpload ? onUpload(file) : console.log("Broken file, plain content : ", file);
} else {
console.log("Wrong extension stupid ...");
}
}
</script>
<div
class="relative flex flex-col min-w-0 break-words w-full mb-6 shadow-lg rounded-lg bg-blueGray-100 border-0"
>
<div class="rounded bg-white mb-0 px-6 py-6">
<div class="text-center flex justify-between">
<h6 class="mt-3 text-blueGray-700 text-xl font-bold">Action</h6>
<div class="">
<label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white" for="file_input">Upload file</label>
<input class="block w-full text-sm text-teal-500 border border-teal-300 rounded-lg cursor-pointer bg-teal-50 dark:text-teal-400 focus:outline-none dark:bg-teal-700 dark:border-teal-600 dark:placeholder-teal-400"
aria-describedby="file_input_help"
bind:this={uploader}
on:change={uploadFile}
id="file_input"
type="file"
/>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-300" id="file_input_help">SVG, PNG, JPG or GIF (MAX. 800x400px).</p>
<button
class="mt-3 bg-teal-500 text-white active:bg-red-500 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
>
Search
</button>
<button
class="mt-3 bg-teal-500 text-white active:bg-red-500 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
>
Filter
</button>
<button
class="mt-3 bg-amber-500 text-white active:bg-red-500 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
>
Apply to System
</button>
<button
class="mt-3 bg-red-600 text-white active:bg-red-500 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
>
Backup
</button>
</div>
</div>
</div>
</div>
<div
class="relative flex flex-col min-w-0 break-words w-full mb-6 shadow-lg rounded-lg border-0 bg-blueGray-200"
>
<div class="rounded mb-0 px-6 py-6">
<table class="items-center w-full bg-transparent">
<thead>
<tr>
<th
class="px-4 align-middle border border-solid py-3 text-sm uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left bg-blueGray-50 text-blueGray-500 border-blueGray-100"
>
#
</th>
{#each headers as cell}
<th
class="px-4 align-middle border border-solid py-3 text-sm uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left bg-blueGray-50 text-blueGray-500 border-blueGray-100"
>
{ cell }
</th>
{/each}
<th
class="px-4 align-middle border border-solid py-3 text-sm uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left bg-blueGray-50 text-blueGray-500 border-blueGray-100"
>
Action
</th>
</tr>
</thead>
<tbody>
{#each data as row, i}
{#if row.length = 4}
<tr class="border-t-8 text-blueGray-500 bg-white text-sm">
<td
class="border-blueGray-200 px-6 align-middle text-sm whitespace-nowrap p-2"
>
{i + 1}
</td>
{#each row as cell}
<td
class="px-4 align-middletext-sm whitespace-nowrap p-2 focus:outline-none focus:bg-teal-400 focus:text-white focus:text-base"
>
<input
type="text"
placeholder="Search here..."
class="border-0 placeholder-blueGray-300 text-blueGray-600 relative bg-white bg-white rounded text-sm shadow outline-none focus:outline-none focus:ring-2 focus:ring-teal-500 w-full pl-10"
bind:value={cell}
/>
</td>
{/each}
<td
class="px-6 align-middle text-sm whitespace-nowrap p-2"
>
<button
class="bg-red-500 text-white active:bg-red-500 font-bold uppercase text-xs px-2 py-1 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
on:click={ () => deleteRow(row) }
>
<i class="fas fa-times"></i>
</button>
</td>
</tr>
{/if}
{/each}
<tr class="text-blueGray-500 border-t-8 bg-white text-sm">
<td
class="border-blueGray-200 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
>
#
</td>
{#each newRow as cell}
<td
class="px-6 align-middletext-sm whitespace-nowrap p-2 focus:outline-none focus:bg-teal-400 focus:text-white focus:text-base"
>
<input
type="text"
placeholder="Search here..."
class="border-0 placeholder-blueGray-300 text-blueGray-600 relative bg-white bg-white rounded text-sm shadow outline-none focus:outline-none focus:ring-2 focus:ring-teal-500 w-full pl-10"
bind:value={cell}
/>
</td>
{/each}
<td
class=" px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
>
<button
class="bg-teal-500 text-white active:bg-red-500 font-bold uppercase text-xs px-2 py-1 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
on:click={ addRow }
>
<i class="fas fa-plus"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="bg-white mb-0 px-6 py-6">
<button
class="mt-3 bg-teal-500 text-white active:bg-red-500 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
on:click={ () => postWGReg(data)}
>
Submit Registration
</button>
<button
class="mt-3 bg-amber-500 text-white active:bg-red-500 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
on:click={ () => checkData() }
>
Check Current Data
</button>
<button
class="mt-3 bg-red-400 text-white active:bg-red-500 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
on:click={ () => clearData() }
>
Clear Data
</button>
</div>
</div>

View File

@ -0,0 +1,298 @@
<script>
import TableDropdown from "components/Dropdowns/TableDropdown.svelte";
import { getCookie } from "components/Utils/CookieHandler.js";
export let filter_action;
export let checked_vals;
let footprint;
let promise;
let checkbox_vals = [];
// let checked_vals = [];
export const wgResponse = null;
export let filter;
// function getCookie(name) {
// let cookieValue = null;
// if (document.cookie && document.cookie !== '') {
// const cookies = document.cookie.split(';');
// for (let i = 0; i < cookies.length; i++) {
// const cookie = cookies[i].trim();
// // Does this cookie string begin with the name we want?
// if (cookie.substring(0, name.length + 1) === (name + '=')) {
// cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
// break;
// }
// }
// }
// return cookieValue;
// }
async function getwgResponse(o_filter) {
let csrftoken = getCookie('csrftoken');
let authToken = getCookie('Token');
console.log(csrftoken);
console.log(authToken);
console.log("-<>-"+checked_vals);
const wgResponse = await fetch(
'/api2/wgFilterClients?'+o_filter, {
method: 'GET',
credentials: 'include',
mode: 'same-origin',
headers: {
'Authorization': "Token "+authToken,
'Accept': 'application/json',
'Content-Type': 'application/json',
}
}
);
return await wgResponse.json();
}
let selectedID = new Set();
const onCheckId = event => {
filter_action = true;
const row_id = event.target.value;
if (event.target.checked) {
selectedID.add(row_id);
checked_vals.push(row_id);
} else {
selectedID.delete(row_id);
const index = checked_vals.indexOf(row_id);
checked_vals.splice(index, 1);
}
selectedID = selectedID;
console.log(checked_vals);
};
const onSelectAll = event => {
filter_action = true;
console.log("Select All...");
console.log(checkbox_vals);
if (event.target.checked) {
selectedID = new Set(checkbox_vals);
} else {
selectedID.clear();
}
selectedID = selectedID;
checked_vals = checkbox_vals;
};
// let promise = getwgResponse();
async function promise_handler(filter){
checkbox_vals = []
const wg_promise = getwgResponse(filter);
const wg_resp = await wg_promise;
console.log("[+] ID Arrays");
console.log(wg_resp);
let i = 0;
// for (let i = 0; i < wg_resp.length; i++) {
// for ( const x in wg_resp.json) {
// for ( const v in x ) {
// console.log(v);
// // console.log(v["id"]);
// }
// }
wg_resp.forEach(function (arrayItem) {
var x = arrayItem.id;
checkbox_vals.push(x);
console.log(x);
});
console.log("IDs ->");
console.log(checkbox_vals);
return wg_resp
}
$: filter ?
// promise = getwgResponse(filter) : promise = getwgResponse("");
promise = promise_handler(filter) : promise = promise_handler("");
export let color = "light";
</script>
{#await promise}
<div
class="rounded relative flex flex-col min-w-0 break-words w-full mb-6 shadow-lg rounded {color === 'light' ? 'bg-white' : 'bg-red-800 text-white'}"
>
<div class="rounded bg-white mb-0 px-6 py-6">
<div class="text-center w-full">
<div class="relative pt-1">
<div class="flex mb-2 items-center justify-between">
<div>
<span class="text-xs font-semibold inline-block py-1 px-2 uppercase rounded-full text-orange-600 bg-orange-200">
Task in progress
</span>
</div>
<div class="text-right">
<span class="text-xs font-semibold inline-block text-orange-600">
0%
</span>
</div>
</div>
<div class="overflow-hidden h-2 mb-4 text-xs flex rounded bg-orange-200">
<div style="width:30%" class="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-orange-500"></div>
</div>
</div>
</div>
</div>
</div>
{:then wgProfileData}
<div
class="relative flex flex-col min-w-0 break-words w-full mb-6 shadow-lg rounded {color === 'light' ? 'bg-white' : 'bg-red-800 text-white'}"
>
<div class="rounded-t mb-0 px-4 py-3 border-0">
<div class="flex flex-wrap items-center">
<div class="relative w-full px-4 max-w-full flex-grow flex-1">
<h3
class="font-semibold text-lg {color === 'light' ? 'text-blueGray-700' : 'text-white'}"
>
User Profiles
</h3>
</div>
</div>
</div>
<div class="block w-full overflow-x-auto">
<!-- Projects table -->
<table class="w-full striped hover">
<thead>
<tr>
<th
class="px-4 align-middle border border-solid py-3 text-sm uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left {color === 'light' ? 'bg-blueGray-300 text-blueGray-500 border-blueGray-100' : 'bg-red-700 text-red-200 border-red-600'}"
>
<input id="select-all" checked={selectedID.size == wgProfileData.length} on:change={onSelectAll} type="checkbox" value="" class="w-4 h-4 text-teal-600 bg-gray-100 rounded border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
<label for="default-checkbox" class="ml-2 text-sm font-bold text-blueGray-500 dark:text-gray-300">#</label>
</th>
<th
class="px-6 align-middle border border-solid py-3 text-sm uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left {color === 'light' ? 'bg-blueGray-50 text-blueGray-500 border-blueGray-100' : 'bg-red-700 text-red-200 border-red-600'}"
>
Name
</th>
<th
class="px-6 align-middle border border-solid py-3 text-sm uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left {color === 'light' ? 'bg-blueGray-50 text-blueGray-500 border-blueGray-100' : 'bg-red-700 text-red-200 border-red-600'}"
>
Mail
</th>
<th
class="px-6 align-middle border border-solid py-3 text-sm uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left {color === 'light' ? 'bg-blueGray-50 text-blueGray-500 border-blueGray-100' : 'bg-red-700 text-red-200 border-red-600'}"
>
Assigned IP
</th>
<th
class="px-6 align-middle border border-solid py-3 text-sm uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left {color === 'light' ? 'bg-blueGray-50 text-blueGray-500 border-blueGray-100' : 'bg-red-700 text-red-200 border-red-600'}"
>
Allowed IP
</th>
<th
class="uppercase px-6 align-middle border border-solid py-3 text-sm uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left {color === 'light' ? 'bg-blueGray-50 text-blueGray-500 border-blueGray-100' : 'bg-red-700 text-red-200 border-red-600'}"
>
Status
</th>
<th
class="px-6 align-middle border border-solid py-3 text-sm uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left {color === 'light' ? 'bg-blueGray-50 text-blueGray-500 border-blueGray-100' : 'bg-red-700 text-red-200 border-red-600'}"
>
Created Time
</th>
<th
class="px-6 align-middle border border-solid py-3 text-sm uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left {color === 'light' ? 'bg-blueGray-50 text-blueGray-500 border-blueGray-100' : 'bg-red-700 text-red-200 border-red-600'}"
>
Action
</th>
</tr>
</thead>
<tbody>
{#each wgProfileData as infRows}
<tr class="{infRows.enabled != true ? 'bg-red-50 text-red-500 text-sm' : 'text-blueGray-500 bg-white text-sm'} ">
<td
class="bg-blueGray-300 border-t-8 px-4 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2 rounded"
>
<input checked={selectedID.has(infRows.id)} id="{ infRows.id }" type="checkbox" value="{ infRows.id }" on:change={onCheckId} class="w-4 h-4 text-teal-600 bg-gray-100 rounded border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
<label for="default-checkbox" class="ml-2 text-sm font-bold text-blueGray-500 dark:text-gray-300">{ infRows.data_id }</label>
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
>
{ infRows.name }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
contenteditable="true" bind:innerHTML={infRows.email} />
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
>
{ infRows.allocated_ips }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
>
{ infRows.allowed_ips }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2 font-bold"
>
{ infRows.enabled != true ? 'Disabled' : 'Enabled' }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
>
{ infRows.updated_at }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2 text-right"
>
<TableDropdown bind:filter={ filter } bind:wg_id={ infRows.id } bind:wg_user_state={ infRows.enabled } />
</td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
{:catch error}
<div class="h-screen w-full">
<div
class="relative flex flex-col min-w-0 break-words w-full mb-6 shadow-lg rounded {color === 'light' ? 'bg-white' : 'bg-red-800 text-white'}"
>
<div class="rounded-t bg-red-200 mb-0 px-6 py-6">
<div class="text-center flex justify-between">
<h6 class="uppercase text-blueGray-500 text-xl font-bold">Error</h6>
</div>
</div>
<div class="rounded-t mt-3 mb-3 px-4 py-3 border-0">
<div class="flex flex-wrap items-center">
<div class="relative w-full h-full px-4 max-w-full flex-grow flex-1">
<p class="text-lg text-red-500"> {error.message} </p>
</div>
</div>
</div>
</div>
</div>
{/await}

View File

@ -128,6 +128,13 @@
>
Create Profile
</button>
<button
class="mt-3 bg-teal-500 text-white active:bg-red-500 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
on:click="{toggleFilter}"
>
Search
</button>
<button
class="mt-3 bg-teal-500 text-white active:bg-red-500 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
@ -167,13 +174,14 @@
<button
class="bg-teal-500 text-white active:bg-red-500 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
on:click="{toggleModal}"
on:click="{() => console.log("Submit after validated")}"
>
Apply
</button>
<button
class="bg-red-400 text-white active:bg-red-500 font-bold uppercase text-xs px-4 py-2 rounded shadow hover:shadow-md outline-none focus:outline-none mr-1 ease-linear transition-all duration-150"
type="button"
on:click="{toggleModal}"
>
Cancel
</button>

View File

@ -3,10 +3,56 @@
import { getCookie } from "components/Utils/CookieHandler.js";
export let submitFilter;
let barWidth = 0;
let filter_org = [];
let filter_org_txt = [];
let filter_email = [];
let filter_email_txt = [];
const addColor = () => barWidth += 1;
function select_email(ip) {
if (!filter_email.includes(ip)) {
filter_email.push(ip);
window.document.getElementById(ip).classList.add('bg-amber-500');
} else {
// filter_email.splice(ip);
const index = filter_email.indexOf(ip);
if (index > -1) {
filter_email.splice(index, 1);
}
window.document.getElementById(ip).classList.remove('bg-amber-500');
}
filter_email_txt = filter_email.join(", ");
console.log(filter_email);
console.log(filter_email_txt);
}
function select_org(ip) {
if (!filter_org.includes(ip)) {
filter_org.push(ip);
window.document.getElementById(ip).classList.add('bg-amber-500');
} else {
// filter_org.splice(ip);
const index = filter_org.indexOf(ip);
if (index > -1) {
filter_org.splice(index, 1);
}
window.document.getElementById(ip).classList.remove('bg-amber-500');
}
filter_org_txt = filter_org.join(", ");
console.log(filter_org);
console.log(filter_org_txt);
}
function progress_start() {
for (let i = 0; i < 1000; i++) {
addColor();
@ -22,7 +68,6 @@
credentials: 'include',
mode: 'same-origin',
headers: {
'X-CSRFToken': csrftoken,
'Authorization': "Token "+authToken,
'Accept': 'application/json',
'Content-Type': 'application/json',
@ -41,7 +86,6 @@
credentials: 'include',
mode: 'same-origin',
headers: {
'X-CSRFToken': csrftoken,
'Authorization': "Token "+authToken,
'Accept': 'application/json',
'Content-Type': 'application/json',
@ -66,7 +110,7 @@
submitFilter = null;
submitFilter = data["name"]+"+"+data["org"]+"+"+data["email_domain"]+"+"+data["user_state"];
submitFilter = "name="+data["name"]+"&orgs="+data["org"]+"&emails="+data["email_domain"]+"&state="+data["user_state"];
console.log(submitFilter);
}
@ -123,14 +167,29 @@
</div>
</div>
{:then wgOrgs}
<select name="org" class="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150" >
<option class="text-blueGray-100" value="" disabled selected>Select the Organization</option>
<option class="text-blueGray-100" value="" >No Organization</option>
{#each wgOrgs as value}
<p> {value} </p>
<option value="{value.orgs}">{value.orgs}</option>
<input
name="org"
class="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
bind:value={filter_org_txt}
/>
<div class="relative pt-1">
<div class="flex-wrap mt-2 mb-2 space-x-4 justify-center">
{#each wgOrgs.orgs as ip_val}
<button
id="{ip_val}"
class="border-2 border-amber-500 px-4 py-0 text-xs font-bold text-blueGray-500 rounded mr-2 active:bg-red-500 hover:bg-teal-500 hover:border-teal-500 hover:text-white"
value="{ip_val}"
type="button"
on:click="{() => select_org(ip_val)}"
>
{ip_val}
</button>
{/each}
</select>
</div>
</div>
{/await}
</div>
@ -160,14 +219,26 @@
</div>
</div>
{:then wgEmail}
<select name="email_domain" class="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150" >
<option class="text-blueGray-100" value="" disabled selected>Select the Email Domain</option>
<option class="text-blueGray-100" value="" >No Email</option>
{#each wgEmail as value}
<p> {value} </p>
<option value="{value.email}">{value.email}</option>
<input
name="email_domain"
class="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
bind:value={filter_email_txt}
/>
<div class="relative pt-1">
<div class="flex-wrap mt-2 mb-2 space-x-4 justify-center">
{#each wgEmail.email as email_val}
<button
id="{email_val}"
class="border-2 border-amber-500 px-4 py-0 text-xs font-bold text-blueGray-500 rounded mr-2 active:bg-red-500 hover:bg-teal-500 hover:border-teal-500 hover:text-white"
value="{email_val}"
type="button"
on:click="{() => select_email(email_val)}"
>
{email_val}
</button>
{/each}
</select>
</div>
</div>
{/await}
</div>
<div class="relative w-full mb-3">

View File

@ -39,12 +39,11 @@
console.log(authToken);
console.log("-<>-"+checked_vals);
const wgResponse = await fetch(
'/api2/wgClients?filter='+o_filter, {
'/api2/wgFilterClients?'+o_filter, {
method: 'GET',
credentials: 'include',
mode: 'same-origin',
headers: {
'X-CSRFToken': csrftoken,
'Authorization': "Token "+authToken,
'Accept': 'application/json',
'Content-Type': 'application/json',
@ -102,7 +101,6 @@
let i = 0;
// for (let i = 0; i < wg_resp.length; i++) {
// for ( const x in wg_resp.json) {
// for ( const v in x ) {
// console.log(v);
@ -227,48 +225,48 @@
<tr class="{infRows.enabled != true ? 'bg-red-50 text-red-500 text-sm' : 'text-blueGray-500 bg-white text-sm'} ">
<td
class="bg-blueGray-300 border-t-8 px-4 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-4 rounded"
class="bg-blueGray-300 border-t-8 px-4 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2 rounded"
>
<input checked={selectedID.has(infRows.id)} id="{ infRows.id }" type="checkbox" value="{ infRows.id }" on:change={onCheckId} class="w-4 h-4 text-teal-600 bg-gray-100 rounded border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
<label for="default-checkbox" class="ml-2 text-sm font-bold text-blueGray-500 dark:text-gray-300">{ infRows.data_id }</label>
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-4"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
>
{ infRows.name }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-4"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
>
{ infRows.email }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-4"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
>
{ infRows.allocated_ips }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-4"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
>
{ infRows.allowed_ips }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-4 font-bold"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2 font-bold"
>
{ infRows.enabled != true ? 'Disabled' : 'Enabled' }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-4"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2"
>
{ infRows.updated_at }
</td>
<td
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-4 text-right"
class="border-t-8 px-6 align-middle border-l-0 border-r-0 text-sm whitespace-nowrap p-2 text-right"
>
<TableDropdown bind:filter={ filter } bind:wg_id={ infRows.id } bind:wg_user_state={ infRows.enabled } />
</td>

View File

@ -137,6 +137,19 @@
</a>
</li>
<li class="items-center">
<a
use:link
href="/admin/wgCRUD"
class="text-xs uppercase py-3 font-bold block {location.href.indexOf('/admin/tables') !== -1 ? 'text-red-500 hover:text-red-600':'text-blueGray-700 hover:text-blueGray-500'}"
>
<i
class="fas fa-table mr-2 text-sm {location.href.indexOf('/admin/tables') !== -1 ? 'opacity-75' : 'text-blueGray-300'}"
></i>
WireGuard CRUD
</a>
</li>
<li class="items-center">
<a
use:link

View File

@ -15,6 +15,7 @@
import wgLogs from "views/admin/wgLogs.svelte";
import wgProfiles from "views/admin/wgProfiles.svelte";
import wgBlast from "views/admin/wgBlast.svelte";
import wgCRUD from "views/admin/wgCRUD.svelte";
import Maps from "views/admin/Maps.svelte";
export let location;
@ -34,6 +35,7 @@
<Route path="tables" component="{Tables}" />
<Route path="wgLogs" component="{wgLogs}" />
<Route path="wgProfiles" component="{wgProfiles}" />
<Route path="wgCRUD" component="{wgCRUD}" />
<Route path="wgBlast" component="{wgBlast}" />
<Route path="maps" component="{Maps}" />
</Router>

View File

@ -0,0 +1,22 @@
<script>
// core components
import axios from 'axios';
import {onMount} from 'svelte';
import CardWGControl from "components/Cards/CardWGControl.svelte";
import CardWGCRUD from "components/Cards/CardWGCRUD.svelte";
import CardUploadCSV from "components/Cards/CardUploadCSV.svelte";
export let location;
let wgProfileFetch = [];
// onMount(async () => {
// await axios.get('http://192.168.10.2:8000/api2/wgClients')
// .then( response => {
// wgProfileFetch = response.data
// });
// console.log(wgProfileFetch);
// });
</script>
<div class="flex flex-wrap mt-4 mb-8">
<CardUploadCSV />
</div>