Skip to content

Commit 79d4179

Browse files
chore(site): migrate a few services to react-query used in the DashboardProvider (#9667)
1 parent 3b088a5 commit 79d4179

29 files changed

+222
-521
lines changed

site/src/api/queries/appearance.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { QueryClient } from "@tanstack/react-query";
2+
import * as API from "api/api";
3+
import { AppearanceConfig } from "api/typesGenerated";
4+
import { getMetadataAsJSON } from "utils/metadata";
5+
6+
export const appearance = () => {
7+
return {
8+
queryKey: ["appearance"],
9+
queryFn: async () =>
10+
getMetadataAsJSON<AppearanceConfig>("appearance") ?? API.getAppearance(),
11+
};
12+
};
13+
14+
export const updateAppearance = (queryClient: QueryClient) => {
15+
return {
16+
mutationFn: API.updateAppearance,
17+
onSuccess: (newConfig: AppearanceConfig) => {
18+
queryClient.setQueryData(["appearance"], newConfig);
19+
},
20+
};
21+
};

site/src/api/queries/buildInfo.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as API from "api/api";
2+
import { BuildInfoResponse } from "api/typesGenerated";
3+
import { getMetadataAsJSON } from "utils/metadata";
4+
5+
export const buildInfo = () => {
6+
return {
7+
queryKey: ["buildInfo"],
8+
queryFn: async () =>
9+
getMetadataAsJSON<BuildInfoResponse>("build-info") ?? API.getBuildInfo(),
10+
};
11+
};

site/src/api/queries/entitlements.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { QueryClient } from "@tanstack/react-query";
2+
import * as API from "api/api";
3+
import { Entitlements } from "api/typesGenerated";
4+
import { getMetadataAsJSON } from "utils/metadata";
5+
6+
const ENTITLEMENTS_QUERY_KEY = ["entitlements"];
7+
8+
export const entitlements = () => {
9+
return {
10+
queryKey: ENTITLEMENTS_QUERY_KEY,
11+
queryFn: async () =>
12+
getMetadataAsJSON<Entitlements>("entitlements") ?? API.getEntitlements(),
13+
};
14+
};
15+
16+
export const refreshEntitlements = (queryClient: QueryClient) => {
17+
return {
18+
mutationFn: API.refreshEntitlements,
19+
onSuccess: async () => {
20+
await queryClient.invalidateQueries({
21+
queryKey: ENTITLEMENTS_QUERY_KEY,
22+
});
23+
},
24+
};
25+
};

site/src/api/queries/experiments.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as API from "api/api";
2+
import { Experiments } from "api/typesGenerated";
3+
import { getMetadataAsJSON } from "utils/metadata";
4+
5+
export const experiments = () => {
6+
return {
7+
queryKey: ["experiments"],
8+
queryFn: async () =>
9+
getMetadataAsJSON<Experiments>("experiments") ?? API.getExperiments(),
10+
};
11+
};

site/src/components/Dashboard/DashboardProvider.tsx

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
1-
import { useMachine } from "@xstate/react";
1+
import { useQuery } from "@tanstack/react-query";
2+
import { buildInfo } from "api/queries/buildInfo";
3+
import { experiments } from "api/queries/experiments";
4+
import { entitlements } from "api/queries/entitlements";
25
import {
36
AppearanceConfig,
47
BuildInfoResponse,
58
Entitlements,
69
Experiments,
710
} from "api/typesGenerated";
811
import { FullScreenLoader } from "components/Loader/FullScreenLoader";
9-
import { createContext, FC, PropsWithChildren, useContext } from "react";
10-
import { appearanceMachine } from "xServices/appearance/appearanceXService";
11-
import { buildInfoMachine } from "xServices/buildInfo/buildInfoXService";
12-
import { entitlementsMachine } from "xServices/entitlements/entitlementsXService";
13-
import { experimentsMachine } from "xServices/experiments/experimentsMachine";
12+
import {
13+
createContext,
14+
FC,
15+
PropsWithChildren,
16+
useContext,
17+
useState,
18+
} from "react";
19+
import { appearance } from "api/queries/appearance";
1420

1521
interface Appearance {
1622
config: AppearanceConfig;
17-
preview: boolean;
23+
isPreview: boolean;
1824
setPreview: (config: AppearanceConfig) => void;
19-
save: (config: AppearanceConfig) => void;
2025
}
2126

2227
interface DashboardProviderValue {
@@ -31,29 +36,16 @@ export const DashboardProviderContext = createContext<
3136
>(undefined);
3237

3338
export const DashboardProvider: FC<PropsWithChildren> = ({ children }) => {
34-
const [buildInfoState] = useMachine(buildInfoMachine);
35-
const [entitlementsState] = useMachine(entitlementsMachine);
36-
const [appearanceState, appearanceSend] = useMachine(appearanceMachine);
37-
const [experimentsState] = useMachine(experimentsMachine);
38-
const { buildInfo } = buildInfoState.context;
39-
const { entitlements } = entitlementsState.context;
40-
const { appearance, preview } = appearanceState.context;
41-
const { experiments } = experimentsState.context;
42-
const isLoading = !buildInfo || !entitlements || !appearance || !experiments;
43-
44-
const setAppearancePreview = (config: AppearanceConfig) => {
45-
appearanceSend({
46-
type: "SET_PREVIEW_APPEARANCE",
47-
appearance: config,
48-
});
49-
};
50-
51-
const saveAppearance = (config: AppearanceConfig) => {
52-
appearanceSend({
53-
type: "SAVE_APPEARANCE",
54-
appearance: config,
55-
});
56-
};
39+
const buildInfoQuery = useQuery(buildInfo());
40+
const entitlementsQuery = useQuery(entitlements());
41+
const experimentsQuery = useQuery(experiments());
42+
const appearanceQuery = useQuery(appearance());
43+
const isLoading =
44+
!buildInfoQuery.data ||
45+
!entitlementsQuery.data ||
46+
!appearanceQuery.data ||
47+
!experimentsQuery.data;
48+
const [configPreview, setConfigPreview] = useState<AppearanceConfig>();
5749

5850
if (isLoading) {
5951
return <FullScreenLoader />;
@@ -62,14 +54,13 @@ export const DashboardProvider: FC<PropsWithChildren> = ({ children }) => {
6254
return (
6355
<DashboardProviderContext.Provider
6456
value={{
65-
buildInfo,
66-
entitlements,
67-
experiments,
57+
buildInfo: buildInfoQuery.data,
58+
entitlements: entitlementsQuery.data,
59+
experiments: experimentsQuery.data,
6860
appearance: {
69-
preview,
70-
config: appearance,
71-
setPreview: setAppearancePreview,
72-
save: saveAppearance,
61+
config: configPreview ?? appearanceQuery.data,
62+
setPreview: setConfigPreview,
63+
isPreview: configPreview !== undefined,
7364
},
7465
}}
7566
>

site/src/components/Dashboard/ServiceBanner/ServiceBanner.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const ServiceBanner: React.FC = () => {
1515
<ServiceBannerView
1616
message={message}
1717
backgroundColor={background_color}
18-
preview={appearance.preview}
18+
isPreview={appearance.isPreview}
1919
/>
2020
);
2121
} else {

site/src/components/Dashboard/ServiceBanner/ServiceBannerView.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ export const Preview: Story = {
2020
args: {
2121
message: "weeeee",
2222
backgroundColor: "#000000",
23-
preview: true,
23+
isPreview: true,
2424
},
2525
};

site/src/components/Dashboard/ServiceBanner/ServiceBannerView.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import { hex } from "color-convert";
77
export interface ServiceBannerViewProps {
88
message: string;
99
backgroundColor: string;
10-
preview: boolean;
10+
isPreview: boolean;
1111
}
1212

1313
export const ServiceBannerView: React.FC<ServiceBannerViewProps> = ({
1414
message,
1515
backgroundColor,
16-
preview,
16+
isPreview,
1717
}) => {
1818
const styles = useStyles();
1919
// We don't want anything funky like an image or a heading in the service
@@ -34,7 +34,7 @@ export const ServiceBannerView: React.FC<ServiceBannerViewProps> = ({
3434
className={styles.container}
3535
style={{ backgroundColor: backgroundColor }}
3636
>
37-
{preview && <Pill text="Preview" type="info" lightBorder />}
37+
{isPreview && <Pill text="Preview" type="info" lightBorder />}
3838
<div
3939
className={styles.centerContent}
4040
style={{

site/src/components/RequireAuth/RequireAuth.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { embedRedirect } from "../../utils/redirect";
66
import { FullScreenLoader } from "../Loader/FullScreenLoader";
77
import { DashboardProvider } from "components/Dashboard/DashboardProvider";
88
import { ProxyProvider } from "contexts/ProxyContext";
9+
import { isApiError } from "api/errors";
910

1011
export const RequireAuth: FC = () => {
1112
const [authState, authSend] = useAuth();
@@ -18,11 +19,11 @@ export const RequireAuth: FC = () => {
1819
useEffect(() => {
1920
const interceptorHandle = axios.interceptors.response.use(
2021
(okResponse) => okResponse,
21-
(error) => {
22+
(error: unknown) => {
2223
// 401 Unauthorized
2324
// If we encountered an authentication error, then our token is probably
2425
// invalid and we should update the auth state to reflect that.
25-
if (error.response.status === 401) {
26+
if (isApiError(error) && error.response.status === 401) {
2627
authSend("SIGN_OUT");
2728
}
2829

site/src/components/WorkspaceStatusBadge/WorkspaceStatusBadge.stories.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,16 @@ import {
1212
MockBuildInfo,
1313
MockEntitlementsWithScheduling,
1414
MockExperiments,
15-
MockAppearance,
15+
MockAppearanceConfig,
1616
} from "testHelpers/entities";
1717
import { WorkspaceStatusBadge } from "./WorkspaceStatusBadge";
1818
import { DashboardProviderContext } from "components/Dashboard/DashboardProvider";
1919
import type { Meta, StoryObj } from "@storybook/react";
2020

2121
const MockedAppearance = {
22-
config: MockAppearance,
23-
preview: false,
24-
setPreview: () => null,
25-
save: () => null,
22+
config: MockAppearanceConfig,
23+
isPreview: false,
24+
setPreview: () => {},
2625
};
2726

2827
const meta: Meta<typeof WorkspaceStatusBadge> = {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy