mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
@@ -1,5 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import { Notification } from '..';
|
||||
import { hasNotificationType, Notification } from '..';
|
||||
import logger from '../../../logger';
|
||||
import { getSettings, NotificationAgentDiscord } from '../../settings';
|
||||
import { BaseAgent, NotificationAgent, NotificationPayload } from './agent';
|
||||
@@ -196,10 +196,12 @@ class DiscordAgent
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Add checking for type here once we add notification type filters for agents
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public shouldSend(_type: Notification): boolean {
|
||||
if (this.getSettings().enabled && this.getSettings().options.webhookUrl) {
|
||||
public shouldSend(type: Notification): boolean {
|
||||
if (
|
||||
this.getSettings().enabled &&
|
||||
this.getSettings().options.webhookUrl &&
|
||||
hasNotificationType(type, this.getSettings().types)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { BaseAgent, NotificationAgent, NotificationPayload } from './agent';
|
||||
import { Notification } from '..';
|
||||
import { hasNotificationType, Notification } from '..';
|
||||
import path from 'path';
|
||||
import { getSettings, NotificationAgentEmail } from '../../settings';
|
||||
import nodemailer from 'nodemailer';
|
||||
@@ -22,12 +22,13 @@ class EmailAgent
|
||||
return settings.notifications.agents.email;
|
||||
}
|
||||
|
||||
// TODO: Add checking for type here once we add notification type filters for agents
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public shouldSend(_type: Notification): boolean {
|
||||
public shouldSend(type: Notification): boolean {
|
||||
const settings = this.getSettings();
|
||||
|
||||
if (settings.enabled) {
|
||||
if (
|
||||
settings.enabled &&
|
||||
hasNotificationType(type, this.getSettings().types)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import { Notification } from '..';
|
||||
import { hasNotificationType, Notification } from '..';
|
||||
import logger from '../../../logger';
|
||||
import { getSettings, NotificationAgentSlack } from '../../settings';
|
||||
import { BaseAgent, NotificationAgent, NotificationPayload } from './agent';
|
||||
@@ -187,10 +187,12 @@ class SlackAgent
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Add checking for type here once we add notification type filters for agents
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public shouldSend(_type: Notification): boolean {
|
||||
if (this.getSettings().enabled && this.getSettings().options.webhookUrl) {
|
||||
public shouldSend(type: Notification): boolean {
|
||||
if (
|
||||
this.getSettings().enabled &&
|
||||
this.getSettings().options.webhookUrl &&
|
||||
hasNotificationType(type, this.getSettings().types)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import { Notification } from '..';
|
||||
import { hasNotificationType, Notification } from '..';
|
||||
import logger from '../../../logger';
|
||||
import { getSettings, NotificationAgentTelegram } from '../../settings';
|
||||
import { BaseAgent, NotificationAgent, NotificationPayload } from './agent';
|
||||
@@ -25,13 +25,12 @@ class TelegramAgent
|
||||
return settings.notifications.agents.telegram;
|
||||
}
|
||||
|
||||
// TODO: Add checking for type here once we add notification type filters for agents
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public shouldSend(_type: Notification): boolean {
|
||||
public shouldSend(type: Notification): boolean {
|
||||
if (
|
||||
this.getSettings().enabled &&
|
||||
this.getSettings().options.botAPI &&
|
||||
this.getSettings().options.chatId
|
||||
this.getSettings().options.chatId &&
|
||||
hasNotificationType(type, this.getSettings().types)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
@@ -9,6 +9,27 @@ export enum Notification {
|
||||
TEST_NOTIFICATION = 32,
|
||||
}
|
||||
|
||||
export const hasNotificationType = (
|
||||
types: Notification | Notification[],
|
||||
value: number
|
||||
): boolean => {
|
||||
let total = 0;
|
||||
|
||||
// If we are not checking any notifications, bail out and return true
|
||||
if (types === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Array.isArray(types)) {
|
||||
// Combine all notification values into one
|
||||
total = types.reduce((a, v) => a + v, 0);
|
||||
} else {
|
||||
total = types;
|
||||
}
|
||||
|
||||
return !!(value & total);
|
||||
};
|
||||
|
||||
class NotificationManager {
|
||||
private activeAgents: NotificationAgent[] = [];
|
||||
|
||||
|
@@ -0,0 +1,70 @@
|
||||
import React from 'react';
|
||||
import { NotificationItem, hasNotificationType } from '..';
|
||||
|
||||
interface NotificationTypeProps {
|
||||
option: NotificationItem;
|
||||
currentTypes: number;
|
||||
parent?: NotificationItem;
|
||||
onUpdate: (newTypes: number) => void;
|
||||
}
|
||||
|
||||
const NotificationType: React.FC<NotificationTypeProps> = ({
|
||||
option,
|
||||
currentTypes,
|
||||
onUpdate,
|
||||
parent,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`relative flex items-start first:mt-0 mt-4 ${
|
||||
!!parent?.value && hasNotificationType(parent.value, currentTypes)
|
||||
? 'opacity-50'
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center h-5">
|
||||
<input
|
||||
id={option.id}
|
||||
name="permissions"
|
||||
type="checkbox"
|
||||
className="w-4 h-4 text-indigo-600 transition duration-150 ease-in-out rounded-md form-checkbox"
|
||||
disabled={
|
||||
!!parent?.value && hasNotificationType(parent.value, currentTypes)
|
||||
}
|
||||
onClick={() => {
|
||||
onUpdate(
|
||||
hasNotificationType(option.value, currentTypes)
|
||||
? currentTypes - option.value
|
||||
: currentTypes + option.value
|
||||
);
|
||||
}}
|
||||
defaultChecked={
|
||||
hasNotificationType(option.value, currentTypes) ||
|
||||
(!!parent?.value &&
|
||||
hasNotificationType(parent.value, currentTypes))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-3 text-sm leading-5">
|
||||
<label htmlFor={option.id} className="font-medium">
|
||||
{option.name}
|
||||
</label>
|
||||
<p className="text-gray-500">{option.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
{(option.children ?? []).map((child) => (
|
||||
<div key={`notification-type-child-${child.id}`} className="pl-6 mt-4">
|
||||
<NotificationType
|
||||
option={child}
|
||||
currentTypes={currentTypes}
|
||||
onUpdate={(newTypes) => onUpdate(newTypes)}
|
||||
parent={option}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotificationType;
|
106
src/components/NotificationTypeSelector/index.tsx
Normal file
106
src/components/NotificationTypeSelector/index.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import NotificationType from './NotificationType';
|
||||
|
||||
const messages = defineMessages({
|
||||
mediarequested: 'Media Requested',
|
||||
mediarequestedDescription:
|
||||
'Sends a notification when new media is requested. For certain agents, this will only send the notification to admins or users with the "Manage Requests" permission.',
|
||||
mediaapproved: 'Media Approved',
|
||||
mediaapprovedDescription: 'Sends a notification when media is approved.',
|
||||
mediaavailable: 'Media Available',
|
||||
mediaavailableDescription:
|
||||
'Sends a notification when media becomes available.',
|
||||
mediafailed: 'Media Failed',
|
||||
mediafailedDescription:
|
||||
'Sends a notification when media fails to be added to services (Radarr/Sonarr). For certain agents, this will only send the notification to admins or users with the "Manage Requests" permission.',
|
||||
});
|
||||
|
||||
export const hasNotificationType = (
|
||||
types: Notification | Notification[],
|
||||
value: number
|
||||
): boolean => {
|
||||
let total = 0;
|
||||
|
||||
if (types === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Array.isArray(types)) {
|
||||
total = types.reduce((a, v) => a + v, 0);
|
||||
} else {
|
||||
total = types;
|
||||
}
|
||||
|
||||
return !!(value & total);
|
||||
};
|
||||
|
||||
export enum Notification {
|
||||
MEDIA_PENDING = 2,
|
||||
MEDIA_APPROVED = 4,
|
||||
MEDIA_AVAILABLE = 8,
|
||||
MEDIA_FAILED = 16,
|
||||
TEST_NOTIFICATION = 32,
|
||||
}
|
||||
|
||||
export interface NotificationItem {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
value: Notification;
|
||||
children?: NotificationItem[];
|
||||
}
|
||||
|
||||
interface NotificationTypeSelectorProps {
|
||||
currentTypes: number;
|
||||
onUpdate: (newTypes: number) => void;
|
||||
}
|
||||
|
||||
const NotificationTypeSelector: React.FC<NotificationTypeSelectorProps> = ({
|
||||
currentTypes,
|
||||
onUpdate,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const types: NotificationItem[] = [
|
||||
{
|
||||
id: 'media-requested',
|
||||
name: intl.formatMessage(messages.mediarequested),
|
||||
description: intl.formatMessage(messages.mediarequestedDescription),
|
||||
value: Notification.MEDIA_PENDING,
|
||||
},
|
||||
{
|
||||
id: 'media-approved',
|
||||
name: intl.formatMessage(messages.mediaapproved),
|
||||
description: intl.formatMessage(messages.mediaapprovedDescription),
|
||||
value: Notification.MEDIA_APPROVED,
|
||||
},
|
||||
{
|
||||
id: 'media-available',
|
||||
name: intl.formatMessage(messages.mediaavailable),
|
||||
description: intl.formatMessage(messages.mediaavailableDescription),
|
||||
value: Notification.MEDIA_AVAILABLE,
|
||||
},
|
||||
{
|
||||
id: 'media-failed',
|
||||
name: intl.formatMessage(messages.mediafailed),
|
||||
description: intl.formatMessage(messages.mediafailedDescription),
|
||||
value: Notification.MEDIA_FAILED,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{types.map((type) => (
|
||||
<NotificationType
|
||||
key={`notification-type-${type.id}`}
|
||||
option={type}
|
||||
currentTypes={currentTypes}
|
||||
onUpdate={onUpdate}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotificationTypeSelector;
|
@@ -7,6 +7,7 @@ import { defineMessages, useIntl } from 'react-intl';
|
||||
import axios from 'axios';
|
||||
import * as Yup from 'yup';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
import NotificationTypeSelector from '../../NotificationTypeSelector';
|
||||
|
||||
const messages = defineMessages({
|
||||
save: 'Save Changes',
|
||||
@@ -19,6 +20,7 @@ const messages = defineMessages({
|
||||
discordsettingsfailed: 'Discord notification settings failed to save.',
|
||||
testsent: 'Test notification sent!',
|
||||
test: 'Test',
|
||||
notificationtypes: 'Notification Types',
|
||||
});
|
||||
|
||||
const NotificationsDiscord: React.FC = () => {
|
||||
@@ -69,7 +71,7 @@ const NotificationsDiscord: React.FC = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ errors, touched, isSubmitting, values, isValid }) => {
|
||||
{({ errors, touched, isSubmitting, values, isValid, setFieldValue }) => {
|
||||
const testSettings = async () => {
|
||||
await axios.post('/api/v1/settings/notifications/discord/test', {
|
||||
enabled: true,
|
||||
@@ -99,7 +101,7 @@ const NotificationsDiscord: React.FC = () => {
|
||||
type="checkbox"
|
||||
id="enabled"
|
||||
name="enabled"
|
||||
className="form-checkbox rounded-md h-6 w-6 text-indigo-600 transition duration-150 ease-in-out"
|
||||
className="w-6 h-6 text-indigo-600 transition duration-150 ease-in-out rounded-md form-checkbox"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -111,7 +113,7 @@ const NotificationsDiscord: React.FC = () => {
|
||||
{intl.formatMessage(messages.webhookUrl)}
|
||||
</label>
|
||||
<div className="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg flex rounded-md shadow-sm">
|
||||
<div className="flex max-w-lg rounded-md shadow-sm">
|
||||
<Field
|
||||
id="webhookUrl"
|
||||
name="webhookUrl"
|
||||
@@ -119,17 +121,41 @@ const NotificationsDiscord: React.FC = () => {
|
||||
placeholder={intl.formatMessage(
|
||||
messages.webhookUrlPlaceholder
|
||||
)}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
className="flex-1 block w-full min-w-0 transition duration-150 ease-in-out bg-gray-700 border border-gray-500 rounded-md form-input sm:text-sm sm:leading-5"
|
||||
/>
|
||||
</div>
|
||||
{errors.webhookUrl && touched.webhookUrl && (
|
||||
<div className="text-red-500 mt-2">{errors.webhookUrl}</div>
|
||||
<div className="mt-2 text-red-500">{errors.webhookUrl}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8 border-t border-gray-700 pt-5">
|
||||
<div className="mt-6">
|
||||
<div role="group" aria-labelledby="label-permissions">
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-baseline">
|
||||
<div>
|
||||
<div
|
||||
className="text-base font-medium leading-6 text-gray-400 sm:text-sm sm:leading-5"
|
||||
id="label-types"
|
||||
>
|
||||
{intl.formatMessage(messages.notificationtypes)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg">
|
||||
<NotificationTypeSelector
|
||||
currentTypes={values.types}
|
||||
onUpdate={(newTypes) =>
|
||||
setFieldValue('types', newTypes)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pt-5 mt-8 border-t border-gray-700">
|
||||
<div className="flex justify-end">
|
||||
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
||||
<span className="inline-flex ml-3 rounded-md shadow-sm">
|
||||
<Button
|
||||
buttonType="warning"
|
||||
disabled={isSubmitting || !isValid}
|
||||
@@ -142,7 +168,7 @@ const NotificationsDiscord: React.FC = () => {
|
||||
{intl.formatMessage(messages.test)}
|
||||
</Button>
|
||||
</span>
|
||||
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
||||
<span className="inline-flex ml-3 rounded-md shadow-sm">
|
||||
<Button
|
||||
buttonType="primary"
|
||||
type="submit"
|
||||
|
@@ -7,6 +7,7 @@ import { defineMessages, useIntl } from 'react-intl';
|
||||
import axios from 'axios';
|
||||
import * as Yup from 'yup';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
import NotificationTypeSelector from '../../NotificationTypeSelector';
|
||||
|
||||
const messages = defineMessages({
|
||||
save: 'Save Changes',
|
||||
@@ -29,6 +30,7 @@ const messages = defineMessages({
|
||||
ssldisabletip:
|
||||
'SSL should be disabled on standard TLS connections (Port 587)',
|
||||
senderName: 'Sender Name',
|
||||
notificationtypes: 'Notification Types',
|
||||
});
|
||||
|
||||
const NotificationsEmail: React.FC = () => {
|
||||
@@ -99,7 +101,7 @@ const NotificationsEmail: React.FC = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ errors, touched, isSubmitting, values, isValid }) => {
|
||||
{({ errors, touched, isSubmitting, values, isValid, setFieldValue }) => {
|
||||
const testSettings = async () => {
|
||||
await axios.post('/api/v1/settings/notifications/email/test', {
|
||||
enabled: true,
|
||||
@@ -292,11 +294,36 @@ const NotificationsEmail: React.FC = () => {
|
||||
id="authPass"
|
||||
name="authPass"
|
||||
type="password"
|
||||
autoComplete="off"
|
||||
className="flex-1 block w-full min-w-0 transition duration-150 ease-in-out bg-gray-700 border border-gray-500 rounded-md form-input sm:text-sm sm:leading-5"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<div role="group" aria-labelledby="label-permissions">
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-baseline">
|
||||
<div>
|
||||
<div
|
||||
className="text-base font-medium leading-6 text-gray-400 sm:text-sm sm:leading-5"
|
||||
id="label-types"
|
||||
>
|
||||
{intl.formatMessage(messages.notificationtypes)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg">
|
||||
<NotificationTypeSelector
|
||||
currentTypes={values.types}
|
||||
onUpdate={(newTypes) =>
|
||||
setFieldValue('types', newTypes)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pt-5 mt-8 border-t border-gray-700">
|
||||
<div className="flex justify-end">
|
||||
<span className="inline-flex ml-3 rounded-md shadow-sm">
|
||||
|
@@ -8,6 +8,7 @@ import axios from 'axios';
|
||||
import * as Yup from 'yup';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
import Alert from '../../../Common/Alert';
|
||||
import NotificationTypeSelector from '../../../NotificationTypeSelector';
|
||||
|
||||
const messages = defineMessages({
|
||||
save: 'Save Changes',
|
||||
@@ -23,6 +24,7 @@ const messages = defineMessages({
|
||||
settingupslack: 'Setting up Slack Notifications',
|
||||
settingupslackDescription:
|
||||
'To use Slack notifications, you will need to create an <WebhookLink>Incoming Webhook</WebhookLink> integration and use the provided webhook URL below.',
|
||||
notificationtypes: 'Notification Types',
|
||||
});
|
||||
|
||||
const NotificationsSlack: React.FC = () => {
|
||||
@@ -44,7 +46,6 @@ const NotificationsSlack: React.FC = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className="mb-">
|
||||
<Alert title={intl.formatMessage(messages.settingupslack)} type="info">
|
||||
{intl.formatMessage(messages.settingupslackDescription, {
|
||||
WebhookLink: function WebhookLink(msg) {
|
||||
@@ -61,7 +62,6 @@ const NotificationsSlack: React.FC = () => {
|
||||
},
|
||||
})}
|
||||
</Alert>
|
||||
</p>
|
||||
<Formik
|
||||
initialValues={{
|
||||
enabled: data.enabled,
|
||||
@@ -92,7 +92,14 @@ const NotificationsSlack: React.FC = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ errors, touched, isSubmitting, values, isValid }) => {
|
||||
{({
|
||||
errors,
|
||||
touched,
|
||||
isSubmitting,
|
||||
values,
|
||||
isValid,
|
||||
setFieldValue,
|
||||
}) => {
|
||||
const testSettings = async () => {
|
||||
await axios.post('/api/v1/settings/notifications/slack/test', {
|
||||
enabled: true,
|
||||
@@ -150,6 +157,30 @@ const NotificationsSlack: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<div role="group" aria-labelledby="label-permissions">
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-baseline">
|
||||
<div>
|
||||
<div
|
||||
className="text-base font-medium leading-6 text-gray-400 sm:text-sm sm:leading-5"
|
||||
id="label-types"
|
||||
>
|
||||
{intl.formatMessage(messages.notificationtypes)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg">
|
||||
<NotificationTypeSelector
|
||||
currentTypes={values.types}
|
||||
onUpdate={(newTypes) =>
|
||||
setFieldValue('types', newTypes)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pt-5 mt-8 border-t border-gray-700">
|
||||
<div className="flex justify-end">
|
||||
<span className="inline-flex ml-3 rounded-md shadow-sm">
|
||||
|
@@ -8,6 +8,7 @@ import axios from 'axios';
|
||||
import * as Yup from 'yup';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
import Alert from '../../Common/Alert';
|
||||
import NotificationTypeSelector from '../../NotificationTypeSelector';
|
||||
|
||||
const messages = defineMessages({
|
||||
save: 'Save Changes',
|
||||
@@ -26,6 +27,7 @@ const messages = defineMessages({
|
||||
'To setup Telegram you need to <CreateBotLink>create a bot</CreateBotLink> and get the bot API key.\
|
||||
Additionally, you need the chat id for the chat you want the bot to send notifications to.\
|
||||
You can do this by adding <GetIdBotLink>@get_id_bot</GetIdBotLink> to the chat or group chat.',
|
||||
notificationtypes: 'Notification Types',
|
||||
});
|
||||
|
||||
const NotificationsTelegram: React.FC = () => {
|
||||
@@ -81,7 +83,7 @@ const NotificationsTelegram: React.FC = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ errors, touched, isSubmitting, values, isValid }) => {
|
||||
{({ errors, touched, isSubmitting, values, isValid, setFieldValue }) => {
|
||||
const testSettings = async () => {
|
||||
await axios.post('/api/v1/settings/notifications/telegram/test', {
|
||||
enabled: true,
|
||||
@@ -100,7 +102,6 @@ const NotificationsTelegram: React.FC = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className="mb-">
|
||||
<Alert
|
||||
title={intl.formatMessage(messages.settinguptelegram)}
|
||||
type="info"
|
||||
@@ -132,7 +133,6 @@ const NotificationsTelegram: React.FC = () => {
|
||||
},
|
||||
})}
|
||||
</Alert>
|
||||
</p>
|
||||
<Form>
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||
<label
|
||||
@@ -158,17 +158,17 @@ const NotificationsTelegram: React.FC = () => {
|
||||
{intl.formatMessage(messages.botAPI)}
|
||||
</label>
|
||||
<div className="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg flex rounded-md shadow-sm">
|
||||
<div className="flex max-w-lg rounded-md shadow-sm">
|
||||
<Field
|
||||
id="botAPI"
|
||||
name="botAPI"
|
||||
type="text"
|
||||
placeholder={intl.formatMessage(messages.botAPI)}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
className="flex-1 block w-full min-w-0 transition duration-150 ease-in-out bg-gray-700 border border-gray-500 rounded-md form-input sm:text-sm sm:leading-5"
|
||||
/>
|
||||
</div>
|
||||
{errors.botAPI && touched.botAPI && (
|
||||
<div className="text-red-500 mt-2">{errors.botAPI}</div>
|
||||
<div className="mt-2 text-red-500">{errors.botAPI}</div>
|
||||
)}
|
||||
</div>
|
||||
<label
|
||||
@@ -178,23 +178,47 @@ const NotificationsTelegram: React.FC = () => {
|
||||
{intl.formatMessage(messages.chatId)}
|
||||
</label>
|
||||
<div className="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg flex rounded-md shadow-sm">
|
||||
<div className="flex max-w-lg rounded-md shadow-sm">
|
||||
<Field
|
||||
id="chatId"
|
||||
name="chatId"
|
||||
type="text"
|
||||
placeholder={intl.formatMessage(messages.chatId)}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
className="flex-1 block w-full min-w-0 transition duration-150 ease-in-out bg-gray-700 border border-gray-500 rounded-md form-input sm:text-sm sm:leading-5"
|
||||
/>
|
||||
</div>
|
||||
{errors.chatId && touched.chatId && (
|
||||
<div className="text-red-500 mt-2">{errors.chatId}</div>
|
||||
<div className="mt-2 text-red-500">{errors.chatId}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8 border-t border-gray-700 pt-5">
|
||||
<div className="mt-6">
|
||||
<div role="group" aria-labelledby="label-permissions">
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-baseline">
|
||||
<div>
|
||||
<div
|
||||
className="text-base font-medium leading-6 text-gray-400 sm:text-sm sm:leading-5"
|
||||
id="label-types"
|
||||
>
|
||||
{intl.formatMessage(messages.notificationtypes)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg">
|
||||
<NotificationTypeSelector
|
||||
currentTypes={values.types}
|
||||
onUpdate={(newTypes) =>
|
||||
setFieldValue('types', newTypes)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pt-5 mt-8 border-t border-gray-700">
|
||||
<div className="flex justify-end">
|
||||
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
||||
<span className="inline-flex ml-3 rounded-md shadow-sm">
|
||||
<Button
|
||||
buttonType="warning"
|
||||
disabled={isSubmitting || !isValid}
|
||||
@@ -207,7 +231,7 @@ const NotificationsTelegram: React.FC = () => {
|
||||
{intl.formatMessage(messages.test)}
|
||||
</Button>
|
||||
</span>
|
||||
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
||||
<span className="inline-flex ml-3 rounded-md shadow-sm">
|
||||
<Button
|
||||
buttonType="primary"
|
||||
type="submit"
|
||||
|
@@ -60,6 +60,14 @@
|
||||
"components.MovieDetails.viewfullcrew": "View Full Crew",
|
||||
"components.MovieDetails.viewrequest": "View Request",
|
||||
"components.MovieDetails.watchtrailer": "Watch Trailer",
|
||||
"components.NotificationTypeSelector.mediaapproved": "Media Approved",
|
||||
"components.NotificationTypeSelector.mediaapprovedDescription": "Sends a notification when media is approved.",
|
||||
"components.NotificationTypeSelector.mediaavailable": "Media Available",
|
||||
"components.NotificationTypeSelector.mediaavailableDescription": "Sends a notification when media becomes available.",
|
||||
"components.NotificationTypeSelector.mediafailed": "Media Failed",
|
||||
"components.NotificationTypeSelector.mediafailedDescription": "Sends a notification when media fails to be added to services (Radarr/Sonarr). For certain agents, this will only send the notification to admins or users with the \"Manage Requests\" permission.",
|
||||
"components.NotificationTypeSelector.mediarequested": "Media Requested",
|
||||
"components.NotificationTypeSelector.mediarequestedDescription": "Sends a notification when new media is requested. For certain agents, this will only send the notification to admins or users with the \"Manage Requests\" permission.",
|
||||
"components.PersonDetails.appearsin": "Appears in",
|
||||
"components.PersonDetails.ascharacter": "as {character}",
|
||||
"components.PersonDetails.crewmember": "Crew Member",
|
||||
@@ -105,6 +113,7 @@
|
||||
"components.RequestModal.status": "Status",
|
||||
"components.Search.searchresults": "Search Results",
|
||||
"components.Settings.Notifications.NotificationsSlack.agentenabled": "Agent Enabled",
|
||||
"components.Settings.Notifications.NotificationsSlack.notificationtypes": "Notification Types",
|
||||
"components.Settings.Notifications.NotificationsSlack.save": "Save Changes",
|
||||
"components.Settings.Notifications.NotificationsSlack.saving": "Saving...",
|
||||
"components.Settings.Notifications.NotificationsSlack.settingupslack": "Setting up Slack Notifications",
|
||||
@@ -128,6 +137,7 @@
|
||||
"components.Settings.Notifications.emailsettingsfailed": "Email notification settings failed to save.",
|
||||
"components.Settings.Notifications.emailsettingssaved": "Email notification settings saved!",
|
||||
"components.Settings.Notifications.enableSsl": "Enable SSL",
|
||||
"components.Settings.Notifications.notificationtypes": "Notification Types",
|
||||
"components.Settings.Notifications.save": "Save Changes",
|
||||
"components.Settings.Notifications.saving": "Saving…",
|
||||
"components.Settings.Notifications.senderName": "Sender Name",
|
||||
|
Reference in New Issue
Block a user