Skip to content

Commit 115813e

Browse files
committed
chore: add extra runtime validation for colors
1 parent f34c7b9 commit 115813e

File tree

2 files changed

+38
-10
lines changed

2 files changed

+38
-10
lines changed

site/src/components/Dashboard/DashboardProvider.tsx

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ import {
1010
} from "api/typesGenerated";
1111
import { FullScreenLoader } from "components/Loader/FullScreenLoader";
1212
import {
13+
type FC,
14+
type PropsWithChildren,
1315
createContext,
14-
FC,
15-
PropsWithChildren,
16+
useCallback,
1617
useContext,
1718
useState,
1819
} from "react";
1920
import { appearance } from "api/queries/appearance";
21+
import { hslToHex, isHexColor, isHslColor } from "utils/colors";
22+
import { displayError } from "components/GlobalSnackbar/utils";
2023

2124
interface Appearance {
2225
config: AppearanceConfig;
@@ -45,8 +48,35 @@ export const DashboardProvider: FC<PropsWithChildren> = ({ children }) => {
4548
!entitlementsQuery.data ||
4649
!appearanceQuery.data ||
4750
!experimentsQuery.data;
51+
4852
const [configPreview, setConfigPreview] = useState<AppearanceConfig>();
4953

54+
// Centralizing the logic for catching malformed configs in one spot, just to
55+
// be on the safe side; don't want to expose raw setConfigPreview outside
56+
// the provider
57+
const setPreview = useCallback((newConfig: AppearanceConfig) => {
58+
// Have runtime safety nets in place, just because so much of the codebase
59+
// relies on HSL for formatting, but server expects hex values. Can't catch
60+
// color format mismatches at the type level
61+
const incomingBg = newConfig.service_banner.background_color;
62+
let configForDispatch = newConfig;
63+
64+
if (typeof incomingBg === "string" && isHslColor(incomingBg)) {
65+
configForDispatch = {
66+
...newConfig,
67+
service_banner: {
68+
...newConfig.service_banner,
69+
background_color: hslToHex(incomingBg),
70+
},
71+
};
72+
} else if (typeof incomingBg === "string" && !isHexColor(incomingBg)) {
73+
displayError(`The value ${incomingBg} is not a valid hex string`);
74+
return;
75+
}
76+
77+
setConfigPreview(configForDispatch);
78+
}, []);
79+
5080
if (isLoading) {
5181
return <FullScreenLoader />;
5282
}
@@ -59,7 +89,7 @@ export const DashboardProvider: FC<PropsWithChildren> = ({ children }) => {
5989
experiments: experimentsQuery.data,
6090
appearance: {
6191
config: configPreview ?? appearanceQuery.data,
62-
setPreview: setConfigPreview,
92+
setPreview: setPreview,
6393
isPreview: configPreview !== undefined,
6494
},
6595
}}

site/src/pages/DeploySettingsPage/AppearanceSettingsPage/AppearanceSettingsPage.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,17 @@ const AppearanceSettingsPage: FC = () => {
1717
const { appearance, entitlements } = useDashboard();
1818
const queryClient = useQueryClient();
1919
const updateAppearanceMutation = useMutation(updateAppearance(queryClient));
20-
const isEntitled =
21-
entitlements.features["appearance"].entitlement !== "not_entitled";
2220

2321
const onSaveAppearance = async (
2422
newConfig: Partial<UpdateAppearanceConfig>,
2523
preview: boolean,
2624
) => {
27-
const newAppearance = {
28-
...appearance.config,
29-
...newConfig,
30-
};
25+
const newAppearance = { ...appearance.config, ...newConfig };
3126
if (preview) {
3227
appearance.setPreview(newAppearance);
3328
return;
3429
}
30+
3531
try {
3632
await updateAppearanceMutation.mutateAsync(newAppearance);
3733
displaySuccess("Successfully updated appearance settings!");
@@ -50,8 +46,10 @@ const AppearanceSettingsPage: FC = () => {
5046

5147
<AppearanceSettingsPageView
5248
appearance={appearance.config}
53-
isEntitled={isEntitled}
5449
onSaveAppearance={onSaveAppearance}
50+
isEntitled={
51+
entitlements.features.appearance.entitlement !== "not_entitled"
52+
}
5553
/>
5654
</>
5755
);

0 commit comments

Comments
 (0)