feat: DefaultPath als Base-Path für User-Workspaces
- WorkspaceHelper.cs: Zentrale Workspace-Auflösung (relativ → absolut) - Session-Workspace wird relativ zum User-DefaultPath gespeichert - System-Prompt bekommt aufgelösten absoluten Pfad - Path-Traversal-Schutz: '..' in Workspace-Pfaden blockiert - Browse-API gibt '..' nicht mehr als Eintrag zurück - Folder-Browser: basePath-Limit, Back-Button navigiert zum Parent - DefaultPath nur durch Admin bearbeitbar (Profil: readonly) - Legacy: Absolute Pfade in session.Workspace weiterhin kompatibel
This commit is contained in:
1 parent
8e7bda50f9
commit
4e1ed81f37
12 files changed
+240
-106
No files matched your search
@@ -504,6 +504,7 @@ function openFolderBrowser(opts = {}) {
|
||||
mode: 'folder',
|
||||
onSelect: opts.onSelect || null,
|
||||
currentAbsPath: opts.startPath || '/',
|
||||
basePath: (opts.basePath || '').replace(/\/+$/, '') || null,
|
||||
history: []
|
||||
};
|
||||
|
||||
@@ -592,16 +593,37 @@ async function fbLoadDir(absPath) {
|
||||
sidebar.innerHTML = '<div class="fe-empty">Leer</div>';
|
||||
}
|
||||
|
||||
document.getElementById('feBack').disabled = _feState.history.length === 0;
|
||||
const currentNorm = data.current.replace(/\/+$/, '');
|
||||
const atBase = _feState.basePath && currentNorm === _feState.basePath;
|
||||
const atRoot = currentNorm === '' || currentNorm === '/';
|
||||
document.getElementById('feBack').disabled = atBase || (atRoot && _feState.history.length === 0);
|
||||
} catch (e) {
|
||||
sidebar.innerHTML = '<div class="fe-error">Netzwerk-Fehler</div>';
|
||||
}
|
||||
}
|
||||
|
||||
function fbGoBack() {
|
||||
if (!_feState || _feState.history.length === 0) return;
|
||||
const prev = _feState.history.pop();
|
||||
fbLoadDir(prev);
|
||||
if (!_feState) return;
|
||||
// Nicht über den basePath hinaus navigieren
|
||||
const currentNorm = _feState.currentAbsPath.replace(/\/+$/, '');
|
||||
if (_feState.basePath && currentNorm === _feState.basePath) return;
|
||||
|
||||
if (_feState.history.length > 0) {
|
||||
const prev = _feState.history.pop();
|
||||
// Prüfe ob der vorherige Pfad über dem basePath liegt
|
||||
if (_feState.basePath && !prev.replace(/\/+$/, '').startsWith(_feState.basePath)) {
|
||||
_feState.history.length = 0;
|
||||
fbLoadDir(_feState.basePath);
|
||||
return;
|
||||
}
|
||||
fbLoadDir(prev);
|
||||
} else {
|
||||
// Kein History-Eintrag → zum Parent navigieren
|
||||
const parent = currentNorm.includes('/') ? currentNorm.substring(0, currentNorm.lastIndexOf('/')) || '/' : '/';
|
||||
if (parent !== currentNorm) {
|
||||
fbLoadDir(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Folder Browser: Create Directory ──
|
||||
|
||||
@@ -10,7 +10,6 @@ registerPage('profile', {
|
||||
var usernameInput = document.getElementById('profileUsername');
|
||||
var displayNameInput = document.getElementById('profileDisplayName');
|
||||
var defaultPathInput = document.getElementById('profileDefaultPath');
|
||||
var defaultPathBrowse = document.getElementById('profileDefaultPathBrowse');
|
||||
var personaInput = document.getElementById('profilePersona');
|
||||
var saveBtn = document.getElementById('profileSaveBtn');
|
||||
var messageDiv = document.getElementById('profileMessage');
|
||||
@@ -43,18 +42,6 @@ registerPage('profile', {
|
||||
displayNameInput.value = profile.displayName || '';
|
||||
defaultPathInput.value = profile.defaultPath || '';
|
||||
|
||||
// Default Path Browse
|
||||
if (defaultPathBrowse) {
|
||||
defaultPathBrowse.addEventListener('click', function() {
|
||||
openFolderBrowser({
|
||||
startPath: defaultPathInput.value.trim() || '/',
|
||||
onSelect: function(path) {
|
||||
defaultPathInput.value = path;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Profil speichern
|
||||
saveBtn.addEventListener('click', async function() {
|
||||
saveBtn.disabled = true;
|
||||
@@ -64,7 +51,6 @@ registerPage('profile', {
|
||||
try {
|
||||
var updated = await apiUpdateProfile({
|
||||
displayName: displayNameInput.value.trim(),
|
||||
defaultPath: defaultPathInput.value.trim() || null,
|
||||
persona: _profileMde.value().trim()
|
||||
});
|
||||
|
||||
|
||||
@@ -129,10 +129,29 @@ registerPage('session', {
|
||||
const workspaceBrowse = document.getElementById('sessionWorkspaceBrowse');
|
||||
if (workspaceBrowse) {
|
||||
workspaceBrowse.addEventListener('click', () => {
|
||||
const defaultPath = (currentUser && currentUser.defaultPath) || '';
|
||||
const currentVal = workspaceEl.value.trim();
|
||||
// Für den Folder-Browser den absoluten Startpfad zusammenbauen
|
||||
let startPath = '/';
|
||||
if (defaultPath && currentVal) {
|
||||
startPath = defaultPath.replace(/\/+$/, '') + '/' + currentVal;
|
||||
} else if (defaultPath) {
|
||||
startPath = defaultPath;
|
||||
} else if (currentVal) {
|
||||
startPath = currentVal;
|
||||
}
|
||||
openFolderBrowser({
|
||||
startPath: workspaceEl.value.trim() || (currentUser && currentUser.defaultPath) || '/',
|
||||
onSelect(path) {
|
||||
workspaceEl.value = path;
|
||||
startPath,
|
||||
basePath: defaultPath || null,
|
||||
onSelect(absolutePath) {
|
||||
// Relativen Pfad zum DefaultPath berechnen
|
||||
if (defaultPath && absolutePath.startsWith(defaultPath)) {
|
||||
let rel = absolutePath.slice(defaultPath.length).replace(/^\/+/, '');
|
||||
workspaceEl.value = rel || '';
|
||||
} else {
|
||||
// Kein DefaultPath oder Pfad außerhalb → absoluten Pfad beibehalten (Legacy)
|
||||
workspaceEl.value = absolutePath;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user