...
This commit is contained in:
144
pkg/servers/ui/static/css/rpcui.css
Normal file
144
pkg/servers/ui/static/css/rpcui.css
Normal file
@@ -0,0 +1,144 @@
|
||||
/* OpenRPC UI Styles */
|
||||
|
||||
.method-tree {
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.method-item {
|
||||
cursor: pointer;
|
||||
padding: 8px 15px;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.method-item:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.method-item.active {
|
||||
background-color: #e9ecef;
|
||||
font-weight: bold;
|
||||
border-left: 3px solid #0d6efd;
|
||||
}
|
||||
|
||||
.param-card {
|
||||
margin-bottom: 15px;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.result-container {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.code-editor {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
min-height: 200px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
white-space: pre;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
padding: 10px;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 4px;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.schema-table {
|
||||
font-size: 0.9rem;
|
||||
width: 100%;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.schema-table th {
|
||||
font-weight: 600;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.schema-required {
|
||||
color: #dc3545;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.schema-optional {
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.method-description {
|
||||
font-size: 0.9rem;
|
||||
color: #6c757d;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.example-container {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.example-header {
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.example-content {
|
||||
background-color: #f8f9fa;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
/* Socket path input styling */
|
||||
.socket-path-container {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.socket-path-label {
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
/* Execute button styling */
|
||||
.execute-button {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* Response styling */
|
||||
.response-success {
|
||||
border-left: 4px solid #28a745;
|
||||
}
|
||||
|
||||
.response-error {
|
||||
border-left: 4px solid #dc3545;
|
||||
}
|
||||
|
||||
/* Loading indicator */
|
||||
.loading-spinner {
|
||||
display: inline-block;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border: 0.2em solid currentColor;
|
||||
border-right-color: transparent;
|
||||
border-radius: 50%;
|
||||
animation: spinner-border .75s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spinner-border {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
141
pkg/servers/ui/static/js/rpcui.js
Normal file
141
pkg/servers/ui/static/js/rpcui.js
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* OpenRPC UI JavaScript
|
||||
* Handles the interactive functionality of the OpenRPC UI
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize form elements
|
||||
const specForm = document.getElementById('specForm');
|
||||
const rpcForm = document.getElementById('rpcForm');
|
||||
const paramsEditor = document.getElementById('paramsEditor');
|
||||
const resultContainer = document.getElementById('resultContainer');
|
||||
const resultOutput = document.getElementById('resultOutput');
|
||||
const errorContainer = document.getElementById('errorContainer');
|
||||
const errorOutput = document.getElementById('errorOutput');
|
||||
|
||||
// Format JSON in the parameters editor
|
||||
if (paramsEditor && paramsEditor.value) {
|
||||
try {
|
||||
const params = JSON.parse(paramsEditor.value);
|
||||
paramsEditor.value = JSON.stringify(params, null, 2);
|
||||
} catch (e) {
|
||||
// If not valid JSON, leave as is
|
||||
console.warn('Could not format parameters as JSON:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle RPC execution
|
||||
if (rpcForm) {
|
||||
rpcForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Hide previous results
|
||||
if (resultContainer) resultContainer.classList.add('d-none');
|
||||
if (errorContainer) errorContainer.classList.add('d-none');
|
||||
|
||||
// Get form data
|
||||
const spec = document.getElementById('spec').value;
|
||||
const method = document.querySelector('input[name="selectedMethod"]').value;
|
||||
const socketPath = document.getElementById('socketPath').value;
|
||||
const paramsText = paramsEditor.value;
|
||||
|
||||
// Show loading indicator
|
||||
const submitButton = rpcForm.querySelector('button[type="submit"]');
|
||||
const originalButtonText = submitButton.innerHTML;
|
||||
submitButton.disabled = true;
|
||||
submitButton.innerHTML = '<span class="loading-spinner me-2"></span>Executing...';
|
||||
|
||||
// Validate
|
||||
if (!spec || !method || !socketPath) {
|
||||
showError('Missing required fields: spec, method, or socketPath');
|
||||
resetButton();
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse params
|
||||
let params;
|
||||
try {
|
||||
params = JSON.parse(paramsText);
|
||||
} catch (e) {
|
||||
showError('Invalid JSON parameters: ' + e.message);
|
||||
resetButton();
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute RPC
|
||||
fetch('/api/rpcui/execute', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
spec: spec,
|
||||
method: method,
|
||||
socketPath: socketPath,
|
||||
params: params
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
showError(data.error);
|
||||
} else {
|
||||
showResult(data.result);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showError('Request failed: ' + error.message);
|
||||
})
|
||||
.finally(() => {
|
||||
resetButton();
|
||||
});
|
||||
|
||||
function resetButton() {
|
||||
submitButton.disabled = false;
|
||||
submitButton.innerHTML = originalButtonText;
|
||||
}
|
||||
|
||||
function showError(message) {
|
||||
if (errorContainer && errorOutput) {
|
||||
errorContainer.classList.remove('d-none');
|
||||
errorOutput.textContent = message;
|
||||
}
|
||||
}
|
||||
|
||||
function showResult(result) {
|
||||
if (resultContainer && resultOutput) {
|
||||
resultContainer.classList.remove('d-none');
|
||||
resultOutput.textContent = JSON.stringify(result, null, 2);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Method tree navigation
|
||||
const methodItems = document.querySelectorAll('.method-item');
|
||||
methodItems.forEach(item => {
|
||||
item.addEventListener('click', function(e) {
|
||||
// Already handled by href, but could add additional functionality here
|
||||
});
|
||||
});
|
||||
|
||||
// Format JSON examples
|
||||
const jsonExamples = document.querySelectorAll('pre code');
|
||||
jsonExamples.forEach(example => {
|
||||
try {
|
||||
const content = example.textContent;
|
||||
const json = JSON.parse(content);
|
||||
example.textContent = JSON.stringify(json, null, 2);
|
||||
} catch (e) {
|
||||
// If not valid JSON, leave as is
|
||||
console.warn('Could not format example as JSON:', e);
|
||||
}
|
||||
});
|
||||
|
||||
// Add syntax highlighting if a library like highlight.js is available
|
||||
if (typeof hljs !== 'undefined') {
|
||||
document.querySelectorAll('pre code').forEach((block) => {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
}
|
||||
});
|
Reference in New Issue
Block a user