mirror of
https://github.com/idanoo/autobrr
synced 2025-07-26 02:09:13 +00:00
feat: show new updates in dashboard (#690)
* feat: show new update banner * feat(http): add request logger * refactor: updates checker * feat: make update check optional * fix: empty releases * add toggle switch for update checks * feat: toggle updates check from settings * feat: toggle updates check from settings * feat: check on toggle enabled --------- Co-authored-by: soup <soup@r4tio.dev>
This commit is contained in:
parent
3fdd7cf5e4
commit
2917a7d42d
24 changed files with 687 additions and 121 deletions
|
@ -2,11 +2,13 @@ import { Fragment } from "react";
|
|||
import { Link, NavLink, Outlet } from "react-router-dom";
|
||||
import { Disclosure, Menu, Transition } from "@headlessui/react";
|
||||
import { BookOpenIcon, UserIcon } from "@heroicons/react/24/solid";
|
||||
import { Bars3Icon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||
import { Bars3Icon, XMarkIcon, MegaphoneIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
import { AuthContext } from "../utils/Context";
|
||||
|
||||
import logo from "../logo.png";
|
||||
import { useQuery } from "react-query";
|
||||
import { APIClient } from "../api/APIClient";
|
||||
|
||||
interface NavItem {
|
||||
name: string;
|
||||
|
@ -27,6 +29,17 @@ export default function Base() {
|
|||
{ name: "Logs", path: "/logs" }
|
||||
];
|
||||
|
||||
|
||||
const { data } = useQuery(
|
||||
["updates"],
|
||||
() => APIClient.updates.getLatestRelease(),
|
||||
{
|
||||
retry: false,
|
||||
refetchOnWindowFocus: false,
|
||||
onError: err => console.log(err)
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
<Disclosure
|
||||
|
@ -185,6 +198,16 @@ export default function Base() {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{data && data.html_url && (
|
||||
<a href={data.html_url} target="_blank">
|
||||
<div className="flex mt-4 py-2 bg-blue-500 rounded justify-center">
|
||||
<MegaphoneIcon className="h-6 w-6 text-blue-100"/>
|
||||
<span className="text-blue-100 font-medium mx-3">New update available!</span>
|
||||
<span className="inline-flex items-center rounded-md bg-blue-100 px-2.5 py-0.5 text-sm font-medium text-blue-800">{data?.name}</span>
|
||||
</div>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Disclosure.Panel className="border-b border-gray-300 dark:border-gray-700 md:hidden">
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
import { useQuery } from "react-query";
|
||||
import { useMutation, useQuery } from "react-query";
|
||||
import { APIClient } from "../../api/APIClient";
|
||||
import { Checkbox } from "../../components/Checkbox";
|
||||
import { SettingsContext } from "../../utils/Context";
|
||||
import { GithubRelease } from "../../types/Update";
|
||||
import { toast } from "react-hot-toast";
|
||||
import Toast from "../../components/notifications/Toast";
|
||||
import { queryClient } from "../../App";
|
||||
|
||||
interface RowItemProps {
|
||||
label: string;
|
||||
value?: string;
|
||||
title?: string;
|
||||
newUpdate?: GithubRelease;
|
||||
}
|
||||
|
||||
const RowItem = ({ label, value, title }: RowItemProps) => {
|
||||
|
@ -23,6 +28,25 @@ const RowItem = ({ label, value, title }: RowItemProps) => {
|
|||
);
|
||||
};
|
||||
|
||||
const RowItemVersion = ({ label, value, title, newUpdate }: RowItemProps) => {
|
||||
if (!value)
|
||||
return null;
|
||||
|
||||
return (
|
||||
<div className="py-4 sm:py-5 sm:grid sm:grid-cols-4 sm:gap-4 sm:px-6">
|
||||
<dt className="font-medium text-gray-500 dark:text-white" title={title}>{label}:</dt>
|
||||
<dd className="mt-1 text-gray-900 dark:text-white sm:mt-0 sm:col-span-2 break-all">
|
||||
{value}
|
||||
{newUpdate && newUpdate.html_url && (
|
||||
<span>
|
||||
<a href={newUpdate.html_url} target="_blank"><span className="ml-2 inline-flex items-center rounded-md bg-green-100 px-2.5 py-0.5 text-sm font-medium text-green-800">{newUpdate.name} available!</span></a>
|
||||
</span>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
function ApplicationSettings() {
|
||||
const [settings, setSettings] = SettingsContext.use();
|
||||
|
||||
|
@ -36,6 +60,38 @@ function ApplicationSettings() {
|
|||
}
|
||||
);
|
||||
|
||||
const { data: updateData } = useQuery(
|
||||
["updates"],
|
||||
() => APIClient.updates.getLatestRelease(),
|
||||
{
|
||||
retry: false,
|
||||
refetchOnWindowFocus: false,
|
||||
onError: err => console.log(err)
|
||||
}
|
||||
);
|
||||
|
||||
const checkUpdateMutation = useMutation(
|
||||
() => APIClient.updates.check(),
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(["updates"]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const toggleCheckUpdateMutation = useMutation(
|
||||
(value: boolean) => APIClient.config.update({ check_for_updates: value }),
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.custom((t) => <Toast type="success" body={"Config successfully updated!"} t={t}/>);
|
||||
|
||||
queryClient.invalidateQueries(["config"]);
|
||||
|
||||
checkUpdateMutation.mutate();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="divide-y divide-gray-200 dark:divide-gray-700 lg:col-span-9">
|
||||
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
||||
|
@ -98,7 +154,7 @@ function ApplicationSettings() {
|
|||
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<div className="px-4 py-5 sm:p-0">
|
||||
<dl className="sm:divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<RowItem label="Version" value={data?.version} />
|
||||
<RowItemVersion label="Version" value={data?.version} newUpdate={updateData ?? undefined} />
|
||||
<RowItem label="Commit" value={data?.commit} />
|
||||
<RowItem label="Build date" value={data?.date} />
|
||||
<RowItem label="Log path" value={data?.log_path} title="Set in config.toml" />
|
||||
|
@ -117,6 +173,16 @@ function ApplicationSettings() {
|
|||
})}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-4 sm:px-6 py-1">
|
||||
<Checkbox
|
||||
label="Check for updates"
|
||||
description="Get notified of new updates."
|
||||
value={data?.check_for_updates ?? true}
|
||||
setValue={(newValue: boolean) => {
|
||||
toggleCheckUpdateMutation.mutate(newValue);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-4 sm:px-6 py-1">
|
||||
<Checkbox
|
||||
label="Dark theme"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue