mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
36
src/components/Common/Alert/index.tsx
Normal file
36
src/components/Common/Alert/index.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
|
||||
interface AlertProps {
|
||||
title: string;
|
||||
type?: 'warning';
|
||||
}
|
||||
|
||||
const Alert: React.FC<AlertProps> = ({ title, children }) => {
|
||||
return (
|
||||
<div className="rounded-md bg-yellow-600 p-4 mb-8">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<svg
|
||||
className="h-5 w-5 text-yellow-200"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<h3 className="text-sm font-medium text-yellow-200">{title}</h3>
|
||||
<div className="mt-2 text-sm text-yellow-300">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Alert;
|
186
src/components/Settings/SettingsAbout/Releases/index.tsx
Normal file
186
src/components/Settings/SettingsAbout/Releases/index.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
import React, { useState } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import LoadingSpinner from '../../../Common/LoadingSpinner';
|
||||
import Alert from '../../../Common/Alert';
|
||||
import Badge from '../../../Common/Badge';
|
||||
import Button from '../../../Common/Button';
|
||||
import Modal from '../../../Common/Modal';
|
||||
import Transition from '../../../Transition';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import globalMessages from '../../../../i18n/globalMessages';
|
||||
|
||||
const messages = defineMessages({
|
||||
releases: 'Releases',
|
||||
releasedataMissing: 'Release data missing. Is GitHub down?',
|
||||
versionChangelog: 'Version Changelog',
|
||||
viewongithub: 'View on GitHub',
|
||||
latestversion: 'Latest Version',
|
||||
currentversion: 'Current Version',
|
||||
viewchangelog: 'View Changelog',
|
||||
runningDevelop: 'You are running a develop version of Overseerr!',
|
||||
runningDevelopMessage:
|
||||
'The changes in your version will not be available below. Please look at the <GithubLink>GitHub repository</GithubLink> for latest updates.',
|
||||
});
|
||||
|
||||
const REPO_RELEASE_API =
|
||||
'https://api.github.com/repos/sct/overseerr/releases?per_page=20';
|
||||
|
||||
interface GitHubRelease {
|
||||
url: string;
|
||||
assets_url: string;
|
||||
upload_url: string;
|
||||
html_url: string;
|
||||
id: number;
|
||||
node_id: string;
|
||||
tag_name: string;
|
||||
target_commitish: string;
|
||||
name: string;
|
||||
draft: boolean;
|
||||
prerelease: boolean;
|
||||
created_at: string;
|
||||
published_at: string;
|
||||
tarball_url: string;
|
||||
zipball_url: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
interface ReleaseProps {
|
||||
release: GitHubRelease;
|
||||
isLatest: boolean;
|
||||
currentVersion: string;
|
||||
}
|
||||
|
||||
const Release: React.FC<ReleaseProps> = ({
|
||||
currentVersion,
|
||||
release,
|
||||
isLatest,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const [isModalOpen, setModalOpen] = useState(false);
|
||||
return (
|
||||
<div className="bg-gray-800 rounded-md flex flex-col sm:flex-row px-4 py-2">
|
||||
<Transition
|
||||
enter="opacity-0 transition duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="opacity-100 transition duration-300"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
show={isModalOpen}
|
||||
>
|
||||
<Modal
|
||||
onCancel={() => setModalOpen(false)}
|
||||
iconSvg={
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
title={intl.formatMessage(messages.versionChangelog)}
|
||||
cancelText={intl.formatMessage(globalMessages.close)}
|
||||
okText={intl.formatMessage(messages.viewongithub)}
|
||||
onOk={() => {
|
||||
window.open(release.html_url, '_blank');
|
||||
}}
|
||||
>
|
||||
<div className="prose">
|
||||
<ReactMarkdown>{release.body}</ReactMarkdown>
|
||||
</div>
|
||||
</Modal>
|
||||
</Transition>
|
||||
<div className="flex mb-4 sm:mb-0 items-center justify-center sm:justify-start">
|
||||
<span className="text-xl">{release.name}</span>
|
||||
{isLatest && (
|
||||
<span className="ml-2">
|
||||
<Badge badgeType="primary">
|
||||
{intl.formatMessage(messages.latestversion)}
|
||||
</Badge>
|
||||
</span>
|
||||
)}
|
||||
{release.name.includes(currentVersion) && (
|
||||
<span className="ml-2">
|
||||
<Badge badgeType="success">
|
||||
{intl.formatMessage(messages.currentversion)}
|
||||
</Badge>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 text-center sm:text-right">
|
||||
<Button buttonType="primary" onClick={() => setModalOpen(true)}>
|
||||
{intl.formatMessage(messages.viewchangelog)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface ReleasesProps {
|
||||
currentVersion: string;
|
||||
}
|
||||
|
||||
const Releases: React.FC<ReleasesProps> = ({ currentVersion }) => {
|
||||
const intl = useIntl();
|
||||
const { data, error } = useSWR<GitHubRelease[]>(REPO_RELEASE_API);
|
||||
|
||||
if (!data && !error) {
|
||||
return <LoadingSpinner />;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="text-gray-300">
|
||||
{intl.formatMessage(messages.releasedataMissing)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="text-xl pb-4 mb-4 border-b border-gray-800">
|
||||
{intl.formatMessage(messages.releases)}
|
||||
</div>
|
||||
{currentVersion.startsWith('develop-') && (
|
||||
<Alert title={intl.formatMessage(messages.runningDevelop)}>
|
||||
{intl.formatMessage(messages.runningDevelopMessage, {
|
||||
GithubLink: function GithubLink(msg) {
|
||||
return (
|
||||
<a
|
||||
href="https://github.com/sct/overseerr"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-yellow-100 underline hover:text-white transition duration-300"
|
||||
>
|
||||
{msg}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
})}
|
||||
</Alert>
|
||||
)}
|
||||
{data?.map((release, index) => {
|
||||
return (
|
||||
<div key={`release-${release.id}`} className="mb-2">
|
||||
<Release
|
||||
release={release}
|
||||
currentVersion={currentVersion}
|
||||
isLatest={index === 0}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Releases;
|
@@ -5,6 +5,7 @@ import List from '../../Common/List';
|
||||
import LoadingSpinner from '../../Common/LoadingSpinner';
|
||||
import { SettingsAboutResponse } from '../../../../server/interfaces/api/settingsInterfaces';
|
||||
import { defineMessages, FormattedNumber, useIntl } from 'react-intl';
|
||||
import Releases from './Releases';
|
||||
|
||||
const messages = defineMessages({
|
||||
overseerrinformation: 'Overseerr Information',
|
||||
@@ -97,6 +98,9 @@ const SettingsAbout: React.FC = () => {
|
||||
</List.Item>
|
||||
</List>
|
||||
</div>
|
||||
<div className="mb-8">
|
||||
<Releases currentVersion={data.version} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@@ -13,6 +13,7 @@ import Modal from '../Common/Modal';
|
||||
import Transition from '../Transition';
|
||||
import axios from 'axios';
|
||||
import SonarrModal from './SonarrModal';
|
||||
import Alert from '../Common/Alert';
|
||||
|
||||
const messages = defineMessages({
|
||||
radarrsettings: 'Radarr Settings',
|
||||
@@ -37,42 +38,6 @@ const messages = defineMessages({
|
||||
no4kimplemented: '(Default 4K servers are not currently implemented)',
|
||||
});
|
||||
|
||||
const NoDefaultAlert: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<div className="rounded-md bg-yellow-600 p-4 mb-8">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<svg
|
||||
className="h-5 w-5 text-yellow-200"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<h3 className="text-sm font-medium text-yellow-200">
|
||||
{intl.formatMessage(messages.nodefault)}
|
||||
</h3>
|
||||
<div className="mt-2 text-sm text-yellow-300">
|
||||
<p>{intl.formatMessage(messages.nodefaultdescription)}</p>
|
||||
<p className="mt-2">
|
||||
{intl.formatMessage(messages.no4kimplemented)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface ServerInstanceProps {
|
||||
name: string;
|
||||
isDefault?: boolean;
|
||||
@@ -188,6 +153,7 @@ const ServerInstance: React.FC<ServerInstanceProps> = ({
|
||||
};
|
||||
|
||||
const SettingsServices: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const {
|
||||
data: radarrData,
|
||||
error: radarrError,
|
||||
@@ -293,7 +259,14 @@ const SettingsServices: React.FC = () => {
|
||||
{radarrData.length > 0 &&
|
||||
!radarrData.some(
|
||||
(radarr) => radarr.isDefault && !radarr.is4k
|
||||
) && <NoDefaultAlert />}
|
||||
) && (
|
||||
<Alert title={intl.formatMessage(messages.nodefault)}>
|
||||
<p>{intl.formatMessage(messages.nodefaultdescription)}</p>
|
||||
<p className="mt-2">
|
||||
{intl.formatMessage(messages.no4kimplemented)}
|
||||
</p>
|
||||
</Alert>
|
||||
)}
|
||||
<ul className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{radarrData.map((radarr) => (
|
||||
<ServerInstance
|
||||
@@ -357,7 +330,14 @@ const SettingsServices: React.FC = () => {
|
||||
{sonarrData.length > 0 &&
|
||||
!sonarrData.some(
|
||||
(sonarr) => sonarr.isDefault && !sonarr.is4k
|
||||
) && <NoDefaultAlert />}
|
||||
) && (
|
||||
<Alert title={intl.formatMessage(messages.nodefault)}>
|
||||
<p>{intl.formatMessage(messages.nodefaultdescription)}</p>
|
||||
<p className="mt-2">
|
||||
{intl.formatMessage(messages.no4kimplemented)}
|
||||
</p>
|
||||
</Alert>
|
||||
)}
|
||||
<ul className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{sonarrData.map((sonarr) => (
|
||||
<ServerInstance
|
||||
|
Reference in New Issue
Block a user