diff --git a/client/src/Components/Inputs/TextInput/index.jsx b/client/src/Components/Inputs/TextInput/index.jsx
index 650dc29c5..58e0e17eb 100644
--- a/client/src/Components/Inputs/TextInput/index.jsx
+++ b/client/src/Components/Inputs/TextInput/index.jsx
@@ -104,6 +104,7 @@ const TextInput = forwardRef(
fontSize={"var(--env-var-font-size-medium)"}
color={theme.palette.primary.contrastTextSecondary}
fontWeight={500}
+ mb={theme.spacing(2)}
>
{label}
{isRequired && }
diff --git a/client/src/Features/Settings/settingsSlice.js b/client/src/Features/Settings/settingsSlice.js
index 967858901..02724af02 100644
--- a/client/src/Features/Settings/settingsSlice.js
+++ b/client/src/Features/Settings/settingsSlice.js
@@ -6,6 +6,7 @@ const initialState = {
apiBaseUrl: "",
logLevel: "debug",
language: "gb",
+ pagespeedApiKey: "",
};
export const getAppSettings = createAsyncThunk(
@@ -33,6 +34,7 @@ export const updateAppSettings = createAsyncThunk(
try {
const parsedSettings = {
language: settings.language,
+ pagespeedApiKey: settings.pagespeedApiKey,
};
const res = await networkService.updateAppSettings({ settings: parsedSettings });
return res.data;
@@ -56,6 +58,7 @@ const handleGetSettingsFulfilled = (state, action) => {
state.apiBaseUrl = action.payload.data.apiBaseUrl;
state.logLevel = action.payload.data.logLevel;
state.language = action.payload.data.language;
+ state.pagespeedApiKey = action.payload.data.pagespeedApiKey;
};
const handleGetSettingsRejected = (state, action) => {
state.isLoading = false;
diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx
index c208dd63c..554ee6857 100644
--- a/client/src/Pages/Settings/index.jsx
+++ b/client/src/Pages/Settings/index.jsx
@@ -6,6 +6,8 @@ import Select from "../../Components/Inputs/Select";
import { useIsAdmin } from "../../Hooks/useIsAdmin";
import Dialog from "../../Components/Dialog";
import ConfigBox from "../../Components/ConfigBox";
+import { PasswordEndAdornment } from "../../Components/Inputs/TextInput/Adornments";
+import { getAppSettings } from "../../Features/Settings/settingsSlice";
// import {
// WalletMultiButton,
// WalletDisconnectButton,
@@ -54,8 +56,11 @@ const Settings = () => {
const [form, setForm] = useState({
enableDistributedUptime: distributedUptimeEnabled,
ttl: checkTTL ? (checkTTL / SECONDS_PER_DAY).toString() : 0,
+ pagespeedApiKey: "",
});
const [version, setVersion] = useState("unknown");
+ const [apiKeyFieldType, setApiKeyFieldType] = useState("password");
+ const [isApiKeySet, setIsApiKeySet] = useState(false);
const [errors, setErrors] = useState({});
const deleteStatsMonitorsInitState = { deleteMonitors: false, deleteStats: false };
const [isOpen, setIsOpen] = useState(deleteStatsMonitorsInitState);
@@ -80,6 +85,28 @@ const Settings = () => {
fetchLatestVersion();
}, []);
+ useEffect(() => {
+ dispatch(getAppSettings());
+ }, []);
+
+ const { pagespeedApiKey } = useSelector((state) => state.settings);
+
+ useEffect(() => {
+ if (pagespeedApiKey) {
+ setIsApiKeySet(true);
+ setForm((prev) => ({
+ ...prev,
+ pagespeedApiKey: t("maskedPageSpeedKeyPlaceholder"),
+ }));
+ } else {
+ setIsApiKeySet(false);
+ setForm((prev) => ({
+ ...prev,
+ pagespeedApiKey: "",
+ }));
+ }
+ }, [pagespeedApiKey]);
+
const handleChange = (event) => {
const { type, checked, value, id } = event.target;
@@ -91,12 +118,17 @@ const Settings = () => {
return;
}
+ let inputValue = value;
+ if (id === "ttl") {
+ inputValue = value.replace(/[^0-9]/g, "");
+ }
+
+ const updatedForm = { ...form, [id]: inputValue };
const { error } = settingsValidation.validate(
- { [id]: value },
- {
- abortEarly: false,
- }
+ updatedForm,
+ { abortEarly: false }
);
+
if (!error || error.details.length === 0) {
setErrors({});
} else {
@@ -107,12 +139,8 @@ const Settings = () => {
setErrors(newErrors);
logger.error("Validation errors:", error.details);
}
- let inputValue = value;
- id === "ttl" && (inputValue = value.replace(/[^0-9]/g, ""));
- setForm((prev) => ({
- ...prev,
- [id]: inputValue,
- }));
+
+ setForm(updatedForm);
};
// TODO Handle saving
@@ -125,7 +153,7 @@ const Settings = () => {
const updatedUser = { ...user, checkTTL: form.ttl };
const [userAction, settingsAction] = await Promise.all([
dispatch(update({ localData: updatedUser })),
- dispatch(updateAppSettings({ settings: { language: language } })),
+ dispatch(updateAppSettings({ settings: { language: language, pagespeedApiKey: form.pagespeedApiKey } })),
]);
if (userAction.payload.success && settingsAction.payload.success) {
@@ -187,6 +215,14 @@ const Settings = () => {
}
};
+ const handleResetApiKey = () => {
+ setIsApiKeySet(false);
+ setForm((prev) => ({
+ ...prev,
+ pagespeedApiKey: "",
+ }));
+ };
+
const languages = Object.keys(i18n.options.resources || {});
return (
@@ -277,6 +313,43 @@ const Settings = () => {
)} */}
+
+
+ {t("pageSpeedApiKeyFieldTitle")}
+
+ {t("pageSpeedApiKeyFieldDescription")}
+
+
+
+
+ )
+ }
+ />
+ {isApiKeySet && (
+
+ {t("pageSpeedApiKeyFieldResetLabel")}
+
+
+ )}
+
+
{/* {isAdmin && (
diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js
index 01a2fd48c..6f27b8f32 100644
--- a/client/src/Validation/validation.js
+++ b/client/src/Validation/validation.js
@@ -257,7 +257,9 @@ const settingsValidation = joi.object({
"number.base": "Please enter a valid number",
"any.required": "Please enter a value"
}),
-});
+ pagespeedApiKey: joi.string().allow("").optional(),
+})
+.unknown(true);
const dayjsValidator = (value, helpers) => {
if (!dayjs(value).isValid()) {
diff --git a/client/src/locales/gb.json b/client/src/locales/gb.json
index a2db25374..46174c62c 100644
--- a/client/src/locales/gb.json
+++ b/client/src/locales/gb.json
@@ -430,6 +430,12 @@
"noFileSelected": "No file selected",
"fallbackPage": "Import a file to upload a list of servers in bulk"
},
- "publicLink": "Public link"
+ "publicLink": "Public link",
+ "maskedPageSpeedKeyPlaceholder": "*************************************",
+ "pageSpeedApiKeyFieldTitle": "Google PageSpeed API key",
+ "pageSpeedApiKeyFieldLabel": "PageSpeed API key",
+ "pageSpeedApiKeyFieldDescription": "Enter your Google PageSpeed API key to enable pagespeed monitoring. Click Reset to update the key.",
+ "pageSpeedApiKeyFieldResetLabel": "API key is set. Click Reset to change it.",
+ "reset": "Reset"
}