From 1af29ce72affbe9b6276f93f18a769f7464f4a2b Mon Sep 17 00:00:00 2001 From: Paulo Andre Azevedo Quirino Date: Fri, 12 Jul 2024 12:28:26 +0100 Subject: [PATCH 01/12] - [FP-2787](https://movai.atlassian.net/browse/FP-2787): IDE - Topics - Can't open multiple Topics tabs --- CHANGELOG.md | 1 + src/plugins/views/Tabs/hooks/useTabLayout.js | 5 ++++- src/tools/index.js | 7 ++++--- src/utils/generalFunctions.js | 10 +++++++++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99ea9ca0..d0aed391 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - [FP-2713](https://movai.atlassian.net/browse/FP-2713): App version is not defined - [QAP-3963](https://movai.atlassian.net/browse/QAP-3963): Review devcontainer configuration for lib-ide - [FP-2840](https://movai.atlassian.net/browse/FP-2840): Update ReadMe's on all apps +- [FP-2787](https://movai.atlassian.net/browse/FP-2787): IDE - Topics - Can't open multiple Topics tabs # 1.2.1 diff --git a/src/plugins/views/Tabs/hooks/useTabLayout.js b/src/plugins/views/Tabs/hooks/useTabLayout.js index 6e9633ca..4f36a84a 100644 --- a/src/plugins/views/Tabs/hooks/useTabLayout.js +++ b/src/plugins/views/Tabs/hooks/useTabLayout.js @@ -627,6 +627,7 @@ const useTabLayout = (props, dockRef) => { if (!tabFromMemory && !data.content) return; const { id, + rid, content, scope, name, @@ -638,6 +639,7 @@ const useTabLayout = (props, dockRef) => { } = tabFromMemory ?? data; tabsById.current.set(id, { id, + rid, scope, name, tabTitle, @@ -647,9 +649,10 @@ const useTabLayout = (props, dockRef) => { isDirty, tabProps }); - const tabData = { id, scope, name, tabTitle, extension }; + const tabData = { id, rid, scope, name, tabTitle, extension }; return { id: id, + rid: rid, title: _getCustomTab(tabData, _closeTab, isDirty), content: content, closable: true diff --git a/src/tools/index.js b/src/tools/index.js index 2dff2ce8..ea5962ab 100644 --- a/src/tools/index.js +++ b/src/tools/index.js @@ -10,11 +10,12 @@ export const addTool = (name, tool) => { export const getToolTabData = (tab, props = {}) => { const { id, name } = tab; + const { rid = id } = tab; const notInstalledTab = getTabData(id, name); - const data = id in APP_TOOLS ? APP_TOOLS[id].tabData : notInstalledTab; + const data = rid in APP_TOOLS ? APP_TOOLS[rid].tabData : notInstalledTab; // Sanitize tab data to avoid TypeError: Converting circular structure to JSON if (!data.content) { - const plugin = PluginManagerIDE.getPlugin(id); + const plugin = PluginManagerIDE.getPlugin(rid); data.content = plugin.render(props) || notInstalledTab.content; } if (props.tabTitle) data.name = props.tabTitle; @@ -24,7 +25,7 @@ export const getToolTabData = (tab, props = {}) => { data.content = React.cloneElement(data.content, mergedProps); } - return data; + return { ...data, ...tab }; }; export const hasTool = name => { diff --git a/src/utils/generalFunctions.js b/src/utils/generalFunctions.js index 7ec837a5..99fe69b9 100644 --- a/src/utils/generalFunctions.js +++ b/src/utils/generalFunctions.js @@ -67,14 +67,22 @@ export function aboutPopup(call, classes = {}) { }); } +const toolIds = JSON.parse(globalThis.localStorage.getItem("toolIds") ?? "{}"); + /** * Open Tool tab * @param {function} call : Plugin call method * @param {string} toolName : Tool Unique Name */ export function openTool(call, toolName = getHomeTab().id, props = {}) { - const tabData = getToolTabData({ id: toolName }, props); + const id = toolIds[toolName] = (toolIds[toolName] || 0) + 1; + const tabData = { ...getToolTabData({ rid: toolName, id: toolName + id }, props, id) }; + tabData.rid = toolName; + tabData.id += id; + tabData.name += id; + tabData.title += id; call(PLUGINS.TABS.NAME, PLUGINS.TABS.CALL.OPEN, tabData); + globalThis.localStorage.setItem("toolIds", JSON.stringify(toolIds)) } /** From 4317639cb29d62a6a329b4205b45f2a2e854cb58 Mon Sep 17 00:00:00 2001 From: Paulo Andre Azevedo Quirino Date: Mon, 29 Jul 2024 17:19:57 +0100 Subject: [PATCH 02/12] Optional multiple tools windows --- src/stories/components/Logs/Logs.jsx | 1 + src/utils/generalFunctions.js | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/stories/components/Logs/Logs.jsx b/src/stories/components/Logs/Logs.jsx index 2c6ea1cd..0eb72f98 100644 --- a/src/stories/components/Logs/Logs.jsx +++ b/src/stories/components/Logs/Logs.jsx @@ -68,6 +68,7 @@ export const getLogsToolTab = () => { name: LOGS_PROFILE.title, tabTitle: LOGS_PROFILE.title, scope: LOGS_PROFILE.name, + multiple: true, extension: "" }; }; diff --git a/src/utils/generalFunctions.js b/src/utils/generalFunctions.js index 99fe69b9..9fa4fe32 100644 --- a/src/utils/generalFunctions.js +++ b/src/utils/generalFunctions.js @@ -76,11 +76,14 @@ const toolIds = JSON.parse(globalThis.localStorage.getItem("toolIds") ?? "{}"); */ export function openTool(call, toolName = getHomeTab().id, props = {}) { const id = toolIds[toolName] = (toolIds[toolName] || 0) + 1; - const tabData = { ...getToolTabData({ rid: toolName, id: toolName + id }, props, id) }; + const tabData = { ...getToolTabData({ rid: toolName, id: toolName + id }, props) }; tabData.rid = toolName; - tabData.id += id; - tabData.name += id; - tabData.title += id; + if (tabData.multiple) { + tabData.id += id; + tabData.name += id; + tabData.title += id; + } else + tabData.id = toolName; call(PLUGINS.TABS.NAME, PLUGINS.TABS.CALL.OPEN, tabData); globalThis.localStorage.setItem("toolIds", JSON.stringify(toolIds)) } From da801f3a16fc1d483ef7c6c4a71e1f6829f9993e Mon Sep 17 00:00:00 2001 From: Paulo Andre Azevedo Quirino Date: Fri, 2 Aug 2024 13:50:08 +0100 Subject: [PATCH 03/12] Implement reusable ids, use same localStorage item --- src/plugins/views/Tabs/hooks/useTabLayout.js | 10 ++++++++++ src/tools/index.js | 9 ++++----- src/utils/generalFunctions.js | 21 +++++++++++--------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/plugins/views/Tabs/hooks/useTabLayout.js b/src/plugins/views/Tabs/hooks/useTabLayout.js index 1a2619e1..352e6c91 100644 --- a/src/plugins/views/Tabs/hooks/useTabLayout.js +++ b/src/plugins/views/Tabs/hooks/useTabLayout.js @@ -348,6 +348,16 @@ const useTabLayout = (props, dockRef) => { // Remove tab and apply new layout tabsById.current.delete(tabId); + const nid = new Number(tabId.substring(tabId.lastIndexOf("-") + 1)); + if (!isNaN(nid)) { + const toolIds = tabsById.current.get("toolIds"); + const toolIdData = toolIds[scope]; + toolIdData.free.unshift(nid); + tabsById.current.set("toolIds", { ...toolIds, [scope]: { + last: toolIdData.last, + free: toolIdData.free, + } }); + } workspaceManager.setTabs(tabsById.current); const dock = getDockFromTabId(tabId); removeTabFromStack(tabId, dock); diff --git a/src/tools/index.js b/src/tools/index.js index ea5962ab..f79a071d 100644 --- a/src/tools/index.js +++ b/src/tools/index.js @@ -9,13 +9,12 @@ export const addTool = (name, tool) => { }; export const getToolTabData = (tab, props = {}) => { - const { id, name } = tab; - const { rid = id } = tab; - const notInstalledTab = getTabData(id, name); - const data = rid in APP_TOOLS ? APP_TOOLS[rid].tabData : notInstalledTab; + const { id, name, scope } = tab; + const notInstalledTab = getTabData(scope, name); + const data = scope in APP_TOOLS ? APP_TOOLS[scope].tabData : notInstalledTab; // Sanitize tab data to avoid TypeError: Converting circular structure to JSON if (!data.content) { - const plugin = PluginManagerIDE.getPlugin(rid); + const plugin = PluginManagerIDE.getPlugin(scope); data.content = plugin.render(props) || notInstalledTab.content; } if (props.tabTitle) data.name = props.tabTitle; diff --git a/src/utils/generalFunctions.js b/src/utils/generalFunctions.js index 9fa4fe32..32cca7be 100644 --- a/src/utils/generalFunctions.js +++ b/src/utils/generalFunctions.js @@ -5,6 +5,7 @@ import movaiIconWhite from "../Branding/movai-logo-white.png"; import { getHomeTab } from "../tools/HomeTab/HomeTab"; import { getShortcutsTab } from "../tools/AppShortcuts/AppShortcuts"; import { getToolTabData } from "../tools"; +import Workspace from "./../utils/Workspace"; //======================================================================================== /* * @@ -67,25 +68,27 @@ export function aboutPopup(call, classes = {}) { }); } -const toolIds = JSON.parse(globalThis.localStorage.getItem("toolIds") ?? "{}"); - /** * Open Tool tab * @param {function} call : Plugin call method * @param {string} toolName : Tool Unique Name */ export function openTool(call, toolName = getHomeTab().id, props = {}) { - const id = toolIds[toolName] = (toolIds[toolName] || 0) + 1; - const tabData = { ...getToolTabData({ rid: toolName, id: toolName + id }, props) }; - tabData.rid = toolName; + const workspace = new Workspace(); + const tabsMap = workspace.getTabs(); + const toolIds = tabsMap.get("toolIds") ?? {}; + const toolIdData = toolIds[toolName] ?? { last: 0, free: [] }; + const id = toolIdData.free.shift() || toolIdData.last++; + const tabData = { ...getToolTabData({ scope: toolName, id: toolName + "-" + id }, props) }; if (tabData.multiple) { - tabData.id += id; - tabData.name += id; - tabData.title += id; + tabData.name += "-" + id; + tabData.title += "-" + id; } else tabData.id = toolName; call(PLUGINS.TABS.NAME, PLUGINS.TABS.CALL.OPEN, tabData); - globalThis.localStorage.setItem("toolIds", JSON.stringify(toolIds)) + + tabsMap.set("toolIds", { ...toolIds, [toolName]: toolIdData }); + workspace.setTabs(tabsMap); } /** From 6c7f08a25930339029ae5c4f53761acd3d8019f6 Mon Sep 17 00:00:00 2001 From: Paulo Andre Azevedo Quirino Date: Mon, 19 Aug 2024 14:32:33 +0100 Subject: [PATCH 04/12] Update CHANGELOG.md --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aab830d7..42095fe5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,7 @@ # v1.2.4 -- [FP-2603](https://movai.atlassian.net/browse/FP-2603): Properties dropdown closing after edit - active tab chang -e is being wrongfully triggered +- [FP-2603](https://movai.atlassian.net/browse/FP-2603): Properties dropdown closing after edit - active tab change is being wrongfully triggered - [FP-2874](https://movai.atlassian.net/browse/FP-2874): IDE app version not correct - [QAP-4055](https://movai.atlassian.net/browse/QAP-4055): Forward test coverage for lib-ide - [FP-2529](https://movai.atlassian.net/browse/FP-2529): Add data-testid to links. Added unit testing to BaseLink From 6b9cc6a5004bc663049885767248b51e58567037 Mon Sep 17 00:00:00 2001 From: Paulo Andre Azevedo Quirino Date: Wed, 21 Aug 2024 14:04:07 +0100 Subject: [PATCH 05/12] discussion_r1724717268: remove rid --- src/plugins/views/Tabs/hooks/useTabLayout.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/plugins/views/Tabs/hooks/useTabLayout.js b/src/plugins/views/Tabs/hooks/useTabLayout.js index 01e72c95..d361d197 100644 --- a/src/plugins/views/Tabs/hooks/useTabLayout.js +++ b/src/plugins/views/Tabs/hooks/useTabLayout.js @@ -645,7 +645,6 @@ const useTabLayout = (props, dockRef) => { if (!tabFromMemory && !data.content) return; const { id, - rid, content, scope, name, @@ -657,7 +656,6 @@ const useTabLayout = (props, dockRef) => { } = tabFromMemory ?? data; tabsById.current.set(id, { id, - rid, scope, name, tabTitle, @@ -667,10 +665,9 @@ const useTabLayout = (props, dockRef) => { isDirty, tabProps }); - const tabData = { id, rid, scope, name, tabTitle, extension }; + const tabData = { id, scope, name, tabTitle, extension }; return { id: id, - rid: rid, title: _getCustomTab(tabData, _closeTab, isDirty), content: content, closable: true From a84e797b5e6845bc69805ecbe89efdc9235c146f Mon Sep 17 00:00:00 2001 From: Paulo Andre Azevedo Quirino Date: Wed, 21 Aug 2024 14:05:48 +0100 Subject: [PATCH 06/12] discussion_r1724718360: nid -> numberId --- src/plugins/views/Tabs/hooks/useTabLayout.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/views/Tabs/hooks/useTabLayout.js b/src/plugins/views/Tabs/hooks/useTabLayout.js index d361d197..58fba0cd 100644 --- a/src/plugins/views/Tabs/hooks/useTabLayout.js +++ b/src/plugins/views/Tabs/hooks/useTabLayout.js @@ -356,11 +356,11 @@ const useTabLayout = (props, dockRef) => { // Remove tab and apply new layout tabsById.current.delete(tabId); - const nid = new Number(tabId.substring(tabId.lastIndexOf("-") + 1)); - if (!isNaN(nid)) { + const numberId = new Number(tabId.substring(tabId.lastIndexOf("-") + 1)); + if (!isNaN(numberId)) { const toolIds = tabsById.current.get("toolIds"); const toolIdData = toolIds[scope]; - toolIdData.free.unshift(nid); + toolIdData.free.unshift(numberId); tabsById.current.set("toolIds", { ...toolIds, [scope]: { last: toolIdData.last, free: toolIdData.free, From 8d8864549ae3e067a5186452f89abb994adf11ef Mon Sep 17 00:00:00 2001 From: Paulo Andre Azevedo Quirino Date: Wed, 21 Aug 2024 14:10:54 +0100 Subject: [PATCH 07/12] discussion_r1724724072: tabsById -> tabsByIdRef --- src/plugins/views/Tabs/hooks/useTabLayout.js | 42 ++++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/plugins/views/Tabs/hooks/useTabLayout.js b/src/plugins/views/Tabs/hooks/useTabLayout.js index 58fba0cd..9d30bb95 100644 --- a/src/plugins/views/Tabs/hooks/useTabLayout.js +++ b/src/plugins/views/Tabs/hooks/useTabLayout.js @@ -26,7 +26,7 @@ const useTabLayout = (props, dockRef) => { const activeTabId = useRef(null); const firstLoad = useRef(true); const preventReloadNewDoc = useRef(false); - const tabsById = useRef(new Map()); + const tabsByIdRef = useRef(new Map()); const [layout, setLayout] = useState({ ...DEFAULT_LAYOUT }); const { addTabToStack, removeTabFromStack, getNextTabFromStack } = useTabStack(workspaceManager); @@ -47,8 +47,8 @@ const useTabLayout = (props, dockRef) => { if (!tab.extension) { const toolName = tab.id; const tabData = getToolTabData(tab, tab.tabProps); - tabsById.current.set(tabData.id, tabData); - workspaceManager.setTabs(tabsById.current); + tabsByIdRef.current.set(tabData.id, tabData); + workspaceManager.setTabs(tabsByIdRef.current); // This fixes an issue where on first load a non editor tab // was being added to the tabStack (HomeTab) and that meant @@ -210,10 +210,10 @@ const useTabLayout = (props, dockRef) => { const tabIndex = box.tabs.findIndex(_el => _el.id === prevTabId); box.tabs[tabIndex] = tabData; box.activeId = tabData.id; - tabsById.current.delete(prevTabId); - tabsById.current.set(tabData.id, tabData); + tabsByIdRef.current.delete(prevTabId); + tabsByIdRef.current.set(tabData.id, tabData); addTabToStack(tabData, location); - workspaceManager.setTabs(tabsById.current); + workspaceManager.setTabs(tabsByIdRef.current); workspaceManager.setLayout(newLayout); } return { newLayout, box }; @@ -339,7 +339,7 @@ const useTabLayout = (props, dockRef) => { */ const _onLayoutRemoveTab = useCallback( (newLayout, tabId, forceClose) => { - const { name, scope, isNew, isDirty } = tabsById.current.get(tabId); + const { name, scope, isNew, isDirty } = tabsByIdRef.current.get(tabId); if (isDirty && !forceClose) { const document = { id: tabId, name, scope, isNew }; @@ -355,18 +355,18 @@ const useTabLayout = (props, dockRef) => { } // Remove tab and apply new layout - tabsById.current.delete(tabId); + tabsByIdRef.current.delete(tabId); const numberId = new Number(tabId.substring(tabId.lastIndexOf("-") + 1)); if (!isNaN(numberId)) { - const toolIds = tabsById.current.get("toolIds"); + const toolIds = tabsByIdRef.current.get("toolIds"); const toolIdData = toolIds[scope]; toolIdData.free.unshift(numberId); - tabsById.current.set("toolIds", { ...toolIds, [scope]: { + tabsByIdRef.current.set("toolIds", { ...toolIds, [scope]: { last: toolIdData.last, free: toolIdData.free, } }); } - workspaceManager.setTabs(tabsById.current); + workspaceManager.setTabs(tabsByIdRef.current); const dock = getDockFromTabId(tabId); removeTabFromStack(tabId, dock); applyLayout(newLayout); @@ -433,13 +433,13 @@ const useTabLayout = (props, dockRef) => { data => { const { instance: model, value: isDirty } = data; const tabId = model.getUrl(); - const currentTabData = tabsById.current.get(tabId); + const currentTabData = tabsByIdRef.current.get(tabId); const currentDirtyState = Boolean(currentTabData?.isDirty); // Doesn't trigger update if dirty state didn't change if (!currentTabData || currentDirtyState === isDirty) return; // Set new dirty state const newTabData = { ...currentTabData, isDirty: isDirty }; - tabsById.current.set(tabId, newTabData); + tabsByIdRef.current.set(tabId, newTabData); // Trigger tab update if (!dockRef.current) return; const currentTab = findTab(tabId); @@ -548,8 +548,8 @@ const useTabLayout = (props, dockRef) => { emit(PLUGINS.TABS.ON.ACTIVE_TAB_CHANGE, { id: tabData.id }); addTabToStack(tabData, tabPosition); - tabsById.current.set(tabData.id, tabData); - workspaceManager.setTabs(tabsById.current); + tabsByIdRef.current.set(tabData.id, tabData); + workspaceManager.setTabs(tabsByIdRef.current); const existingTab = findTab(tabData.id); if (existingTab) { @@ -641,7 +641,7 @@ const useTabLayout = (props, dockRef) => { */ const loadTab = useCallback( data => { - const tabFromMemory = tabsById.current.get(data.id); + const tabFromMemory = tabsByIdRef.current.get(data.id); if (!tabFromMemory && !data.content) return; const { id, @@ -654,7 +654,7 @@ const useTabLayout = (props, dockRef) => { isNew, tabProps } = tabFromMemory ?? data; - tabsById.current.set(id, { + tabsByIdRef.current.set(id, { id, scope, name, @@ -686,7 +686,7 @@ const useTabLayout = (props, dockRef) => { (newLayout, tabId, direction) => { const isActuallyTabChange = activeTabId.current !== tabId; const dock = getDockFromTabId(tabId); - const tabData = tabsById.current.get(tabId); + const tabData = tabsByIdRef.current.get(tabId); let newActiveTabId = tabId; // Attempt to close tab @@ -753,7 +753,7 @@ const useTabLayout = (props, dockRef) => { * @returns {string} active tab id */ const getActiveTab = useCallback(() => { - return tabsById.current.get(activeTabId.current); + return tabsByIdRef.current.get(activeTabId.current); }, []); /** @@ -829,7 +829,7 @@ const useTabLayout = (props, dockRef) => { layoutActiveIdIsValid(lastLayout); - tabsById.current = lastTabs; + tabsByIdRef.current = lastTabs; // Install current tabs plugins lastTabs.forEach(tab => { const { content, ...others } = tab; @@ -839,7 +839,7 @@ const useTabLayout = (props, dockRef) => { Promise.allSettled(tabs).then(_tabs => { _tabs.forEach(tab => { tab.status === "fulfilled" && - tabsById.current.set(tab.value.id, tab.value); + tabsByIdRef.current.set(tab.value.id, tab.value); }); setLayout(lastLayout); From ac1ef18f19ce511c20011640421bc2fa26ce19d0 Mon Sep 17 00:00:00 2001 From: Paulo Andre Azevedo Quirino Date: Wed, 21 Aug 2024 14:12:21 +0100 Subject: [PATCH 08/12] discussion_r1724769292: remove unused var from getToolTabData --- src/tools/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/index.js b/src/tools/index.js index f79a071d..8f99dd93 100644 --- a/src/tools/index.js +++ b/src/tools/index.js @@ -9,7 +9,7 @@ export const addTool = (name, tool) => { }; export const getToolTabData = (tab, props = {}) => { - const { id, name, scope } = tab; + const { name, scope } = tab; const notInstalledTab = getTabData(scope, name); const data = scope in APP_TOOLS ? APP_TOOLS[scope].tabData : notInstalledTab; // Sanitize tab data to avoid TypeError: Converting circular structure to JSON From 1aa8871f187de9a00bc07a54fcc5c30c02b34be5 Mon Sep 17 00:00:00 2001 From: Paulo Andre Azevedo Quirino Date: Wed, 21 Aug 2024 14:14:07 +0100 Subject: [PATCH 09/12] discussion_r1724774129: getTabData -> getNotInstalledTabData --- src/tools/NotInstalled/NotInstalled.jsx | 2 +- src/tools/index.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/NotInstalled/NotInstalled.jsx b/src/tools/NotInstalled/NotInstalled.jsx index 60137828..aba949bf 100644 --- a/src/tools/NotInstalled/NotInstalled.jsx +++ b/src/tools/NotInstalled/NotInstalled.jsx @@ -13,7 +13,7 @@ const NotInstalled = props => { export default NotInstalled; -export const getTabData = (id, name) => { +export const getNotInstalledTabData = (id, name) => { const tabTitle = name || id; return { id: id, diff --git a/src/tools/index.js b/src/tools/index.js index 8f99dd93..7a22a04b 100644 --- a/src/tools/index.js +++ b/src/tools/index.js @@ -1,6 +1,6 @@ import React from "react"; import PluginManagerIDE from "../engine/PluginManagerIDE/PluginManagerIDE"; -import { getTabData } from "./NotInstalled/NotInstalled"; +import { getNotInstalledTabData } from "./NotInstalled/NotInstalled"; const APP_TOOLS = {}; @@ -10,7 +10,7 @@ export const addTool = (name, tool) => { export const getToolTabData = (tab, props = {}) => { const { name, scope } = tab; - const notInstalledTab = getTabData(scope, name); + const notInstalledTab = getNotInstalledTabData(scope, name); const data = scope in APP_TOOLS ? APP_TOOLS[scope].tabData : notInstalledTab; // Sanitize tab data to avoid TypeError: Converting circular structure to JSON if (!data.content) { From 9afe1a9125d61ef2eadda54035f8394cc16905b0 Mon Sep 17 00:00:00 2001 From: Paulo Andre Azevedo Quirino Date: Wed, 21 Aug 2024 18:07:28 +0100 Subject: [PATCH 10/12] issuecomment-2302048848: Compute toolIds on load --- src/plugins/views/Tabs/hooks/useTabLayout.js | 12 +--- src/utils/generalFunctions.js | 61 ++++++++++++++++++-- 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/plugins/views/Tabs/hooks/useTabLayout.js b/src/plugins/views/Tabs/hooks/useTabLayout.js index 9d30bb95..667bb1e7 100644 --- a/src/plugins/views/Tabs/hooks/useTabLayout.js +++ b/src/plugins/views/Tabs/hooks/useTabLayout.js @@ -15,6 +15,7 @@ import { PLUGINS } from "../../../../utils/Constants"; import { getIconByScope } from "../../../../utils/Utils"; +import { freeToolId } from "../../../../utils/generalFunctions"; import PluginManagerIDE from "../../../../engine/PluginManagerIDE/PluginManagerIDE"; import Workspace from "../../../../utils/Workspace"; import { getToolTabData } from "../../../../tools"; @@ -356,16 +357,7 @@ const useTabLayout = (props, dockRef) => { // Remove tab and apply new layout tabsByIdRef.current.delete(tabId); - const numberId = new Number(tabId.substring(tabId.lastIndexOf("-") + 1)); - if (!isNaN(numberId)) { - const toolIds = tabsByIdRef.current.get("toolIds"); - const toolIdData = toolIds[scope]; - toolIdData.free.unshift(numberId); - tabsByIdRef.current.set("toolIds", { ...toolIds, [scope]: { - last: toolIdData.last, - free: toolIdData.free, - } }); - } + freeToolId(tabId); workspaceManager.setTabs(tabsByIdRef.current); const dock = getDockFromTabId(tabId); removeTabFromStack(tabId, dock); diff --git a/src/utils/generalFunctions.js b/src/utils/generalFunctions.js index 32cca7be..ccdbf078 100644 --- a/src/utils/generalFunctions.js +++ b/src/utils/generalFunctions.js @@ -68,17 +68,67 @@ export function aboutPopup(call, classes = {}) { }); } +function breakToolId(tabId) { + const index = tabId.search(/\d/); + const alpha = tabId.substring(0, index - 1); + + if (index < 0) + return [alpha]; + + const number = new Number(tabId.substring(index)); + + return [alpha, number]; +} + +function computeIds(tabsMap) { + const res = {}; + + for (const [tabId] of tabsMap) { + const [alpha, number] = breakToolId(tabId); + const index = tabId.search(/\d/); + if (index < 0) + continue; + const specific = res[alpha] ?? { last: 0, busy: {}, free: [] }; + specific.busy[number] = 1; + if (number > specific.last) + specific.last = number; + res[alpha] = specific; + } + + for (const toolName in res) { + const specific = res[toolName]; + for (let j = 0; j < specific.last; j++) + if (!specific.busy[j]) + specific.free.push(j); + delete specific.busy; + specific.last++; + } + + return res; +} + +const workspace = new Workspace(); +const tabsMap = workspace.getTabs(); +const toolIds = computeIds(tabsMap); + +export function freeToolId(tabId) { + const [alpha, number] = breakToolId(tabId); + + if (!number) + return; + + const toolIdData = toolIds[alpha]; + toolIdData.free.unshift(number); +} + /** * Open Tool tab * @param {function} call : Plugin call method * @param {string} toolName : Tool Unique Name */ export function openTool(call, toolName = getHomeTab().id, props = {}) { - const workspace = new Workspace(); - const tabsMap = workspace.getTabs(); - const toolIds = tabsMap.get("toolIds") ?? {}; const toolIdData = toolIds[toolName] ?? { last: 0, free: [] }; - const id = toolIdData.free.shift() || toolIdData.last++; + const id = toolIdData.free.shift() ?? toolIdData.last++; const tabData = { ...getToolTabData({ scope: toolName, id: toolName + "-" + id }, props) }; if (tabData.multiple) { tabData.name += "-" + id; @@ -87,8 +137,7 @@ export function openTool(call, toolName = getHomeTab().id, props = {}) { tabData.id = toolName; call(PLUGINS.TABS.NAME, PLUGINS.TABS.CALL.OPEN, tabData); - tabsMap.set("toolIds", { ...toolIds, [toolName]: toolIdData }); - workspace.setTabs(tabsMap); + toolIds[toolName] = toolIdData; } /** From 873e813d962b9d0c5374a040cfd1eab11721237c Mon Sep 17 00:00:00 2001 From: Paulo Andre Azevedo Quirino Date: Mon, 26 Aug 2024 09:10:54 +0100 Subject: [PATCH 11/12] Add some comments --- src/utils/generalFunctions.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/utils/generalFunctions.js b/src/utils/generalFunctions.js index ccdbf078..9ab4bb77 100644 --- a/src/utils/generalFunctions.js +++ b/src/utils/generalFunctions.js @@ -68,6 +68,7 @@ export function aboutPopup(call, classes = {}) { }); } +/* breaks a tool id into the alphabetical and numerical components */ function breakToolId(tabId) { const index = tabId.search(/\d/); const alpha = tabId.substring(0, index - 1); @@ -80,9 +81,18 @@ function breakToolId(tabId) { return [alpha, number]; } +/* get the structure from the tabsMap that will allow us + * to efficently organize tool ids. + */ function computeIds(tabsMap) { const res = {}; + /* get a map of this format: + * { + * Topics: { last: 3, busy: [2] }, + * VarsDebug: { last 2, busy: [1] }, + * } + */ for (const [tabId] of tabsMap) { const [alpha, number] = breakToolId(tabId); const index = tabId.search(/\d/); @@ -95,6 +105,12 @@ function computeIds(tabsMap) { res[alpha] = specific; } + /* turn it into: + * { + * Topics: { last: 3, free: [1] }, + * VarsDebug: { last 2, free: [] }, + * } + */ for (const toolName in res) { const specific = res[toolName]; for (let j = 0; j < specific.last; j++) @@ -111,6 +127,7 @@ const workspace = new Workspace(); const tabsMap = workspace.getTabs(); const toolIds = computeIds(tabsMap); +/* free a tool id */ export function freeToolId(tabId) { const [alpha, number] = breakToolId(tabId); From a76b1c666ca73de67dcc1397a1ac6efe267a590a Mon Sep 17 00:00:00 2001 From: Manuel Nogueira Date: Wed, 28 Aug 2024 19:22:09 +0100 Subject: [PATCH 12/12] Modified logic a bit to make it more readable --- src/plugins/views/Tabs/hooks/useTabLayout.js | 15 +-- src/plugins/views/Tabs/tabHelpers.js | 66 ++++++++++++ src/utils/generalFunctions.js | 104 ++++--------------- 3 files changed, 97 insertions(+), 88 deletions(-) create mode 100644 src/plugins/views/Tabs/tabHelpers.js diff --git a/src/plugins/views/Tabs/hooks/useTabLayout.js b/src/plugins/views/Tabs/hooks/useTabLayout.js index 667bb1e7..513c29ef 100644 --- a/src/plugins/views/Tabs/hooks/useTabLayout.js +++ b/src/plugins/views/Tabs/hooks/useTabLayout.js @@ -15,10 +15,10 @@ import { PLUGINS } from "../../../../utils/Constants"; import { getIconByScope } from "../../../../utils/Utils"; -import { freeToolId } from "../../../../utils/generalFunctions"; import PluginManagerIDE from "../../../../engine/PluginManagerIDE/PluginManagerIDE"; import Workspace from "../../../../utils/Workspace"; import { getToolTabData } from "../../../../tools"; +import { freeToolId } from "../tabHelpers"; import useTabStack from "./useTabStack"; const useTabLayout = (props, dockRef) => { @@ -55,7 +55,7 @@ const useTabLayout = (props, dockRef) => { // was being added to the tabStack (HomeTab) and that meant // that the last tab to enter tabStack would always be // HomeTab, instead of the correct last tab - if(!firstLoad.current){ + if (!firstLoad.current) { addTabToStack(tabData, DOCK_POSITIONS.DOCK); } @@ -340,7 +340,8 @@ const useTabLayout = (props, dockRef) => { */ const _onLayoutRemoveTab = useCallback( (newLayout, tabId, forceClose) => { - const { name, scope, isNew, isDirty } = tabsByIdRef.current.get(tabId); + const { name, scope, isNew, isDirty, tabIncrement } = + tabsByIdRef.current.get(tabId); if (isDirty && !forceClose) { const document = { id: tabId, name, scope, isNew }; @@ -357,7 +358,7 @@ const useTabLayout = (props, dockRef) => { // Remove tab and apply new layout tabsByIdRef.current.delete(tabId); - freeToolId(tabId); + freeToolId({ scope, tabIncrement }); workspaceManager.setTabs(tabsByIdRef.current); const dock = getDockFromTabId(tabId); removeTabFromStack(tabId, dock); @@ -644,6 +645,7 @@ const useTabLayout = (props, dockRef) => { extension, isDirty, isNew, + tabIncrement, tabProps } = tabFromMemory ?? data; tabsByIdRef.current.set(id, { @@ -655,9 +657,10 @@ const useTabLayout = (props, dockRef) => { extension, isNew, isDirty, + tabIncrement, tabProps }); - const tabData = { id, scope, name, tabTitle, extension }; + const tabData = { id, scope, name, tabTitle, tabIncrement, extension }; return { id: id, title: _getCustomTab(tabData, _closeTab, isDirty), @@ -699,7 +702,7 @@ const useTabLayout = (props, dockRef) => { // Emit new active tab id if (!tabId) return; - if(isActuallyTabChange){ + if (isActuallyTabChange) { activeTabId.current = newActiveTabId; emit(PLUGINS.TABS.ON.ACTIVE_TAB_CHANGE, { id: newActiveTabId }); } diff --git a/src/plugins/views/Tabs/tabHelpers.js b/src/plugins/views/Tabs/tabHelpers.js new file mode 100644 index 00000000..cd0bde6f --- /dev/null +++ b/src/plugins/views/Tabs/tabHelpers.js @@ -0,0 +1,66 @@ +import Workspace from "./../../../utils/Workspace"; + +// This is not a new instance as Workspace is a singleton +const workspace = new Workspace(); +// Extract only the tabs that have tabIncrement +const tabsMap = [...workspace.getTabs().values()].filter(x => x.tabIncrement); +// Compute the tool tab map +export const toolIds = computeTabMap(tabsMap); + +/* get the structure from the tabsMap that will allow us + * to efficently organize tool ids. + */ +function computeTabMap(tabsMap) { + const computedToolTabMap = {}; + + /* Compute a map of this format: + * { + * Topics: { last: 3, busy: [2] }, + * VarsDebug: { last 2, busy: [1] }, + * } + */ + for (const tabData of tabsMap) { + const { scope, tabIncrement } = tabData; + + const tabIncrementStatusData = computedToolTabMap[scope] ?? { + last: 1, + busy: {}, + free: [] + }; + tabIncrementStatusData.busy[tabIncrement] = 1; + + if (tabIncrement > tabIncrementStatusData.last) + tabIncrementStatusData.last = tabIncrement; + + computedToolTabMap[scope] = tabIncrementStatusData; + } + + /* turn it into: + * { + * Topics: { last: 3, free: [1] }, + * VarsDebug: { last 2, free: [] }, + * } + */ + for (const toolScope in computedToolTabMap) { + const tabIncrementStatusData = computedToolTabMap[toolScope]; + + for (let i = 1; i < tabIncrementStatusData.last; i++) + if (!tabIncrementStatusData.busy[i]) tabIncrementStatusData.free.push(i); + + delete tabIncrementStatusData.busy; + tabIncrementStatusData.last++; + } + + return computedToolTabMap; +} + +/* free a tool id */ +export function freeToolId(tabData) { + if (!tabData.tabIncrement) return; + + const toolIdData = toolIds[tabData.scope]; + if (toolIdData) { + toolIdData.free.unshift(tabData.tabIncrement); + toolIdData.free.sort(); + } +} diff --git a/src/utils/generalFunctions.js b/src/utils/generalFunctions.js index 9ab4bb77..4685f554 100644 --- a/src/utils/generalFunctions.js +++ b/src/utils/generalFunctions.js @@ -1,11 +1,11 @@ import { i18n } from "@mov-ai/mov-fe-lib-react"; import AppSettings from "../App/AppSettings"; -import { PLUGINS } from "../utils/Constants"; import movaiIconWhite from "../Branding/movai-logo-white.png"; +import { PLUGINS } from "../utils/Constants"; +import { toolIds } from "../plugins/views/Tabs/tabHelpers"; import { getHomeTab } from "../tools/HomeTab/HomeTab"; import { getShortcutsTab } from "../tools/AppShortcuts/AppShortcuts"; import { getToolTabData } from "../tools"; -import Workspace from "./../utils/Workspace"; //======================================================================================== /* * @@ -68,93 +68,33 @@ export function aboutPopup(call, classes = {}) { }); } -/* breaks a tool id into the alphabetical and numerical components */ -function breakToolId(tabId) { - const index = tabId.search(/\d/); - const alpha = tabId.substring(0, index - 1); - - if (index < 0) - return [alpha]; - - const number = new Number(tabId.substring(index)); - - return [alpha, number]; -} - -/* get the structure from the tabsMap that will allow us - * to efficently organize tool ids. +/** + * Open Tool tab + * @param {function} call : Plugin call method + * @param {string} toolScope : Tool Unique Scope */ -function computeIds(tabsMap) { - const res = {}; +export function openTool(call, toolScope = getHomeTab().scope, props = {}) { + const tabData = getToolTabData({ scope: toolScope }, props); - /* get a map of this format: - * { - * Topics: { last: 3, busy: [2] }, - * VarsDebug: { last 2, busy: [1] }, - * } - */ - for (const [tabId] of tabsMap) { - const [alpha, number] = breakToolId(tabId); - const index = tabId.search(/\d/); - if (index < 0) - continue; - const specific = res[alpha] ?? { last: 0, busy: {}, free: [] }; - specific.busy[number] = 1; - if (number > specific.last) - specific.last = number; - res[alpha] = specific; - } + if (tabData.tabIncrement) { + const toolIdData = toolIds[toolScope] ?? { last: 1, free: [] }; + const currentIncrement = toolIdData.free.shift() ?? toolIdData.last++; - /* turn it into: - * { - * Topics: { last: 3, free: [1] }, - * VarsDebug: { last 2, free: [] }, - * } - */ - for (const toolName in res) { - const specific = res[toolName]; - for (let j = 0; j < specific.last; j++) - if (!specific.busy[j]) - specific.free.push(j); - delete specific.busy; - specific.last++; - } + tabData.id += "_" + currentIncrement; - return res; -} - -const workspace = new Workspace(); -const tabsMap = workspace.getTabs(); -const toolIds = computeIds(tabsMap); - -/* free a tool id */ -export function freeToolId(tabId) { - const [alpha, number] = breakToolId(tabId); + // We don't want to have a Topics 1. + // First opened tool should be just the tool name. + // From then on, yes, increment, so Topics, Topics 2, etc. + if (currentIncrement > 1) { + tabData.name += " " + currentIncrement; + tabData.title += " " + currentIncrement; + tabData.tabIncrement = currentIncrement; + } - if (!number) - return; - - const toolIdData = toolIds[alpha]; - toolIdData.free.unshift(number); -} + toolIds[toolScope] = toolIdData; + } -/** - * Open Tool tab - * @param {function} call : Plugin call method - * @param {string} toolName : Tool Unique Name - */ -export function openTool(call, toolName = getHomeTab().id, props = {}) { - const toolIdData = toolIds[toolName] ?? { last: 0, free: [] }; - const id = toolIdData.free.shift() ?? toolIdData.last++; - const tabData = { ...getToolTabData({ scope: toolName, id: toolName + "-" + id }, props) }; - if (tabData.multiple) { - tabData.name += "-" + id; - tabData.title += "-" + id; - } else - tabData.id = toolName; call(PLUGINS.TABS.NAME, PLUGINS.TABS.CALL.OPEN, tabData); - - toolIds[toolName] = toolIdData; } /**