Updated UI
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
/**
|
||||
* Workspace Manager Module
|
||||
* Handles request collections, workspaces, environments, and persistence
|
||||
*/
|
||||
const WorkspaceManager = (() => {
|
||||
"use strict";
|
||||
|
||||
const STORAGE_KEY = 'DoxaApi.workspaces';
|
||||
const CURRENT_WS_KEY = 'DoxaApi.currentWorkspace';
|
||||
const ENV_KEY = 'DoxaApi.environments';
|
||||
|
||||
/**
|
||||
* Workspace structure
|
||||
*/
|
||||
class Workspace {
|
||||
constructor(name = 'Default') {
|
||||
this.id = generateId();
|
||||
this.name = name;
|
||||
this.description = '';
|
||||
this.collections = [];
|
||||
this.createdAt = Date.now();
|
||||
this.updatedAt = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collection structure (folders for organizing requests)
|
||||
*/
|
||||
class Collection {
|
||||
constructor(name = 'New Collection') {
|
||||
this.id = generateId();
|
||||
this.name = name;
|
||||
this.description = '';
|
||||
this.requests = [];
|
||||
this.folders = [];
|
||||
this.createdAt = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request in a collection
|
||||
*/
|
||||
class SavedRequest {
|
||||
constructor(name = 'New Request', method = 'GET', path = '') {
|
||||
this.id = generateId();
|
||||
this.name = name;
|
||||
this.method = method;
|
||||
this.path = path;
|
||||
this.description = '';
|
||||
this.tags = [];
|
||||
this.params = {
|
||||
path: {},
|
||||
query: {},
|
||||
header: {},
|
||||
cookie: {}
|
||||
};
|
||||
this.body = null;
|
||||
this.bodyType = 'json';
|
||||
this.formData = {};
|
||||
this.auth = null;
|
||||
this.createdAt = Date.now();
|
||||
this.updatedAt = Date.now();
|
||||
}
|
||||
|
||||
clone() {
|
||||
const copy = new SavedRequest(this.name, this.method, this.path);
|
||||
copy.id = generateId();
|
||||
copy.description = this.description;
|
||||
copy.tags = [...this.tags];
|
||||
copy.params = JSON.parse(JSON.stringify(this.params));
|
||||
copy.body = this.body;
|
||||
copy.bodyType = this.bodyType;
|
||||
copy.formData = { ...this.formData };
|
||||
copy.auth = this.auth;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Environment for variable substitution
|
||||
*/
|
||||
class Environment {
|
||||
constructor(name = 'Default') {
|
||||
this.id = generateId();
|
||||
this.name = name;
|
||||
this.description = '';
|
||||
this.variables = {};
|
||||
this.isActive = false;
|
||||
this.createdAt = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate unique ID
|
||||
*/
|
||||
function generateId() {
|
||||
return 'id_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all workspaces
|
||||
*/
|
||||
function getWorkspaces() {
|
||||
try {
|
||||
const data = localStorage.getItem(STORAGE_KEY);
|
||||
return data ? JSON.parse(data).map(deserializeWorkspace) : [];
|
||||
} catch (e) {
|
||||
console.error('Failed to load workspaces:', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current active workspace
|
||||
*/
|
||||
function getCurrentWorkspace() {
|
||||
const workspaces = getWorkspaces();
|
||||
if (workspaces.length === 0) {
|
||||
const ws = new Workspace('Default');
|
||||
saveWorkspace(ws);
|
||||
return ws;
|
||||
}
|
||||
return workspaces[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Save workspace
|
||||
*/
|
||||
function saveWorkspace(workspace) {
|
||||
workspace.updatedAt = Date.now();
|
||||
const workspaces = getWorkspaces();
|
||||
const index = workspaces.findIndex(w => w.id === workspace.id);
|
||||
|
||||
if (index >= 0) {
|
||||
workspaces[index] = workspace;
|
||||
} else {
|
||||
workspaces.push(workspace);
|
||||
}
|
||||
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(workspaces));
|
||||
return workspace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete workspace
|
||||
*/
|
||||
function deleteWorkspace(workspaceId) {
|
||||
let workspaces = getWorkspaces();
|
||||
workspaces = workspaces.filter(w => w.id !== workspaceId);
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(workspaces));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add collection to workspace
|
||||
*/
|
||||
function addCollection(workspaceId, collection) {
|
||||
const workspace = getWorkspaces().find(w => w.id === workspaceId);
|
||||
if (workspace) {
|
||||
workspace.collections.push(collection);
|
||||
saveWorkspace(workspace);
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save request to collection
|
||||
*/
|
||||
function saveRequestToCollection(workspaceId, collectionId, request) {
|
||||
const workspace = getWorkspaces().find(w => w.id === workspaceId);
|
||||
if (!workspace) return null;
|
||||
|
||||
const collection = findCollectionRecursive(workspace.collections, collectionId);
|
||||
if (!collection) return null;
|
||||
|
||||
request.updatedAt = Date.now();
|
||||
const index = collection.requests.findIndex(r => r.id === request.id);
|
||||
|
||||
if (index >= 0) {
|
||||
collection.requests[index] = request;
|
||||
} else {
|
||||
collection.requests.push(request);
|
||||
}
|
||||
|
||||
saveWorkspace(workspace);
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find collection recursively in folder structure
|
||||
*/
|
||||
function findCollectionRecursive(collections, collectionId) {
|
||||
for (const col of collections) {
|
||||
if (col.id === collectionId) return col;
|
||||
if (col.folders) {
|
||||
const found = findCollectionRecursive(col.folders, collectionId);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all requests in workspace
|
||||
*/
|
||||
function getAllRequests(workspaceId) {
|
||||
const workspace = getWorkspaces().find(w => w.id === workspaceId);
|
||||
if (!workspace) return [];
|
||||
|
||||
const requests = [];
|
||||
|
||||
function traverse(collections) {
|
||||
collections.forEach(col => {
|
||||
requests.push(...(col.requests || []));
|
||||
if (col.folders) {
|
||||
traverse(col.folders);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
traverse(workspace.collections);
|
||||
return requests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search requests in workspace
|
||||
*/
|
||||
function searchRequests(workspaceId, query) {
|
||||
const allRequests = getAllRequests(workspaceId);
|
||||
const lowerQuery = query.toLowerCase();
|
||||
|
||||
return allRequests.filter(req =>
|
||||
req.name.toLowerCase().includes(lowerQuery) ||
|
||||
req.path.toLowerCase().includes(lowerQuery) ||
|
||||
req.description.toLowerCase().includes(lowerQuery) ||
|
||||
(req.tags && req.tags.some(t => t.toLowerCase().includes(lowerQuery)))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get environments
|
||||
*/
|
||||
function getEnvironments() {
|
||||
try {
|
||||
const data = localStorage.getItem(ENV_KEY);
|
||||
return data ? JSON.parse(data).map(deserializeEnvironment) : [];
|
||||
} catch (e) {
|
||||
console.error('Failed to load environments:', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save environment
|
||||
*/
|
||||
function saveEnvironment(environment) {
|
||||
const environments = getEnvironments();
|
||||
const index = environments.findIndex(e => e.id === environment.id);
|
||||
|
||||
if (index >= 0) {
|
||||
environments[index] = environment;
|
||||
} else {
|
||||
environments.push(environment);
|
||||
}
|
||||
|
||||
localStorage.setItem(ENV_KEY, JSON.stringify(environments));
|
||||
return environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete environment
|
||||
*/
|
||||
function deleteEnvironment(environmentId) {
|
||||
let environments = getEnvironments();
|
||||
environments = environments.filter(e => e.id !== environmentId);
|
||||
localStorage.setItem(ENV_KEY, JSON.stringify(environments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get active environment
|
||||
*/
|
||||
function getActiveEnvironment() {
|
||||
const environments = getEnvironments();
|
||||
return environments.find(e => e.isActive) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set active environment
|
||||
*/
|
||||
function setActiveEnvironment(environmentId) {
|
||||
const environments = getEnvironments();
|
||||
environments.forEach(e => e.isActive = e.id === environmentId);
|
||||
localStorage.setItem(ENV_KEY, JSON.stringify(environments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute variables in string
|
||||
*/
|
||||
function substituteVariables(str, environment) {
|
||||
if (!str || !environment) return str;
|
||||
|
||||
let result = str;
|
||||
Object.entries(environment.variables).forEach(([name, value]) => {
|
||||
result = result.replace(new RegExp(`\\$\\{${name}\\}|\\$${name}\\b`, 'g'), String(value || ''));
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export workspace as JSON
|
||||
*/
|
||||
function exportWorkspace(workspaceId) {
|
||||
const workspace = getWorkspaces().find(w => w.id === workspaceId);
|
||||
if (!workspace) return null;
|
||||
|
||||
return {
|
||||
version: '1.0',
|
||||
exported: new Date().toISOString(),
|
||||
workspace: workspace,
|
||||
environments: getEnvironments()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Import workspace from JSON
|
||||
*/
|
||||
function importWorkspace(json) {
|
||||
try {
|
||||
const data = typeof json === 'string' ? JSON.parse(json) : json;
|
||||
|
||||
// Validate version
|
||||
if (!data.version) throw new Error('Invalid format: missing version');
|
||||
|
||||
// Create new workspace with imported data
|
||||
const workspace = data.workspace;
|
||||
workspace.id = generateId();
|
||||
workspace.createdAt = Date.now();
|
||||
workspace.updatedAt = Date.now();
|
||||
|
||||
// Import environments
|
||||
if (data.environments && Array.isArray(data.environments)) {
|
||||
data.environments.forEach(env => {
|
||||
env.id = generateId();
|
||||
saveEnvironment(env);
|
||||
});
|
||||
}
|
||||
|
||||
// Save workspace
|
||||
return saveWorkspace(workspace);
|
||||
} catch (e) {
|
||||
console.error('Failed to import workspace:', e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate request
|
||||
*/
|
||||
function duplicateRequest(request) {
|
||||
const duplicate = request.clone();
|
||||
duplicate.name = `${request.name} (copy)`;
|
||||
return duplicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate collection
|
||||
*/
|
||||
function duplicateCollection(collection) {
|
||||
const duplicate = new Collection(collection.name + ' (copy)');
|
||||
duplicate.description = collection.description;
|
||||
duplicate.requests = collection.requests.map(r => r.clone ? r.clone() : r);
|
||||
if (collection.folders) {
|
||||
duplicate.folders = collection.folders.map(f => duplicateCollection(f));
|
||||
}
|
||||
return duplicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get recent requests
|
||||
*/
|
||||
function getRecentRequests(workspaceId, limit = 10) {
|
||||
return getAllRequests(workspaceId)
|
||||
.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0))
|
||||
.slice(0, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize workspace (helper for JSON parsing)
|
||||
*/
|
||||
function deserializeWorkspace(data) {
|
||||
const ws = Object.assign(new Workspace(data.name), data);
|
||||
return ws;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize environment (helper for JSON parsing)
|
||||
*/
|
||||
function deserializeEnvironment(data) {
|
||||
const env = Object.assign(new Environment(data.name), data);
|
||||
return env;
|
||||
}
|
||||
|
||||
// Public API
|
||||
return {
|
||||
Workspace,
|
||||
Collection,
|
||||
SavedRequest,
|
||||
Environment,
|
||||
generateId,
|
||||
getWorkspaces,
|
||||
getCurrentWorkspace,
|
||||
saveWorkspace,
|
||||
deleteWorkspace,
|
||||
addCollection,
|
||||
saveRequestToCollection,
|
||||
getAllRequests,
|
||||
searchRequests,
|
||||
getEnvironments,
|
||||
saveEnvironment,
|
||||
deleteEnvironment,
|
||||
getActiveEnvironment,
|
||||
setActiveEnvironment,
|
||||
substituteVariables,
|
||||
exportWorkspace,
|
||||
importWorkspace,
|
||||
duplicateRequest,
|
||||
duplicateCollection,
|
||||
getRecentRequests
|
||||
};
|
||||
})();
|
||||
|
||||
// Export for use in other modules
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = WorkspaceManager;
|
||||
}
|
||||
Reference in New Issue
Block a user