mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-10-31 16:01:00 +01:00
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
This commit is contained in:
parent
05cf96de0e
commit
bc424f062f
@ -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")
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.rendering;
|
||||
|
||||
import com.djrapitops.plan.delivery.webserver.Addresses;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.WebserverSettings;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* In charge of correcting the root address in the javascript bundle.
|
||||
* <p>
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
@ -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<PublicHtmlFiles> publicHtmlFiles;
|
||||
private final Lazy<Theme> theme;
|
||||
private final Lazy<DBSystem> dbSystem;
|
||||
private final Lazy<Addresses> addresses;
|
||||
private final Lazy<BundleAddressCorrection> bundleAddressCorrection;
|
||||
private static final String ERROR_HTML_FILE = "error.html";
|
||||
|
||||
@Inject
|
||||
@ -61,14 +61,14 @@ public class PageFactory {
|
||||
Lazy<Theme> theme,
|
||||
Lazy<DBSystem> dbSystem,
|
||||
Lazy<ServerInfo> serverInfo,
|
||||
Lazy<Addresses> addresses
|
||||
Lazy<BundleAddressCorrection> bundleAddressCorrection
|
||||
) {
|
||||
this.versionChecker = versionChecker;
|
||||
this.files = files;
|
||||
this.publicHtmlFiles = publicHtmlFiles;
|
||||
this.theme = theme;
|
||||
this.dbSystem = dbSystem;
|
||||
this.addresses = addresses;
|
||||
this.bundleAddressCorrection = bundleAddressCorrection;
|
||||
}
|
||||
|
||||
public Page playersPage() throws IOException {
|
||||
@ -81,18 +81,12 @@ public class PageFactory {
|
||||
WebResource resource = ResourceService.getInstance().getResource(
|
||||
"Plan", fileName, () -> getPublicHtmlOrJarResource(fileName)
|
||||
);
|
||||
return new ReactPage(getBasePath(), resource);
|
||||
return new ReactPage(bundleAddressCorrection.get(), resource);
|
||||
} catch (UncheckedIOException readFail) {
|
||||
throw readFail.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
private String getBasePath() {
|
||||
String address = addresses.get().getMainAddress()
|
||||
.orElseGet(addresses.get()::getFallbackLocalhostAddress);
|
||||
return addresses.get().getBasePath(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a server page.
|
||||
*
|
||||
|
@ -16,8 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.rendering.pages;
|
||||
|
||||
import com.djrapitops.plan.delivery.rendering.BundleAddressCorrection;
|
||||
import com.djrapitops.plan.delivery.web.resource.WebResource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* Represents React index.html.
|
||||
@ -26,20 +26,17 @@ import org.apache.commons.lang3.StringUtils;
|
||||
*/
|
||||
public class ReactPage implements Page {
|
||||
|
||||
private final String basePath;
|
||||
private final BundleAddressCorrection bundleAddressCorrection;
|
||||
private final WebResource reactHtml;
|
||||
|
||||
public ReactPage(String basePath, WebResource reactHtml) {
|
||||
this.basePath = basePath;
|
||||
public ReactPage(BundleAddressCorrection bundleAddressCorrection, WebResource reactHtml) {
|
||||
this.bundleAddressCorrection = bundleAddressCorrection;
|
||||
this.reactHtml = reactHtml;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toHtml() {
|
||||
return StringUtils.replaceEach(
|
||||
reactHtml.asString(),
|
||||
new String[]{"/static", "/pageExtensionApi.js"},
|
||||
new String[]{basePath + "/static", basePath + "/pageExtensionApi.js"});
|
||||
return bundleAddressCorrection.correctAddressForWebserver(reactHtml.asString(), "index.html");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,6 +20,7 @@ import com.djrapitops.plan.delivery.domain.container.PlayerContainer;
|
||||
import com.djrapitops.plan.delivery.domain.keys.PlayerKeys;
|
||||
import com.djrapitops.plan.delivery.formatting.Formatter;
|
||||
import com.djrapitops.plan.delivery.formatting.Formatters;
|
||||
import com.djrapitops.plan.delivery.rendering.BundleAddressCorrection;
|
||||
import com.djrapitops.plan.delivery.rendering.html.icon.Family;
|
||||
import com.djrapitops.plan.delivery.rendering.html.icon.Icon;
|
||||
import com.djrapitops.plan.delivery.rendering.pages.Page;
|
||||
@ -75,6 +76,7 @@ public class ResponseFactory {
|
||||
private final DBSystem dbSystem;
|
||||
private final Theme theme;
|
||||
private final Lazy<Addresses> addresses;
|
||||
private final Lazy<BundleAddressCorrection> bundleAddressCorrection;
|
||||
private final Formatter<Long> httpLastModifiedFormatter;
|
||||
|
||||
@Inject
|
||||
@ -86,7 +88,8 @@ public class ResponseFactory {
|
||||
DBSystem dbSystem,
|
||||
Formatters formatters,
|
||||
Theme theme,
|
||||
Lazy<Addresses> addresses
|
||||
Lazy<Addresses> addresses,
|
||||
Lazy<BundleAddressCorrection> bundleAddressCorrection
|
||||
) {
|
||||
this.files = files;
|
||||
this.publicHtmlFiles = publicHtmlFiles;
|
||||
@ -97,6 +100,7 @@ public class ResponseFactory {
|
||||
this.addresses = addresses;
|
||||
|
||||
httpLastModifiedFormatter = formatters.httpLastModifiedLong();
|
||||
this.bundleAddressCorrection = bundleAddressCorrection;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,9 +236,7 @@ public class ResponseFactory {
|
||||
String content = UnaryChain.of(resource.asString())
|
||||
.chain(this::replaceMainAddressPlaceholder)
|
||||
.chain(theme::replaceThemeColors)
|
||||
.chain(contents -> StringUtils.replace(contents,
|
||||
".p=\"/\"",
|
||||
".p=\"" + getBasePath() + "/\""))
|
||||
.chain(contents -> bundleAddressCorrection.get().correctAddressForWebserver(contents, fileName))
|
||||
.apply();
|
||||
ResponseBuilder responseBuilder = Response.builder()
|
||||
.setMimeType(MimeType.JS)
|
||||
@ -244,7 +246,7 @@ public class ResponseFactory {
|
||||
if (fileName.contains(STATIC_BUNDLE_FOLDER)) {
|
||||
resource.getLastModified().ifPresent(lastModified -> responseBuilder
|
||||
// Can't cache main bundle in browser since base path might change
|
||||
.setHeader(HttpHeader.CACHE_CONTROL.asString(), fileName.contains("main") ? CacheStrategy.CHECK_ETAG : CacheStrategy.CACHE_IN_BROWSER)
|
||||
.setHeader(HttpHeader.CACHE_CONTROL.asString(), fileName.contains("index") ? CacheStrategy.CHECK_ETAG : CacheStrategy.CACHE_IN_BROWSER)
|
||||
.setHeader(HttpHeader.LAST_MODIFIED.asString(), httpLastModifiedFormatter.apply(lastModified))
|
||||
.setHeader(HttpHeader.ETAG.asString(), lastModified));
|
||||
}
|
||||
@ -254,12 +256,6 @@ public class ResponseFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private String getBasePath() {
|
||||
String address = addresses.get().getMainAddress()
|
||||
.orElseGet(addresses.get()::getFallbackLocalhostAddress);
|
||||
return addresses.get().getBasePath(address);
|
||||
}
|
||||
|
||||
private String replaceMainAddressPlaceholder(String resource) {
|
||||
String address = addresses.get().getAccessAddress()
|
||||
.orElseGet(addresses.get()::getFallbackLocalhostAddress);
|
||||
@ -275,7 +271,7 @@ public class ResponseFactory {
|
||||
WebResource resource = getPublicOrJarResource(fileName);
|
||||
String content = UnaryChain.of(resource.asString())
|
||||
.chain(theme::replaceThemeColors)
|
||||
.chain(contents -> StringUtils.replace(contents, "/static", getBasePath() + "/static"))
|
||||
.chain(contents -> bundleAddressCorrection.get().correctAddressForWebserver(contents, fileName))
|
||||
.apply();
|
||||
|
||||
ResponseBuilder responseBuilder = Response.builder()
|
||||
|
@ -147,8 +147,9 @@ public class ResponseResolver {
|
||||
String plugin = "Plan";
|
||||
resolverService.registerResolver(plugin, "/robots.txt", fileResolver(responseFactory::robotsResponse));
|
||||
resolverService.registerResolver(plugin, "/manifest.json", fileResolver(() -> responseFactory.jsonFileResponse("manifest.json")));
|
||||
resolverService.registerResolver(plugin, "/asset-manifest.json", fileResolver(() -> responseFactory.jsonFileResponse("asset-manifest.json")));
|
||||
resolverService.registerResolver(plugin, "/favicon.ico", fileResolver(responseFactory::faviconResponse));
|
||||
resolverService.registerResolver(plugin, "/logo192.png", fileResolver(() -> responseFactory.imageResponse("logo192.png")));
|
||||
resolverService.registerResolver(plugin, "/logo512.png", fileResolver(() -> responseFactory.imageResponse("logo512.png")));
|
||||
resolverService.registerResolver(plugin, "/pageExtensionApi.js", fileResolver(() -> responseFactory.javaScriptResponse("pageExtensionApi.js")));
|
||||
|
||||
resolverService.registerResolver(plugin, "/query", queryPageResolver);
|
||||
|
@ -37,7 +37,7 @@ import java.util.Optional;
|
||||
@Singleton
|
||||
public class StaticResourceResolver implements NoAuthResolver {
|
||||
|
||||
private static final String PART_REGEX = "(vendor|css|js|img|static)";
|
||||
private static final String PART_REGEX = "(static)";
|
||||
public static final String PATH_REGEX = "^.*/" + PART_REGEX + "/.*";
|
||||
|
||||
private final ResponseFactory responseFactory;
|
||||
|
@ -214,7 +214,7 @@ public class GraphsJSONResolver extends JSONResolver {
|
||||
case GRAPH_OPTIMIZED_PERFORMANCE:
|
||||
return List.of(WebPermission.PAGE_SERVER_PERFORMANCE_GRAPHS, WebPermission.PAGE_NETWORK_PERFORMANCE);
|
||||
case GRAPH_ONLINE:
|
||||
return List.of(WebPermission.PAGE_SERVER_OVERVIEW_PLAYERS_ONLINE_GRAPH);
|
||||
return List.of(WebPermission.PAGE_SERVER_OVERVIEW_PLAYERS_ONLINE_GRAPH, WebPermission.PAGE_NETWORK_OVERVIEW_GRAPHS_ONLINE);
|
||||
case GRAPH_UNIQUE_NEW:
|
||||
return List.of(WebPermission.PAGE_SERVER_ONLINE_ACTIVITY_GRAPHS_DAY_BY_DAY);
|
||||
case GRAPH_HOURLY_UNIQUE_NEW:
|
||||
|
@ -106,7 +106,7 @@ public class ExportTestUtilities {
|
||||
|
||||
assertFalse(driver.findElement(By.tagName("body")).getText().contains("Bad Gateway"), "502 Bad Gateway, nginx could not reach Plan");
|
||||
|
||||
Awaitility.await()
|
||||
Awaitility.await("waitForElementToBeVisible .load-in")
|
||||
.atMost(Duration.of(10, ChronoUnit.SECONDS))
|
||||
.until(() -> getMainPageElement(driver).map(WebElement::isDisplayed).orElse(false));
|
||||
|
||||
|
@ -28,6 +28,7 @@ import com.djrapitops.plan.settings.config.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plan.settings.config.paths.DisplaySettings;
|
||||
import com.djrapitops.plan.settings.config.paths.WebserverSettings;
|
||||
import com.djrapitops.plan.storage.database.Database;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.commands.StoreWebUserTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.StoreServerPlayerTransaction;
|
||||
@ -47,6 +48,7 @@ import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.chrome.ChromeDriver;
|
||||
import org.openqa.selenium.logging.LogEntry;
|
||||
import org.openqa.selenium.logging.LogType;
|
||||
import org.testcontainers.shaded.org.awaitility.Awaitility;
|
||||
import utilities.RandomData;
|
||||
import utilities.TestConstants;
|
||||
import utilities.TestResources;
|
||||
@ -57,6 +59,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -291,8 +294,11 @@ class AccessControlVisibilityTest {
|
||||
|
||||
private void registerProxy(Database database) throws ExecutionException, InterruptedException {
|
||||
database.executeTransaction(new StoreServerInformationTransaction(
|
||||
new Server(TestConstants.SERVER_TWO_UUID, "Proxy", "https://localhost", TestConstants.VERSION)
|
||||
new Server(null, TestConstants.SERVER_TWO_UUID, "Proxy", "https://localhost", true, TestConstants.VERSION)
|
||||
)).get();
|
||||
Awaitility.await("Proxy was not registered")
|
||||
.atMost(5, TimeUnit.SECONDS)
|
||||
.until(() -> !database.query(ServerQueries.fetchProxyServers()).isEmpty());
|
||||
}
|
||||
|
||||
@DisplayName("Network element is visible with permission")
|
||||
|
@ -11,27 +11,18 @@
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link href="%PUBLIC_URL%/manifest.json" rel="manifest"/>
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
<link href="/manifest.json" rel="manifest"/>
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>Plan | Player Analytics</title>
|
||||
|
||||
|
||||
<link crossorigin="anonymous"
|
||||
href="https://fonts.googleapis.com/css?family=Nunito:400,700,800,900&display=swap&subset=latin-ext"
|
||||
rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<script src="%PUBLIC_URL%/pageExtensionApi.js"></script>
|
||||
<script>/* This script tag will be replaced with scripts */</script>
|
||||
<script src="/pageExtensionApi.js"></script>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<script src="/src/index.jsx" type="module"></script>
|
||||
</body>
|
||||
</html>
|
@ -3,6 +3,7 @@
|
||||
"name": "dashboard",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"proxy": "http://localhost:8800",
|
||||
"dependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
@ -37,17 +38,14 @@
|
||||
"react-i18next": "^13.5.0",
|
||||
"react-mcjsonchat": "^1.0.0",
|
||||
"react-router-dom": "6",
|
||||
"react-scripts": "5.0.1",
|
||||
"sass": "^1.69.5",
|
||||
"source-map-explorer": "^2.5.2",
|
||||
"swagger-ui": "^5.10.3",
|
||||
"web-vitals": "^3.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"start": "vite",
|
||||
"build": "vite build",
|
||||
"analyze": "source-map-explorer 'build/static/js/*.js'"
|
||||
},
|
||||
"eslintConfig": {
|
||||
@ -67,5 +65,9 @@
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-react": "^4.2.0",
|
||||
"vite": "^5.0.0"
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user