refactor: unified google vein, prefixed module loading, cfg separation

- Unified google vein with OAuth + Sheets API
- Prefixed vein module loading (vein_google) to avoid pip package shadowing
- Preload pip packages before vein loading
- Added common/auth framework
- Rebranded sbwrapper from Pawprint to Soleprint
- Removed cfg/ from history (now separate repo)
- Keep cfg/standalone/ as sample configuration
- gitignore cfg/amar/ and cfg/dlt/ (private configs)
This commit is contained in:
buenosairesam
2026-01-26 21:55:44 -03:00
parent 6e18324a43
commit c4e702eae3
18 changed files with 1135 additions and 116 deletions

View File

@@ -1,6 +1,6 @@
// Pawprint Wrapper - Sidebar Logic
// Soleprint Wrapper - Sidebar Logic
class PawprintSidebar {
class SoleprintSidebar {
constructor() {
this.config = null;
this.currentUser = null;
@@ -28,38 +28,38 @@ class PawprintSidebar {
async loadConfig() {
try {
const response = await fetch('/wrapper/config.json');
const response = await fetch("/wrapper/config.json");
this.config = await response.json();
console.log('[Pawprint] Config loaded:', this.config.nest_name);
console.log("[Soleprint] Config loaded:", this.config.nest_name);
} catch (error) {
console.error('[Pawprint] Failed to load config:', error);
console.error("[Soleprint] Failed to load config:", error);
// Use default config
this.config = {
nest_name: 'default',
nest_name: "default",
wrapper: {
environment: {
backend_url: 'http://localhost:8000',
frontend_url: 'http://localhost:3000'
backend_url: "http://localhost:8000",
frontend_url: "http://localhost:3000",
},
users: []
}
users: [],
},
};
}
}
createSidebar() {
const sidebar = document.createElement('div');
sidebar.id = 'pawprint-sidebar';
const sidebar = document.createElement("div");
sidebar.id = "pawprint-sidebar";
sidebar.innerHTML = this.getSidebarHTML();
document.body.appendChild(sidebar);
this.sidebar = sidebar;
}
createToggleButton() {
const button = document.createElement('button');
button.id = 'sidebar-toggle';
const button = document.createElement("button");
button.id = "sidebar-toggle";
button.innerHTML = '<span class="icon">◀</span>';
button.title = 'Toggle Pawprint Sidebar (Ctrl+Shift+P)';
button.title = "Toggle Soleprint Sidebar (Ctrl+Shift+P)";
document.body.appendChild(button);
this.toggleBtn = button;
}
@@ -69,7 +69,7 @@ class PawprintSidebar {
return `
<div class="sidebar-header">
<h2>🐾 Pawprint</h2>
<h2>🐾 Soleprint</h2>
<div class="nest-name">${this.config.nest_name}</div>
</div>
@@ -83,22 +83,26 @@ class PawprintSidebar {
<div id="current-user-display" style="display: none;">
<div class="current-user">
Logged in as: <strong id="current-username"></strong>
<button class="logout-btn" onclick="pawprintSidebar.logout()">
<button class="logout-btn" onclick="soleprintSidebar.logout()">
Logout
</button>
</div>
</div>
<div class="user-cards">
${users.map(user => `
<div class="user-card" data-user-id="${user.id}" onclick="pawprintSidebar.loginAs('${user.id}')">
${users
.map(
(user) => `
<div class="user-card" data-user-id="${user.id}" onclick="soleprintSidebar.loginAs('${user.id}')">
<div class="icon">${user.icon}</div>
<div class="info">
<span class="label">${user.label}</span>
<span class="role">${user.role}</span>
</div>
</div>
`).join('')}
`,
)
.join("")}
</div>
</div>
@@ -119,18 +123,18 @@ class PawprintSidebar {
</div>
<div class="sidebar-footer">
Pawprint Dev Tools
Soleprint Dev Tools
</div>
`;
}
setupEventListeners() {
// Toggle button
this.toggleBtn.addEventListener('click', () => this.toggle());
this.toggleBtn.addEventListener("click", () => this.toggle());
// Keyboard shortcut: Ctrl+Shift+P
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.shiftKey && e.key === 'P') {
document.addEventListener("keydown", (e) => {
if (e.ctrlKey && e.shiftKey && e.key === "P") {
e.preventDefault();
this.toggle();
}
@@ -138,28 +142,29 @@ class PawprintSidebar {
}
toggle() {
this.sidebar.classList.toggle('expanded');
this.sidebar.classList.toggle("expanded");
this.saveSidebarState();
}
saveSidebarState() {
const isExpanded = this.sidebar.classList.contains('expanded');
localStorage.setItem('pawprint_sidebar_expanded', isExpanded);
const isExpanded = this.sidebar.classList.contains("expanded");
localStorage.setItem("pawprint_sidebar_expanded", isExpanded);
}
loadSidebarState() {
const isExpanded = localStorage.getItem('pawprint_sidebar_expanded') === 'true';
const isExpanded =
localStorage.getItem("pawprint_sidebar_expanded") === "true";
if (isExpanded) {
this.sidebar.classList.add('expanded');
this.sidebar.classList.add("expanded");
}
}
showStatus(message, type = 'info') {
const container = document.getElementById('status-container');
const statusDiv = document.createElement('div');
showStatus(message, type = "info") {
const container = document.getElementById("status-container");
const statusDiv = document.createElement("div");
statusDiv.className = `status-message ${type}`;
statusDiv.textContent = message;
container.innerHTML = '';
container.innerHTML = "";
container.appendChild(statusDiv);
// Auto-remove after 5 seconds
@@ -169,22 +174,22 @@ class PawprintSidebar {
}
async loginAs(userId) {
const user = this.config.wrapper.users.find(u => u.id === userId);
const user = this.config.wrapper.users.find((u) => u.id === userId);
if (!user) return;
this.showStatus(`Logging in as ${user.label}... ⏳`, 'info');
this.showStatus(`Logging in as ${user.label}... ⏳`, "info");
try {
const backendUrl = this.config.wrapper.environment.backend_url;
const response = await fetch(`${backendUrl}/api/token/`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
username: user.username,
password: user.password
})
password: user.password,
}),
});
if (!response.ok) {
@@ -194,17 +199,20 @@ class PawprintSidebar {
const data = await response.json();
// Store tokens
localStorage.setItem('access_token', data.access);
localStorage.setItem('refresh_token', data.refresh);
localStorage.setItem("access_token", data.access);
localStorage.setItem("refresh_token", data.refresh);
// Store user info
localStorage.setItem('user_info', JSON.stringify({
username: user.username,
label: user.label,
role: data.details?.role || user.role
}));
localStorage.setItem(
"user_info",
JSON.stringify({
username: user.username,
label: user.label,
role: data.details?.role || user.role,
}),
);
this.showStatus(`✓ Logged in as ${user.label}`, 'success');
this.showStatus(`✓ Logged in as ${user.label}`, "success");
this.currentUser = user;
this.updateCurrentUserDisplay();
@@ -212,19 +220,18 @@ class PawprintSidebar {
setTimeout(() => {
window.location.reload();
}, 1000);
} catch (error) {
console.error('[Pawprint] Login error:', error);
this.showStatus(`✗ Login failed: ${error.message}`, 'error');
console.error("[Soleprint] Login error:", error);
this.showStatus(`✗ Login failed: ${error.message}`, "error");
}
}
logout() {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
localStorage.removeItem('user_info');
localStorage.removeItem("access_token");
localStorage.removeItem("refresh_token");
localStorage.removeItem("user_info");
this.showStatus('✓ Logged out', 'success');
this.showStatus("✓ Logged out", "success");
this.currentUser = null;
this.updateCurrentUserDisplay();
@@ -235,52 +242,54 @@ class PawprintSidebar {
}
checkCurrentUser() {
const userInfo = localStorage.getItem('user_info');
const userInfo = localStorage.getItem("user_info");
if (userInfo) {
try {
this.currentUser = JSON.parse(userInfo);
this.updateCurrentUserDisplay();
} catch (error) {
console.error('[Pawprint] Failed to parse user info:', error);
console.error("[Soleprint] Failed to parse user info:", error);
}
}
}
updateCurrentUserDisplay() {
const display = document.getElementById('current-user-display');
const username = document.getElementById('current-username');
const display = document.getElementById("current-user-display");
const username = document.getElementById("current-username");
if (this.currentUser) {
display.style.display = 'block';
display.style.display = "block";
username.textContent = this.currentUser.username;
// Highlight active user card
document.querySelectorAll('.user-card').forEach(card => {
card.classList.remove('active');
document.querySelectorAll(".user-card").forEach((card) => {
card.classList.remove("active");
});
const activeCard = document.querySelector(`.user-card[data-user-id="${this.getUserIdByUsername(this.currentUser.username)}"]`);
const activeCard = document.querySelector(
`.user-card[data-user-id="${this.getUserIdByUsername(this.currentUser.username)}"]`,
);
if (activeCard) {
activeCard.classList.add('active');
activeCard.classList.add("active");
}
} else {
display.style.display = 'none';
display.style.display = "none";
}
}
getUserIdByUsername(username) {
const user = this.config.wrapper.users.find(u => u.username === username);
const user = this.config.wrapper.users.find((u) => u.username === username);
return user ? user.id : null;
}
}
// Initialize sidebar when DOM is ready
const pawprintSidebar = new PawprintSidebar();
const soleprintSidebar = new SoleprintSidebar();
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => pawprintSidebar.init());
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => soleprintSidebar.init());
} else {
pawprintSidebar.init();
soleprintSidebar.init();
}
console.log('[Pawprint] Sidebar script loaded');
console.log("[Soleprint] Sidebar script loaded");