mirror of
https://github.com/karl0ss/homepage.git
synced 2025-04-29 12:03:41 +01:00
revalidate config changes, check on focus changes
This commit is contained in:
parent
5f0c1ec70a
commit
c980c70798
27
src/pages/api/hash.js
Normal file
27
src/pages/api/hash.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { join } from "path";
|
||||||
|
import { createHash } from "crypto";
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
|
||||||
|
import checkAndCopyConfig from "utils/config/config";
|
||||||
|
|
||||||
|
const configs = ["docker.yaml", "settings.yaml", "services.yaml", "bookmarks.yaml"];
|
||||||
|
|
||||||
|
function hash(buffer) {
|
||||||
|
const hashSum = createHash("sha256");
|
||||||
|
hashSum.update(buffer);
|
||||||
|
return hashSum.digest("hex");
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function handler(req, res) {
|
||||||
|
const hashes = configs.map((config) => {
|
||||||
|
checkAndCopyConfig(config);
|
||||||
|
const configYaml = join(process.cwd(), "config", config);
|
||||||
|
return hash(readFileSync(configYaml, "utf8"));
|
||||||
|
});
|
||||||
|
|
||||||
|
const combinedHash = hash(hashes.join(""));
|
||||||
|
|
||||||
|
res.send({
|
||||||
|
hash: combinedHash,
|
||||||
|
});
|
||||||
|
}
|
@ -3,7 +3,7 @@ import useSWR, { SWRConfig } from "swr";
|
|||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import { useEffect, useContext } from "react";
|
import { useEffect, useContext, useState } from "react";
|
||||||
import { BiError } from "react-icons/bi";
|
import { BiError } from "react-icons/bi";
|
||||||
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
|
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
|
||||||
|
|
||||||
@ -17,6 +17,7 @@ import { ColorContext } from "utils/contexts/color";
|
|||||||
import { ThemeContext } from "utils/contexts/theme";
|
import { ThemeContext } from "utils/contexts/theme";
|
||||||
import { SettingsContext } from "utils/contexts/settings";
|
import { SettingsContext } from "utils/contexts/settings";
|
||||||
import { bookmarksResponse, servicesResponse, widgetsResponse } from "utils/config/api-response";
|
import { bookmarksResponse, servicesResponse, widgetsResponse } from "utils/config/api-response";
|
||||||
|
import useWindowFocus from "utils/hooks/window-focus";
|
||||||
|
|
||||||
const ThemeToggle = dynamic(() => import("components/toggles/theme"), {
|
const ThemeToggle = dynamic(() => import("components/toggles/theme"), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
@ -49,6 +50,7 @@ export async function getStaticProps() {
|
|||||||
"/api/services": services,
|
"/api/services": services,
|
||||||
"/api/bookmarks": bookmarks,
|
"/api/bookmarks": bookmarks,
|
||||||
"/api/widgets": widgets,
|
"/api/widgets": widgets,
|
||||||
|
"/api/hash": false,
|
||||||
},
|
},
|
||||||
...(await serverSideTranslations(settings.language ?? "en")),
|
...(await serverSideTranslations(settings.language ?? "en")),
|
||||||
},
|
},
|
||||||
@ -67,7 +69,47 @@ export async function getStaticProps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Index({ initialSettings, fallback }) {
|
export default function Index({ initialSettings, fallback }) {
|
||||||
|
const windowFocused = useWindowFocus();
|
||||||
|
const [stale, setStale] = useState(false);
|
||||||
const { data: errorsData } = useSWR("/api/validate");
|
const { data: errorsData } = useSWR("/api/validate");
|
||||||
|
const { data: hashData, mutate: mutateHash } = useSWR("/api/hash");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (windowFocused) {
|
||||||
|
mutateHash();
|
||||||
|
}
|
||||||
|
}, [windowFocused, mutateHash]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hashData) {
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
const previousHash = localStorage.getItem("hash");
|
||||||
|
|
||||||
|
if (!previousHash) {
|
||||||
|
localStorage.setItem("hash", hashData.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousHash && previousHash !== hashData.hash) {
|
||||||
|
setStale(true);
|
||||||
|
localStorage.setItem("hash", hashData.hash);
|
||||||
|
|
||||||
|
fetch("/api/revalidate").then((res) => {
|
||||||
|
if (res.ok) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [hashData]);
|
||||||
|
|
||||||
|
if (stale) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center h-screen">
|
||||||
|
<div className="w-24 h-24 border-2 border-theme-400 border-solid rounded-full animate-spin border-t-transparent" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (errorsData && errorsData.length > 0) {
|
if (errorsData && errorsData.length > 0) {
|
||||||
return (
|
return (
|
||||||
|
26
src/utils/hooks/window-focus.js
Normal file
26
src/utils/hooks/window-focus.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
const hasFocus = () => typeof document !== "undefined" && document.hasFocus();
|
||||||
|
|
||||||
|
const useWindowFocus = () => {
|
||||||
|
const [focused, setFocused] = useState(hasFocus);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setFocused(hasFocus());
|
||||||
|
|
||||||
|
const onFocus = () => setFocused(true);
|
||||||
|
const onBlur = () => setFocused(false);
|
||||||
|
|
||||||
|
window.addEventListener("focus", onFocus);
|
||||||
|
window.addEventListener("blur", onBlur);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("focus", onFocus);
|
||||||
|
window.removeEventListener("blur", onBlur);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return focused;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useWindowFocus;
|
Loading…
x
Reference in New Issue
Block a user