refactor: switch from Fetch API to Axios (#1520)
* refactor: switch from Fetch API to Axios * fix: remove unwanted changes * fix: rewrite error handling for Axios and remove IPv4 first setting * style: run prettier * style: run prettier * fix: add back custom proxy agent * fix: add back custom proxy agent * fix: correct rebase issue * fix: resolve review comments
This commit is contained in:
@@ -5,6 +5,7 @@ import useSettings from '@app/hooks/useSettings';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -83,24 +84,17 @@ const NotificationsDiscord = () => {
|
||||
validationSchema={NotificationsDiscordSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/notifications/discord', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
await axios.post('/api/v1/settings/notifications/discord', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
botUsername: values.botUsername,
|
||||
botAvatarUrl: values.botAvatarUrl,
|
||||
webhookUrl: values.webhookUrl,
|
||||
webhookRoleId: values.webhookRoleId,
|
||||
enableMentions: values.enableMentions,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
botUsername: values.botUsername,
|
||||
botAvatarUrl: values.botAvatarUrl,
|
||||
webhookUrl: values.webhookUrl,
|
||||
webhookRoleId: values.webhookRoleId,
|
||||
enableMentions: values.enableMentions,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.discordsettingssaved), {
|
||||
appearance: 'success',
|
||||
@@ -139,27 +133,17 @@ const NotificationsDiscord = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/discord/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
botUsername: values.botUsername,
|
||||
botAvatarUrl: values.botAvatarUrl,
|
||||
webhookUrl: values.webhookUrl,
|
||||
webhookRoleId: values.webhookRoleId,
|
||||
enableMentions: values.enableMentions,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/notifications/discord/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
botUsername: values.botUsername,
|
||||
botAvatarUrl: values.botAvatarUrl,
|
||||
webhookUrl: values.webhookUrl,
|
||||
webhookRoleId: values.webhookRoleId,
|
||||
enableMentions: values.enableMentions,
|
||||
},
|
||||
});
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -5,6 +5,7 @@ import SettingsBadge from '@app/components/Settings/SettingsBadge';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -147,31 +148,24 @@ const NotificationsEmail = () => {
|
||||
validationSchema={NotificationsEmailSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/notifications/email', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
await axios.post('/api/v1/settings/notifications/email', {
|
||||
enabled: values.enabled,
|
||||
options: {
|
||||
userEmailRequired: values.userEmailRequired,
|
||||
emailFrom: values.emailFrom,
|
||||
smtpHost: values.smtpHost,
|
||||
smtpPort: Number(values.smtpPort),
|
||||
secure: values.encryption === 'implicit',
|
||||
ignoreTls: values.encryption === 'none',
|
||||
requireTls: values.encryption === 'opportunistic',
|
||||
authUser: values.authUser,
|
||||
authPass: values.authPass,
|
||||
allowSelfSigned: values.allowSelfSigned,
|
||||
senderName: values.senderName,
|
||||
pgpPrivateKey: values.pgpPrivateKey,
|
||||
pgpPassword: values.pgpPassword,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
options: {
|
||||
userEmailRequired: values.userEmailRequired,
|
||||
emailFrom: values.emailFrom,
|
||||
smtpHost: values.smtpHost,
|
||||
smtpPort: Number(values.smtpPort),
|
||||
secure: values.encryption === 'implicit',
|
||||
ignoreTls: values.encryption === 'none',
|
||||
requireTls: values.encryption === 'opportunistic',
|
||||
authUser: values.authUser,
|
||||
authPass: values.authPass,
|
||||
allowSelfSigned: values.allowSelfSigned,
|
||||
senderName: values.senderName,
|
||||
pgpPrivateKey: values.pgpPrivateKey,
|
||||
pgpPassword: values.pgpPassword,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/settings/public');
|
||||
|
||||
addToast(intl.formatMessage(messages.emailsettingssaved), {
|
||||
@@ -203,33 +197,23 @@ const NotificationsEmail = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/email/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
options: {
|
||||
emailFrom: values.emailFrom,
|
||||
smtpHost: values.smtpHost,
|
||||
smtpPort: Number(values.smtpPort),
|
||||
secure: values.encryption === 'implicit',
|
||||
ignoreTls: values.encryption === 'none',
|
||||
requireTls: values.encryption === 'opportunistic',
|
||||
authUser: values.authUser,
|
||||
authPass: values.authPass,
|
||||
allowSelfSigned: values.allowSelfSigned,
|
||||
senderName: values.senderName,
|
||||
pgpPrivateKey: values.pgpPrivateKey,
|
||||
pgpPassword: values.pgpPassword,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/notifications/email/test', {
|
||||
enabled: true,
|
||||
options: {
|
||||
emailFrom: values.emailFrom,
|
||||
smtpHost: values.smtpHost,
|
||||
smtpPort: Number(values.smtpPort),
|
||||
secure: values.encryption === 'implicit',
|
||||
ignoreTls: values.encryption === 'none',
|
||||
requireTls: values.encryption === 'opportunistic',
|
||||
authUser: values.authUser,
|
||||
authPass: values.authPass,
|
||||
allowSelfSigned: values.allowSelfSigned,
|
||||
senderName: values.senderName,
|
||||
pgpPrivateKey: values.pgpPrivateKey,
|
||||
pgpPassword: values.pgpPassword,
|
||||
},
|
||||
});
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -4,6 +4,7 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/solid';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -94,22 +95,15 @@ const NotificationsGotify = () => {
|
||||
validationSchema={NotificationsGotifySchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/notifications/gotify', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
await axios.post('/api/v1/settings/notifications/gotify', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
url: values.url,
|
||||
token: values.token,
|
||||
priority: Number(values.priority),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
url: values.url,
|
||||
token: values.token,
|
||||
priority: Number(values.priority),
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.gotifysettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -147,25 +141,15 @@ const NotificationsGotify = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/gotify/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
url: values.url,
|
||||
token: values.token,
|
||||
priority: Number(values.priority),
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/notifications/gotify/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
url: values.url,
|
||||
token: values.token,
|
||||
priority: Number(values.priority),
|
||||
},
|
||||
});
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -4,6 +4,7 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -68,21 +69,14 @@ const NotificationsLunaSea = () => {
|
||||
validationSchema={NotificationsLunaSeaSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/notifications/lunasea', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
await axios.post('/api/v1/settings/notifications/lunasea', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
profileName: values.profileName,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
profileName: values.profileName,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.settingsSaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -120,24 +114,14 @@ const NotificationsLunaSea = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/lunasea/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
profileName: values.profileName,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/notifications/lunasea/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
profileName: values.profileName,
|
||||
},
|
||||
});
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -5,6 +5,7 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -67,21 +68,14 @@ const NotificationsPushbullet = () => {
|
||||
validationSchema={NotificationsPushbulletSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/notifications/pushbullet', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
await axios.post('/api/v1/settings/notifications/pushbullet', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
channelTag: values.channelTag,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
channelTag: values.channelTag,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.pushbulletSettingsSaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -119,24 +113,14 @@ const NotificationsPushbullet = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/pushbullet/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
channelTag: values.channelTag,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/notifications/pushbullet/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
channelTag: values.channelTag,
|
||||
},
|
||||
});
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -5,6 +5,7 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import type { PushoverSound } from '@server/api/pushover';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -93,21 +94,14 @@ const NotificationsPushover = () => {
|
||||
validationSchema={NotificationsPushoverSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/notifications/pushover', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
await axios.post('/api/v1/settings/notifications/pushover', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
userToken: values.userToken,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
userToken: values.userToken,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.pushoversettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -145,25 +139,16 @@ const NotificationsPushover = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/pushover/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
userToken: values.userToken,
|
||||
sound: values.sound,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/notifications/pushover/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
userToken: values.userToken,
|
||||
sound: values.sound,
|
||||
},
|
||||
});
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -64,20 +65,13 @@ const NotificationsSlack = () => {
|
||||
validationSchema={NotificationsSlackSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/notifications/slack', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
await axios.post('/api/v1/settings/notifications/slack', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.slacksettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -115,23 +109,13 @@ const NotificationsSlack = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/slack/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/notifications/slack/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
},
|
||||
});
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -5,6 +5,7 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -98,24 +99,17 @@ const NotificationsTelegram = () => {
|
||||
validationSchema={NotificationsTelegramSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/notifications/telegram', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
await axios.post('/api/v1/settings/notifications/telegram', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
botAPI: values.botAPI,
|
||||
chatId: values.chatId,
|
||||
messageThreadId: values.messageThreadId,
|
||||
sendSilently: values.sendSilently,
|
||||
botUsername: values.botUsername,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
botAPI: values.botAPI,
|
||||
chatId: values.chatId,
|
||||
messageThreadId: values.messageThreadId,
|
||||
sendSilently: values.sendSilently,
|
||||
botUsername: values.botUsername,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.telegramsettingssaved), {
|
||||
appearance: 'success',
|
||||
@@ -154,27 +148,17 @@ const NotificationsTelegram = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/telegram/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
botAPI: values.botAPI,
|
||||
chatId: values.chatId,
|
||||
messageThreadId: values.messageThreadId,
|
||||
sendSilently: values.sendSilently,
|
||||
botUsername: values.botUsername,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/notifications/telegram/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
botAPI: values.botAPI,
|
||||
chatId: values.chatId,
|
||||
messageThreadId: values.messageThreadId,
|
||||
sendSilently: values.sendSilently,
|
||||
botUsername: values.botUsername,
|
||||
},
|
||||
});
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -4,6 +4,7 @@ import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -57,17 +58,10 @@ const NotificationsWebPush = () => {
|
||||
}}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/notifications/webpush', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
options: {},
|
||||
}),
|
||||
await axios.post('/api/v1/settings/notifications/webpush', {
|
||||
enabled: values.enabled,
|
||||
options: {},
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/settings/public');
|
||||
addToast(intl.formatMessage(messages.webpushsettingssaved), {
|
||||
appearance: 'success',
|
||||
@@ -98,20 +92,10 @@ const NotificationsWebPush = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/webpush/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
options: {},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/notifications/webpush/test', {
|
||||
enabled: true,
|
||||
options: {},
|
||||
});
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
ArrowPathIcon,
|
||||
QuestionMarkCircleIcon,
|
||||
} from '@heroicons/react/24/solid';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import dynamic from 'next/dynamic';
|
||||
import Link from 'next/link';
|
||||
@@ -149,22 +150,15 @@ const NotificationsWebhook = () => {
|
||||
validationSchema={NotificationsWebhookSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/notifications/webhook', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
await axios.post('/api/v1/settings/notifications/webhook', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
jsonPayload: JSON.stringify(values.jsonPayload),
|
||||
authHeader: values.authHeader,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
jsonPayload: JSON.stringify(values.jsonPayload),
|
||||
authHeader: values.authHeader,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.webhooksettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -213,25 +207,16 @@ const NotificationsWebhook = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/webhook/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
jsonPayload: JSON.stringify(values.jsonPayload),
|
||||
authHeader: values.authHeader,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/notifications/webhook/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
jsonPayload: JSON.stringify(values.jsonPayload),
|
||||
authHeader: values.authHeader,
|
||||
},
|
||||
});
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
RadarrSettings,
|
||||
SonarrSettings,
|
||||
} from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Formik } from 'formik';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -95,24 +96,19 @@ const OverrideRuleModal = ({
|
||||
}) => {
|
||||
setIsTesting(true);
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/sonarr/test', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
const response = await axios.post<DVRTestResponse>(
|
||||
'/api/v1/settings/sonarr/test',
|
||||
{
|
||||
hostname,
|
||||
apiKey,
|
||||
port: Number(port),
|
||||
baseUrl,
|
||||
useSsl,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data: DVRTestResponse = await res.json();
|
||||
}
|
||||
);
|
||||
|
||||
setIsValidated(true);
|
||||
setTestResponse(data);
|
||||
setTestResponse(response.data);
|
||||
} catch (e) {
|
||||
setIsValidated(false);
|
||||
} finally {
|
||||
@@ -179,27 +175,13 @@ const OverrideRuleModal = ({
|
||||
sonarrServiceId: values.sonarrServiceId,
|
||||
};
|
||||
if (!rule) {
|
||||
const res = await fetch('/api/v1/overrideRule', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(submission),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/overrideRule', submission);
|
||||
addToast(intl.formatMessage(messages.ruleCreated), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
});
|
||||
} else {
|
||||
const res = await fetch(`/api/v1/overrideRule/${rule.id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(submission),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.put(`/api/v1/overrideRule/${rule.id}`, submission);
|
||||
addToast(intl.formatMessage(messages.ruleUpdated), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
|
||||
@@ -12,6 +12,7 @@ import type {
|
||||
SonarrSettings,
|
||||
} from '@server/lib/settings';
|
||||
import type { Keyword } from '@server/models/common';
|
||||
import axios from 'axios';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import useSWR from 'swr';
|
||||
@@ -64,34 +65,26 @@ const OverrideRuleTiles = ({
|
||||
for (const service of services) {
|
||||
const { hostname, port, apiKey, baseUrl, useSsl = false } = service;
|
||||
try {
|
||||
const res = await fetch(
|
||||
const response = await axios.post<DVRTestResponse>(
|
||||
`/api/v1/settings/${
|
||||
radarrServices.includes(service as RadarrSettings)
|
||||
? 'radarr'
|
||||
: 'sonarr'
|
||||
}/test`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
hostname,
|
||||
apiKey,
|
||||
port: Number(port),
|
||||
baseUrl,
|
||||
useSsl,
|
||||
}),
|
||||
hostname,
|
||||
apiKey,
|
||||
port: Number(port),
|
||||
baseUrl,
|
||||
useSsl,
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
const data: DVRTestResponse = await res.json();
|
||||
results.push({
|
||||
type: radarrServices.includes(service as RadarrSettings)
|
||||
? 'radarr'
|
||||
: 'sonarr',
|
||||
id: service.id,
|
||||
...data,
|
||||
...response.data,
|
||||
});
|
||||
} catch {
|
||||
results.push({
|
||||
@@ -120,9 +113,8 @@ const OverrideRuleTiles = ({
|
||||
.flat()
|
||||
.filter((keywordId) => keywordId)
|
||||
.map(async (keywordId) => {
|
||||
const res = await fetch(`/api/v1/keyword/${keywordId}`);
|
||||
if (!res.ok) throw new Error();
|
||||
const keyword: Keyword = await res.json();
|
||||
const response = await axios.get(`/api/v1/keyword/${keywordId}`);
|
||||
const keyword: Keyword = response.data;
|
||||
return keyword;
|
||||
})
|
||||
);
|
||||
@@ -132,11 +124,10 @@ const OverrideRuleTiles = ({
|
||||
.filter((users) => users)
|
||||
.join(',');
|
||||
if (allUsersFromRules) {
|
||||
const res = await fetch(
|
||||
const response = await axios.get(
|
||||
`/api/v1/user?includeIds=${encodeURIComponent(allUsersFromRules)}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
const users: User[] = (await res.json()).results;
|
||||
const users: User[] = response.data.results;
|
||||
setUsers(users);
|
||||
}
|
||||
setUsers(users);
|
||||
@@ -295,10 +286,7 @@ const OverrideRuleTiles = ({
|
||||
<div className="-ml-px flex w-0 flex-1">
|
||||
<button
|
||||
onClick={async () => {
|
||||
const res = await fetch(`/api/v1/overrideRule/${rule.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.delete(`/api/v1/overrideRule/${rule.id}`);
|
||||
revalidate();
|
||||
}}
|
||||
className="focus:ring-blue relative inline-flex w-0 flex-1 items-center justify-center rounded-br-lg border border-transparent py-4 text-sm font-medium leading-5 text-gray-200 transition duration-150 ease-in-out hover:text-white focus:z-10 focus:border-gray-500 focus:outline-none"
|
||||
|
||||
@@ -5,6 +5,7 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import type { RadarrSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Formik } from 'formik';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -154,24 +155,19 @@ const RadarrModal = ({ onClose, radarr, onSave }: RadarrModalProps) => {
|
||||
}) => {
|
||||
setIsTesting(true);
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/radarr/test', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
const response = await axios.post<RadarrTestResponse>(
|
||||
'/api/v1/settings/radarr/test',
|
||||
{
|
||||
hostname,
|
||||
apiKey,
|
||||
port: Number(port),
|
||||
baseUrl,
|
||||
useSsl,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
}
|
||||
);
|
||||
|
||||
setIsValidated(true);
|
||||
setTestResponse(data);
|
||||
setTestResponse(response.data);
|
||||
if (initialLoad.current) {
|
||||
addToast(intl.formatMessage(messages.toastRadarrTestSuccess), {
|
||||
appearance: 'success',
|
||||
@@ -264,23 +260,12 @@ const RadarrModal = ({ onClose, radarr, onSave }: RadarrModalProps) => {
|
||||
tagRequests: values.tagRequests,
|
||||
};
|
||||
if (!radarr) {
|
||||
const res = await fetch('/api/v1/settings/radarr', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(submission),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/radarr', submission);
|
||||
} else {
|
||||
const res = await fetch(`/api/v1/settings/radarr/${radarr.id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(submission),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.put(
|
||||
`/api/v1/settings/radarr/${radarr.id}`,
|
||||
submission
|
||||
);
|
||||
}
|
||||
|
||||
onSave();
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import { ApiErrorCode } from '@server/constants/error';
|
||||
import { MediaServerType } from '@server/constants/server';
|
||||
import type { JellyfinSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
@@ -178,25 +179,13 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
|
||||
}
|
||||
|
||||
try {
|
||||
const searchParams = new URLSearchParams({
|
||||
sync: params.sync ? 'true' : 'false',
|
||||
...(params.enable ? { enable: params.enable } : {}),
|
||||
await axios.get('/api/v1/settings/jellyfin/library', {
|
||||
params,
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/jellyfin/library?${searchParams.toString()}`
|
||||
);
|
||||
if (!res.ok) throw new Error(res.statusText, { cause: res });
|
||||
setIsSyncing(false);
|
||||
revalidate();
|
||||
} catch (e) {
|
||||
let errorData;
|
||||
try {
|
||||
errorData = await e.cause?.text();
|
||||
errorData = JSON.parse(errorData);
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
if (errorData?.message === 'SYNC_ERROR_GROUPED_FOLDERS') {
|
||||
if (e?.response?.data?.message === 'SYNC_ERROR_GROUPED_FOLDERS') {
|
||||
toasts.addToast(
|
||||
intl.formatMessage(
|
||||
messages.jellyfinSyncFailedAutomaticGroupedFolders
|
||||
@@ -206,7 +195,7 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
|
||||
appearance: 'warning',
|
||||
}
|
||||
);
|
||||
} else if (errorData?.message === 'SYNC_ERROR_NO_LIBRARIES') {
|
||||
} else if (e?.response?.data?.message === 'SYNC_ERROR_NO_LIBRARIES') {
|
||||
toasts.addToast(
|
||||
intl.formatMessage(messages.jellyfinSyncFailedNoLibrariesFound),
|
||||
{
|
||||
@@ -229,32 +218,16 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
|
||||
};
|
||||
|
||||
const startScan = async () => {
|
||||
const res = await fetch('/api/v1/settings/jellyfin/sync', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
start: true,
|
||||
}),
|
||||
await axios.post('/api/v1/settings/jellyfin/sync', {
|
||||
start: true,
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
revalidateSync();
|
||||
};
|
||||
|
||||
const cancelScan = async () => {
|
||||
const res = await fetch('/api/v1/settings/jellyfin/sync', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
cancel: true,
|
||||
}),
|
||||
await axios.post('/api/v1/settings/jellyfin/sync', {
|
||||
cancel: true,
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
revalidateSync();
|
||||
};
|
||||
|
||||
@@ -269,19 +242,15 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
|
||||
.join(',');
|
||||
}
|
||||
|
||||
const searchParams = new URLSearchParams(params.enable ? params : {});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/jellyfin/library?${searchParams.toString()}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
} else {
|
||||
const searchParams = new URLSearchParams({
|
||||
enable: [...activeLibraries, libraryId].join(','),
|
||||
await axios.get('/api/v1/settings/jellyfin/library', {
|
||||
params,
|
||||
});
|
||||
} else {
|
||||
await axios.get('/api/v1/settings/jellyfin/library', {
|
||||
params: {
|
||||
enable: [...activeLibraries, libraryId].join(','),
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/jellyfin/library?${searchParams.toString()}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
}
|
||||
if (onComplete) {
|
||||
onComplete();
|
||||
@@ -491,22 +460,15 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
|
||||
validationSchema={JellyfinSettingsSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/jellyfin', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ip: values.hostname,
|
||||
port: Number(values.port),
|
||||
useSsl: values.useSsl,
|
||||
urlBase: values.urlBase,
|
||||
externalHostname: values.jellyfinExternalUrl,
|
||||
jellyfinForgotPasswordUrl: values.jellyfinForgotPasswordUrl,
|
||||
apiKey: values.apiKey,
|
||||
} as JellyfinSettings),
|
||||
});
|
||||
if (!res.ok) throw new Error(res.statusText, { cause: res });
|
||||
await axios.post('/api/v1/settings/jellyfin', {
|
||||
ip: values.hostname,
|
||||
port: Number(values.port),
|
||||
useSsl: values.useSsl,
|
||||
urlBase: values.urlBase,
|
||||
externalHostname: values.jellyfinExternalUrl,
|
||||
jellyfinForgotPasswordUrl: values.jellyfinForgotPasswordUrl,
|
||||
apiKey: values.apiKey,
|
||||
} as JellyfinSettings);
|
||||
|
||||
addToast(
|
||||
intl.formatMessage(
|
||||
@@ -519,14 +481,7 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
let errorData;
|
||||
try {
|
||||
errorData = await e.cause?.text();
|
||||
errorData = JSON.parse(errorData);
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
if (errorData?.message === ApiErrorCode.InvalidUrl) {
|
||||
if (e?.response?.data?.message === ApiErrorCode.InvalidUrl) {
|
||||
addToast(
|
||||
intl.formatMessage(
|
||||
messages.invalidurlerror,
|
||||
|
||||
@@ -20,6 +20,7 @@ import type {
|
||||
CacheResponse,
|
||||
} from '@server/interfaces/api/settingsInterfaces';
|
||||
import type { JobId } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import cronstrue from 'cronstrue/i18n';
|
||||
import { Fragment, useReducer, useState } from 'react';
|
||||
import type { MessageDescriptor } from 'react-intl';
|
||||
@@ -189,10 +190,7 @@ const SettingsJobs = () => {
|
||||
}
|
||||
|
||||
const runJob = async (job: Job) => {
|
||||
const res = await fetch(`/api/v1/settings/jobs/${job.id}/run`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post(`/api/v1/settings/jobs/${job.id}/run`);
|
||||
addToast(
|
||||
intl.formatMessage(messages.jobstarted, {
|
||||
jobname: intl.formatMessage(messages[job.id] ?? messages.unknownJob),
|
||||
@@ -206,10 +204,7 @@ const SettingsJobs = () => {
|
||||
};
|
||||
|
||||
const cancelJob = async (job: Job) => {
|
||||
const res = await fetch(`/api/v1/settings/jobs/${job.id}/cancel`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post(`/api/v1/settings/jobs/${job.id}/cancel`);
|
||||
addToast(
|
||||
intl.formatMessage(messages.jobcancelled, {
|
||||
jobname: intl.formatMessage(messages[job.id] ?? messages.unknownJob),
|
||||
@@ -223,10 +218,7 @@ const SettingsJobs = () => {
|
||||
};
|
||||
|
||||
const flushCache = async (cache: CacheItem) => {
|
||||
const res = await fetch(`/api/v1/settings/cache/${cache.id}/flush`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post(`/api/v1/settings/cache/${cache.id}/flush`);
|
||||
addToast(
|
||||
intl.formatMessage(messages.cacheflushed, { cachename: cache.name }),
|
||||
{
|
||||
@@ -253,19 +245,12 @@ const SettingsJobs = () => {
|
||||
}
|
||||
|
||||
setIsSaving(true);
|
||||
const res = await fetch(
|
||||
await axios.post(
|
||||
`/api/v1/settings/jobs/${jobModalState.job.id}/schedule`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
schedule: jobScheduleCron.join(' '),
|
||||
}),
|
||||
schedule: jobScheduleCron.join(' '),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.jobScheduleEditSaved), {
|
||||
appearance: 'success',
|
||||
|
||||
@@ -16,6 +16,7 @@ import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import { ArrowPathIcon } from '@heroicons/react/24/solid';
|
||||
import type { UserSettingsGeneralResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
||||
import type { MainSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
@@ -84,10 +85,7 @@ const SettingsMain = () => {
|
||||
|
||||
const regenerate = async () => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/main/regenerate', {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/main/regenerate');
|
||||
|
||||
revalidate();
|
||||
addToast(intl.formatMessage(messages.toastApiKeySuccess), {
|
||||
@@ -140,25 +138,18 @@ const SettingsMain = () => {
|
||||
validationSchema={MainSettingsSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/main', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
applicationTitle: values.applicationTitle,
|
||||
applicationUrl: values.applicationUrl,
|
||||
hideAvailable: values.hideAvailable,
|
||||
locale: values.locale,
|
||||
discoverRegion: values.discoverRegion,
|
||||
streamingRegion: values.streamingRegion,
|
||||
originalLanguage: values.originalLanguage,
|
||||
partialRequestsEnabled: values.partialRequestsEnabled,
|
||||
enableSpecialEpisodes: values.enableSpecialEpisodes,
|
||||
cacheImages: values.cacheImages,
|
||||
}),
|
||||
await axios.post('/api/v1/settings/main', {
|
||||
applicationTitle: values.applicationTitle,
|
||||
applicationUrl: values.applicationUrl,
|
||||
hideAvailable: values.hideAvailable,
|
||||
locale: values.locale,
|
||||
discoverRegion: values.discoverRegion,
|
||||
streamingRegion: values.streamingRegion,
|
||||
originalLanguage: values.originalLanguage,
|
||||
partialRequestsEnabled: values.partialRequestsEnabled,
|
||||
enableSpecialEpisodes: values.enableSpecialEpisodes,
|
||||
cacheImages: values.cacheImages,
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/settings/public');
|
||||
mutate('/api/v1/status');
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import type { NetworkSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
@@ -38,13 +39,9 @@ const messages = defineMessages('components.Settings.SettingsNetwork', {
|
||||
"Use ',' as a separator, and '*.' as a wildcard for subdomains",
|
||||
proxyBypassLocalAddresses: 'Bypass Proxy for Local Addresses',
|
||||
validationProxyPort: 'You must provide a valid port',
|
||||
advancedNetworkSettings: 'Advanced Network Settings',
|
||||
networkDisclaimer:
|
||||
'Network parameters from your container/system should be used instead of these settings. See the {docs} for more information.',
|
||||
docs: 'documentation',
|
||||
forceIpv4First: 'Force IPv4 Resolution First',
|
||||
forceIpv4FirstTip:
|
||||
'Force Jellyseerr to resolve IPv4 addresses first instead of IPv6',
|
||||
});
|
||||
|
||||
const SettingsNetwork = () => {
|
||||
@@ -89,7 +86,6 @@ const SettingsNetwork = () => {
|
||||
<Formik
|
||||
initialValues={{
|
||||
csrfProtection: data?.csrfProtection,
|
||||
forceIpv4First: data?.forceIpv4First,
|
||||
trustProxy: data?.trustProxy,
|
||||
proxyEnabled: data?.proxy?.enabled,
|
||||
proxyHostname: data?.proxy?.hostname,
|
||||
@@ -104,28 +100,20 @@ const SettingsNetwork = () => {
|
||||
validationSchema={NetworkSettingsSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/network', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
await axios.post('/api/v1/settings/network', {
|
||||
csrfProtection: values.csrfProtection,
|
||||
trustProxy: values.trustProxy,
|
||||
proxy: {
|
||||
enabled: values.proxyEnabled,
|
||||
hostname: values.proxyHostname,
|
||||
port: values.proxyPort,
|
||||
useSsl: values.proxySsl,
|
||||
user: values.proxyUser,
|
||||
password: values.proxyPassword,
|
||||
bypassFilter: values.proxyBypassFilter,
|
||||
bypassLocalAddresses: values.proxyBypassLocalAddresses,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
csrfProtection: values.csrfProtection,
|
||||
forceIpv4First: values.forceIpv4First,
|
||||
trustProxy: values.trustProxy,
|
||||
proxy: {
|
||||
enabled: values.proxyEnabled,
|
||||
hostname: values.proxyHostname,
|
||||
port: values.proxyPort,
|
||||
useSsl: values.proxySsl,
|
||||
user: values.proxyUser,
|
||||
password: values.proxyPassword,
|
||||
bypassFilter: values.proxyBypassFilter,
|
||||
bypassLocalAddresses: values.proxyBypassLocalAddresses,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/settings/public');
|
||||
mutate('/api/v1/status');
|
||||
|
||||
@@ -381,46 +369,6 @@ const SettingsNetwork = () => {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<h3 className="heading mt-10">
|
||||
{intl.formatMessage(messages.advancedNetworkSettings)}
|
||||
</h3>
|
||||
<p className="description">
|
||||
{intl.formatMessage(messages.networkDisclaimer, {
|
||||
docs: (
|
||||
<a
|
||||
href="https://docs.jellyseerr.dev/troubleshooting"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-white"
|
||||
>
|
||||
{intl.formatMessage(messages.docs)}
|
||||
</a>
|
||||
),
|
||||
})}
|
||||
</p>
|
||||
<div className="form-row">
|
||||
<label htmlFor="forceIpv4First" className="checkbox-label">
|
||||
<span className="mr-2">
|
||||
{intl.formatMessage(messages.forceIpv4First)}
|
||||
</span>
|
||||
<SettingsBadge badgeType="advanced" className="mr-2" />
|
||||
<SettingsBadge badgeType="restartRequired" />
|
||||
<SettingsBadge badgeType="experimental" />
|
||||
<span className="label-tip">
|
||||
{intl.formatMessage(messages.forceIpv4FirstTip)}
|
||||
</span>
|
||||
</label>
|
||||
<div className="form-input-area">
|
||||
<Field
|
||||
type="checkbox"
|
||||
id="forceIpv4First"
|
||||
name="forceIpv4First"
|
||||
onChange={() => {
|
||||
setFieldValue('forceIpv4First', !values.forceIpv4First);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="actions">
|
||||
<div className="flex justify-end">
|
||||
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
} from '@heroicons/react/24/solid';
|
||||
import type { PlexDevice } from '@server/interfaces/api/plexInterfaces';
|
||||
import type { PlexSettings, TautulliSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Formik } from 'formik';
|
||||
import { orderBy } from 'lodash';
|
||||
import { useMemo, useState } from 'react';
|
||||
@@ -243,15 +244,9 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
params.enable = activeLibraries.join(',');
|
||||
}
|
||||
|
||||
const searchParams = new URLSearchParams({
|
||||
sync: params.sync ? 'true' : 'false',
|
||||
...(params.enable ? { enable: params.enable } : {}),
|
||||
await axios.get('/api/v1/settings/plex/library', {
|
||||
params,
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/plex/library?${searchParams.toString()}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
setIsSyncing(false);
|
||||
revalidate();
|
||||
};
|
||||
@@ -270,12 +265,11 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch('/api/v1/settings/plex/devices/servers');
|
||||
if (!res.ok) throw new Error();
|
||||
const data: PlexDevice[] = await res.json();
|
||||
|
||||
if (data) {
|
||||
setAvailableServers(data);
|
||||
const response = await axios.get<PlexDevice[]>(
|
||||
'/api/v1/settings/plex/devices/servers'
|
||||
);
|
||||
if (response.data) {
|
||||
setAvailableServers(response.data);
|
||||
}
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
@@ -298,30 +292,16 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
};
|
||||
|
||||
const startScan = async () => {
|
||||
const res = await fetch('/api/v1/settings/plex/sync', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
start: true,
|
||||
}),
|
||||
await axios.post('/api/v1/settings/plex/sync', {
|
||||
start: true,
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
revalidateSync();
|
||||
};
|
||||
|
||||
const cancelScan = async () => {
|
||||
const res = await fetch('/api/v1/settings/plex/sync', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
cancel: true,
|
||||
}),
|
||||
await axios.post('/api/v1/settings/plex/sync', {
|
||||
cancel: true,
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
revalidateSync();
|
||||
};
|
||||
|
||||
@@ -336,19 +316,15 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
.join(',');
|
||||
}
|
||||
|
||||
const searchParams = new URLSearchParams(params.enable ? params : {});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/plex/library?${searchParams.toString()}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
} else {
|
||||
const searchParams = new URLSearchParams({
|
||||
enable: [...activeLibraries, libraryId].join(','),
|
||||
await axios.get('/api/v1/settings/plex/library', {
|
||||
params,
|
||||
});
|
||||
} else {
|
||||
await axios.get('/api/v1/settings/plex/library', {
|
||||
params: {
|
||||
enable: [...activeLibraries, libraryId].join(','),
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/plex/library?${searchParams.toString()}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
}
|
||||
|
||||
if (onComplete) {
|
||||
@@ -416,19 +392,12 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const res = await fetch('/api/v1/settings/plex', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ip: values.hostname,
|
||||
port: Number(values.port),
|
||||
useSsl: values.useSsl,
|
||||
webAppUrl: values.webAppUrl,
|
||||
} as PlexSettings),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/plex', {
|
||||
ip: values.hostname,
|
||||
port: Number(values.port),
|
||||
useSsl: values.useSsl,
|
||||
webAppUrl: values.webAppUrl,
|
||||
} as PlexSettings);
|
||||
|
||||
syncLibraries();
|
||||
|
||||
@@ -782,27 +751,14 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
validationSchema={TautulliSettingsSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/tautulli', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
hostname: values.tautulliHostname,
|
||||
port: Number(values.tautulliPort),
|
||||
useSsl: values.tautulliUseSsl,
|
||||
urlBase: values.tautulliUrlBase,
|
||||
apiKey: values.tautulliApiKey,
|
||||
externalUrl: values.tautulliExternalUrl,
|
||||
} as TautulliSettings),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error('Failed to fetch');
|
||||
}
|
||||
|
||||
// Continue with any necessary processing
|
||||
await axios.post('/api/v1/settings/tautulli', {
|
||||
hostname: values.tautulliHostname,
|
||||
port: Number(values.tautulliPort),
|
||||
useSsl: values.tautulliUseSsl,
|
||||
urlBase: values.tautulliUrlBase,
|
||||
apiKey: values.tautulliApiKey,
|
||||
externalUrl: values.tautulliExternalUrl,
|
||||
} as TautulliSettings);
|
||||
|
||||
addToast(
|
||||
intl.formatMessage(messages.toastTautulliSettingsSuccess),
|
||||
|
||||
@@ -17,6 +17,7 @@ import { PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/solid';
|
||||
import type OverrideRule from '@server/entity/OverrideRule';
|
||||
import type { OverrideRuleResultsResponse } from '@server/interfaces/api/overrideRuleInterfaces';
|
||||
import type { RadarrSettings, SonarrSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Fragment, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import useSWR, { mutate } from 'swr';
|
||||
@@ -248,14 +249,9 @@ const SettingsServices = () => {
|
||||
});
|
||||
|
||||
const deleteServer = async () => {
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/${deleteServerModal.type}/${deleteServerModal.serverId}`,
|
||||
{
|
||||
method: 'DELETE',
|
||||
}
|
||||
await axios.delete(
|
||||
`/api/v1/settings/${deleteServerModal.type}/${deleteServerModal.serverId}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
setDeleteServerModal({ open: false, serverId: null, type: 'radarr' });
|
||||
revalidateRadarr();
|
||||
revalidateSonarr();
|
||||
|
||||
@@ -10,6 +10,7 @@ import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import { MediaServerType } from '@server/constants/server';
|
||||
import type { MainSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
@@ -116,29 +117,22 @@ const SettingsUsers = () => {
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/main', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
localLogin: values.localLogin,
|
||||
mediaServerLogin: values.mediaServerLogin,
|
||||
newPlexLogin: values.newPlexLogin,
|
||||
defaultQuotas: {
|
||||
movie: {
|
||||
quotaLimit: values.movieQuotaLimit,
|
||||
quotaDays: values.movieQuotaDays,
|
||||
},
|
||||
tv: {
|
||||
quotaLimit: values.tvQuotaLimit,
|
||||
quotaDays: values.tvQuotaDays,
|
||||
},
|
||||
await axios.post('/api/v1/settings/main', {
|
||||
localLogin: values.localLogin,
|
||||
mediaServerLogin: values.mediaServerLogin,
|
||||
newPlexLogin: values.newPlexLogin,
|
||||
defaultQuotas: {
|
||||
movie: {
|
||||
quotaLimit: values.movieQuotaLimit,
|
||||
quotaDays: values.movieQuotaDays,
|
||||
},
|
||||
defaultPermissions: values.defaultPermissions,
|
||||
}),
|
||||
tv: {
|
||||
quotaLimit: values.tvQuotaLimit,
|
||||
quotaDays: values.tvQuotaDays,
|
||||
},
|
||||
},
|
||||
defaultPermissions: values.defaultPermissions,
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/settings/public');
|
||||
|
||||
addToast(intl.formatMessage(messages.toastSettingsSuccess), {
|
||||
|
||||
@@ -5,6 +5,7 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import type { SonarrSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Formik } from 'formik';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -163,24 +164,19 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
|
||||
}) => {
|
||||
setIsTesting(true);
|
||||
try {
|
||||
const res = await fetch('/api/v1/settings/sonarr/test', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
const response = await axios.post<SonarrTestResponse>(
|
||||
'/api/v1/settings/sonarr/test',
|
||||
{
|
||||
hostname,
|
||||
apiKey,
|
||||
port: Number(port),
|
||||
baseUrl,
|
||||
useSsl,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data: SonarrTestResponse = await res.json();
|
||||
}
|
||||
);
|
||||
|
||||
setIsValidated(true);
|
||||
setTestResponse(data);
|
||||
setTestResponse(response.data);
|
||||
if (initialLoad.current) {
|
||||
addToast(intl.formatMessage(messages.toastSonarrTestSuccess), {
|
||||
appearance: 'success',
|
||||
@@ -297,23 +293,12 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
|
||||
tagRequests: values.tagRequests,
|
||||
};
|
||||
if (!sonarr) {
|
||||
const res = await fetch('/api/v1/settings/sonarr', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(submission),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.post('/api/v1/settings/sonarr', submission);
|
||||
} else {
|
||||
const res = await fetch(`/api/v1/settings/sonarr/${sonarr.id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(submission),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
await axios.put(
|
||||
`/api/v1/settings/sonarr/${sonarr.id}`,
|
||||
submission
|
||||
);
|
||||
}
|
||||
|
||||
onSave();
|
||||
|
||||
Reference in New Issue
Block a user