From bc424f062fcd92f3000932fbfa79ae8c0b05cac0 Mon Sep 17 00:00:00 2001
From: Aurora Lahtela <24460436+AuroraLS3@users.noreply.github.com>
Date: Sun, 10 Dec 2023 09:29:01 +0200
Subject: [PATCH] 3236/vite migration (#3354)
* Migrate to Vite
* Remove asset-manifest.json which vite doesn't generate
* Fix tree-shaking removing Export URL if-blocks from services
* Implement address correction for the vite bundle
* Fixed issue with single proxy online graph 403 without page.server.overview.players.online.graph
Affects issues:
- Close #3236
---
Plan/common/build.gradle | 3 +-
.../plan/delivery/export/ReactExporter.java | 36 +-
.../rendering/BundleAddressCorrection.java | 155 +
.../delivery/rendering/pages/PageFactory.java | 16 +-
.../delivery/rendering/pages/ReactPage.java | 13 +-
.../delivery/webserver/ResponseFactory.java | 20 +-
.../delivery/webserver/ResponseResolver.java | 3 +-
.../resolver/StaticResourceResolver.java | 2 +-
.../resolver/json/GraphsJSONResolver.java | 2 +-
.../delivery/export/ExportTestUtilities.java | 2 +-
.../AccessControlVisibilityTest.java | 8 +-
Plan/react/dashboard/{public => }/index.html | 15 +-
Plan/react/dashboard/package.json | 12 +-
Plan/react/dashboard/src/{App.js => App.jsx} | 0
.../components/{CardTabs.js => CardTabs.jsx} | 0
.../{Datapoint.js => Datapoint.jsx} | 0
.../{ErrorBoundary.js => ErrorBoundary.jsx} | 0
.../{Scrollable.js => Scrollable.jsx} | 0
.../accordion/{Accordion.js => Accordion.jsx} | 0
...ErrorsAccordion.js => ErrorsAccordion.jsx} | 0
...ServerAccordion.js => ServerAccordion.jsx} | 0
...ssionAccordion.js => SessionAccordion.jsx} | 0
.../{AlertPopupArea.js => AlertPopupArea.jsx} | 0
.../alert/{QueryPath.js => QueryPath.jsx} | 0
.../animation/{LoadIn.js => LoadIn.jsx} | 0
...nCalendar.js => PlayerSessionCalendar.jsx} | 0
.../{ServerCalendar.js => ServerCalendar.jsx} | 0
.../cards/{CardHeader.js => CardHeader.jsx} | 0
...olocationsCard.js => GeolocationsCard.jsx} | 0
...0DaysCard.js => InsightsFor30DaysCard.jsx} | 0
.../{PingTableCard.js => PingTableCard.jsx} | 0
.../{PlayerListCard.js => PlayerListCard.jsx} | 0
...phCard.js => PlayerRetentionGraphCard.jsx} | 0
...inCurrentCard.js => PluginCurrentCard.jsx} | 0
...inHistoryCard.js => PluginHistoryCard.jsx} | 0
...illsTableCard.js => PvpKillsTableCard.jsx} | 0
...SessionsCard.js => RecentSessionsCard.jsx} | 0
.../{ServerPieCard.js => ServerPieCard.jsx} | 0
.../common/{TrendCard.js => TrendCard.jsx} | 0
.../{WorldPieCard.js => WorldPieCard.jsx} | 0
...raphsCard.js => PerformanceGraphsCard.jsx} | 0
...kViewDataCard.js => QuickViewDataCard.jsx} | 0
...iewGraphCard.js => QuickViewGraphCard.jsx} | 0
...rversTableCard.js => ServersTableCard.jsx} | 0
...ConnectionsCard.js => ConnectionsCard.jsx} | 0
.../{NicknamesCard.js => NicknamesCard.jsx} | 0
...OverviewCard.js => PlayerOverviewCard.jsx} | 0
...nsCard.js => PlayerRecentSessionsCard.jsx} | 0
...WorldPieCard.js => PlayerWorldPieCard.jsx} | 0
...NumbersCard.js => PvpPveAsNumbersCard.jsx} | 0
.../{FilterDropdown.js => FilterDropdown.jsx} | 0
.../query/{FilterList.js => FilterList.jsx} | 0
...eryOptionsCard.js => QueryOptionsCard.jsx} | 0
...ViewCard.js => SessionsWithinViewCard.jsx} | 0
...nDatesFilter.js => BetweenDatesFilter.jsx} | 0
.../query/filter/{Filter.js => Filter.jsx} | 0
...oiceFilter.js => MultipleChoiceFilter.jsx} | 0
...GroupsFilter.js => PluginGroupsFilter.jsx} | 0
...rbaseCard.js => CurrentPlayerbaseCard.jsx} | 0
...sGraphCard.js => JoinAddressGraphCard.jsx} | 0
...sGroupCard.js => JoinAddressGroupCard.jsx} | 0
...js => NetworkOnlineActivityGraphsCard.jsx} | 0
...ActivityCard.js => OnlineActivityCard.jsx} | 0
...hsCard.js => OnlineActivityGraphsCard.jsx} | 0
...raphsCard.js => PerformanceGraphsCard.jsx} | 0
...tCard.js => PlayerbaseDevelopmentCard.jsx} | 0
...WorldPieCard.js => ServerWorldPieCard.jsx} | 0
...Card.js => OnlineActivityInsightsCard.jsx} | 0
...htsCard.js => PerformanceInsightsCard.jsx} | 0
...ghtsCard.js => PlayerbaseInsightsCard.jsx} | 0
...InsightsCard.js => PvpPveInsightsCard.jsx} | 0
...nsightsCard.js => SessionInsightsCard.jsx} | 0
...ard.js => OnlineActivityAsNumbersCard.jsx} | 0
...rsCard.js => PerformanceAsNumbersCard.jsx} | 0
...TrendsCard.js => PlayerbaseTrendsCard.jsx} | 0
...NumbersCard.js => PvpPveAsNumbersCard.jsx} | 0
...nsCard.js => ServerRecentSessionsCard.jsx} | 0
...onCard.js => ServerWeekComparisonCard.jsx} | 0
...NumbersCard.js => ServerAsNumbersCard.jsx} | 0
.../{CurrentUptime.js => CurrentUptime.jsx} | 0
.../{ExtensionCard.js => ExtensionCard.jsx} | 0
.../{ExtensionIcon.js => ExtensionIcon.jsx} | 0
.../{ExtensionTable.js => ExtensionTable.jsx} | 0
...tionPlotGraph.js => FunctionPlotGraph.jsx} | 0
...ionBarGraph.js => GeolocationBarGraph.jsx} | 0
...ionWorldMap.js => GeolocationWorldMap.jsx} | 0
.../components/graphs/{Graph.js => Graph.jsx} | 0
.../{GroupBarGraph.js => GroupBarGraph.jsx} | 0
.../graphs/{GroupPie.js => GroupPie.jsx} | 0
...GroupVisualizer.js => GroupVisualizer.jsx} | 0
...inAddressGraph.js => JoinAddressGraph.jsx} | 0
.../graphs/{LineGraph.js => LineGraph.jsx} | 0
...PlayerPingGraph.js => PlayerPingGraph.jsx} | 0
...PlayerbaseGraph.js => PlayerbaseGraph.jsx} | 0
...sOnlineGraph.js => PlayersOnlineGraph.jsx} | 0
.../graphs/{PunchCard.js => PunchCard.jsx} | 0
.../graphs/{ServerPie.js => ServerPie.jsx} | 0
...Graph.js => StackedPlayersOnlineGraph.jsx} | 0
...TimeByTimeGraph.js => TimeByTimeGraph.jsx} | 0
.../graphs/{WorldPie.js => WorldPie.jsx} | 0
...rmanceGraph.js => AllPerformanceGraph.jsx} | 0
...nceGraph.js => CpuRamPerformanceGraph.jsx} | 0
...manceGraph.js => DiskPerformanceGraph.jsx} | 0
.../{PingGraph.js => PingGraph.jsx} | 0
...rmanceGraph.js => TpsPerformanceGraph.jsx} | 0
...anceGraph.js => WorldPerformanceGraph.jsx} | 0
.../{BasicDropdown.js => BasicDropdown.jsx} | 0
.../{DateInputField.js => DateInputField.jsx} | 0
.../input/{MultiSelect.js => MultiSelect.jsx} | 0
.../input/{SearchField.js => SearchField.jsx} | 0
.../input/{Select.js => Select.jsx} | 0
.../{TimeInputField.js => TimeInputField.jsx} | 0
.../input/{Toggle.js => Toggle.jsx} | 0
...seWithButton.js => CollapseWithButton.jsx} | 0
.../src/components/layout/{End.js => End.jsx} | 0
.../layout/{OpaqueText.js => OpaqueText.jsx} | 0
.../{SideNavTabs.js => SideNavTabs.jsx} | 0
...ableCardBody.js => ExtendableCardBody.jsx} | 0
.../{ExtendableRow.js => ExtendableRow.jsx} | 0
...electorModal.js => ColorSelectorModal.jsx} | 0
...Modal.js => FinalizeRegistrationModal.jsx} | 0
...sswordModal.js => ForgotPasswordModal.jsx} | 0
.../modal/{HelpModal.js => HelpModal.jsx} | 0
...ionModal.js => PluginInformationModal.jsx} | 0
...rListModal.js => QueryPlayerListModal.jsx} | 0
...onModal.js => VersionInformationModal.jsx} | 0
...vityIndexHelp.js => ActivityIndexHelp.jsx} | 0
...missionHelp.js => GroupPermissionHelp.jsx} | 0
...tionHelp.js => NewPlayerRetentionHelp.jsx} | 0
...phHelp.js => PlayerRetentionGraphHelp.jsx} | 0
.../navigation/{Header.js => Header.jsx} | 0
.../navigation/{Loader.js => Loader.jsx} | 0
...inPageRedirect.js => MainPageRedirect.jsx} | 0
...vigationItem.js => PageNavigationItem.jsx} | 0
.../navigation/{Sidebar.js => Sidebar.jsx} | 0
.../{AsNumbersTable.js => AsNumbersTable.jsx} | 0
...ComparisonTable.js => ComparisonTable.jsx} | 0
...DataTablesTable.js => DataTablesTable.jsx} | 0
.../table/{GroupTable.js => GroupTable.jsx} | 0
.../table/{KillsTable.js => KillsTable.jsx} | 0
...le.js => OnlineActivityAsNumbersTable.jsx} | 0
...Table.js => PerformanceAsNumbersTable.jsx} | 0
.../table/{PingTable.js => PingTable.jsx} | 0
...able.js => PlayerPvpPveAsNumbersTable.jsx} | 0
...able.js => ServerPvpPveAsNumbersTable.jsx} | 0
.../{ServersTable.js => ServersTable.jsx} | 0
.../table/{TableRow.js => TableRow.jsx} | 0
.../text/{ColoredText.js => ColoredText.jsx} | 0
.../{FormattedDate.js => FormattedDate.jsx} | 0
.../{FormattedTime.js => FormattedTime.jsx} | 0
.../trend/{BigTrend.js => BigTrend.jsx} | 0
.../{ComparingLabel.js => ComparingLabel.jsx} | 0
.../trend/{SmallTrend.js => SmallTrend.jsx} | 0
...ticationHook.js => authenticationHook.jsx} | 0
...tPopupContext.js => alertPopupContext.jsx} | 0
...js => configurationStorageContextHook.jsx} | 0
...tHook.js => dropdownStatusContextHook.jsx} | 0
...ontextHook.js => groupEditContextHook.jsx} | 0
.../{metadataHook.js => metadataHook.jsx} | 0
.../{navigationHook.js => navigationHook.jsx} | 0
...ExtensionHook.js => pageExtensionHook.jsx} | 0
...preferencesHook.js => preferencesHook.jsx} | 0
...esultContext.js => queryResultContext.jsx} | 0
...text.js => serverExtensionDataContext.jsx} | 0
.../src/hooks/{themeHook.js => themeHook.jsx} | 0
.../dashboard/src/{index.js => index.jsx} | 2 +
.../src/service/backendConfiguration.js | 8 +-
.../src/util/format/SimpleDateFormat.js | 6 +-
.../src/views/{ErrorView.js => ErrorView.jsx} | 0
.../views/{SwaggerView.js => SwaggerView.jsx} | 0
.../{Geolocations.js => Geolocations.jsx} | 0
.../layout/{ErrorPage.js => ErrorPage.jsx} | 0
.../layout/{ErrorsPage.js => ErrorsPage.jsx} | 0
.../layout/{LoginPage.js => LoginPage.jsx} | 0
.../layout/{ManagePage.js => ManagePage.jsx} | 0
.../{NetworkPage.js => NetworkPage.jsx} | 0
.../layout/{PlayerPage.js => PlayerPage.jsx} | 0
.../{PlayersPage.js => PlayersPage.jsx} | 0
.../layout/{QueryPage.js => QueryPage.jsx} | 0
.../{RegisterPage.js => RegisterPage.jsx} | 0
.../layout/{ServerPage.js => ServerPage.jsx} | 0
.../manage/{GroupsView.js => GroupsView.jsx} | 0
...eolocations.js => NetworkGeolocations.jsx} | 0
...nAddresses.js => NetworkJoinAddresses.jsx} | 0
...NetworkOverview.js => NetworkOverview.jsx} | 0
...kPerformance.js => NetworkPerformance.jsx} | 0
...etention.js => NetworkPlayerRetention.jsx} | 0
...rview.js => NetworkPlayerbaseOverview.jsx} | 0
...ginHistory.js => NetworkPluginHistory.jsx} | 0
.../{NetworkServers.js => NetworkServers.jsx} | 0
...NetworkSessions.js => NetworkSessions.jsx} | 0
.../{PlayerOverview.js => PlayerOverview.jsx} | 0
...ayerPluginData.js => PlayerPluginData.jsx} | 0
.../{PlayerPvpPve.js => PlayerPvpPve.jsx} | 0
.../{PlayerServers.js => PlayerServers.jsx} | 0
.../{PlayerSessions.js => PlayerSessions.jsx} | 0
.../players/{AllPlayers.js => AllPlayers.jsx} | 0
.../{NewQueryView.js => NewQueryView.jsx} | 0
...QueryResultView.js => QueryResultView.jsx} | 0
.../{OnlineActivity.js => OnlineActivity.jsx} | 0
...baseOverview.js => PlayerbaseOverview.jsx} | 0
...Geolocations.js => ServerGeolocations.jsx} | 0
...inAddresses.js => ServerJoinAddresses.jsx} | 0
.../{ServerOverview.js => ServerOverview.jsx} | 0
...erPerformance.js => ServerPerformance.jsx} | 0
...Retention.js => ServerPlayerRetention.jsx} | 0
.../{ServerPlayers.js => ServerPlayers.jsx} | 0
...rverPluginData.js => ServerPluginData.jsx} | 0
...uginHistory.js => ServerPluginHistory.jsx} | 0
.../{ServerPvpPve.js => ServerPvpPve.jsx} | 0
.../{ServerSessions.js => ServerSessions.jsx} | 0
...PluginData.js => ServerWidePluginData.jsx} | 0
Plan/react/dashboard/vite.config.js | 30 +
Plan/react/dashboard/yarn.lock | 8404 +----------------
214 files changed, 615 insertions(+), 8122 deletions(-)
create mode 100644 Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/BundleAddressCorrection.java
rename Plan/react/dashboard/{public => }/index.html (56%)
rename Plan/react/dashboard/src/{App.js => App.jsx} (100%)
rename Plan/react/dashboard/src/components/{CardTabs.js => CardTabs.jsx} (100%)
rename Plan/react/dashboard/src/components/{Datapoint.js => Datapoint.jsx} (100%)
rename Plan/react/dashboard/src/components/{ErrorBoundary.js => ErrorBoundary.jsx} (100%)
rename Plan/react/dashboard/src/components/{Scrollable.js => Scrollable.jsx} (100%)
rename Plan/react/dashboard/src/components/accordion/{Accordion.js => Accordion.jsx} (100%)
rename Plan/react/dashboard/src/components/accordion/{ErrorsAccordion.js => ErrorsAccordion.jsx} (100%)
rename Plan/react/dashboard/src/components/accordion/{ServerAccordion.js => ServerAccordion.jsx} (100%)
rename Plan/react/dashboard/src/components/accordion/{SessionAccordion.js => SessionAccordion.jsx} (100%)
rename Plan/react/dashboard/src/components/alert/{AlertPopupArea.js => AlertPopupArea.jsx} (100%)
rename Plan/react/dashboard/src/components/alert/{QueryPath.js => QueryPath.jsx} (100%)
rename Plan/react/dashboard/src/components/animation/{LoadIn.js => LoadIn.jsx} (100%)
rename Plan/react/dashboard/src/components/calendar/{PlayerSessionCalendar.js => PlayerSessionCalendar.jsx} (100%)
rename Plan/react/dashboard/src/components/calendar/{ServerCalendar.js => ServerCalendar.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/{CardHeader.js => CardHeader.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{GeolocationsCard.js => GeolocationsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{InsightsFor30DaysCard.js => InsightsFor30DaysCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{PingTableCard.js => PingTableCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{PlayerListCard.js => PlayerListCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{PlayerRetentionGraphCard.js => PlayerRetentionGraphCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{PluginCurrentCard.js => PluginCurrentCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{PluginHistoryCard.js => PluginHistoryCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{PvpKillsTableCard.js => PvpKillsTableCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{RecentSessionsCard.js => RecentSessionsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{ServerPieCard.js => ServerPieCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{TrendCard.js => TrendCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/common/{WorldPieCard.js => WorldPieCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/network/{PerformanceGraphsCard.js => PerformanceGraphsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/network/{QuickViewDataCard.js => QuickViewDataCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/network/{QuickViewGraphCard.js => QuickViewGraphCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/network/{ServersTableCard.js => ServersTableCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/player/{ConnectionsCard.js => ConnectionsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/player/{NicknamesCard.js => NicknamesCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/player/{PlayerOverviewCard.js => PlayerOverviewCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/player/{PlayerRecentSessionsCard.js => PlayerRecentSessionsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/player/{PlayerWorldPieCard.js => PlayerWorldPieCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/player/{PvpPveAsNumbersCard.js => PvpPveAsNumbersCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/query/{FilterDropdown.js => FilterDropdown.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/query/{FilterList.js => FilterList.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/query/{QueryOptionsCard.js => QueryOptionsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/query/{SessionsWithinViewCard.js => SessionsWithinViewCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/query/filter/{BetweenDatesFilter.js => BetweenDatesFilter.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/query/filter/{Filter.js => Filter.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/query/filter/{MultipleChoiceFilter.js => MultipleChoiceFilter.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/query/filter/{PluginGroupsFilter.js => PluginGroupsFilter.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/graphs/{CurrentPlayerbaseCard.js => CurrentPlayerbaseCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/graphs/{JoinAddressGraphCard.js => JoinAddressGraphCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/graphs/{JoinAddressGroupCard.js => JoinAddressGroupCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/graphs/{NetworkOnlineActivityGraphsCard.js => NetworkOnlineActivityGraphsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/graphs/{OnlineActivityCard.js => OnlineActivityCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/graphs/{OnlineActivityGraphsCard.js => OnlineActivityGraphsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/graphs/{PerformanceGraphsCard.js => PerformanceGraphsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/graphs/{PlayerbaseDevelopmentCard.js => PlayerbaseDevelopmentCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/graphs/{ServerWorldPieCard.js => ServerWorldPieCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/insights/{OnlineActivityInsightsCard.js => OnlineActivityInsightsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/insights/{PerformanceInsightsCard.js => PerformanceInsightsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/insights/{PlayerbaseInsightsCard.js => PlayerbaseInsightsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/insights/{PvpPveInsightsCard.js => PvpPveInsightsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/insights/{SessionInsightsCard.js => SessionInsightsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/tables/{OnlineActivityAsNumbersCard.js => OnlineActivityAsNumbersCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/tables/{PerformanceAsNumbersCard.js => PerformanceAsNumbersCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/tables/{PlayerbaseTrendsCard.js => PlayerbaseTrendsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/tables/{PvpPveAsNumbersCard.js => PvpPveAsNumbersCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/tables/{ServerRecentSessionsCard.js => ServerRecentSessionsCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/tables/{ServerWeekComparisonCard.js => ServerWeekComparisonCard.jsx} (100%)
rename Plan/react/dashboard/src/components/cards/server/values/{ServerAsNumbersCard.js => ServerAsNumbersCard.jsx} (100%)
rename Plan/react/dashboard/src/components/datapoint/{CurrentUptime.js => CurrentUptime.jsx} (100%)
rename Plan/react/dashboard/src/components/extensions/{ExtensionCard.js => ExtensionCard.jsx} (100%)
rename Plan/react/dashboard/src/components/extensions/{ExtensionIcon.js => ExtensionIcon.jsx} (100%)
rename Plan/react/dashboard/src/components/extensions/{ExtensionTable.js => ExtensionTable.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{FunctionPlotGraph.js => FunctionPlotGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{GeolocationBarGraph.js => GeolocationBarGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{GeolocationWorldMap.js => GeolocationWorldMap.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{Graph.js => Graph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{GroupBarGraph.js => GroupBarGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{GroupPie.js => GroupPie.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{GroupVisualizer.js => GroupVisualizer.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{JoinAddressGraph.js => JoinAddressGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{LineGraph.js => LineGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{PlayerPingGraph.js => PlayerPingGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{PlayerbaseGraph.js => PlayerbaseGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{PlayersOnlineGraph.js => PlayersOnlineGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{PunchCard.js => PunchCard.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{ServerPie.js => ServerPie.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{StackedPlayersOnlineGraph.js => StackedPlayersOnlineGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{TimeByTimeGraph.js => TimeByTimeGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/{WorldPie.js => WorldPie.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/performance/{AllPerformanceGraph.js => AllPerformanceGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/performance/{CpuRamPerformanceGraph.js => CpuRamPerformanceGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/performance/{DiskPerformanceGraph.js => DiskPerformanceGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/performance/{PingGraph.js => PingGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/performance/{TpsPerformanceGraph.js => TpsPerformanceGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/graphs/performance/{WorldPerformanceGraph.js => WorldPerformanceGraph.jsx} (100%)
rename Plan/react/dashboard/src/components/input/{BasicDropdown.js => BasicDropdown.jsx} (100%)
rename Plan/react/dashboard/src/components/input/{DateInputField.js => DateInputField.jsx} (100%)
rename Plan/react/dashboard/src/components/input/{MultiSelect.js => MultiSelect.jsx} (100%)
rename Plan/react/dashboard/src/components/input/{SearchField.js => SearchField.jsx} (100%)
rename Plan/react/dashboard/src/components/input/{Select.js => Select.jsx} (100%)
rename Plan/react/dashboard/src/components/input/{TimeInputField.js => TimeInputField.jsx} (100%)
rename Plan/react/dashboard/src/components/input/{Toggle.js => Toggle.jsx} (100%)
rename Plan/react/dashboard/src/components/layout/{CollapseWithButton.js => CollapseWithButton.jsx} (100%)
rename Plan/react/dashboard/src/components/layout/{End.js => End.jsx} (100%)
rename Plan/react/dashboard/src/components/layout/{OpaqueText.js => OpaqueText.jsx} (100%)
rename Plan/react/dashboard/src/components/layout/{SideNavTabs.js => SideNavTabs.jsx} (100%)
rename Plan/react/dashboard/src/components/layout/extension/{ExtendableCardBody.js => ExtendableCardBody.jsx} (100%)
rename Plan/react/dashboard/src/components/layout/extension/{ExtendableRow.js => ExtendableRow.jsx} (100%)
rename Plan/react/dashboard/src/components/modal/{ColorSelectorModal.js => ColorSelectorModal.jsx} (100%)
rename Plan/react/dashboard/src/components/modal/{FinalizeRegistrationModal.js => FinalizeRegistrationModal.jsx} (100%)
rename Plan/react/dashboard/src/components/modal/{ForgotPasswordModal.js => ForgotPasswordModal.jsx} (100%)
rename Plan/react/dashboard/src/components/modal/{HelpModal.js => HelpModal.jsx} (100%)
rename Plan/react/dashboard/src/components/modal/{PluginInformationModal.js => PluginInformationModal.jsx} (100%)
rename Plan/react/dashboard/src/components/modal/{QueryPlayerListModal.js => QueryPlayerListModal.jsx} (100%)
rename Plan/react/dashboard/src/components/modal/{VersionInformationModal.js => VersionInformationModal.jsx} (100%)
rename Plan/react/dashboard/src/components/modal/help/{ActivityIndexHelp.js => ActivityIndexHelp.jsx} (100%)
rename Plan/react/dashboard/src/components/modal/help/{GroupPermissionHelp.js => GroupPermissionHelp.jsx} (100%)
rename Plan/react/dashboard/src/components/modal/help/{NewPlayerRetentionHelp.js => NewPlayerRetentionHelp.jsx} (100%)
rename Plan/react/dashboard/src/components/modal/help/{PlayerRetentionGraphHelp.js => PlayerRetentionGraphHelp.jsx} (100%)
rename Plan/react/dashboard/src/components/navigation/{Header.js => Header.jsx} (100%)
rename Plan/react/dashboard/src/components/navigation/{Loader.js => Loader.jsx} (100%)
rename Plan/react/dashboard/src/components/navigation/{MainPageRedirect.js => MainPageRedirect.jsx} (100%)
rename Plan/react/dashboard/src/components/navigation/{PageNavigationItem.js => PageNavigationItem.jsx} (100%)
rename Plan/react/dashboard/src/components/navigation/{Sidebar.js => Sidebar.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{AsNumbersTable.js => AsNumbersTable.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{ComparisonTable.js => ComparisonTable.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{DataTablesTable.js => DataTablesTable.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{GroupTable.js => GroupTable.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{KillsTable.js => KillsTable.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{OnlineActivityAsNumbersTable.js => OnlineActivityAsNumbersTable.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{PerformanceAsNumbersTable.js => PerformanceAsNumbersTable.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{PingTable.js => PingTable.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{PlayerPvpPveAsNumbersTable.js => PlayerPvpPveAsNumbersTable.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{ServerPvpPveAsNumbersTable.js => ServerPvpPveAsNumbersTable.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{ServersTable.js => ServersTable.jsx} (100%)
rename Plan/react/dashboard/src/components/table/{TableRow.js => TableRow.jsx} (100%)
rename Plan/react/dashboard/src/components/text/{ColoredText.js => ColoredText.jsx} (100%)
rename Plan/react/dashboard/src/components/text/{FormattedDate.js => FormattedDate.jsx} (100%)
rename Plan/react/dashboard/src/components/text/{FormattedTime.js => FormattedTime.jsx} (100%)
rename Plan/react/dashboard/src/components/trend/{BigTrend.js => BigTrend.jsx} (100%)
rename Plan/react/dashboard/src/components/trend/{ComparingLabel.js => ComparingLabel.jsx} (100%)
rename Plan/react/dashboard/src/components/trend/{SmallTrend.js => SmallTrend.jsx} (100%)
rename Plan/react/dashboard/src/hooks/{authenticationHook.js => authenticationHook.jsx} (100%)
rename Plan/react/dashboard/src/hooks/context/{alertPopupContext.js => alertPopupContext.jsx} (100%)
rename Plan/react/dashboard/src/hooks/context/{configurationStorageContextHook.js => configurationStorageContextHook.jsx} (100%)
rename Plan/react/dashboard/src/hooks/context/{dropdownStatusContextHook.js => dropdownStatusContextHook.jsx} (100%)
rename Plan/react/dashboard/src/hooks/context/{groupEditContextHook.js => groupEditContextHook.jsx} (100%)
rename Plan/react/dashboard/src/hooks/{metadataHook.js => metadataHook.jsx} (100%)
rename Plan/react/dashboard/src/hooks/{navigationHook.js => navigationHook.jsx} (100%)
rename Plan/react/dashboard/src/hooks/{pageExtensionHook.js => pageExtensionHook.jsx} (100%)
rename Plan/react/dashboard/src/hooks/{preferencesHook.js => preferencesHook.jsx} (100%)
rename Plan/react/dashboard/src/hooks/{queryResultContext.js => queryResultContext.jsx} (100%)
rename Plan/react/dashboard/src/hooks/{serverExtensionDataContext.js => serverExtensionDataContext.jsx} (100%)
rename Plan/react/dashboard/src/hooks/{themeHook.js => themeHook.jsx} (100%)
rename Plan/react/dashboard/src/{index.js => index.jsx} (96%)
rename Plan/react/dashboard/src/views/{ErrorView.js => ErrorView.jsx} (100%)
rename Plan/react/dashboard/src/views/{SwaggerView.js => SwaggerView.jsx} (100%)
rename Plan/react/dashboard/src/views/common/{Geolocations.js => Geolocations.jsx} (100%)
rename Plan/react/dashboard/src/views/layout/{ErrorPage.js => ErrorPage.jsx} (100%)
rename Plan/react/dashboard/src/views/layout/{ErrorsPage.js => ErrorsPage.jsx} (100%)
rename Plan/react/dashboard/src/views/layout/{LoginPage.js => LoginPage.jsx} (100%)
rename Plan/react/dashboard/src/views/layout/{ManagePage.js => ManagePage.jsx} (100%)
rename Plan/react/dashboard/src/views/layout/{NetworkPage.js => NetworkPage.jsx} (100%)
rename Plan/react/dashboard/src/views/layout/{PlayerPage.js => PlayerPage.jsx} (100%)
rename Plan/react/dashboard/src/views/layout/{PlayersPage.js => PlayersPage.jsx} (100%)
rename Plan/react/dashboard/src/views/layout/{QueryPage.js => QueryPage.jsx} (100%)
rename Plan/react/dashboard/src/views/layout/{RegisterPage.js => RegisterPage.jsx} (100%)
rename Plan/react/dashboard/src/views/layout/{ServerPage.js => ServerPage.jsx} (100%)
rename Plan/react/dashboard/src/views/manage/{GroupsView.js => GroupsView.jsx} (100%)
rename Plan/react/dashboard/src/views/network/{NetworkGeolocations.js => NetworkGeolocations.jsx} (100%)
rename Plan/react/dashboard/src/views/network/{NetworkJoinAddresses.js => NetworkJoinAddresses.jsx} (100%)
rename Plan/react/dashboard/src/views/network/{NetworkOverview.js => NetworkOverview.jsx} (100%)
rename Plan/react/dashboard/src/views/network/{NetworkPerformance.js => NetworkPerformance.jsx} (100%)
rename Plan/react/dashboard/src/views/network/{NetworkPlayerRetention.js => NetworkPlayerRetention.jsx} (100%)
rename Plan/react/dashboard/src/views/network/{NetworkPlayerbaseOverview.js => NetworkPlayerbaseOverview.jsx} (100%)
rename Plan/react/dashboard/src/views/network/{NetworkPluginHistory.js => NetworkPluginHistory.jsx} (100%)
rename Plan/react/dashboard/src/views/network/{NetworkServers.js => NetworkServers.jsx} (100%)
rename Plan/react/dashboard/src/views/network/{NetworkSessions.js => NetworkSessions.jsx} (100%)
rename Plan/react/dashboard/src/views/player/{PlayerOverview.js => PlayerOverview.jsx} (100%)
rename Plan/react/dashboard/src/views/player/{PlayerPluginData.js => PlayerPluginData.jsx} (100%)
rename Plan/react/dashboard/src/views/player/{PlayerPvpPve.js => PlayerPvpPve.jsx} (100%)
rename Plan/react/dashboard/src/views/player/{PlayerServers.js => PlayerServers.jsx} (100%)
rename Plan/react/dashboard/src/views/player/{PlayerSessions.js => PlayerSessions.jsx} (100%)
rename Plan/react/dashboard/src/views/players/{AllPlayers.js => AllPlayers.jsx} (100%)
rename Plan/react/dashboard/src/views/query/{NewQueryView.js => NewQueryView.jsx} (100%)
rename Plan/react/dashboard/src/views/query/{QueryResultView.js => QueryResultView.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{OnlineActivity.js => OnlineActivity.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{PlayerbaseOverview.js => PlayerbaseOverview.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{ServerGeolocations.js => ServerGeolocations.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{ServerJoinAddresses.js => ServerJoinAddresses.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{ServerOverview.js => ServerOverview.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{ServerPerformance.js => ServerPerformance.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{ServerPlayerRetention.js => ServerPlayerRetention.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{ServerPlayers.js => ServerPlayers.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{ServerPluginData.js => ServerPluginData.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{ServerPluginHistory.js => ServerPluginHistory.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{ServerPvpPve.js => ServerPvpPve.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{ServerSessions.js => ServerSessions.jsx} (100%)
rename Plan/react/dashboard/src/views/server/{ServerWidePluginData.js => ServerWidePluginData.jsx} (100%)
create mode 100644 Plan/react/dashboard/vite.config.js
diff --git a/Plan/common/build.gradle b/Plan/common/build.gradle
index 249e3c559..8b0cfcd5e 100644
--- a/Plan/common/build.gradle
+++ b/Plan/common/build.gradle
@@ -113,13 +113,14 @@ task updateVersion(type: Copy) {
node {
download = true
- version = "16.14.2"
+ version = "20.9.0"
nodeProjectDir = file("$rootDir/react/dashboard")
}
task yarnBundle(type: YarnTask) {
inputs.files(fileTree("$rootDir/react/dashboard/src"))
inputs.file("$rootDir/react/dashboard/package.json")
+ inputs.file("$rootDir/react/dashboard/vite.config.js")
outputs.dir("$rootDir/react/dashboard/build")
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/export/ReactExporter.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/export/ReactExporter.java
index 518242031..0ca33a5fe 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/export/ReactExporter.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/export/ReactExporter.java
@@ -16,6 +16,7 @@
*/
package com.djrapitops.plan.delivery.export;
+import com.djrapitops.plan.delivery.rendering.BundleAddressCorrection;
import com.djrapitops.plan.delivery.web.AssetVersions;
import com.djrapitops.plan.delivery.web.resolver.Response;
import com.djrapitops.plan.delivery.web.resolver.request.Request;
@@ -52,23 +53,25 @@ public class ReactExporter extends FileExporter {
private final PlanConfig config;
private final RootJSONResolver jsonHandler;
private final AssetVersions assetVersions;
+ private final BundleAddressCorrection bundleAddressCorrection;
@Inject
public ReactExporter(
PlanFiles files,
PlanConfig config,
RootJSONResolver jsonHandler,
- AssetVersions assetVersions
+ AssetVersions assetVersions,
+ BundleAddressCorrection bundleAddressCorrection
) {
this.files = files;
this.config = config;
this.jsonHandler = jsonHandler;
this.assetVersions = assetVersions;
+ this.bundleAddressCorrection = bundleAddressCorrection;
}
public void exportReactFiles(Path toDirectory) throws IOException {
exportIndexHtml(toDirectory);
- exportAsset(toDirectory, "asset-manifest.json");
exportAsset(toDirectory, "favicon.ico");
exportAsset(toDirectory, "logo192.png");
exportAsset(toDirectory, "logo512.png");
@@ -104,17 +107,18 @@ public class ReactExporter extends FileExporter {
Path to = toDirectory.resolve(path);
Resource resource = files.getResourceFromJar("web/" + path);
// Make static asset loading work with subdirectory addresses
- if (path.endsWith(".css") || "asset-manifest.json".equals(path)) {
+ if (path.endsWith(".css")) {
String contents = resource.asString();
- String withReplacedStatic = StringUtils.replace(contents, "/static", getBasePath() + "/static");
- export(to, withReplacedStatic);
+ String withReplaced = bundleAddressCorrection.correctAddressForExport(contents, path);
+ export(to, withReplaced);
} else if (path.endsWith(".js")) {
String withReplacedConstants = StringUtils.replaceEach(
resource.asString(),
- new String[]{"PLAN_BASE_ADDRESS", "PLAN_EXPORTED_VERSION", ".p=\"/\""},
- new String[]{config.get(WebserverSettings.EXTERNAL_LINK), "true", ".p=\"" + getBasePath() + "/\""}
+ new String[]{"PLAN_BASE_ADDRESS", "PLAN_EXPORTED_VERSION"},
+ new String[]{config.get(WebserverSettings.EXTERNAL_LINK), "true"}
);
- export(to, withReplacedConstants);
+ String withReplaced = bundleAddressCorrection.correctAddressForExport(withReplacedConstants, path);
+ export(to, withReplaced);
} else {
export(to, resource);
}
@@ -141,25 +145,11 @@ public class ReactExporter extends FileExporter {
private void exportIndexHtml(Path toDirectory) throws IOException {
String contents = files.getResourceFromJar("web/index.html")
.asString();
- String basePath = getBasePath();
- contents = StringUtils.replaceEach(contents,
- new String[]{"/static", "/pageExtensionApi.js"},
- new String[]{basePath + "/static", basePath + "/pageExtensionApi.js"});
+ contents = bundleAddressCorrection.correctAddressForExport(contents, "index.html");
export(toDirectory.resolve("index.html"), contents);
}
- private String getBasePath() {
- String basePath = config.get(WebserverSettings.EXTERNAL_LINK)
- .replace("http://", "")
- .replace("https://", "");
- if (StringUtils.contains(basePath, '/')) {
- return basePath.substring(StringUtils.indexOf(basePath, '/'));
- } else {
- return "";
- }
- }
-
private void exportAsset(Path toDirectory, String asset) throws IOException {
export(toDirectory.resolve(asset), files.getResourceFromJar("web/" + asset));
}
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/BundleAddressCorrection.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/BundleAddressCorrection.java
new file mode 100644
index 000000000..fb0f2c1a8
--- /dev/null
+++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/BundleAddressCorrection.java
@@ -0,0 +1,155 @@
+/*
+ * This file is part of Player Analytics (Plan).
+ *
+ * Plan is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License v3 as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Plan is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Plan. If not, see
+ * The javascript bundle assumes everything is hosted at /,
+ * but hosting settings affect the address and it could be hosted at a subdirectory like /plan/
+ *
+ * @author AuroraLS3
+ */
+@Singleton
+public class BundleAddressCorrection {
+
+ private static final String STATIC = "static";
+ private static final Pattern JAVASCRIPT_ADDRESS_PATTERN = Pattern.compile("\"(\\./|/?static)(.+?)\\.(json|js|css)\"");
+
+ private final PlanConfig config;
+ private final Addresses addresses;
+
+ @Inject
+ public BundleAddressCorrection(PlanConfig config, Addresses addresses) {
+ this.config = config;
+ this.addresses = addresses;
+ }
+
+ private String getExportBasePath() {
+ return addresses.getBasePath(config.get(WebserverSettings.EXTERNAL_LINK));
+ }
+
+ private String getWebserverBasePath() {
+ String address = addresses.getMainAddress()
+ .orElseGet(addresses::getFallbackLocalhostAddress);
+ return addresses.getBasePath(address);
+ }
+
+ public String correctAddressForWebserver(String content, String fileName) {
+ String basePath = getWebserverBasePath();
+ return correctAddress(content, fileName, basePath);
+ }
+
+ public String correctAddressForExport(String content, String fileName) {
+ String basePath = getExportBasePath();
+ return correctAddress(content, fileName, basePath);
+ }
+
+ // basePath is either empty if the address doesn't have a subdirectory, or a subdirectory.
+ @Nullable
+ private String correctAddress(String content, String fileName, String basePath) {
+ if (fileName.endsWith(".css")) {
+ return correctAddressInCss(content, basePath);
+ } else if (fileName.endsWith(".js")) {
+ return correctAddressInJavascript(content, basePath);
+ } else if ("index.html".equals(fileName)) {
+ return correctAddressInHtml(content, basePath);
+ }
+ return content;
+ }
+
+ private String correctAddressInHtml(String content, String basePath) {
+ String endingSlash = basePath.endsWith("/") ? "" : "/";
+ return StringUtils.replaceEach(content,
+ new String[]{"src=\"/", "href=\"/"},
+ new String[]{"src=\"" + basePath + endingSlash, "href=\"" + basePath + endingSlash});
+ }
+
+ private String correctAddressInCss(String content, String basePath) {
+ String endingSlash = basePath.endsWith("/") ? "" : "/";
+ return StringUtils.replace(content, "/static", basePath + endingSlash + STATIC);
+ }
+
+ private String correctAddressInJavascript(String content, String basePath) {
+ int lastIndex = 0;
+ StringBuilder output = new StringBuilder();
+
+ Matcher matcher = JAVASCRIPT_ADDRESS_PATTERN.matcher(content);
+ while (matcher.find()) {
+ String addressStart = matcher.group(1);
+ String file = matcher.group(2);
+ String extension = matcher.group(3);
+ int startIndex = matcher.start();
+ int endIndex = matcher.end();
+
+ // If basePath is empty the website is hosted at root of the tree /
+ boolean atUrlRoot = basePath.isEmpty();
+
+ // This handles /static and static representation
+ boolean startsWithSlash = addressStart.startsWith("/");
+ String startingSlash = startsWithSlash ? "/" : "";
+ // This handles basePath containing a slash after subdirectory, such as /plan/ instead of /plan
+ String endingSlash = basePath.endsWith("/") ? "" : "/";
+
+ // Without subdirectory we can use the address as is, and it doesn't need changes,
+ // otherwise we can add the directory to the start.
+ String staticReplacement = atUrlRoot
+ ? startingSlash + STATIC
+ : basePath + endingSlash + STATIC;
+ String relativeReplacement = atUrlRoot
+ ? "./"
+ : basePath + endingSlash + "static/";
+
+ // Replaces basePath starting slash if the replaced thing does not start with slash
+ if (!startsWithSlash && staticReplacement.startsWith("/")) {
+ staticReplacement = staticReplacement.substring(1);
+ }
+
+ // Replacement examples when basepath is empty, "/plan" or "/plan/"
+ // "./Filename-hash.js" -> "./Filename-hash.js" or "/plan/static/Filename-hash.js"
+ // "/static/Filename-hash.js" -> "/static/Filename-hash.js" or "/plan/static/Filename-hash.js"
+ // "static/Filename-hash.js" -> "static/Filename-hash.js" or "plan/static/Filename-hash.js"
+ String replacementAddress = StringUtils.equalsAny(addressStart, "/static", STATIC)
+ ? staticReplacement
+ : relativeReplacement;
+ String replacement = '"' + replacementAddress + file + '.' + extension + '"';
+
+ output.append(content, lastIndex, startIndex) // Append non-match
+ .append(replacement); // Append replaced address
+
+ lastIndex = endIndex;
+ }
+ // Append rest of the content that didn't match
+ if (lastIndex < content.length()) {
+ output.append(content, lastIndex, content.length());
+ }
+
+ return output.toString();
+ }
+
+}
diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/pages/PageFactory.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/pages/PageFactory.java
index 787a42155..030698da5 100644
--- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/pages/PageFactory.java
+++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/pages/PageFactory.java
@@ -16,11 +16,11 @@
*/
package com.djrapitops.plan.delivery.rendering.pages;
+import com.djrapitops.plan.delivery.rendering.BundleAddressCorrection;
import com.djrapitops.plan.delivery.rendering.html.icon.Icon;
import com.djrapitops.plan.delivery.web.ResourceService;
import com.djrapitops.plan.delivery.web.resolver.exception.NotFoundException;
import com.djrapitops.plan.delivery.web.resource.WebResource;
-import com.djrapitops.plan.delivery.webserver.Addresses;
import com.djrapitops.plan.identification.ServerInfo;
import com.djrapitops.plan.identification.ServerUUID;
import com.djrapitops.plan.settings.theme.Theme;
@@ -50,7 +50,7 @@ public class PageFactory {
private final Lazy