mirror of
https://github.com/Forceu/Gokapi.git
synced 2025-12-30 21:39:36 -06:00
Add new API keys to UI without reloading, add small animation, remove html_users.tmpl originaly from unpublished branch
This commit is contained in:
@@ -220,6 +220,16 @@ td.newItem {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes subtleHighlightNewApiKey {
|
||||
0% {
|
||||
background-color: green; /* Pale green for new items */
|
||||
}
|
||||
100% {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply the animation to the updated table cells */
|
||||
.updatedDownloadCount {
|
||||
animation: subtleHighlight 0.5s ease-out;
|
||||
@@ -230,4 +240,9 @@ td.newItem {
|
||||
animation: subtleHighlightNewItem 0.5s ease-out;
|
||||
}
|
||||
|
||||
.newApiKey {
|
||||
animation: subtleHighlightNewApiKey 0.7s ease-out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
.btn-secondary,.btn-secondary:hover,.btn-secondary:focus{color:#333;text-shadow:none}body{background:url(../../assets/background.jpg)no-repeat 50% fixed;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover;display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-pack:center;-webkit-box-pack:center;justify-content:center}td{vertical-align:middle;position:relative}a{color:inherit}a:hover{color:inherit;filter:brightness(80%)}.dropzone{background:#2f343a!important;color:#fff;border-radius:5px}.dropzone:hover{background:#33393f!important;color:#fff;border-radius:5px}.card{margin:0 auto;float:none;margin-bottom:10px;border:2px solid #33393f}.card-body{background-color:#212529;color:#ddd}.card-title{font-weight:900}.admin-input{text-align:center}.form-control:disabled{background:#bababa}.break{flex-basis:100%;height:0}.bd-placeholder-img{font-size:1.125rem;text-anchor:middle;-webkit-user-select:none;-moz-user-select:none;user-select:none}@media(min-width:768px){.bd-placeholder-img-lg{font-size:3.5rem}.break{flex-basis:0}}.masthead{margin-bottom:2rem}.masthead-brand{margin-bottom:0}.nav-masthead .nav-link{padding:.25rem 0;font-weight:700;color:rgba(255,255,255,.5);background-color:initial;border-bottom:.25rem solid transparent}.nav-masthead .nav-link:hover,.nav-masthead .nav-link:focus{border-bottom-color:rgba(255,255,255,.25)}.nav-masthead .nav-link+.nav-link{margin-left:1rem}.nav-masthead .active{color:#fff;border-bottom-color:#fff}#qroverlay{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.3)}#qrcode{position:absolute;top:50%;left:50%;margin-top:-105px;margin-left:-105px;width:210px;height:210px;border:5px solid #fff}.toastnotification{pointer-events:none;position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background-color:#333;color:#fff;padding:15px;border-radius:5px;box-shadow:0 2px 5px rgba(0,0,0,.3);opacity:0;transition:opacity .3s ease-in-out;z-index:9999}.toastnotification.show{opacity:1;pointer-events:auto}.apiperm-granted{cursor:pointer;color:#19b90e}.apiperm-notgranted{cursor:pointer;color:#7e7e7e}.apiperm-processing{color:#e5eb00}.gokapi-dialog{background-color:#212529;color:#ddd}td.newItem{background-color:green}@keyframes subtleHighlight{0%{background-color:#444950}100%{background-color:initial}}@keyframes subtleHighlightNewItem{0%{background-color:#a8e6a3}100%{background-color:green}}.updatedDownloadCount{animation:subtleHighlight .5s ease-out}.updatedDownloadCount.newItem{animation:subtleHighlightNewItem .5s ease-out}.filename{font-weight:700;font-size:14px;margin-bottom:5px}.upload-progress-container{display:flex;align-items:center}.upload-progress-bar{position:relative;height:10px;background-color:#eee;flex:1;margin-right:10px;border-radius:4px}.upload-progress-bar-progress{position:absolute;top:0;left:0;height:100%;background-color:#0a0;border-radius:4px;transition:width .2s ease-in-out}.upload-progress-info{font-size:12px}.us-container{margin-top:10px;margin-bottom:20px}.uploaderror{font-weight:700;color:red;margin-bottom:5px}.uploads-container{background-color:#2f343a;border:2px solid rgba(0,0,0,.3);border-radius:5px;margin-left:0;margin-right:0;max-width:none;visibility:hidden}
|
||||
.btn-secondary,.btn-secondary:hover,.btn-secondary:focus{color:#333;text-shadow:none}body{background:url(../../assets/background.jpg)no-repeat 50% fixed;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover;display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-pack:center;-webkit-box-pack:center;justify-content:center}td{vertical-align:middle;position:relative}a{color:inherit}a:hover{color:inherit;filter:brightness(80%)}.dropzone{background:#2f343a!important;color:#fff;border-radius:5px}.dropzone:hover{background:#33393f!important;color:#fff;border-radius:5px}.card{margin:0 auto;float:none;margin-bottom:10px;border:2px solid #33393f}.card-body{background-color:#212529;color:#ddd}.card-title{font-weight:900}.admin-input{text-align:center}.form-control:disabled{background:#bababa}.break{flex-basis:100%;height:0}.bd-placeholder-img{font-size:1.125rem;text-anchor:middle;-webkit-user-select:none;-moz-user-select:none;user-select:none}@media(min-width:768px){.bd-placeholder-img-lg{font-size:3.5rem}.break{flex-basis:0}}.masthead{margin-bottom:2rem}.masthead-brand{margin-bottom:0}.nav-masthead .nav-link{padding:.25rem 0;font-weight:700;color:rgba(255,255,255,.5);background-color:initial;border-bottom:.25rem solid transparent}.nav-masthead .nav-link:hover,.nav-masthead .nav-link:focus{border-bottom-color:rgba(255,255,255,.25)}.nav-masthead .nav-link+.nav-link{margin-left:1rem}.nav-masthead .active{color:#fff;border-bottom-color:#fff}#qroverlay{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.3)}#qrcode{position:absolute;top:50%;left:50%;margin-top:-105px;margin-left:-105px;width:210px;height:210px;border:5px solid #fff}.toastnotification{pointer-events:none;position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background-color:#333;color:#fff;padding:15px;border-radius:5px;box-shadow:0 2px 5px rgba(0,0,0,.3);opacity:0;transition:opacity .3s ease-in-out;z-index:9999}.toastnotification.show{opacity:1;pointer-events:auto}.apiperm-granted{cursor:pointer;color:#19b90e}.apiperm-notgranted{cursor:pointer;color:#7e7e7e}.apiperm-processing{color:#e5eb00}.gokapi-dialog{background-color:#212529;color:#ddd}td.newItem{background-color:green}@keyframes subtleHighlight{0%{background-color:#444950}100%{background-color:initial}}@keyframes subtleHighlightNewItem{0%{background-color:#a8e6a3}100%{background-color:green}}@keyframes subtleHighlightNewApiKey{0%{background-color:green}100%{background-color:initial}}.updatedDownloadCount{animation:subtleHighlight .5s ease-out}.updatedDownloadCount.newItem{animation:subtleHighlightNewItem .5s ease-out}.newApiKey{animation:subtleHighlightNewApiKey .7s ease-out}.filename{font-weight:700;font-size:14px;margin-bottom:5px}.upload-progress-container{display:flex;align-items:center}.upload-progress-bar{position:relative;height:10px;background-color:#eee;flex:1;margin-right:10px;border-radius:4px}.upload-progress-bar-progress{position:absolute;top:0;left:0;height:100%;background-color:#0a0;border-radius:4px;transition:width .2s ease-in-out}.upload-progress-info{font-size:12px}.us-container{margin-top:10px;margin-bottom:20px}.uploaderror{font-weight:700;color:red;margin-bottom:5px}.uploads-container{background-color:#2f343a;border:2px solid rgba(0,0,0,.3);border-radius:5px;margin-left:0;margin-right:0;max-width:none;visibility:hidden}
|
||||
@@ -278,52 +278,6 @@ function requestFileInfo(fileId, uid) {
|
||||
}
|
||||
|
||||
|
||||
function addFriendlyNameChange() {
|
||||
document.querySelectorAll(".apiname").forEach(function(node) {
|
||||
node.onclick = function() {
|
||||
if (this.classList.contains("isBeingEdited"))
|
||||
return;
|
||||
this.classList.add("isBeingEdited");
|
||||
var val = this.innerHTML;
|
||||
var input = document.createElement("input");
|
||||
input.size = 5;
|
||||
input.value = val;
|
||||
let row = this;
|
||||
let allowEdit = true;
|
||||
|
||||
let submitEntry = function() {
|
||||
if (!allowEdit)
|
||||
return;
|
||||
allowEdit = false;
|
||||
var newName = input.value;
|
||||
input.parentNode.innerHTML = newName;
|
||||
|
||||
row.classList.remove("isBeingEdited");
|
||||
|
||||
apiAuthFriendlyName(row.id, newName)
|
||||
.catch(error => {
|
||||
alert("Unable to save name: " + error);
|
||||
console.error('Error:', error);
|
||||
});
|
||||
};
|
||||
|
||||
input.onblur = submitEntry;
|
||||
input.addEventListener("keyup", function(event) {
|
||||
// Enter
|
||||
if (event.keyCode === 13) {
|
||||
event.preventDefault();
|
||||
submitEntry();
|
||||
}
|
||||
});
|
||||
this.innerHTML = "";
|
||||
this.appendChild(input);
|
||||
input.focus();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function parseProgressStatus(eventData) {
|
||||
let container = document.getElementById(`us-container-${eventData.chunk_id}`);
|
||||
if (container == null) {
|
||||
@@ -601,12 +555,11 @@ function deleteApiKey(apiKey) {
|
||||
|
||||
|
||||
function newApiKey() {
|
||||
|
||||
document.getElementById("button-newapi").disabled = true;
|
||||
|
||||
apiAuthCreate()
|
||||
.then(data => {
|
||||
location.reload();
|
||||
addRowApi(data.Id);
|
||||
document.getElementById("button-newapi").disabled = false;
|
||||
})
|
||||
.catch(error => {
|
||||
alert("Unable to create API key: " + error);
|
||||
@@ -615,6 +568,99 @@ function newApiKey() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function addFriendlyNameChange(apiKey) {
|
||||
let cell = document.getElementById("friendlyname-" + apiKey);
|
||||
if (cell.classList.contains("isBeingEdited"))
|
||||
return;
|
||||
cell.classList.add("isBeingEdited");
|
||||
let currentName = cell.innerHTML;
|
||||
let input = document.createElement("input");
|
||||
input.size = 5;
|
||||
input.value = currentName;
|
||||
let allowEdit = true;
|
||||
|
||||
let submitEntry = function() {
|
||||
if (!allowEdit)
|
||||
return;
|
||||
allowEdit = false;
|
||||
let newName = input.value;
|
||||
cell.innerHTML = newName;
|
||||
|
||||
cell.classList.remove("isBeingEdited");
|
||||
|
||||
apiAuthFriendlyName(apiKey, newName)
|
||||
.catch(error => {
|
||||
alert("Unable to save name: " + error);
|
||||
console.error('Error:', error);
|
||||
});
|
||||
};
|
||||
|
||||
input.onblur = submitEntry;
|
||||
input.addEventListener("keyup", function(event) {
|
||||
// Enter
|
||||
if (event.keyCode === 13) {
|
||||
event.preventDefault();
|
||||
submitEntry();
|
||||
}
|
||||
});
|
||||
cell.innerHTML = "";
|
||||
cell.appendChild(input);
|
||||
input.focus();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function addRowApi(apiKey) {
|
||||
|
||||
let table = document.getElementById("apitable");
|
||||
let row = table.insertRow(0);
|
||||
row.id = "row-" + apiKey;
|
||||
let cellFriendlyName = row.insertCell(0);
|
||||
let cellId = row.insertCell(1);
|
||||
let cellLastUsed = row.insertCell(2);
|
||||
let cellPermissions = row.insertCell(3);
|
||||
let cellButtons = row.insertCell(4);
|
||||
let cellEmpty = row.insertCell(5);
|
||||
|
||||
cellFriendlyName.classList.add("newApiKey");
|
||||
cellId.classList.add("newApiKey");
|
||||
cellLastUsed.classList.add("newApiKey");
|
||||
cellPermissions.classList.add("newApiKey");
|
||||
cellButtons.classList.add("newApiKey");
|
||||
cellEmpty.classList.add("newApiKey");
|
||||
|
||||
|
||||
cellFriendlyName.innerText = "Unnamed key";
|
||||
cellFriendlyName.id = "friendlyname-" + apiKey;
|
||||
cellFriendlyName.onclick = function() {
|
||||
addFriendlyNameChange(apiKey);
|
||||
};
|
||||
cellId.innerText = apiKey;
|
||||
cellLastUsed.innerText = "Never";
|
||||
cellButtons.innerHTML = '<button type="button" data-clipboard-text="' + apiKey + '" onclick="showToast()" title="Copy API Key" class="copyurl btn btn-outline-light btn-sm"><i class="bi bi-copy"></i></button> <button id="delete-' + apiKey + '" type="button" class="btn btn-outline-danger btn-sm" onclick="deleteApiKey(\'' + apiKey + '\')" title="Delete"><i class="bi bi-trash3"></i></button>';
|
||||
cellPermissions.innerHTML = `
|
||||
<i id="perm_view_` + apiKey + `" class="bi bi-eye apiperm-granted" title="List Uploads" onclick='changeApiPermission("` + apiKey + `","PERM_VIEW", "perm_view_` + apiKey + `");'></i>
|
||||
<i id="perm_upload_` + apiKey + `" class="bi bi-file-earmark-arrow-up apiperm-granted" title="Upload" onclick='changeApiPermission("` + apiKey + `","PERM_UPLOAD", "perm_upload_` + apiKey + `");'></i>
|
||||
<i id="perm_edit_` + apiKey + `" class="bi bi-pencil apiperm-granted" title="Edit Uploads" onclick='changeApiPermission("` + apiKey + `","PERM_EDIT", "perm_edit_` + apiKey + `");'></i>
|
||||
<i id="perm_delete_` + apiKey + `" class="bi bi-trash3 apiperm-granted" title="Delete Uploads" onclick='changeApiPermission("` + apiKey + `","PERM_DELETE", "perm_delete_` + apiKey + `");'></i>
|
||||
<i id="perm_replace_` + apiKey + `" class="bi bi-recycle apiperm-notgranted" title="Replace Uploads" onclick='changeApiPermission("` + apiKey + `","PERM_REPLACE", "perm_replace_` + apiKey + `");'></i>
|
||||
<i id="perm_api_` + apiKey + `" class="bi bi-sliders2 apiperm-notgranted" title="Manage API Keys" onclick='changeApiPermission("` + apiKey + `","PERM_API_MOD", "perm_api_` + apiKey + `");'></i>`;
|
||||
|
||||
setTimeout(() => {
|
||||
cellFriendlyName.classList.remove("newApiKey");
|
||||
cellId.classList.remove("newApiKey");
|
||||
cellLastUsed.classList.remove("newApiKey");
|
||||
cellPermissions.classList.remove("newApiKey");
|
||||
cellButtons.classList.remove("newApiKey");
|
||||
cellEmpty.classList.remove("newApiKey");
|
||||
}, 700);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function deleteFile(id) {
|
||||
|
||||
document.getElementById("button-delete-" + id).disabled = true;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -21,11 +21,11 @@
|
||||
<th scope="col"><button id="button-newapi" type="button" class="btn btn-outline-light btn-sm" onclick="newApiKey()"><i class="bi bi-plus-circle-fill"></i> New Key</button></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody id="apitable">
|
||||
{{ range .ApiKeys }}
|
||||
{{ if not .IsSystemKey }}
|
||||
<tr id="row-{{ .Id }}">
|
||||
<td scope="col" id="{{ .Id }}" class="apiname">{{ .FriendlyName }}</td>
|
||||
<td scope="col" id="friendlyname-{{ .Id }}" onClick="addFriendlyNameChange('{{ .Id }}')">{{ .FriendlyName }}</td>
|
||||
<td scope="col">{{ .Id }}</td>
|
||||
<td scope="col">{{ .GetReadableDate }}</td>
|
||||
<td scope="col">
|
||||
@@ -52,7 +52,6 @@
|
||||
</div>
|
||||
<script src="./js/min/admin.min.{{ template "js_admin_version"}}.js"></script>
|
||||
<script>
|
||||
addFriendlyNameChange();
|
||||
var systemKey = "{{.SystemKey}}";
|
||||
</script>
|
||||
{{ template "footer" true }}
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
{{ define "users" }}
|
||||
{{ template "header" . }}
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div id="container" class="card" style="width: 80%">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">API Keys</h3>
|
||||
<br>
|
||||
Please visit the <a target="_blank" href="./apidocumentation">API documentation</a> for more information about the API.<br>Click on the API key name to give it a new name. Permissions can be changed by clicking on them.
|
||||
<br>
|
||||
<br>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-dark">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Email</th>
|
||||
<th scope="col">Group</th>
|
||||
<th scope="col">Permissions</th>
|
||||
<th scope="col">Actions</th>
|
||||
<th scope="col"><button id="button-newapi" type="button" class="btn btn-outline-light btn-sm" onclick="newApiKey()"><i class="bi bi-plus-circle-fill"></i> New Key</button></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Users }}
|
||||
<tr id="row-{{ .Id }}">
|
||||
<td scope="col" id="{{ .Id }}">{{ .Name }}</td>
|
||||
<td scope="col">{{ .Email }}</td>
|
||||
<td scope="col">{{ .UserLevel }}</td>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td scope="col"><button type="button" data-clipboard-text="{{ .Id }}" onclick="showToast()" title="Copy API Key" class="copyurl btn btn-outline-light btn-sm"><i class="bi bi-copy"></i></button> <button id="delete-{{ .Id }}" type="button" class="btn btn-outline-danger btn-sm" onclick="deleteApiKey('{{ .Id }}')" title="Delete"><i class="bi bi-trash3"></i></button></td>
|
||||
<td scope="col"></td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="toastnotification" class="toastnotification">API key copied to clipboard</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="./js/min/admin.min.{{ template "js_admin_version"}}.js"></script>
|
||||
<script>
|
||||
document.querySelectorAll(".apiname").forEach(function(node) {
|
||||
node.onclick = function() {
|
||||
if (this.classList.contains("isBeingEdited"))
|
||||
return;
|
||||
this.classList.add("isBeingEdited");
|
||||
var val = this.innerHTML;
|
||||
var input = document.createElement("input");
|
||||
input.size = 5;
|
||||
input.value = val;
|
||||
let row = this;
|
||||
let allowEdit = true;
|
||||
let submitEntry = function() {
|
||||
if (!allowEdit)
|
||||
return;
|
||||
allowEdit = false;
|
||||
var val = input.value;
|
||||
input.parentNode.innerHTML = val;
|
||||
let xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.open("GET", "./api/auth/friendlyname");
|
||||
xmlhttp.setRequestHeader("apiKeyToModify", row.id);
|
||||
xmlhttp.setRequestHeader("friendlyName", val);
|
||||
xmlhttp.setRequestHeader("apikey", systemKey);
|
||||
xmlhttp.send();
|
||||
row.classList.remove("isBeingEdited");
|
||||
|
||||
//xmlhttp.onreadystatechange = (e) => {
|
||||
//}
|
||||
}
|
||||
input.onblur = submitEntry;
|
||||
input.addEventListener("keyup", function(event) {
|
||||
//Enter
|
||||
if (event.keyCode === 13) {
|
||||
event.preventDefault();
|
||||
submitEntry();
|
||||
}
|
||||
});
|
||||
this.innerHTML = "";
|
||||
this.appendChild(input);
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
var systemKey = "{{.SystemKey}}";
|
||||
</script>
|
||||
{{ template "footer" true }}
|
||||
{{ end }}
|
||||
Reference in New Issue
Block a user