From fe779f5516389dd23c5d5ef8d8a05c99271f62b0 Mon Sep 17 00:00:00 2001
From: Nicholas de Paola <3079166+ndepaola@users.noreply.github.com>
Date: Thu, 18 May 2023 23:35:24 +1000
Subject: [PATCH] god fucking dammit
bad ugly not good solution to the race condition on page load,
but it works perfectly so w/e
i'm delaying each query until the backend URL to query is specified
the (imo) correct solution here is to correctly invalidate tags
in the presence of a race condition. seems like there's a PR to do
that here: https://github.com/reduxjs/redux-toolkit/pull/3116
but no movement on it for the last few months
related issue: https://github.com/reduxjs/redux-toolkit/issues/3386
---
frontend/jest.config.mjs | 1 +
frontend/src/features/backend/backend.tsx | 13 ++++++------
frontend/src/features/backend/backendSlice.ts | 2 ++
frontend/src/features/import/importCSV.tsx | 6 +++++-
frontend/src/features/import/importText.tsx | 10 +++++++--
frontend/src/features/import/importURL.tsx | 14 ++++++++++---
.../src/features/support/supportBackend.tsx | 7 ++++++-
.../src/features/support/supportDeveloper.tsx | 2 +-
frontend/src/features/ui/footer.tsx | 7 ++++++-
frontend/src/features/ui/navbar.tsx | 7 +++++--
frontend/src/pages/about.tsx | 7 ++++++-
frontend/src/pages/contributions.tsx | 21 +++++++++++++++----
12 files changed, 74 insertions(+), 23 deletions(-)
diff --git a/frontend/jest.config.mjs b/frontend/jest.config.mjs
index fce991f31..65948c569 100644
--- a/frontend/jest.config.mjs
+++ b/frontend/jest.config.mjs
@@ -13,6 +13,7 @@ const config = {
testEnvironment: "jest-environment-jsdom",
injectGlobals: true,
+ testTimeout: 20_000,
};
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
diff --git a/frontend/src/features/backend/backend.tsx b/frontend/src/features/backend/backend.tsx
index ec73aa138..e3d4edddf 100644
--- a/frontend/src/features/backend/backend.tsx
+++ b/frontend/src/features/backend/backend.tsx
@@ -21,7 +21,11 @@ import {
setLocalStorageBackendURL,
} from "@/common/cookies";
import { standardiseURL } from "@/common/processing";
-import { clearURL, setURL } from "@/features/backend/backendSlice";
+import {
+ clearURL,
+ selectBackendURL,
+ setURL,
+} from "@/features/backend/backendSlice";
require("bootstrap-icons/font/bootstrap-icons.css");
interface BackendConfigProps {
@@ -90,10 +94,7 @@ export function BackendConfig(props: BackendConfigProps) {
>([]);
const [validating, setValidating] = useState(false);
- const [triggerFn, getBackendInfoQuery] =
- apiSlice.endpoints.getBackendInfo.useLazyQuery();
-
- const backendURL = useSelector((state: RootState) => state.backend.url);
+ const backendURL = useSelector(selectBackendURL);
const clearBackendURL = () => {
dispatch(clearURL());
clearLocalStorageBackendURL();
@@ -139,7 +140,6 @@ export function BackendConfig(props: BackendConfigProps) {
setLocalStorageBackendURL(formattedURL);
dispatch(apiSlice.util.invalidateTags([QueryTags.BackendSpecific]));
setLocalBackendURL("");
- triggerFn();
}
setValidating(false);
};
@@ -149,7 +149,6 @@ export function BackendConfig(props: BackendConfigProps) {
if (backendURL != undefined) {
dispatch(setURL(backendURL));
dispatch(apiSlice.util.invalidateTags([QueryTags.BackendSpecific]));
- triggerFn();
}
}, []);
diff --git a/frontend/src/features/backend/backendSlice.ts b/frontend/src/features/backend/backendSlice.ts
index 127596838..00091391c 100644
--- a/frontend/src/features/backend/backendSlice.ts
+++ b/frontend/src/features/backend/backendSlice.ts
@@ -27,3 +27,5 @@ export const backendSlice = createSlice({
export const { setURL, clearURL } = backendSlice.actions;
export default backendSlice.reducer;
+
+export const selectBackendURL = (state: RootState) => state.backend.url;
diff --git a/frontend/src/features/import/importCSV.tsx b/frontend/src/features/import/importCSV.tsx
index 5ee3feeec..5174cd3f5 100644
--- a/frontend/src/features/import/importCSV.tsx
+++ b/frontend/src/features/import/importCSV.tsx
@@ -24,6 +24,7 @@ import {
convertLinesIntoSlotProjectMembers,
processLines,
} from "@/common/processing";
+import { selectBackendURL } from "@/features/backend/backendSlice";
import { addMembers, selectProjectSize } from "@/features/project/projectSlice";
const BorderedTable = styled(Table)`
@@ -138,7 +139,10 @@ function SampleCSV() {
export function ImportCSV() {
const dispatch = useDispatch();
- const dfcPairsQuery = useGetDFCPairsQuery();
+ const backendURL = useSelector(selectBackendURL);
+ const dfcPairsQuery = useGetDFCPairsQuery(undefined, {
+ skip: backendURL == null,
+ });
const [showCSVModal, setShowCSVModal] = useState(false);
const handleCloseCSVModal = () => setShowCSVModal(false);
const handleShowCSVModal = () => setShowCSVModal(true);
diff --git a/frontend/src/features/import/importText.tsx b/frontend/src/features/import/importText.tsx
index 9006c45c7..2428d721f 100644
--- a/frontend/src/features/import/importText.tsx
+++ b/frontend/src/features/import/importText.tsx
@@ -27,12 +27,18 @@ import {
stripTextInParentheses,
} from "@/common/processing";
import { CardDocument } from "@/common/types";
+import { selectBackendURL } from "@/features/backend/backendSlice";
import { addMembers, selectProjectSize } from "@/features/project/projectSlice";
export function ImportText() {
// TODO: add an accordion here for explaining how to search for each different card type with prefixes
- const sampleCardsQuery = useGetSampleCardsQuery();
- const dfcPairsQuery = useGetDFCPairsQuery();
+ const backendURL = useSelector(selectBackendURL);
+ const sampleCardsQuery = useGetSampleCardsQuery(undefined, {
+ skip: backendURL == null,
+ });
+ const dfcPairsQuery = useGetDFCPairsQuery(undefined, {
+ skip: backendURL == null,
+ });
const dispatch = useDispatch();
const [showTextModal, setShowTextModal] = useState(false);
diff --git a/frontend/src/features/import/importURL.tsx b/frontend/src/features/import/importURL.tsx
index ea17eb9ce..d5ec5ebc0 100644
--- a/frontend/src/features/import/importURL.tsx
+++ b/frontend/src/features/import/importURL.tsx
@@ -26,13 +26,21 @@ import {
convertLinesIntoSlotProjectMembers,
processStringAsMultipleLines,
} from "@/common/processing";
+import { selectBackendURL } from "@/features/backend/backendSlice";
import { addMembers, selectProjectSize } from "@/features/project/projectSlice";
import { Spinner } from "@/features/ui/spinner";
export function ImportURL() {
- const dfcPairsQuery = useGetDFCPairsQuery();
- const importSitesQuery = useGetImportSitesQuery();
- const backendInfoQuery = useGetBackendInfoQuery();
+ const backendURL = useSelector(selectBackendURL);
+ const dfcPairsQuery = useGetDFCPairsQuery(undefined, {
+ skip: backendURL == null,
+ });
+ const importSitesQuery = useGetImportSitesQuery(undefined, {
+ skip: backendURL == null,
+ });
+ const backendInfoQuery = useGetBackendInfoQuery(undefined, {
+ skip: backendURL == null,
+ });
const projectSize = useSelector(selectProjectSize);
const dispatch = useDispatch();
diff --git a/frontend/src/features/support/supportBackend.tsx b/frontend/src/features/support/supportBackend.tsx
index 5d7327f2d..7ce2997ec 100644
--- a/frontend/src/features/support/supportBackend.tsx
+++ b/frontend/src/features/support/supportBackend.tsx
@@ -1,8 +1,10 @@
import React from "react";
import Button from "react-bootstrap/Button";
import Modal from "react-bootstrap/Modal";
+import { useSelector } from "react-redux";
import { useGetBackendInfoQuery } from "@/app/api";
+import { selectBackendURL } from "@/features/backend/backendSlice";
import { Spinner } from "@/features/ui/spinner";
interface SupportBackendModalProps {
@@ -14,7 +16,10 @@ interface SupportBackendModalProps {
}
export function SupportBackendModal(props: SupportBackendModalProps) {
- const backendInfoQuery = useGetBackendInfoQuery();
+ const backendURL = useSelector(selectBackendURL);
+ const backendInfoQuery = useGetBackendInfoQuery(undefined, {
+ skip: backendURL == null,
+ });
return (
diff --git a/frontend/src/features/support/supportDeveloper.tsx b/frontend/src/features/support/supportDeveloper.tsx
index 1f733e324..f3be9e05e 100644
--- a/frontend/src/features/support/supportDeveloper.tsx
+++ b/frontend/src/features/support/supportDeveloper.tsx
@@ -31,7 +31,7 @@ export function SupportDeveloperModal(props: SupportDeveloperModalProps) {
I'm responsible for this website, the code that image repository
- servers run on, and the desktop tool that automates
+ servers run on, and the desktop tool that automates{" "}
{MakePlayingCards}
diff --git a/frontend/src/features/ui/footer.tsx b/frontend/src/features/ui/footer.tsx
index 1991e54c2..c57ec6c10 100644
--- a/frontend/src/features/ui/footer.tsx
+++ b/frontend/src/features/ui/footer.tsx
@@ -1,6 +1,8 @@
import Link from "next/link";
+import { useSelector } from "react-redux";
import { useGetBackendInfoQuery } from "@/app/api";
+import { selectBackendURL } from "@/features/backend/backendSlice";
function Spacer() {
return (
@@ -9,7 +11,10 @@ function Spacer() {
}
export default function Footer() {
- const backendInfoQuery = useGetBackendInfoQuery();
+ const backendURL = useSelector(selectBackendURL);
+ const backendInfoQuery = useGetBackendInfoQuery(undefined, {
+ skip: backendURL == null,
+ });
return (
<>
diff --git a/frontend/src/features/ui/navbar.tsx b/frontend/src/features/ui/navbar.tsx
index 8b5eaf41b..b37779b88 100644
--- a/frontend/src/features/ui/navbar.tsx
+++ b/frontend/src/features/ui/navbar.tsx
@@ -13,6 +13,7 @@ import { useGetBackendInfoQuery } from "@/app/api";
import { RootState } from "@/app/store";
import { ProjectName } from "@/common/constants";
import { BackendConfig } from "@/features/backend/backend";
+import { selectBackendURL } from "@/features/backend/backendSlice";
import { SupportBackendModal } from "@/features/support/supportBackend";
import { SupportDeveloperModal } from "@/features/support/supportDeveloper";
import DisableSSR from "@/features/ui/disableSSR";
@@ -30,7 +31,10 @@ const BoldCollapse = styled(BSNavbar.Collapse)`
`;
export default function Navbar() {
- const backendInfoQuery = useGetBackendInfoQuery();
+ const backendURL = useSelector(selectBackendURL);
+ const backendInfoQuery = useGetBackendInfoQuery(undefined, {
+ skip: backendURL == null,
+ });
const [showBackendConfig, setShowBackendConfig] = useState(false);
const [showSupportDeveloperModal, setShowSupportDeveloperModal] =
@@ -47,7 +51,6 @@ export default function Navbar() {
setShowSupportBackendModal(false);
const handleShowSupportBackendModal = () => setShowSupportBackendModal(true);
- const backendURL = useSelector((state: RootState) => state.backend.url);
const name =
(backendInfoQuery.isSuccess ? backendInfoQuery.data?.name : null) ??
ProjectName;
diff --git a/frontend/src/pages/about.tsx b/frontend/src/pages/about.tsx
index ba796e8ef..fa3a7f593 100644
--- a/frontend/src/pages/about.tsx
+++ b/frontend/src/pages/about.tsx
@@ -1,9 +1,11 @@
import Head from "next/head";
+import { useSelector } from "react-redux";
import styled from "styled-components";
import { useGetBackendInfoQuery } from "@/app/api";
import { ProjectName } from "@/common/constants";
import { MakePlayingCards, MakePlayingCardsURL } from "@/common/constants";
+import { selectBackendURL } from "@/features/backend/backendSlice";
import Footer from "@/features/ui/footer";
import Layout from "@/features/ui/layout";
@@ -12,7 +14,10 @@ const CentreAligned = styled.div`
`;
function BackendDescription() {
- const backendInfoQuery = useGetBackendInfoQuery();
+ const backendURL = useSelector(selectBackendURL);
+ const backendInfoQuery = useGetBackendInfoQuery(undefined, {
+ skip: backendURL == null,
+ });
return (
<>
diff --git a/frontend/src/pages/contributions.tsx b/frontend/src/pages/contributions.tsx
index fac63596f..2f18b8420 100644
--- a/frontend/src/pages/contributions.tsx
+++ b/frontend/src/pages/contributions.tsx
@@ -3,6 +3,7 @@ import Link from "next/link";
import React from "react";
import Alert from "react-bootstrap/Alert";
import Table from "react-bootstrap/Table";
+import { useSelector } from "react-redux";
import styled from "styled-components";
import { useGetBackendInfoQuery, useGetContributionsQuery } from "@/app/api";
@@ -15,6 +16,7 @@ import {
Token,
} from "@/common/constants";
import { SourceContribution } from "@/common/types";
+import { selectBackendURL } from "@/features/backend/backendSlice";
import Footer from "@/features/ui/footer";
import Layout from "@/features/ui/layout";
import { Spinner } from "@/features/ui/spinner";
@@ -24,8 +26,13 @@ const AutoLayoutTable = styled(Table)`
`;
function ContributionsSummary() {
- const contributionsQuery = useGetContributionsQuery();
- const backendInfoQuery = useGetBackendInfoQuery();
+ const backendURL = useSelector(selectBackendURL);
+ const contributionsQuery = useGetContributionsQuery(undefined, {
+ skip: backendURL == null,
+ });
+ const backendInfoQuery = useGetBackendInfoQuery(undefined, {
+ skip: backendURL == null,
+ });
const totalImages =
contributionsQuery.data?.card_count_by_type != null
@@ -73,7 +80,10 @@ function ContributionsSummary() {
}
function ContributionGuidelines() {
- const backendInfoQuery = useGetBackendInfoQuery();
+ const backendURL = useSelector(selectBackendURL);
+ const backendInfoQuery = useGetBackendInfoQuery(undefined, {
+ skip: backendURL == null,
+ });
const name = backendInfoQuery.data?.name ?? ProjectName;
@@ -166,7 +176,10 @@ function sourceContributionRow(contribution: SourceContribution) {
}
function ContributionsPerSource() {
- const contributionsQuery = useGetContributionsQuery();
+ const backendURL = useSelector(selectBackendURL);
+ const contributionsQuery = useGetContributionsQuery(undefined, {
+ skip: backendURL == null,
+ });
return contributionsQuery.isSuccess ? (
contributionsQuery.isLoading || contributionsQuery.data?.sources == null ? (