api_diff / templates /compare.html
kumudraj01's picture
spell fix
5970584
Raw
History Blame Contribute Delete
13.7 kB
<!DOCTYPE html>
<html>
<head>
<title>Compare APIs</title>
<link
rel="stylesheet"
href="{{ url_for('static', path='/css/styles.css') }}"
/>
<style>
.progress-container {
display: none;
width: 100%;
margin: 20px 0;
text-align: center;
}
.progress-bar {
width: 100%;
height: 20px;
background-color: #f3f3f3;
border-radius: 10px;
overflow: hidden;
}
.progress {
width: 0%;
height: 100%;
background-color: #4caf50;
transition: width 0.3s ease;
}
.loading-text {
margin-top: 10px;
color: #666;
}
.spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid #f3f3f3;
border-top: 3px solid #4caf50;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-right: 10px;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
#processingStatus {
margin-top: 10px;
font-weight: bold;
color: #4caf50;
}
.progress-steps {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
position: relative;
}
.progress-step {
background: #f3f3f3;
border-radius: 50%;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 1;
}
.progress-step.active {
background: #4caf50;
color: white;
}
.progress-step-label {
position: absolute;
top: 35px;
font-size: 12px;
width: 80px;
text-align: center;
left: 50%;
transform: translateX(-50%);
}
.step-line {
position: absolute;
top: 15px;
height: 2px;
background: #f3f3f3;
width: calc(100% - 30px);
left: 15px;
}
.step-line-progress {
height: 100%;
width: 0;
background: #4caf50;
transition: width 0.3s ease;
}
.session-timeout-warning {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
border: 1px solid #ccc;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.session-timeout-warning h3 {
margin: 0 0 10px;
}
.session-timeout-warning p {
margin: 0 0 20px;
}
.session-timeout-warning button {
margin-right: 10px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<img
src="{{ url_for('static', path='/images/TD-logo.jpeg') }}"
alt="Logo"
class="logo"
/>
<div class="user-menu">
<div>Welcome, {{ username }}!</div>
<div class="user-menu-content">
<a href="/logout">Logout</a>
</div>
</div>
</div>
{% if error %}
<div class="error">{{ error }}</div>
{% endif %}
<div id="session-timeout" class="session-timeout-warning">
<h3>Session Timeout Warning</h3>
<p>
Your session will expire in
<span id="timeout-countdown">60</span> seconds due to inactivity.
</p>
<button class="continue" onclick="extendSession()">
Continue Session
</button>
<button class="logout" onclick="window.location.href='/logout'">
Logout
</button>
</div>
<div class="progress-container" id="progressContainer">
<div class="progress-steps">
<div class="step-line">
<div class="step-line-progress" id="stepLineProgress"></div>
</div>
<div class="progress-step" id="step1">
1
<div class="progress-step-label">Validating</div>
</div>
<div class="progress-step" id="step2">
2
<div class="progress-step-label">Processing</div>
</div>
<div class="progress-step" id="step3">
3
<div class="progress-step-label">Fetching</div>
</div>
<div class="progress-step" id="step4">
4
<div class="progress-step-label">Comparing</div>
</div>
</div>
<div class="progress-bar">
<div class="progress" id="progressBar"></div>
</div>
<div class="loading-text">
<span class="spinner"></span>
<span id="loadingText">Processing API requests...</span>
</div>
<div id="processingStatus"></div>
</div>
<form method="POST" action="/compare" id="compareForm">
<div class="grid">
<div>
<h3>First API</h3>
<div class="form-group">
<label for="api1_url">URL:</label>
<input
type="url"
id="api1_url"
name="api1_url"
class="form-control"
required
/>
</div>
<div class="form-group">
<label for="api1_method">Method:</label>
<select
id="api1_method"
name="api1_method"
class="form-control"
required
>
{% for method in methods %}
<option value="{{ method }}">{{ method }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="api1_headers">Headers (JSON):</label>
<textarea
id="api1_headers"
name="api1_headers"
class="form-control"
rows="4"
>
{}</textarea
>
</div>
<div class="form-group">
<label for="api1_payload">Payload (JSON):</label>
<textarea
id="api1_payload"
name="api1_payload"
class="form-control"
rows="6"
>
{}</textarea
>
</div>
</div>
<div>
<h3>Second API</h3>
<div class="form-group">
<label for="api2_url">URL:</label>
<input
type="url"
id="api2_url"
name="api2_url"
class="form-control"
required
/>
</div>
<div class="form-group">
<label for="api2_method">Method:</label>
<select
id="api2_method"
name="api2_method"
class="form-control"
required
>
{% for method in methods %}
<option value="{{ method }}">{{ method }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="api2_headers">Headers (JSON):</label>
<textarea
id="api2_headers"
name="api2_headers"
class="form-control"
rows="4"
>
{}</textarea
>
</div>
<div class="form-group">
<label for="api2_payload">Payload (JSON):</label>
<textarea
id="api2_payload"
name="api2_payload"
class="form-control"
rows="6"
>
{}</textarea
>
</div>
</div>
</div>
<div class="form-group">
<label>View Mode:</label>
<div class="radio-group">
<input
type="radio"
id="line"
name="view_mode"
value="line"
checked
/>
<label for="line">Line by Line</label>
<input type="radio" id="tree" name="view_mode" value="tree" />
<label for="tree">Tree View</label>
</div>
</div>
<button type="submit" class="button" id="compareButton">
Compare APIs
</button>
</form>
</div>
<script>
// Session timeout handling
let warningTimeout;
let logoutTimeout;
const activityEvents = [
"mousedown",
"mousemove",
"keypress",
"scroll",
"touchstart",
];
const warningTime = 19 * 60 * 1000; // Show warning 1 minute before timeout (19 minutes)
const logoutTime = 20 * 60 * 1000; // Logout after 20 minutes
function resetTimers() {
clearTimeout(warningTimeout);
clearTimeout(logoutTimeout);
startTimers();
}
function startTimers() {
warningTimeout = setTimeout(showTimeoutWarning, warningTime);
logoutTimeout = setTimeout(logout, logoutTime);
}
function showTimeoutWarning() {
const warningDialog = document.getElementById("session-timeout");
warningDialog.style.display = "block";
// Start countdown
let countdown = 60;
const countdownElement = document.getElementById("timeout-countdown");
const countdownInterval = setInterval(() => {
countdown--;
countdownElement.textContent = countdown;
if (countdown <= 0) {
clearInterval(countdownInterval);
}
}, 1000);
}
function extendSession() {
const warningDialog = document.getElementById("session-timeout");
warningDialog.style.display = "none";
resetTimers();
// Call backend to extend session
fetch("/extend-session", { method: "POST" });
}
function logout() {
window.location.href = "/logout";
}
// Add activity event listeners
activityEvents.forEach((event) => {
document.addEventListener(event, resetTimers);
});
// Start timers when page loads
startTimers();
document
.getElementById("compareForm")
.addEventListener("submit", function (e) {
// Show progress container
document.getElementById("progressContainer").style.display = "block";
document.getElementById("compareButton").disabled = true;
// Connect to WebSocket for progress updates
const ws = new WebSocket(`ws://${window.location.host}/ws`);
ws.onmessage = function (event) {
const data = JSON.parse(event.data);
if (data.type === "processing") {
updateProgress(data.status);
}
};
function updateProgress(status) {
const progressBar = document.getElementById("progressBar");
const loadingText = document.getElementById("loadingText");
const processingStatus =
document.getElementById("processingStatus");
const steps = {
starting: {
step: 1,
progress: 25,
text: "Starting API comparison...",
},
validating: {
step: 1,
progress: 50,
text: "Validating inputs...",
},
processing: {
step: 2,
progress: 60,
text: "Processing request...",
},
fetching: {
step: 3,
progress: 75,
text: "Fetching API responses...",
},
comparing: {
step: 4,
progress: 90,
text: "Comparing results...",
},
};
if (steps[status]) {
const { step, progress, text } = steps[status];
progressBar.style.width = `${progress}%`;
loadingText.textContent = text;
processingStatus.textContent = text;
// Update step indicators
for (let i = 1; i <= 4; i++) {
const stepEl = document.getElementById(`step${i}`);
if (i <= step) {
stepEl.classList.add("active");
}
}
// Update progress line
document.getElementById("stepLineProgress").style.width = `${
(step - 1) * 33.33
}%`;
}
}
});
// Validate JSON input
function validateJson(input, fieldName) {
try {
if (input.value.trim()) {
JSON.parse(input.value);
}
input.style.borderColor = "";
return true;
} catch (e) {
input.style.borderColor = "red";
alert(`Invalid JSON in ${fieldName}`);
return false;
}
}
// Add JSON validation to payload and headers fields
["api1_payload", "api2_payload", "api1_headers", "api2_headers"].forEach(
(id) => {
const element = document.getElementById(id);
element.addEventListener("blur", () => validateJson(element, id));
}
);
</script>
<div
style="text-align: center; margin-top: 20px; color: #666; font-size: 12px"
>
Copyright © 2025 TELUS Digital. All rights reserved.<br />
For internal use only.
</div>
</body>
</html>