feat: connect alpine workspace management to admin api
This commit is contained in:
+147
-52
@@ -1,25 +1,39 @@
|
||||
// Populate profile from stored user
|
||||
try {
|
||||
var u = JSON.parse(localStorage.getItem('crank_user'));
|
||||
if (u) {
|
||||
document.getElementById('profile-avatar').textContent = u.initials || 'AT';
|
||||
document.getElementById('profile-display-name').textContent = u.name || 'Operator';
|
||||
document.getElementById('profile-email').textContent = u.email || '';
|
||||
var fi = document.getElementById('field-firstname');
|
||||
var fe = document.getElementById('field-email');
|
||||
if (fi && u.name) fi.value = u.name;
|
||||
if (fe && u.email) fe.value = u.email;
|
||||
}
|
||||
} catch (e) {}
|
||||
function populateProfile() {
|
||||
try {
|
||||
var user = JSON.parse(localStorage.getItem('crank_user'));
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject language switcher into section-profile card body, before Save button
|
||||
(function() {
|
||||
document.getElementById('profile-avatar').textContent = user.initials || 'AT';
|
||||
document.getElementById('profile-display-name').textContent = user.name || 'Operator';
|
||||
document.getElementById('profile-email').textContent = user.email || '';
|
||||
|
||||
var firstName = document.getElementById('field-firstname');
|
||||
var email = document.getElementById('field-email');
|
||||
if (firstName && user.name) {
|
||||
firstName.value = user.name;
|
||||
}
|
||||
if (email && user.email) {
|
||||
email.value = user.email;
|
||||
}
|
||||
} catch (_error) {
|
||||
}
|
||||
}
|
||||
|
||||
function injectLanguageSwitcher() {
|
||||
var profileSection = document.getElementById('section-profile');
|
||||
if (!profileSection) return;
|
||||
if (!profileSection) {
|
||||
return;
|
||||
}
|
||||
|
||||
var cardBody = profileSection.querySelector('.section-card-body');
|
||||
if (!cardBody) return;
|
||||
if (!cardBody) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('html/fragments/lang-switcher.html')
|
||||
.then(function(r) { return r.text(); })
|
||||
.then(function(response) { return response.text(); })
|
||||
.then(function(html) {
|
||||
var saveRow = cardBody.querySelector('div[style*="justify-content:flex-end"]');
|
||||
if (saveRow) {
|
||||
@@ -27,47 +41,128 @@ try {
|
||||
} else {
|
||||
cardBody.insertAdjacentHTML('beforeend', html);
|
||||
}
|
||||
if (typeof applyLang === 'function') applyLang();
|
||||
if (typeof applyLang === 'function') {
|
||||
applyLang();
|
||||
}
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
// Settings sidebar navigation
|
||||
var navItems = document.querySelectorAll('.settings-nav-item[data-section]');
|
||||
navItems.forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
navItems.forEach(function(b) { b.classList.remove('active'); });
|
||||
this.classList.add('active');
|
||||
var target = document.getElementById('section-' + this.dataset.section);
|
||||
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
function bindSectionNavigation() {
|
||||
var navItems = document.querySelectorAll('.settings-nav-item[data-section]');
|
||||
navItems.forEach(function (button) {
|
||||
button.addEventListener('click', function () {
|
||||
navItems.forEach(function (item) { item.classList.remove('active'); });
|
||||
this.classList.add('active');
|
||||
var target = document.getElementById('section-' + this.dataset.section);
|
||||
if (target) {
|
||||
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Hash navigation (e.g. settings.html#security)
|
||||
if (window.location.hash) {
|
||||
var hash = window.location.hash.slice(1);
|
||||
var btn = document.querySelector('.settings-nav-item[data-section="' + hash + '"]');
|
||||
if (btn) setTimeout(function() { btn.click(); }, 100);
|
||||
}
|
||||
// Default: scroll to profile
|
||||
else {
|
||||
var profileBtn = document.querySelector('.settings-nav-item[data-section="profile"]');
|
||||
if (profileBtn) profileBtn.classList.add('active');
|
||||
}
|
||||
var initialSection = window.location.hash ? window.location.hash.slice(1) : 'profile';
|
||||
var initialButton = document.querySelector('.settings-nav-item[data-section="' + initialSection + '"]')
|
||||
|| document.querySelector('.settings-nav-item[data-section="profile"]');
|
||||
if (initialButton) {
|
||||
setTimeout(function () { initialButton.click(); }, 50);
|
||||
}
|
||||
|
||||
// IntersectionObserver scroll-spy: highlight active sidebar item as user scrolls
|
||||
var observer = new IntersectionObserver(function(entries) {
|
||||
entries.forEach(function(entry) {
|
||||
if (entry.isIntersecting) {
|
||||
var sectionId = entry.target.id; // e.g. "section-profile"
|
||||
var name = sectionId.replace('section-', ''); // e.g. "profile"
|
||||
document.querySelectorAll('.settings-nav-item[data-section]').forEach(function(b) {
|
||||
b.classList.toggle('active', b.dataset.section === name);
|
||||
var observer = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (!entry.isIntersecting) {
|
||||
return;
|
||||
}
|
||||
var section = entry.target.id.replace('section-', '');
|
||||
document.querySelectorAll('.settings-nav-item[data-section]').forEach(function (button) {
|
||||
button.classList.toggle('active', button.dataset.section === section);
|
||||
});
|
||||
});
|
||||
}, { threshold: 0.3 });
|
||||
|
||||
document.querySelectorAll('[id^="section-"]').forEach(function (section) {
|
||||
if (section.style.display !== 'none') {
|
||||
observer.observe(section);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.3 });
|
||||
}
|
||||
|
||||
// Observe all visible sections (not hidden ones)
|
||||
document.querySelectorAll('[id^="section-"]').forEach(function(el) {
|
||||
if (el.style.display !== 'none') observer.observe(el);
|
||||
async function loadWorkspaceSettings() {
|
||||
if (!window.CrankApi || !window.whenWorkspacesReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
await window.whenWorkspacesReady();
|
||||
var workspace = window.getCurrentWorkspace ? window.getCurrentWorkspace() : null;
|
||||
if (!workspace) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var record = await window.CrankApi.getWorkspace(workspace.id);
|
||||
var item = record.workspace;
|
||||
var settings = item.settings || {};
|
||||
|
||||
document.getElementById('settings-ws-slug').value = item.slug || '';
|
||||
document.getElementById('settings-ws-display-name').value = item.display_name || '';
|
||||
document.getElementById('settings-ws-description').value = settings.description || '';
|
||||
document.getElementById('settings-ws-timezone').value = settings.timezone || 'UTC';
|
||||
document.getElementById('settings-ws-protocol').value = settings.default_protocol || 'rest';
|
||||
|
||||
document.querySelectorAll('#section-workspace .lang-btn').forEach(function (button) {
|
||||
button.classList.toggle('active', button.dataset.lang === (settings.language || (localStorage.getItem('crank_lang') || 'en')));
|
||||
});
|
||||
|
||||
var saveButton = document.getElementById('settings-ws-save-btn');
|
||||
if (saveButton.dataset.bound === 'true') {
|
||||
return;
|
||||
}
|
||||
saveButton.dataset.bound = 'true';
|
||||
|
||||
saveButton.addEventListener('click', async function () {
|
||||
var saveButton = this;
|
||||
var original = saveButton.textContent;
|
||||
saveButton.disabled = true;
|
||||
saveButton.textContent = 'Saving…';
|
||||
|
||||
try {
|
||||
await window.CrankApi.updateWorkspace(item.id, {
|
||||
slug: document.getElementById('settings-ws-slug').value.trim(),
|
||||
display_name: document.getElementById('settings-ws-display-name').value.trim(),
|
||||
settings: {
|
||||
description: document.getElementById('settings-ws-description').value.trim(),
|
||||
timezone: document.getElementById('settings-ws-timezone').value,
|
||||
default_protocol: document.getElementById('settings-ws-protocol').value,
|
||||
language: localStorage.getItem('crank_lang') || 'en',
|
||||
color: (workspace.settings && workspace.settings.color) || '#0d9488',
|
||||
},
|
||||
});
|
||||
|
||||
if (window.refreshWorkspaces) {
|
||||
var workspaces = await window.refreshWorkspaces();
|
||||
var updated = workspaces.find(function (entry) { return entry.id === item.id; });
|
||||
if (updated && window.setCurrentWorkspace) {
|
||||
window.setCurrentWorkspace(updated);
|
||||
}
|
||||
}
|
||||
|
||||
saveButton.textContent = 'Saved ✓';
|
||||
} catch (error) {
|
||||
alert(error.message || 'Failed to save workspace settings');
|
||||
saveButton.textContent = original;
|
||||
} finally {
|
||||
setTimeout(function () {
|
||||
saveButton.disabled = false;
|
||||
saveButton.textContent = original;
|
||||
}, 1200);
|
||||
}
|
||||
});
|
||||
} catch (_error) {
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
populateProfile();
|
||||
injectLanguageSwitcher();
|
||||
bindSectionNavigation();
|
||||
loadWorkspaceSettings();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user