From 340b341b1e60042100a2f067ed7b71afe29b1500 Mon Sep 17 00:00:00 2001 From: Elias Kristoffer Bruvik <70512270+eliasbruvik@users.noreply.github.com> Date: Tue, 19 Nov 2024 08:28:47 +0100 Subject: [PATCH] FIX-2594 Priority servers (#2599) --- Src/WitsmlExplorer.Api/Models/Connection.cs | 1 + Src/WitsmlExplorer.Api/Models/Server.cs | 2 + .../__testUtils__/testUtils.tsx | 1 + .../components/ContentViews/ServerManager.tsx | 104 +++++++++++++++--- .../ContextMenus/BhaRunContextMenu.tsx | 3 + .../ContextMenus/CopyComponentsToServer.tsx | 4 +- .../ContextMenus/FluidContextMenu.tsx | 4 +- .../ContextMenus/FluidsReportContextMenu.tsx | 3 + .../FormationMarkerContextMenu.tsx | 3 + .../ContextMenus/LogCurveInfoContextMenu.tsx | 5 +- .../ContextMenus/LogObjectContextMenu.tsx | 3 + .../ContextMenus/LogsContextMenu.tsx | 4 +- .../ContextMenus/MessageObjectContextMenu.tsx | 3 + .../ContextMenus/MudLogContextMenu.tsx | 3 + .../ContextMenus/ObjectMenuItems.tsx | 7 +- .../ObjectsSidebarContextMenu.tsx | 4 +- .../ContextMenus/RigContextMenu.tsx | 3 + .../ContextMenus/RiskContextMenu.tsx | 3 + .../ContextMenus/TrajectoryContextMenu.tsx | 3 + .../TrajectoryStationContextMenu.tsx | 4 +- .../TubularComponentContextMenu.tsx | 4 +- .../ContextMenus/TubularContextMenu.tsx | 3 + .../ContextMenus/WbGeometryContextMenu.tsx | 3 + .../WbGeometrySectionContextMenu.tsx | 4 +- .../ContextMenus/WellContextMenu.tsx | 4 +- .../ContextMenus/WellboreContextMenu.tsx | 4 +- .../components/Modals/ObjectPickerModal.tsx | 4 +- .../components/Modals/ServerModal.tsx | 35 +++++- .../Modals/ShowLogDataOnServerModal.tsx | 4 +- .../components/Sidebar/FilterPanel.tsx | 20 +++- .../contexts/filter.tsx | 12 +- .../hooks/useServerFilter.ts | 46 ++++++++ Src/WitsmlExplorer.Frontend/models/server.ts | 4 +- .../tools/localStorageHelpers.tsx | 1 + 34 files changed, 281 insertions(+), 34 deletions(-) create mode 100644 Src/WitsmlExplorer.Frontend/hooks/useServerFilter.ts diff --git a/Src/WitsmlExplorer.Api/Models/Connection.cs b/Src/WitsmlExplorer.Api/Models/Connection.cs index 9fdfb6d4d..8d503154c 100644 --- a/Src/WitsmlExplorer.Api/Models/Connection.cs +++ b/Src/WitsmlExplorer.Api/Models/Connection.cs @@ -14,6 +14,7 @@ public Connection(Server server) CredentialIds = server.CredentialIds; Id = server.Id; DepthLogDecimals = server.DepthLogDecimals; + IsPriority = server.IsPriority; } [JsonPropertyName("usernames")] diff --git a/Src/WitsmlExplorer.Api/Models/Server.cs b/Src/WitsmlExplorer.Api/Models/Server.cs index d71951a6c..401d61a0d 100644 --- a/Src/WitsmlExplorer.Api/Models/Server.cs +++ b/Src/WitsmlExplorer.Api/Models/Server.cs @@ -25,6 +25,8 @@ public Server() : base(Guid.NewGuid()) public IList CredentialIds { get; init; } [JsonPropertyName("depthLogDecimals")] public int DepthLogDecimals { get; init; } + [JsonPropertyName("isPriority")] + public bool IsPriority { get; init; } public override string ToString() { diff --git a/Src/WitsmlExplorer.Frontend/__testUtils__/testUtils.tsx b/Src/WitsmlExplorer.Frontend/__testUtils__/testUtils.tsx index aab96cc8b..b70398cc2 100644 --- a/Src/WitsmlExplorer.Frontend/__testUtils__/testUtils.tsx +++ b/Src/WitsmlExplorer.Frontend/__testUtils__/testUtils.tsx @@ -157,6 +157,7 @@ export function getServer(overrides?: Partial): Server { roles: [], credentialIds: [], depthLogDecimals: 0, + isPriority: false, ...overrides }; } diff --git a/Src/WitsmlExplorer.Frontend/components/ContentViews/ServerManager.tsx b/Src/WitsmlExplorer.Frontend/components/ContentViews/ServerManager.tsx index 008f9e478..3f37c1d89 100644 --- a/Src/WitsmlExplorer.Frontend/components/ContentViews/ServerManager.tsx +++ b/Src/WitsmlExplorer.Frontend/components/ContentViews/ServerManager.tsx @@ -1,6 +1,7 @@ import { useIsAuthenticated } from "@azure/msal-react"; import { ButtonProps, + Switch, Table, TextField, Typography @@ -14,23 +15,31 @@ import UserCredentialsModal, { } from "components/Modals/UserCredentialsModal"; import ProgressSpinner from "components/ProgressSpinner"; import { Button } from "components/StyledComponents/Button"; +import { CommonPanelContainer } from "components/StyledComponents/Container"; import { useConnectedServer } from "contexts/connectedServerContext"; -import { getSearchRegex } from "contexts/filter"; +import { FilterContext } from "contexts/filter"; import { useLoggedInUsernames } from "contexts/loggedInUsernamesContext"; import { LoggedInUsernamesActionType } from "contexts/loggedInUsernamesReducer"; +import { UserTheme } from "contexts/operationStateReducer"; import OperationType from "contexts/operationType"; -import { useGetServers } from "hooks/query/useGetServers"; +import { getServersQueryKey, useGetServers } from "hooks/query/useGetServers"; import { useOperationState } from "hooks/useOperationState"; -import { Server, emptyServer } from "models/server"; +import { useServerFilter } from "hooks/useServerFilter"; +import { emptyServer, Server } from "models/server"; import { adminRole, getUserAppRoles, msalEnabled } from "msal/MsalAuthProvider"; -import React, { ChangeEvent, useEffect, useState } from "react"; +import React, { ChangeEvent, useContext, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { getWellsViewPath } from "routes/utils/pathBuilder"; import AuthorizationService from "services/authorizationService"; import NotificationService from "services/notificationService"; +import ServerService from "services/serverService"; import styled from "styled-components"; import { Colors } from "styles/Colors"; import Icon from "styles/Icons"; +import { + setLocalStorageItem, + STORAGE_FILTER_PRIORITYSERVERS_KEY +} from "tools/localStorageHelpers"; const NEW_SERVER_ID = "1"; @@ -42,18 +51,16 @@ const ServerManager = (): React.ReactElement => { placeholderData: [] }); const { - operationState: { colors }, + operationState: { colors, theme }, dispatchOperation } = useOperationState(); const editDisabled = msalEnabled && !getUserAppRoles().includes(adminRole); const navigate = useNavigate(); const { connectedServer, setConnectedServer } = useConnectedServer(); const { dispatchLoggedInUsernames } = useLoggedInUsernames(); - const [filter, setFilter] = useState(""); - const searchRegex = getSearchRegex(filter); - const filteredServers = servers?.filter( - (s) => !filter || searchRegex.test(s.name) || searchRegex.test(s.url) - ); + const [filterByName, setFilterByName] = useState(""); + const { selectedFilter, updateSelectedFilter } = useContext(FilterContext); + const filteredServers = useServerFilter(servers, filterByName); useEffect(() => { if (isError) { @@ -100,6 +107,36 @@ const ServerManager = (): React.ReactElement => { }); }; + const togglePriority = async (server: Server) => { + try { + // Optimistically update the query cache to avoid full rerenders and to keep the scroll position. + queryClient.setQueryData(getServersQueryKey(), (oldServers: Server[]) => + oldServers?.map((s) => + s.id === server.id ? { ...s, isPriority: !s.isPriority } : s + ) + ); + + const freshServer = await ServerService.updateServer({ + ...server, + isPriority: !server.isPriority + }); + if (freshServer) { + AuthorizationService.onServerStateChange(freshServer); + } + } catch (error) { + // Roll back on failure + queryClient.setQueryData(getServersQueryKey(), (oldServers: Server[]) => + oldServers?.map((s) => (s.id === server.id ? server : s)) + ); + + NotificationService.Instance.alertDispatcher.dispatch({ + serverUrl: null, + message: `Unable to update priority: ${error.message}`, + isSuccess: false + }); + } + }; + const CellStyle = { color: colors.interactive.primaryResting, padding: "0.3rem", @@ -144,11 +181,34 @@ const ServerManager = (): React.ReactElement => { ) => - setFilter(e.target.value) + setFilterByName(e.target.value) } /> + + { + setLocalStorageItem( + STORAGE_FILTER_PRIORITYSERVERS_KEY, + !selectedFilter.filterPriorityServers + ); + updateSelectedFilter({ + filterPriorityServers: !selectedFilter.filterPriorityServers + }); + }} + size={theme === UserTheme.Compact ? "small" : "default"} + /> + + Only show priority servers + + +