mirror of
https://github.com/gusaul/grpcox.git
synced 2025-01-24 13:14:39 +00:00
feat(request-list): Support CRUD for request list
by using this request list, user doesn't need to memorise the endpoint & the request anymore, they can store the request and come again if they need it. at the moment the data is store in IndexDB (browser), hence it doesn't need backend effort.
This commit is contained in:
parent
c83858ebfc
commit
464de07064
|
@ -200,4 +200,53 @@ circle {
|
|||
transform: scaleY(1.0);
|
||||
-webkit-transform: scaleY(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
.save-button-dropdown {
|
||||
padding-left: 10px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.save-button-dropdown .dropdown-menu.show {
|
||||
transform: translate3d(639px, 46px, 0px);
|
||||
}
|
||||
|
||||
.one-long-line {
|
||||
margin-bottom: 0;
|
||||
margin-left: 5px;
|
||||
max-width: 100%;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
}
|
||||
.one-long-line:hover {
|
||||
cursor: pointer;
|
||||
overflow:visible;
|
||||
}
|
||||
|
||||
.column-row-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.column-row-left .md-form{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.search {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.request-list {
|
||||
display: flex;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.request-list .fa {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.request-list.selected {
|
||||
background: #dadfe3;;
|
||||
}
|
|
@ -14,14 +14,37 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container pt-50">
|
||||
<div class="row animated fadeIn">
|
||||
<div class="col">
|
||||
<div class="container-fluid pt-50">
|
||||
<div class="row animated fadeIn justify-content-md-center">
|
||||
<div class="col-3">
|
||||
<div class="row">
|
||||
<div class="col" style="padding-left: 70px;">
|
||||
<div class="row column-row-left">
|
||||
<div class="md-form input-group">
|
||||
<input type="text" class="form-control search" id="search-request" onkeyup="search(this)">
|
||||
<label for="search-request" class="">Search Request</label>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush list" id="request-list"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-7">
|
||||
<div class="md-form input-group">
|
||||
<input type="text" class="form-control" id="server-target">
|
||||
<label for="server-target">gRPC Server Target</label>
|
||||
<div class="input-group-append">
|
||||
<button id="get-services" class="btn btn-mdb-color waves-effect m-0" type="button"><i class="fa fa-plug"></i></button>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-mdb-color waves-effect m-0 dropdown-toggle save-button-dropdown" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="true">
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="btnGroupDrop1">
|
||||
<a class="dropdown-item" id="show-modal-save-request">Save</a>
|
||||
<a class="dropdown-item" id="show-modal-save-as-request">Save As</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="custom-control custom-checkbox">
|
||||
|
@ -174,15 +197,42 @@
|
|||
<div class="rect5"></div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Save request-->
|
||||
<div class="modal fade" id="saveRequest" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Input the name for the request</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="form-group row">
|
||||
<label for="input-request-name" class="col-sm-2 col-form-label">Name</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" id="input-request-name">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
<button id="save-request" type="button" class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
|
||||
<script type="text/javascript" src="js/popper.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="js/mdb.min.js"></script>
|
||||
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.1/ace.js"></script>
|
||||
<script type="text/javascript" src="js/db.js"></script>
|
||||
<script type="text/javascript" src="js/style.js"></script>
|
||||
<script type="text/javascript" src="js/proto.js"></script>
|
||||
<script type="text/javascript" src="js/ctx.metadata.js"></script>
|
||||
<script type="text/javascript" src="js/request.list.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
143
index/js/db.js
Normal file
143
index/js/db.js
Normal file
|
@ -0,0 +1,143 @@
|
|||
const objectStoreRequests = "requests";
|
||||
let dbConn = null;
|
||||
|
||||
function gdb(){
|
||||
if (!window.indexedDB) {
|
||||
alert(`Your browser doesn't support IndexedDB`)
|
||||
return;
|
||||
}
|
||||
return new Promise(function (success, error){
|
||||
if (dbConn !== null){
|
||||
success(dbConn)
|
||||
return
|
||||
}
|
||||
|
||||
const request = indexedDB.open('grpcox',1);
|
||||
request.onerror = (event) => {
|
||||
error(request.error)
|
||||
};
|
||||
|
||||
request.onsuccess = (event) => {
|
||||
// add implementation here
|
||||
console.log("success open DB")
|
||||
dbConn = event.target.result;
|
||||
success(dbConn);
|
||||
};
|
||||
// create the Contacts object store and indexes
|
||||
request.onupgradeneeded = (event) => {
|
||||
let dbConn = event.target.result;
|
||||
let store = dbConn.createObjectStore(objectStoreRequests,{
|
||||
keyPath:"name"
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function getRequest(name) {
|
||||
return new Promise(async function (success, error){
|
||||
let db = await gdb()
|
||||
const txn = db.transaction(objectStoreRequests, 'readwrite');
|
||||
const store = txn.objectStore(objectStoreRequests);
|
||||
let idbRequest = store.get(name);
|
||||
idbRequest.onerror = function (param) {
|
||||
error(idbRequest.error.name)
|
||||
}
|
||||
idbRequest.onsuccess = function (event) {
|
||||
success(event.target.result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getAllRequestKey() {
|
||||
return new Promise(async function (success, error){
|
||||
let db = await gdb();
|
||||
const txn = db.transaction(objectStoreRequests, 'readwrite');
|
||||
// get the Contacts object store
|
||||
const store = txn.objectStore(objectStoreRequests);
|
||||
let idbRequest = store.getAllKeys();
|
||||
idbRequest.onerror = function (param) {
|
||||
error(param.target)
|
||||
}
|
||||
idbRequest.onsuccess = function (event) {
|
||||
success(event.target.result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function insertRequest(request) {
|
||||
return new Promise(async function(success, error){
|
||||
let db = await gdb()
|
||||
|
||||
// create a new transaction
|
||||
const txn = db.transaction(objectStoreRequests, 'readwrite');
|
||||
|
||||
const store = txn.objectStore(objectStoreRequests);
|
||||
|
||||
let query = store.add(request);
|
||||
|
||||
// handle success case
|
||||
query.onsuccess = function (event) {
|
||||
success('success')
|
||||
};
|
||||
|
||||
// handle the error case
|
||||
query.onerror = function (event) {
|
||||
if (query.error.name === "ConstraintError") {
|
||||
error('Duplicate request name')
|
||||
return
|
||||
}
|
||||
error(query.error.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function updateRequest(request) {
|
||||
return new Promise(async function(success, error){
|
||||
let db = await gdb()
|
||||
|
||||
// create a new transaction
|
||||
const txn = db.transaction(objectStoreRequests, 'readwrite');
|
||||
|
||||
const store = txn.objectStore(objectStoreRequests);
|
||||
|
||||
let query = store.put(request);
|
||||
|
||||
// handle success case
|
||||
query.onsuccess = function (event) {
|
||||
success('success')
|
||||
};
|
||||
|
||||
// handle the error case
|
||||
query.onerror = function (event) {
|
||||
if (query.error.name === "ConstraintError") {
|
||||
error('Duplicate request name')
|
||||
return
|
||||
}
|
||||
error(query.error.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function deleteRequest(name){
|
||||
return new Promise(async function (success, error){
|
||||
let db = await gdb()
|
||||
|
||||
// create a new transaction
|
||||
const txn = db.transaction(objectStoreRequests, 'readwrite');
|
||||
|
||||
const store = txn.objectStore(objectStoreRequests);
|
||||
|
||||
let query = store.delete(name);
|
||||
|
||||
// handle success case
|
||||
query.onsuccess = function (event) {
|
||||
success('success')
|
||||
};
|
||||
|
||||
// handle the error case
|
||||
query.onerror = function (event) {
|
||||
error(query.error.name)
|
||||
}
|
||||
})
|
||||
}
|
162
index/js/request.list.js
Normal file
162
index/js/request.list.js
Normal file
|
@ -0,0 +1,162 @@
|
|||
$('#save-request').click(function(){
|
||||
let requestName = document.getElementById("input-request-name").value;
|
||||
if (requestName === "") {
|
||||
alert("request name is require")
|
||||
} else {
|
||||
let data = getReqResData();
|
||||
data.name = requestName
|
||||
insertRequest(data).then(success => {
|
||||
window.location.reload()
|
||||
}).catch(error => {
|
||||
alert(error);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
$('#show-modal-save-request').click(function () {
|
||||
const reqData = getReqResData();
|
||||
const activeRequestName = getActiveRequestListName();
|
||||
if ( activeRequestName === ""){
|
||||
console.log(activeRequestName);
|
||||
// generate name
|
||||
// name format will be method
|
||||
$('#input-request-name').val(`${reqData.selected_function}`)
|
||||
$('#saveRequest').modal('toggle');
|
||||
} else {
|
||||
reqData.name = activeRequestName
|
||||
updateRequest(reqData).catch(error => {
|
||||
alert(error);
|
||||
})
|
||||
}
|
||||
});
|
||||
$('#show-modal-save-as-request').click(function () {
|
||||
const reqData = getReqResData();
|
||||
// generate name
|
||||
// name format will be method
|
||||
$('#input-request-name').val(`copy ${reqData.selected_function}`)
|
||||
$('#saveRequest').modal('toggle');
|
||||
});
|
||||
|
||||
function getReqResData() {
|
||||
const serverTarget = document.getElementById("server-target").value;
|
||||
const selectService = document.getElementById("select-service").value;
|
||||
const selectFunction = document.getElementById("select-function").value;
|
||||
const responseHTML = document.getElementById("json-response").innerHTML;
|
||||
const schemaProtoHTML = document.getElementById("schema-proto").innerHTML;
|
||||
editor = ace.edit("editor");
|
||||
return {
|
||||
server_target:serverTarget,
|
||||
selected_service:selectService,
|
||||
selected_function:selectFunction,
|
||||
raw_request:editor.getValue(),
|
||||
response_html:responseHTML,
|
||||
schema_proto_html:schemaProtoHTML,
|
||||
}
|
||||
}
|
||||
|
||||
function setReqResData(data) {
|
||||
$('#server-target').val(data.server_target);
|
||||
target = data.server_target;
|
||||
$("#select-service").html(new Option(data.selected_service, data.selected_service,true,true));
|
||||
$('#choose-service').show();
|
||||
$("#select-function").html(new Option(data.selected_function.substr(data.selected_service.length), data.selected_function,true,true));
|
||||
$('#choose-function').show();
|
||||
generate_editor(data.raw_request);
|
||||
$('#body-request').show();
|
||||
$('#schema-proto').html(data.schema_proto_html);
|
||||
$('#json-response').html(data.response_html);
|
||||
$('#response').show();
|
||||
}
|
||||
|
||||
function resetReqResData() {
|
||||
target="";
|
||||
$('#choose-service').hide();
|
||||
$('#choose-function').hide();
|
||||
$('#body-request').hide();
|
||||
$('#response').hide();
|
||||
}
|
||||
|
||||
async function renderRequestList() {
|
||||
const ul = document.getElementById("request-list")
|
||||
ul.innerHTML = ""
|
||||
|
||||
const nameList = await getAllRequestKey();
|
||||
|
||||
nameList.forEach(function (item){
|
||||
let node = document.createElement("li")
|
||||
node.classList.add("list-group-item","request-list")
|
||||
node.setAttribute("request-name",item)
|
||||
node.addEventListener("click", function(el){
|
||||
updateRequestView(el.target.children[1])
|
||||
});
|
||||
node.innerHTML = `
|
||||
<a title="Delete this request" class="delete-request" onclick="removeRequest(this)"><i class="fa fa-times"></i></a>
|
||||
<p class="one-long-line request" onclick="updateRequestView(this)">${item}</p>
|
||||
`
|
||||
ul.appendChild(node);
|
||||
})
|
||||
}
|
||||
|
||||
function removeRequestSelectedClass(){
|
||||
const elems = document.querySelectorAll(".request-list");
|
||||
[].forEach.call(elems, function(el) {
|
||||
el.classList.remove("selected");
|
||||
});
|
||||
}
|
||||
|
||||
function getActiveRequestListName(){
|
||||
const elems = document.querySelectorAll(".request-list");
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
const e = elems[i]
|
||||
if (e.classList.contains("selected")) {
|
||||
return e.innerText;
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
function setServerTargetActive() {
|
||||
const elems = document.querySelectorAll('[for="server-target"]');
|
||||
[].forEach.call(elems, function(el) {
|
||||
el.classList.add("active");
|
||||
});
|
||||
}
|
||||
|
||||
function updateRequestView(elm) {
|
||||
if (elm) {
|
||||
getRequest(elm.innerText).then(data => {
|
||||
resetReqResData()
|
||||
setReqResData(data)
|
||||
removeRequestSelectedClass()
|
||||
elm.parentElement.classList.add('selected')
|
||||
setServerTargetActive();
|
||||
}).catch(error => {
|
||||
alert(error)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function removeRequest(elm) {
|
||||
const requestName = elm.parentElement.lastElementChild.innerText;
|
||||
deleteRequest(requestName).then(()=>{
|
||||
window.location.reload()
|
||||
}).catch((error)=>{
|
||||
alert(error)
|
||||
})
|
||||
}
|
||||
|
||||
function search(elm) {
|
||||
const li = document.querySelectorAll(".request-list")
|
||||
li.forEach(function (el) {
|
||||
if (el.getAttribute("request-name").toLowerCase().includes(elm.value.toLowerCase())){
|
||||
el.style.display = ""
|
||||
}else{
|
||||
el.style.display = "none"
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
renderRequestList()
|
||||
});
|
|
@ -1,6 +1,11 @@
|
|||
var target, use_tls, editor;
|
||||
|
||||
$('#get-services').click(function(){
|
||||
|
||||
// reset all selected list
|
||||
resetReqResData()
|
||||
removeRequestSelectedClass()
|
||||
|
||||
var t = get_valid_target();
|
||||
|
||||
use_tls = "false";
|
||||
|
|
Loading…
Reference in New Issue
Block a user