mirror of
https://github.com/fosrl/pangolin.git
synced 2026-03-05 18:26:40 +00:00
🚧 wip
This commit is contained in:
@@ -1279,6 +1279,8 @@
|
|||||||
"settingsErrorUpdateDescription": "An error occurred while updating settings",
|
"settingsErrorUpdateDescription": "An error occurred while updating settings",
|
||||||
"sidebarCollapse": "Collapse",
|
"sidebarCollapse": "Collapse",
|
||||||
"sidebarExpand": "Expand",
|
"sidebarExpand": "Expand",
|
||||||
|
"productUpdateMoreInfo": "{noOfUpdates} more updates",
|
||||||
|
"productUpdateInfo": "{noOfUpdates} updates",
|
||||||
"pangolinUpdateAvailable": "New version available",
|
"pangolinUpdateAvailable": "New version available",
|
||||||
"pangolinUpdateAvailableInfo": "Version {version} is ready to install",
|
"pangolinUpdateAvailableInfo": "Version {version} is ready to install",
|
||||||
"pangolinUpdateAvailableReleaseNotes": "View release notes",
|
"pangolinUpdateAvailableReleaseNotes": "View release notes",
|
||||||
|
|||||||
@@ -3,29 +3,59 @@
|
|||||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||||
import { useLocalStorage } from "@app/hooks/useLocalStorage";
|
import { useLocalStorage } from "@app/hooks/useLocalStorage";
|
||||||
import { cn } from "@app/lib/cn";
|
import { cn } from "@app/lib/cn";
|
||||||
import { versionsQueries } from "@app/lib/queries";
|
import { productUpdatesQueries } from "@app/lib/queries";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQueries } from "@tanstack/react-query";
|
||||||
import { ArrowRight, BellIcon, XIcon } from "lucide-react";
|
import { ArrowRight, BellIcon, XIcon } from "lucide-react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
interface ProductUpdatesProps {}
|
export default function ProductUpdates() {
|
||||||
|
const data = useQueries({
|
||||||
|
queries: [
|
||||||
|
productUpdatesQueries.list,
|
||||||
|
productUpdatesQueries.latestVersion
|
||||||
|
],
|
||||||
|
combine(result) {
|
||||||
|
return {
|
||||||
|
updates: result[0].data?.data ?? [],
|
||||||
|
latestVersion: result[1].data
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const t = useTranslations();
|
||||||
|
|
||||||
export default function ProductUpdates({}: ProductUpdatesProps) {
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-1 relative z-1 overflow-clip">
|
<div className="flex flex-col gap-1 overflow-clip">
|
||||||
{/* <small className="text-xs text-muted-foreground flex items-center gap-1">
|
{data.updates.length > 0 && (
|
||||||
<BellIcon className="flex-none size-3" />
|
<small className="text-xs text-muted-foreground flex items-center gap-1">
|
||||||
<span>3 more updates</span>
|
<BellIcon className="flex-none size-3" />
|
||||||
</small> */}
|
<span>
|
||||||
<NewVersionAvailable />
|
{t("productUpdateMoreInfo", {
|
||||||
|
noOfUpdates: data.updates.length
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</small>
|
||||||
|
)}
|
||||||
|
<NewVersionAvailable version={data.latestVersion} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function NewVersionAvailable() {
|
type NewVersionAvailableProps = {
|
||||||
|
version:
|
||||||
|
| Awaited<
|
||||||
|
ReturnType<
|
||||||
|
NonNullable<
|
||||||
|
typeof productUpdatesQueries.latestVersion.queryFn
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
| undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
function NewVersionAvailable({ version }: NewVersionAvailableProps) {
|
||||||
const { env } = useEnvContext();
|
const { env } = useEnvContext();
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const { data: version } = useQuery(versionsQueries.latestVersion());
|
|
||||||
|
|
||||||
const [ignoredVersionUpdate, setIgnoredVersionUpdate] = useLocalStorage<
|
const [ignoredVersionUpdate, setIgnoredVersionUpdate] = useLocalStorage<
|
||||||
string | null
|
string | null
|
||||||
@@ -33,8 +63,8 @@ function NewVersionAvailable() {
|
|||||||
|
|
||||||
const showNewVersionPopup =
|
const showNewVersionPopup =
|
||||||
version?.data &&
|
version?.data &&
|
||||||
ignoredVersionUpdate !== version.data.pangolin.latestVersion &&
|
ignoredVersionUpdate !== version.data?.pangolin.latestVersion &&
|
||||||
env.app.version !== version.data.pangolin.latestVersion;
|
env.app.version !== version.data?.pangolin.latestVersion;
|
||||||
|
|
||||||
if (!showNewVersionPopup) return null;
|
if (!showNewVersionPopup) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +1,58 @@
|
|||||||
import {
|
import { keepPreviousData, queryOptions } from "@tanstack/react-query";
|
||||||
type InfiniteData,
|
|
||||||
type QueryClient,
|
|
||||||
keepPreviousData,
|
|
||||||
queryOptions,
|
|
||||||
type skipToken
|
|
||||||
} from "@tanstack/react-query";
|
|
||||||
import { durationToMs } from "./durationToMs";
|
import { durationToMs } from "./durationToMs";
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
import { remote } from "./api";
|
import { remote } from "./api";
|
||||||
import type ResponseT from "@server/types/Response";
|
import type ResponseT from "@server/types/Response";
|
||||||
|
|
||||||
export const versionsQueries = {
|
type ProductUpdate = {
|
||||||
latestVersion: () =>
|
link: string | null;
|
||||||
queryOptions({
|
edition: "enterprise" | "community" | "cloud" | null;
|
||||||
queryKey: ["LATEST_VERSION"] as const,
|
id: number;
|
||||||
queryFn: async ({ signal }) => {
|
priority: "CRITICAL" | "IMPORTANT" | "NORMAL" | null;
|
||||||
const data = await remote.get<
|
title: string;
|
||||||
ResponseT<{
|
contents: string;
|
||||||
pangolin: {
|
publishedAt: Date;
|
||||||
latestVersion: string;
|
showUntil: Date;
|
||||||
releaseNotes: string;
|
};
|
||||||
};
|
|
||||||
}>
|
export const productUpdatesQueries = {
|
||||||
>("/latest-version");
|
list: queryOptions({
|
||||||
return data.data;
|
queryKey: ["PRODUCT_UPDATES"] as const,
|
||||||
},
|
queryFn: async ({ signal }) => {
|
||||||
placeholderData: keepPreviousData,
|
const data = await remote.get<ResponseT<ProductUpdate[]>>(
|
||||||
refetchInterval: (query) => {
|
"/product-updates",
|
||||||
if (query.state.data) {
|
{ signal }
|
||||||
return durationToMs(30, "minutes");
|
);
|
||||||
}
|
return data.data;
|
||||||
return false;
|
},
|
||||||
},
|
refetchInterval: (query) => {
|
||||||
enabled: build === "oss" || build === "enterprise" // disabled in cloud version
|
if (query.state.data) {
|
||||||
// because we don't need to listen for new versions there
|
return durationToMs(5, "minutes");
|
||||||
})
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
latestVersion: queryOptions({
|
||||||
|
queryKey: ["LATEST_VERSION"] as const,
|
||||||
|
queryFn: async ({ signal }) => {
|
||||||
|
const data = await remote.get<
|
||||||
|
ResponseT<{
|
||||||
|
pangolin: {
|
||||||
|
latestVersion: string;
|
||||||
|
releaseNotes: string;
|
||||||
|
};
|
||||||
|
}>
|
||||||
|
>("/versions", { signal });
|
||||||
|
return data.data;
|
||||||
|
},
|
||||||
|
placeholderData: keepPreviousData,
|
||||||
|
refetchInterval: (query) => {
|
||||||
|
if (query.state.data) {
|
||||||
|
return durationToMs(30, "minutes");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
enabled: build === "oss" || build === "enterprise" // disabled in cloud version
|
||||||
|
// because we don't need to listen for new versions there
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user