From b394cfe6057218655c9f9990da289f33d1a4a0a6 Mon Sep 17 00:00:00 2001 From: Lukas Polak Date: Tue, 22 Oct 2024 23:01:51 +0200 Subject: [PATCH 1/4] Distinguish tasks in localStorage by database --- frontend/client/custom-types.ts | 4 ++++ frontend/client/tasks/server-docking-task.tsx | 10 ++++++---- frontend/client/viewer/application.tsx | 3 --- frontend/client/viewer/components/tasks-tab.tsx | 16 ++++++++++------ .../client/viewer/components/tasks-table.tsx | 17 ++++++++++------- 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/frontend/client/custom-types.ts b/frontend/client/custom-types.ts index 96807ef..8c2cc69 100644 --- a/frontend/client/custom-types.ts +++ b/frontend/client/custom-types.ts @@ -291,4 +291,8 @@ export interface ServerTask { export interface ServerTaskLocalStorageData extends ServerTask { //potentially may contain more data discriminator: 'server'; // used to distinguish between ClientTask and ServerTask +} + +export function getLocalStorageKey(predictionInfo: PredictionInfo, key: string) { + return `${predictionInfo.id}_${predictionInfo.database}_${key}`; } \ No newline at end of file diff --git a/frontend/client/tasks/server-docking-task.tsx b/frontend/client/tasks/server-docking-task.tsx index d76b3fe..5a53d64 100644 --- a/frontend/client/tasks/server-docking-task.tsx +++ b/frontend/client/tasks/server-docking-task.tsx @@ -1,5 +1,5 @@ import { PredictionInfo, getApiEndpoint } from "../prankweb-api"; -import { PocketData, Point3D, ServerTaskInfo, ServerTaskLocalStorageData } from "../custom-types"; +import { getLocalStorageKey, PocketData, Point3D, ServerTaskInfo, ServerTaskLocalStorageData } from "../custom-types"; import { getPocketAtomCoordinates } from "../viewer/molstar-visualise"; import { PluginUIContext } from "molstar/lib/mol-plugin-ui/context"; @@ -148,9 +148,11 @@ export async function pollForDockingTask(predictionInfo: PredictionInfo) { return; }); //we could handle the error, but we do not care if the poll fails sometimes + const localStorageKey = getLocalStorageKey(predictionInfo, "serverTasks"); + if (taskStatusJSON) { //look into the local storage and check if there are any updates - let savedTasks = localStorage.getItem(`${predictionInfo.id}_serverTasks`); + let savedTasks = localStorage.getItem(localStorageKey); if (!savedTasks) savedTasks = "[]"; const tasks: ServerTaskLocalStorageData[] = JSON.parse(savedTasks); if (tasks.length === 0) return; @@ -179,12 +181,12 @@ export async function pollForDockingTask(predictionInfo: PredictionInfo) { } //save the updated tasks - localStorage.setItem(`${predictionInfo.id}_serverTasks`, JSON.stringify(tasks)); + localStorage.setItem(localStorageKey, JSON.stringify(tasks)); } } }); } - return localStorage.getItem(`${predictionInfo.id}_serverTasks`); + return localStorage.getItem(localStorageKey); } /** diff --git a/frontend/client/viewer/application.tsx b/frontend/client/viewer/application.tsx index c203537..ea2781d 100644 --- a/frontend/client/viewer/application.tsx +++ b/frontend/client/viewer/application.tsx @@ -58,9 +58,6 @@ export async function renderProteinView(predictionInfo: PredictionInfo) { visualizationToolbox.style.display = MolstarPlugin.layout.state.isExpanded ? "none" : "block"; }); - // Before rendering the data, clear the results of client-side tasks (currently removed). - // localStorage.removeItem(`${predictionInfo.id}_clientTasks`); - // Render pocket list on the right side (or bottom for smartphones) using React. const pocketListContainer = (window.innerWidth >= 768) ? document.getElementById('pocket-list-aside') : document.getElementById('pocket-list-aside-mobile'); const pocketListRoot = createRoot(pocketListContainer!); diff --git a/frontend/client/viewer/components/tasks-tab.tsx b/frontend/client/viewer/components/tasks-tab.tsx index a9f8aaf..cad91a0 100644 --- a/frontend/client/viewer/components/tasks-tab.tsx +++ b/frontend/client/viewer/components/tasks-tab.tsx @@ -4,7 +4,7 @@ import TextField from '@mui/material/TextField'; import MenuItem from '@mui/material/MenuItem'; import FormControl from '@mui/material/FormControl'; import Select, { SelectChangeEvent } from '@mui/material/Select'; -import { ClientTaskLocalStorageData, ClientTaskType, PocketData, ServerTaskLocalStorageData, ServerTaskType } from "../../custom-types"; +import { ClientTaskLocalStorageData, ClientTaskType, PocketData, ServerTaskLocalStorageData, ServerTaskType, getLocalStorageKey } from "../../custom-types"; import { Button, Paper, Typography } from "@mui/material"; import "./tasks-tab.css"; @@ -38,7 +38,9 @@ export default function TasksTab(props: { pockets: PocketData[], predictionInfo: type: TaskType.Client, name: "Volume", compute: (params, customName, pocketIndex) => { - let savedTasks = localStorage.getItem(`${props.predictionInfo.id}_clientTasks`); + const localStorageKey = getLocalStorageKey(props.predictionInfo, "clientTasks"); + + let savedTasks = localStorage.getItem(localStorageKey); if (savedTasks) { const tasks: ClientTaskLocalStorageData[] = JSON.parse(savedTasks); const task = tasks.find(task => task.pocket === (pocketIndex + 1) && task.type === ClientTaskType.Volume); @@ -50,7 +52,7 @@ export default function TasksTab(props: { pockets: PocketData[], predictionInfo: const promise = computePocketVolume(props.plugin, props.pockets[pocketIndex]); promise.then((volume: number) => { - savedTasks = localStorage.getItem(`${props.predictionInfo.id}_clientTasks`); + savedTasks = localStorage.getItem(localStorageKey); if (!savedTasks) savedTasks = "[]"; const tasks: ClientTaskLocalStorageData[] = JSON.parse(savedTasks); @@ -62,7 +64,7 @@ export default function TasksTab(props: { pockets: PocketData[], predictionInfo: "discriminator": "client", }); - localStorage.setItem(`${props.predictionInfo.id}_clientTasks`, JSON.stringify(tasks)); + localStorage.setItem(localStorageKey, JSON.stringify(tasks)); }); }, parameterDescriptions: [] @@ -106,7 +108,9 @@ export default function TasksTab(props: { pockets: PocketData[], predictionInfo: handleInvalidDockingInput(""); - let savedTasks = localStorage.getItem(`${props.predictionInfo.id}_serverTasks`); + const localStorageKey = getLocalStorageKey(props.predictionInfo, "serverTasks"); + + let savedTasks = localStorage.getItem(localStorageKey); if (!savedTasks) savedTasks = "[]"; const tasks: ServerTaskLocalStorageData[] = JSON.parse(savedTasks); tasks.push({ @@ -119,7 +123,7 @@ export default function TasksTab(props: { pockets: PocketData[], predictionInfo: "responseData": null, "discriminator": "server", }); - localStorage.setItem(`${props.predictionInfo.id}_serverTasks`, JSON.stringify(tasks)); + localStorage.setItem(localStorageKey, JSON.stringify(tasks)); const taskPostRequest = computeDockingTaskOnBackend(props.predictionInfo, props.pockets[pocketIndex], smiles, props.plugin, exhaustiveness); if (taskPostRequest === null) { tasks[tasks.length - 1].status = "failed"; diff --git a/frontend/client/viewer/components/tasks-table.tsx b/frontend/client/viewer/components/tasks-table.tsx index 67a275e..1bfda41 100644 --- a/frontend/client/viewer/components/tasks-table.tsx +++ b/frontend/client/viewer/components/tasks-table.tsx @@ -12,7 +12,7 @@ import { useInterval } from "./tools"; import "bootstrap-icons/font/bootstrap-icons.css"; import { PocketData, ServerTaskTypeVisualizationDescriptors } from "../../custom-types"; -import { ClientTaskLocalStorageData, ServerTaskLocalStorageData, ServerTaskTypeDescriptors, ClientTaskTypeDescriptors, ClientTaskType, ServerTaskType } from "../../custom-types"; +import { ClientTaskLocalStorageData, ServerTaskLocalStorageData, ServerTaskTypeDescriptors, ClientTaskTypeDescriptors, ClientTaskType, ServerTaskType, getLocalStorageKey } from "../../custom-types"; import { dockingHash, downloadDockingResult, pollForDockingTask } from "../../tasks/server-docking-task"; import { Order, getComparator, isInstanceOfClientTaskLocalStorageData, isInstanceOfServerTaskLocalStorageData } from "./tools"; import { PredictionInfo } from "../../prankweb-api"; @@ -104,12 +104,15 @@ function EnhancedTableHead(props: EnhancedTableProps) { export function TasksTable(props: { pocket: PocketData | null, predictionInfo: PredictionInfo; }) { - let serverTasks = localStorage.getItem(`${props.predictionInfo.id}_serverTasks`); + const localStorageServerKey = getLocalStorageKey(props.predictionInfo, "serverTasks"); + const localStorageClientKey = getLocalStorageKey(props.predictionInfo, "clientTasks"); + + let serverTasks = localStorage.getItem(localStorageServerKey); if (!serverTasks) serverTasks = "[]"; let serverTasksParsed: ServerTaskLocalStorageData[] = JSON.parse(serverTasks); if (props.pocket !== null) serverTasksParsed = serverTasksParsed.filter((task: ServerTaskLocalStorageData) => task.pocket === Number(props.pocket!.rank)); - let clientTasks = localStorage.getItem(`${props.predictionInfo.id}_clientTasks`); + let clientTasks = localStorage.getItem(localStorageClientKey); if (!clientTasks) clientTasks = "[]"; let clientTasksParsed: ClientTaskLocalStorageData[] = JSON.parse(clientTasks); if (props.pocket !== null) clientTasksParsed = clientTasksParsed.filter((task: ClientTaskLocalStorageData) => task.pocket === Number(props.pocket!.rank)); @@ -171,16 +174,16 @@ export function TasksTable(props: { pocket: PocketData | null, predictionInfo: P useInterval(pollDocking, 1000 * 7); const removeClientTaskFromLocalStorage = (task: ClientTaskLocalStorageData) => () => { - const clientTasksParsed: ClientTaskLocalStorageData[] = JSON.parse(localStorage.getItem(`${props.predictionInfo.id}_clientTasks`) || "[]"); + const clientTasksParsed: ClientTaskLocalStorageData[] = JSON.parse(localStorage.getItem(localStorageClientKey) || "[]"); const newClientTasks = clientTasksParsed.filter((t: ClientTaskLocalStorageData) => t.created !== task.created); - localStorage.setItem(`${props.predictionInfo.id}_clientTasks`, JSON.stringify(newClientTasks)); + localStorage.setItem(localStorageClientKey, JSON.stringify(newClientTasks)); setRender(numRenders + 1); }; const removeServerTaskFromLocalStorage = (task: ServerTaskLocalStorageData) => () => { - const serverTasksParsed: ServerTaskLocalStorageData[] = JSON.parse(localStorage.getItem(`${props.predictionInfo.id}_serverTasks`) || "[]"); + const serverTasksParsed: ServerTaskLocalStorageData[] = JSON.parse(localStorage.getItem(localStorageServerKey) || "[]"); const newServerTasks = serverTasksParsed.filter((t: ServerTaskLocalStorageData) => t.created !== task.created); - localStorage.setItem(`${props.predictionInfo.id}_serverTasks`, JSON.stringify(newServerTasks)); + localStorage.setItem(localStorageServerKey, JSON.stringify(newServerTasks)); setRender(numRenders + 1); }; From 7706585710fbc0284629c0c2e657a715452e181d Mon Sep 17 00:00:00 2001 From: Lukas Polak Date: Wed, 23 Oct 2024 18:45:54 +0200 Subject: [PATCH 2/4] Change ligand default coloring for docking visualization --- frontend/client/visualize/docking/main.tsx | 3 +-- frontend/client/visualize/docking/visualization-box.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/client/visualize/docking/main.tsx b/frontend/client/visualize/docking/main.tsx index 774d3e0..363e119 100644 --- a/frontend/client/visualize/docking/main.tsx +++ b/frontend/client/visualize/docking/main.tsx @@ -170,8 +170,7 @@ async function loadLigandIntoMolstar(plugin: PluginUIContext | undefined, docked const structure = await plugin.builders.structure.createStructure(mdl, { name: 'model', params: {} }); const representation = await plugin.builders.structure.representation.addRepresentation(structure, { type: 'ball-and-stick', - color: 'uniform', - colorParams: { value: Color(0xff00ff) }, + color: 'element-symbol' }); // hide the ligands, keep just the first model visible diff --git a/frontend/client/visualize/docking/visualization-box.tsx b/frontend/client/visualize/docking/visualization-box.tsx index e93ef6e..4ac3065 100644 --- a/frontend/client/visualize/docking/visualization-box.tsx +++ b/frontend/client/visualize/docking/visualization-box.tsx @@ -44,7 +44,7 @@ export function DockingTaskVisualizationBox({ plugin, changePocketsView, pocket, plugin.canvas3d?.requestCameraReset(); }; - const tooltipText = `Ligands shown in blue color are a part of the loaded structure.\nLigands shown in violet color are the docked ligands.\n\nNote that the bounding box does not represent the actual bounding box size and is shown for reference only.`; + const tooltipText = `Ligands shown in blue color are a part of the loaded structure.\nLigands colored by element symbols are the docked ligands.\n\nNote that the bounding box does not represent the actual bounding box size and is shown for reference only.`; return ( <> From 7cc31032fff0cb40e14d2a3bd4fdb42657689e9a Mon Sep 17 00:00:00 2001 From: Lukas Polak Date: Wed, 23 Oct 2024 19:39:25 +0200 Subject: [PATCH 3/4] Adjust docking visualization div sizes --- frontend/client/visualize/docking/main.tsx | 4 ++-- frontend/client/visualize/docking/visualization-box.tsx | 4 ++-- frontend/server/configuration.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/client/visualize/docking/main.tsx b/frontend/client/visualize/docking/main.tsx index 363e119..c5079ac 100644 --- a/frontend/client/visualize/docking/main.tsx +++ b/frontend/client/visualize/docking/main.tsx @@ -146,11 +146,11 @@ export function DockingTask(dp: DockingTaskProps) { } return
-
+
p.rank === pocketRank)} changeBoundingBoxRefs={changeBoundingBoxRefs} polymerRepresentations={polymerRepresentations} />
-
+
; diff --git a/frontend/client/visualize/docking/visualization-box.tsx b/frontend/client/visualize/docking/visualization-box.tsx index 4ac3065..47331fd 100644 --- a/frontend/client/visualize/docking/visualization-box.tsx +++ b/frontend/client/visualize/docking/visualization-box.tsx @@ -48,10 +48,10 @@ export function DockingTaskVisualizationBox({ plugin, changePocketsView, pocket, return ( <> -
+
{tooltipText}} placement="left-end"> - +
diff --git a/frontend/server/configuration.js b/frontend/server/configuration.js index c02ed6f..6e2884d 100644 --- a/frontend/server/configuration.js +++ b/frontend/server/configuration.js @@ -7,5 +7,5 @@ module.exports = { //"proxy-directory": "../../data/database/", // Use the option bellow to proxy commands to task runner instance. // This allows you to run tasks or connect to existing instance (https://prankweb.cz). - "proxy-service": "https://prankweb.cz", + "proxy-service": "http://localhost:8020", }; From 58a5fdcf3e98ba40b75ca53c4cf2cd346b7c3b7c Mon Sep 17 00:00:00 2001 From: Lukas Polak Date: Wed, 23 Oct 2024 19:53:25 +0200 Subject: [PATCH 4/4] Revert proxy-service --- frontend/server/configuration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/server/configuration.js b/frontend/server/configuration.js index 6e2884d..c02ed6f 100644 --- a/frontend/server/configuration.js +++ b/frontend/server/configuration.js @@ -7,5 +7,5 @@ module.exports = { //"proxy-directory": "../../data/database/", // Use the option bellow to proxy commands to task runner instance. // This allows you to run tasks or connect to existing instance (https://prankweb.cz). - "proxy-service": "http://localhost:8020", + "proxy-service": "https://prankweb.cz", };