From a6d87a06225e33a0a003a2854d450337440b4a79 Mon Sep 17 00:00:00 2001 From: Flawid DSouza Date: Thu, 14 Mar 2024 15:45:35 +0530 Subject: [PATCH] feat(electron+ui): Workspace > In Filesystem (Git Friendly) > Plugins Implemented --- packages/electron/src/app.js | 28 ++ packages/electron/src/db.js | 243 +++++++++++++++++- packages/electron/src/preload.js | 88 +++---- packages/ui/src/App.vue | 2 +- packages/ui/src/components/NavBar.vue | 2 +- packages/ui/src/components/Sidebar.vue | 2 +- .../components/modals/PluginManagerModal.vue | 10 +- packages/ui/src/db.ts | 77 +++++- packages/ui/src/store.js | 77 ++++-- packages/ui/src/utils/array.ts | 2 +- 10 files changed, 427 insertions(+), 104 deletions(-) diff --git a/packages/electron/src/app.js b/packages/electron/src/app.js index 89d53067..f82df7da 100644 --- a/packages/electron/src/app.js +++ b/packages/electron/src/app.js @@ -252,6 +252,34 @@ app.whenReady().then(async() => { return operationQueue.enqueue(() => db.deleteResponsesByCollectionId(...args)) }) + ipcMain.handle('getWorkspacePlugins', (_, ...args) => { + return operationQueue.enqueue(() => db.getWorkspacePlugins(...args)) + }) + + ipcMain.handle('createPlugin', (_, ...args) => { + return operationQueue.enqueue(() => db.createPlugin(...args)) + }) + + ipcMain.handle('updatePlugin', (_, ...args) => { + return operationQueue.enqueue(() => db.updatePlugin(...args)) + }) + + ipcMain.handle('deletePlugin', (_, ...args) => { + return operationQueue.enqueue(() => db.deletePlugin(...args)) + }) + + ipcMain.handle('deletePluginsByWorkspace', (_, ...args) => { + return operationQueue.enqueue(() => db.deletePluginsByWorkspace(...args)) + }) + + ipcMain.handle('deletePluginsByCollectionIds', (_, ...args) => { + return operationQueue.enqueue(() => db.deletePluginsByCollectionIds(...args)) + }) + + ipcMain.handle('createPlugins', (_, ...args) => { + return operationQueue.enqueue(() => db.createPlugins(...args)) + }) + ipcMain.handle('openFolderSelectionDialog', () => helpers.openFolderSelectionDialog()) createWindow() diff --git a/packages/electron/src/db.js b/packages/electron/src/db.js index 7b0a0111..6f0ba19e 100644 --- a/packages/electron/src/db.js +++ b/packages/electron/src/db.js @@ -10,7 +10,7 @@ async function getCollection(workspace, dir = workspace.location) { const filesAndFolders = await fs.readdir(dir, { withFileTypes: true }) for (let fileOrFolder of filesAndFolders) { - if (fileOrFolder.name.endsWith('.responses.json') || fileOrFolder.name === '_.json') { + if (fileOrFolder.name.endsWith('.responses.json') || fileOrFolder.name.endsWith('.plugins.json') || fileOrFolder.name === '_.json') { continue } @@ -194,13 +194,24 @@ async function updateCollection(workspace, collectionId, updatedFields) { await fs.rename(renameFrom, renameTo) idMap.set(collectionId, renameTo) + const responsesRenameFrom = renameFrom.replace('.json', '.responses.json') + const responsesRenameTo = renameTo.replace('.json', '.responses.json') + try { - const responsesRenameFrom = renameFrom.replace('.json', '.responses.json') - const responsesRenameTo = renameTo.replace('.json', '.responses.json') await fs.access(responsesRenameFrom) await fs.rename(responsesRenameFrom, responsesRenameTo) } catch (err) { - console.log(`Skipping renaming responses file: ${responsesPath} as it does not exist`) + console.log(`Skipping renaming responses file: ${responsesRenameFrom} as it does not exist`) + } + + const pluginsRenameFrom = renameFrom.replace('.json', '.plugins.json') + const pluginsRenameTo = renameTo.replace('.json', '.plugins.json') + + try { + await fs.access(pluginsRenameFrom) + await fs.rename(pluginsRenameFrom, pluginsRenameTo) + } catch (err) { + console.log(`Skipping renaming plugins file: ${pluginsRenameFrom} as it does not exist`) } console.log(`Renamed ${renameFrom} to ${renameTo}`) @@ -213,12 +224,34 @@ async function updateCollection(workspace, collectionId, updatedFields) { let renameTo = `${updatedFields.parentId != null ? idMap.get(updatedFields.parentId) : workspace.location}/${path.basename(collectionPath)}` await fs.rename(renameFrom, renameTo) idMap.set(collectionId, renameTo) - // if folder, we also need to update idMap with the new parent folder for all children inside this folder, else they'll have the old parent path in their id - // and will error out when trying to update them - const stats = await fs.stat(renameTo) - if (stats.isDirectory()) { + + // endsWith('.json') means it's a file, else it's a folder + if (renameFrom.endsWith('.json')) { + const responsesRenameFrom = renameFrom.replace('.json', '.responses.json') + const responsesRenameTo = renameTo.replace('.json', '.responses.json') + + try { + await fs.access(responsesRenameFrom) + await fs.rename(responsesRenameFrom, responsesRenameTo) + } catch (err) { + console.log(`Skipping renaming responses file: ${responsesRenameFrom} as it does not exist`) + } + + const pluginsRenameFrom = renameFrom.replace('.json', '.plugins.json') + const pluginsRenameTo = renameTo.replace('.json', '.plugins.json') + + try { + await fs.access(pluginsRenameFrom) + await fs.rename(pluginsRenameFrom, pluginsRenameTo) + } catch (err) { + console.log(`Skipping renaming plugins file: ${pluginsRenameFrom} as it does not exist`) + } + } else { + // if folder, we also need to update idMap with the new parent folder for all children inside this folder, else they'll have the old parent path in their id + // and will error out when trying to update them await updateIdMapForChildren(renameFrom, renameTo) } + console.log(`Moved ${renameFrom} to ${renameTo}`) return } @@ -336,7 +369,8 @@ async function getResponsesByCollectionId(workspace, collectionId) { responses.forEach((response) => { response.buffer = Buffer.from(response.buffer, 'base64') }) - return responses + // reverse the responses so that the latest response is shown first + return responses.reverse() } return [] @@ -477,6 +511,190 @@ async function deleteResponsesByCollectionId(workspace, collectionId) { await fs.rm(responsesPath) } +async function getWorkspacePlugins(workspace) { + console.log('getWorkspacePlugins', { + workspace, + }) + + const items = [] + + // Workspace Plugins + const workspacePluginsPath = `${workspace.location}/_.plugins.json` + try { + const workspacePluginsData = JSON.parse(await fs.readFile(workspacePluginsPath, 'utf8')) + workspacePluginsData.forEach((plugin) => { + plugin.workspaceId = workspace._id + }) + items.push(...workspacePluginsData) + } catch (err) { + // If there is no plugins file for a workspace, it's fine, just continue + } + + // Collection and Folder Plugins + const collectionItems = await getCollection(workspace) + for (const item of collectionItems) { + if (item._type === 'request_group') { + const collectionPluginsPath = `${item._id}/_.plugins.json` + try { + const collectionPluginsData = JSON.parse(await fs.readFile(collectionPluginsPath, 'utf8')) + collectionPluginsData.forEach((plugin) => { + plugin.collectionId = item._id + }) + items.push(...collectionPluginsData) + } catch (err) { + // If there is no plugins file for a collection, it's fine, just continue + } + } else { + const itemPluginsPath = item._id.replace('.json', '.plugins.json') + try { + const itemPluginsData = JSON.parse(await fs.readFile(itemPluginsPath, 'utf8')) + itemPluginsData.forEach((plugin) => { + plugin.collectionId = item._id + }) + items.push(...itemPluginsData) + } catch (err) { + // If there is no plugins file for an item, it's fine, just continue + } + } + } + + return items +} + +async function createPlugin(workspace, plugin) { + console.log('createPlugin', { + workspace, + plugin, + }) + + let pluginPath = '' + if (plugin.collectionId) { + const collectionPath = idMap.get(plugin.collectionId) + const stats = await fs.stat(collectionPath) + if (stats.isDirectory()) { + pluginPath = `${collectionPath}/_.plugins.json` + } else { + const collectionItemName = path.basename(collectionPath, '.json') + const collectionPathParentPath = path.dirname(collectionPath) + pluginPath = `${collectionPathParentPath}/${collectionItemName}.plugins.json` + } + } else { + pluginPath = `${workspace.location}/_.plugins.json` + } + + try { + let existingPlugins = [] + try { + existingPlugins = JSON.parse(await fs.readFile(pluginPath, 'utf8')) + } catch (err) { + // If file doesn't exist, we will create a new one + } + existingPlugins.push(plugin) + await fs.writeFile(pluginPath, JSON.stringify(existingPlugins, null, 4)) + console.log(`Plugin created at: ${pluginPath}`) + } catch (err) { + console.error(`Error creating plugin in: ${pluginPath}`, err) + } +} + +async function updatePlugin(workspace, collectionId, pluginId, updatedFields) { + console.log('updatePlugin', { + workspace, + collectionId, + pluginId, + updatedFields, + }) + + const collectionPath = idMap.get(collectionId) + const pluginPath = collectionPath.endsWith('.json') ? collectionPath.replace('.json', '.plugins.json') : `${collectionPath}/_.plugins.json` + + try { + const existingPlugins = JSON.parse(await fs.readFile(pluginPath, 'utf8')) + const pluginIndex = existingPlugins.findIndex(plugin => plugin._id === pluginId) + + if (pluginIndex !== -1) { + existingPlugins[pluginIndex] = { ...existingPlugins[pluginIndex], ...updatedFields } + await fs.writeFile(pluginPath, JSON.stringify(existingPlugins, null, 4)) + console.log(`Plugin ${pluginId} updated in ${pluginPath}`) + } else { + console.log(`Plugin ${pluginId} not found for update in ${pluginPath}`) + } + } catch (err) { + console.error(`Error updating plugin ${pluginId} in ${pluginPath}`, err) + } +} + +async function deletePlugin(workspace, collectionId, pluginId) { + console.log('deletePlugin', { + workspace, + collectionId, + pluginId, + }) + + const collectionPath = idMap.get(collectionId) + const pluginPath = collectionPath.endsWith('.json') ? collectionPath.replace('.json', '.plugins.json') : `${collectionPath}/_.plugins.json` + + try { + let existingPlugins = JSON.parse(await fs.readFile(pluginPath, 'utf8')) + const filteredPlugins = existingPlugins.filter(plugin => plugin._id !== pluginId) + + if (filteredPlugins.length < existingPlugins.length) { + await fs.writeFile(pluginPath, JSON.stringify(filteredPlugins, null, 4)) + console.log(`Plugin ${pluginId} deleted in${pluginPath}`) + } else { + console.log(`Plugin ${pluginId} not found for deletion in ${pluginPath}`) + } + } catch (err) { + console.error(`Error deleting plugin ${pluginId} in ${pluginPath}`, err) + } +} + +async function deletePluginsByWorkspace(workspace) { + console.log('deletePluginsByWorkspace', { + workspace, + }) + + const workspacePluginsPath = `${workspace.location}/_.plugins.json` + try { + await fs.access(workspacePluginsPath) + await fs.unlink(workspacePluginsPath) + console.log(`All workspace plugins deleted: ${workspace.location}`) + } catch (err) { + console.log(`No workspace plugins found for deletion in: ${workspace.location}`) + } +} + +async function deletePluginsByCollectionIds(workspace, collectionIds) { + console.log('deletePluginsByCollectionIds', { + workspace, + collectionIds, + }) + + for (const collectionId of collectionIds) { + const collectionPath = idMap.get(collectionId) + const pluginPath = collectionPath.endsWith('_.json') ? `${path.dirname(collectionPath)}/_.plugins.json` : collectionPath.replace('.json', '.plugins.json') + + try { + await fs.access(pluginPath) + await fs.unlink(pluginPath) + console.log(`Deleted plugins for collection: ${collectionId}`) + } catch(err) { + console.log(`No plugins found for deletion for collection: ${collectionId}`) + } + } +} + +async function createPlugins(workspace, plugins) { + console.log('createPlugins', { + workspace, + plugins, + }) + + for (const plugin of plugins) { + await createPlugin(workspace, plugin) + } +} + module.exports = { getCollectionForWorkspace, getCollectionById, @@ -492,4 +710,11 @@ module.exports = { deleteResponsesByIds, deleteResponsesByCollectionIds, deleteResponsesByCollectionId, + getWorkspacePlugins, + createPlugin, + updatePlugin, + deletePlugin, + deletePluginsByWorkspace, + deletePluginsByCollectionIds, + createPlugins, } diff --git a/packages/electron/src/preload.js b/packages/electron/src/preload.js index 922c1da5..16c8026c 100644 --- a/packages/electron/src/preload.js +++ b/packages/electron/src/preload.js @@ -1,57 +1,35 @@ const { contextBridge, ipcRenderer } = require('electron') -contextBridge.exposeInMainWorld ( - 'electronIPC', { - sendRequest(data) { - return ipcRenderer.invoke('sendRequest', data) - }, - cancelRequest(requestId) { - return ipcRenderer.invoke('cancelRequest', requestId) - }, - getCollectionForWorkspace(...args) { - return ipcRenderer.invoke('getCollectionForWorkspace', ...args) - }, - getCollectionById(...args) { - return ipcRenderer.invoke('getCollectionById', ...args) - }, - createCollection(...args) { - return ipcRenderer.invoke('createCollection', ...args) - }, - createCollections(...args) { - return ipcRenderer.invoke('createCollections', ...args) - }, - updateCollection(...args) { - return ipcRenderer.invoke('updateCollection', ...args) - }, - deleteCollectionsByWorkspaceId(...args) { - return ipcRenderer.invoke('deleteCollectionsByWorkspaceId', ...args) - }, - deleteCollectionsByIds(...args) { - return ipcRenderer.invoke('deleteCollectionsByIds', ...args) - }, - getResponsesByCollectionId(...args) { - return ipcRenderer.invoke('getResponsesByCollectionId', ...args) - }, - createResponse(...args) { - return ipcRenderer.invoke('createResponse', ...args) - }, - updateResponse(...args) { - return ipcRenderer.invoke('updateResponse', ...args) - }, - deleteResponse(...args) { - return ipcRenderer.invoke('deleteResponse', ...args) - }, - deleteResponsesByIds(...args) { - return ipcRenderer.invoke('deleteResponsesByIds', ...args) - }, - deleteResponsesByCollectionIds(...args) { - return ipcRenderer.invoke('deleteResponsesByCollectionIds', ...args) - }, - deleteResponsesByCollectionId(...args) { - return ipcRenderer.invoke('deleteResponsesByCollectionId', ...args) - }, - openFolderSelectionDialog(...args) { - return ipcRenderer.invoke('openFolderSelectionDialog', ...args) - }, - } -) +const ipcFunctions = [ + 'sendRequest', + 'cancelRequest', + 'getCollectionForWorkspace', + 'getCollectionById', + 'createCollection', + 'createCollections', + 'updateCollection', + 'deleteCollectionsByWorkspaceId', + 'deleteCollectionsByIds', + 'getResponsesByCollectionId', + 'createResponse', + 'updateResponse', + 'deleteResponse', + 'deleteResponsesByIds', + 'deleteResponsesByCollectionIds', + 'deleteResponsesByCollectionId', + 'getWorkspacePlugins', + 'createPlugin', + 'updatePlugin', + 'deletePlugin', + 'deletePluginsByWorkspace', + 'deletePluginsByCollectionIds', + 'createPlugins', + 'openFolderSelectionDialog', +] + +const electronIPC = ipcFunctions.reduce((acc, funcName) => { + acc[funcName] = (...args) => ipcRenderer.invoke(funcName, ...args) + return acc +}, {}) + +contextBridge.exposeInMainWorld('electronIPC', electronIPC) diff --git a/packages/ui/src/App.vue b/packages/ui/src/App.vue index 1fae7b26..df4d56b1 100644 --- a/packages/ui/src/App.vue +++ b/packages/ui/src/App.vue @@ -265,7 +265,7 @@ export default { } }, async created() { - this.$store.dispatch('loadPlugins') + this.$store.dispatch('loadGlobalPlugins') await this.$store.dispatch('loadWorkspaces') if(import.meta.env.MODE === 'desktop' || import.meta.env.MODE === 'desktop-electron' || import.meta.env.MODE === 'web-standalone') { diff --git a/packages/ui/src/components/NavBar.vue b/packages/ui/src/components/NavBar.vue index 387289a7..33620dfa 100644 --- a/packages/ui/src/components/NavBar.vue +++ b/packages/ui/src/components/NavBar.vue @@ -140,7 +140,7 @@ export default { async exportCollection() { const collection = await getCollectionForWorkspace(this.activeWorkspace._id) for(const item of collection) { - item.plugins = this.$store.state.plugins.filter(plugin => plugin.collectionId === item._id) + item.plugins = this.$store.state.plugins.workspace.filter(plugin => plugin.collectionId === item._id) } exportRestfoxCollection(collection, this.activeWorkspace.environments) }, diff --git a/packages/ui/src/components/Sidebar.vue b/packages/ui/src/components/Sidebar.vue index ddf542f2..10224b0c 100644 --- a/packages/ui/src/components/Sidebar.vue +++ b/packages/ui/src/components/Sidebar.vue @@ -304,7 +304,7 @@ export default { collectionItemToExport.parentId = null const collection = flattenTree([collectionItemToExport]) for(const item of collection) { - item.plugins = this.$store.state.plugins.filter(plugin => plugin.collectionId === item._id) + item.plugins = this.$store.state.plugins.workspace.filter(plugin => plugin.collectionId === item._id) } exportRestfoxCollection(collection) } diff --git a/packages/ui/src/components/modals/PluginManagerModal.vue b/packages/ui/src/components/modals/PluginManagerModal.vue index 7ef013d2..02dda8eb 100644 --- a/packages/ui/src/components/modals/PluginManagerModal.vue +++ b/packages/ui/src/components/modals/PluginManagerModal.vue @@ -134,21 +134,17 @@ export default { } }, plugins() { - let plugins = this.$store.state.plugins.filter(plugin => !plugin.workspaceId) - if(this.collectionItem) { - plugins = plugins.filter(plugin => plugin.collectionId === this.collectionItem._id) - } else { - plugins = plugins.filter(plugin => !plugin.collectionId) + return this.$store.state.plugins.workspace.filter(plugin => plugin.collectionId === this.collectionItem._id) } - return plugins + return this.$store.state.plugins.global }, currentWorkspacePlugins() { if(!this.activeWorkspace) { return [] } - return this.$store.state.plugins.filter(plugin => plugin.workspaceId === this.activeWorkspace._id) + return this.$store.state.plugins.workspace.filter(plugin => plugin.workspaceId === this.activeWorkspace._id) }, activeWorkspace() { return this.$store.state.activeWorkspace diff --git a/packages/ui/src/db.ts b/packages/ui/src/db.ts index 04a8f234..6ff4f8f7 100644 --- a/packages/ui/src/db.ts +++ b/packages/ui/src/db.ts @@ -236,31 +236,94 @@ export async function deleteResponsesByCollectionId(workspaceId, collectionId) { // Plugins -export async function getAllPlugins() { - return db.plugins.toArray() +export async function getGlobalPlugins() { + // we can't use where here because where null of workspaceId and collectionId is not supported by indexedDB + const allPlugins = await db.plugins.toArray() + return allPlugins.filter(plugin => plugin.workspaceId == null && plugin.collectionId == null) } -export async function createPlugin(plugin) { +export async function getWorkspacePlugins(workspaceId: string) { + if(import.meta.env.MODE === 'desktop-electron') { + const workspace = await db.workspaces.get(workspaceId) + if (workspace._type === 'file') { + return window.electronIPC.getWorkspacePlugins(workspace) + } + } + + const workspacePlugins = await db.plugins.where({ workspaceId }).toArray() + + const collectionIds = await getAllCollectionIdsForGivenWorkspace(workspaceId) + const collectionItemPlugins = await db.plugins.where('collectionId').anyOf(collectionIds).toArray() + + return [ + ...workspacePlugins, + ...collectionItemPlugins + ] +} + +export async function createPlugin(plugin, workspaceId=null) { + if(import.meta.env.MODE === 'desktop-electron' && workspaceId !== null) { + const workspace = await db.workspaces.get(workspaceId) + if (workspace._type === 'file') { + return window.electronIPC.createPlugin(workspace, plugin) + } + } + await db.plugins.put(plugin) } -export async function updatePlugin(pluginId, updatedFields) { +export async function updatePlugin(pluginId, updatedFields, workspaceId=null, collectionId=null) { + if(import.meta.env.MODE === 'desktop-electron' && workspaceId !== null) { + const workspace = await db.workspaces.get(workspaceId) + if (workspace._type === 'file') { + return window.electronIPC.updatePlugin(workspace, collectionId, pluginId, updatedFields) + } + } + await db.plugins.update(pluginId, updatedFields) } -export async function deletePlugin(pluginId) { +export async function deletePlugin(pluginId, workspaceId=null, collectionId=null) { + if(import.meta.env.MODE === 'desktop-electron' && workspaceId !== null) { + const workspace = await db.workspaces.get(workspaceId) + if (workspace._type === 'file') { + return window.electronIPC.deletePlugin(workspace, collectionId, pluginId) + } + } + await db.plugins.where({ _id: pluginId }).delete() } export async function deletePluginsByWorkspace(workspaceId) { + if(import.meta.env.MODE === 'desktop-electron') { + const workspace = await db.workspaces.get(workspaceId) + if (workspace._type === 'file') { + return window.electronIPC.deletePluginsByWorkspace(workspace) + } + } + await db.plugins.where({ workspaceId }).delete() } -export async function deletePluginsByCollectionIds(collectionIds) { +export async function deletePluginsByCollectionIds(workspaceId, collectionIds) { + if(import.meta.env.MODE === 'desktop-electron') { + const workspace = await db.workspaces.get(workspaceId) + if (workspace._type === 'file') { + return window.electronIPC.deletePluginsByCollectionIds(workspace, collectionIds) + } + } + await db.plugins.where('collectionId').anyOf(collectionIds).delete() } // used for import -export async function createPlugins(plugin) { +export async function createPlugins(plugin, workspaceId=null) { + if(import.meta.env.MODE === 'desktop-electron' && workspaceId !== null) { + const workspace = await db.workspaces.get(workspaceId) + if (workspace._type === 'file') { + return window.electronIPC.createPlugins(workspace, plugin) + } + } + await db.plugins.bulkPut(plugin) } diff --git a/packages/ui/src/store.js b/packages/ui/src/store.js index bd4cdd89..eddeda34 100644 --- a/packages/ui/src/store.js +++ b/packages/ui/src/store.js @@ -38,7 +38,8 @@ import { deletePluginsByCollectionIds, modifyCollections, deleteCollectionsByWorkspaceId, - getAllPlugins, + getGlobalPlugins, + getWorkspacePlugins, deleteCollectionsByIds, createPlugin, updatePlugin, @@ -211,7 +212,10 @@ const store = createStore({ sidebarContextMenuElement: null, workspaces: [], activeWorkspace: null, - plugins: [], + plugins: { + global: [], + workspace: [], + }, requestResponseLayout: 'left-right', theme: 'light', githubStarCount: '0', @@ -238,7 +242,7 @@ const store = createStore({ return state.collectionTree }, enabledPlugins(state) { - return state.plugins.filter(plugin => plugin.enabled) + return [...state.plugins.global, ...state.plugins.workspace].filter(plugin => plugin.enabled) } }, mutations: { @@ -396,11 +400,14 @@ const store = createStore({ setWorkspaces(state, workspaces) { state.workspaces = workspaces }, - setActiveWorkspace(state, workspace) { + async setActiveWorkspace(state, workspace) { state.activeWorkspace = workspace if(workspace === null) { state.tabs = [] state.activeTab = null + state.plugins.workspace = [] + } else { + state.plugins.workspace = await getWorkspacePlugins(workspace._id) } }, async addPlugin(state, plugin) { @@ -414,8 +421,15 @@ const store = createStore({ createdAt: new Date().getTime(), updatedAt: new Date().getTime() } - await createPlugin(newPlugin) - state.plugins.push(newPlugin) + + + if(newPlugin.workspaceId === null && newPlugin.collectionId === null) { + await createPlugin(newPlugin) + state.plugins.global.push(newPlugin) + } else { + await createPlugin(newPlugin, state.activeWorkspace._id) + state.plugins.workspace.push(newPlugin) + } }, async updatePlugin(state, plugin) { const updatePluginData = { @@ -424,21 +438,41 @@ const store = createStore({ workspaceId: plugin.workspaceId, updatedAt: new Date().getTime() } - await updatePlugin(plugin._id, updatePluginData) - const foundPlugin = state.plugins.find(item => item._id === plugin._id) + + const foundPlugin = [...state.plugins.global, ...state.plugins.workspace].find(item => item._id === plugin._id) + + if(foundPlugin.workspaceId === null && foundPlugin.collectionId === null) { + await updatePlugin(plugin._id, updatePluginData) + } else { + await updatePlugin(plugin._id, updatePluginData, state.activeWorkspace._id, foundPlugin.collectionId ?? null) + } + foundPlugin.name = updatePluginData.name foundPlugin.code = updatePluginData.code foundPlugin.workspaceId = updatePluginData.workspaceId foundPlugin.updatedAt = updatePluginData.updatedAt }, async updatePluginStatus(state, plugin) { - await updatePlugin(plugin._id, { enabled: plugin.enabled }) - const foundPlugin = state.plugins.find(item => item._id === plugin._id) + const foundPlugin = [...state.plugins.global, ...state.plugins.workspace].find(item => item._id === plugin._id) + + if(foundPlugin.workspaceId === null && foundPlugin.collectionId === null) { + await updatePlugin(plugin._id, { enabled: plugin.enabled }) + } else { + await updatePlugin(plugin._id, { enabled: plugin.enabled }, state.activeWorkspace._id, foundPlugin.collectionId ?? null) + } + foundPlugin.enabled = plugin.enabled }, async deletePlugin(state, pluginId) { - await deletePlugin(pluginId) - state.plugins = state.plugins.filter(plugin => plugin._id !== pluginId) + const foundPlugin = [...state.plugins.global, ...state.plugins.workspace].find(item => item._id === pluginId) + + if(foundPlugin.workspaceId === null && foundPlugin.collectionId === null) { + await deletePlugin(pluginId) + state.plugins.global = state.plugins.global.filter(plugin => plugin._id !== pluginId) + } else { + await deletePlugin(pluginId, state.activeWorkspace._id, foundPlugin.collectionId ?? null) + state.plugins.workspace = state.plugins.workspace.filter(plugin => plugin._id !== pluginId) + } }, async saveResponse(state, response) { if(response._id) { @@ -485,8 +519,8 @@ const store = createStore({ async deleteCollectionItem(context, collectionItem) { const childIds = getChildIds(context.state.collection, collectionItem._id) await deleteResponsesByCollectionIds(collectionItem.workspaceId, childIds) - await deletePluginsByCollectionIds(childIds) - context.state.plugins = context.state.plugins.filter(plugin => childIds.includes(plugin.collectionId) === false) + await deletePluginsByCollectionIds(collectionItem.workspaceId, childIds) + context.state.plugins.workspace = context.state.plugins.workspace.filter(plugin => childIds.includes(plugin.collectionId) === false) await deleteCollectionsByIds(context.state.activeWorkspace._id, childIds) await removeFromTree(context.state.collectionTree, '_id', collectionItem._id) childIds.forEach(childId => { @@ -652,9 +686,8 @@ const store = createStore({ updateCollection(item.workspaceId, item._id, { sortOrder: index }) }) }, - async loadPlugins(context) { - const plugins = await getAllPlugins() - context.state.plugins = plugins + async loadGlobalPlugins(context) { + context.state.plugins.global = await getGlobalPlugins() }, async getEnvironmentForRequest(context, request) { let requestParentArray = [] @@ -748,10 +781,10 @@ const store = createStore({ async deleteWorkspace(context, workspaceId) { const collectionIds = await getAllCollectionIdsForGivenWorkspace(workspaceId) await deleteResponsesByCollectionIds(workspaceId, collectionIds) - await deletePluginsByCollectionIds(collectionIds) - context.state.plugins = context.state.plugins.filter(plugin => collectionIds.includes(plugin.collectionId) === false) + await deletePluginsByCollectionIds(workspaceId, collectionIds) + context.state.plugins.workspace = context.state.plugins.workspace.filter(plugin => collectionIds.includes(plugin.collectionId) === false) await deletePluginsByWorkspace(workspaceId) - context.state.plugins = context.state.plugins.filter(plugin => plugin.workspaceId !== workspaceId) + context.state.plugins.workspace = context.state.plugins.workspace.filter(plugin => plugin.workspaceId !== workspaceId) await deleteCollectionsByWorkspaceId(workspaceId) await deleteWorkspace(workspaceId) context.state.workspaces = context.state.workspaces.filter(item => item._id !== workspaceId) @@ -829,8 +862,8 @@ const store = createStore({ plugin.createdAt = new Date().getTime() plugin.updatedAt = new Date().getTime() }) - await createPlugins(plugins) - context.state.plugins.push(...plugins) + await createPlugins(plugins, context.state.activeWorkspace._id) + context.state.plugins.workspace.push(...plugins) } context.commit('setCollection', await getCollectionForWorkspace(context.state.activeWorkspace._id)) diff --git a/packages/ui/src/utils/array.ts b/packages/ui/src/utils/array.ts index 267fc02d..2921f437 100644 --- a/packages/ui/src/utils/array.ts +++ b/packages/ui/src/utils/array.ts @@ -1,5 +1,5 @@ export function mergeArraysByProperty(arr1: object[], arr2: object[], property: string) { - const merged = [] + const merged: any[] = [] const lookup = new Map() // Add all items from the first array to the lookup map