@plutonhq/core-frontend 0.1.23 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/@types/index.js +4 -1
- package/dist-lib/@types/index.js.map +1 -1
- package/dist-lib/@types/settings.d.ts +14 -0
- package/dist-lib/@types/settings.d.ts.map +1 -1
- package/dist-lib/@types/settings.js +34 -0
- package/dist-lib/@types/settings.js.map +1 -0
- package/dist-lib/components/Plan/Backups/Backups.d.ts.map +1 -1
- package/dist-lib/components/Plan/Backups/Backups.js +189 -159
- package/dist-lib/components/Plan/Backups/Backups.js.map +1 -1
- package/dist-lib/components/Plan/PlanSettings/PlanNotificationSettings.d.ts.map +1 -1
- package/dist-lib/components/Plan/PlanSettings/PlanNotificationSettings.js +148 -90
- package/dist-lib/components/Plan/PlanSettings/PlanNotificationSettings.js.map +1 -1
- package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewer.d.ts +32 -0
- package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewer.d.ts.map +1 -0
- package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewer.js +252 -0
- package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewer.js.map +1 -0
- package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewerFile.d.ts +23 -0
- package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewerFile.d.ts.map +1 -0
- package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewerFile.js +72 -0
- package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewerFile.js.map +1 -0
- package/dist-lib/components/Restore/RestoreFileSelector/RestoreFileSelector.d.ts.map +1 -1
- package/dist-lib/components/Restore/RestoreFileSelector/RestoreFileSelector.js +188 -198
- package/dist-lib/components/Restore/RestoreFileSelector/RestoreFileSelector.js.map +1 -1
- package/dist-lib/components/Restore/RestoreFileSelector/RestoreFileSelector.module.scss.js +20 -64
- package/dist-lib/components/Restore/RestoreFileSelector/RestoreFileSelector.module.scss.js.map +1 -1
- package/dist-lib/components/Restore/RestoredFileBrowser/RestoredFileBrowser.d.ts.map +1 -1
- package/dist-lib/components/Restore/RestoredFileBrowser/RestoredFileBrowser.js +125 -159
- package/dist-lib/components/Restore/RestoredFileBrowser/RestoredFileBrowser.js.map +1 -1
- package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.d.ts.map +1 -1
- package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.js +52 -47
- package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.js.map +1 -1
- package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.module.scss.js +12 -6
- package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.module.scss.js.map +1 -1
- package/dist-lib/components/Settings/IntegrationSettings/NtfySettings.d.ts +9 -0
- package/dist-lib/components/Settings/IntegrationSettings/NtfySettings.d.ts.map +1 -0
- package/dist-lib/components/Settings/IntegrationSettings/NtfySettings.js +79 -0
- package/dist-lib/components/Settings/IntegrationSettings/NtfySettings.js.map +1 -0
- package/dist-lib/components/Settings/IntegrationSettings/SMTPSettings.d.ts +4 -3
- package/dist-lib/components/Settings/IntegrationSettings/SMTPSettings.d.ts.map +1 -1
- package/dist-lib/components/Settings/IntegrationSettings/SMTPSettings.js +37 -35
- package/dist-lib/components/Settings/IntegrationSettings/SMTPSettings.js.map +1 -1
- package/dist-lib/components/Settings/IntegrationSettings/ValidateEmailIntegration.d.ts +10 -0
- package/dist-lib/components/Settings/IntegrationSettings/ValidateEmailIntegration.d.ts.map +1 -0
- package/dist-lib/components/Settings/IntegrationSettings/ValidateEmailIntegration.js +49 -0
- package/dist-lib/components/Settings/IntegrationSettings/ValidateEmailIntegration.js.map +1 -0
- package/dist-lib/components/Storage/EditStorage/EditStorage.js +10 -10
- package/dist-lib/components/Storage/EditStorage/EditStorage.js.map +1 -1
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowser.module.scss.js +74 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowser.module.scss.js.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserDirectories.d.ts +17 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserDirectories.d.ts.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserDirectories.js +57 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserDirectories.js.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileList.d.ts +18 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileList.d.ts.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileList.js +24 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileList.js.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileRow.d.ts +18 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileRow.d.ts.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileRow.js +37 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileRow.js.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserGoUpRow.d.ts +9 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserGoUpRow.d.ts.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserGoUpRow.js +15 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserGoUpRow.js.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserToolbar.d.ts +11 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserToolbar.d.ts.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserToolbar.js +18 -0
- package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserToolbar.js.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotDatabase.d.ts +12 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotDatabase.d.ts.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotDatabase.js +70 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotDatabase.js.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotNavigation.d.ts +22 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotNavigation.d.ts.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotNavigation.js +79 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotNavigation.js.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotSort.d.ts +6 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotSort.d.ts.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotSort.js +18 -0
- package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotSort.js.map +1 -0
- package/dist-lib/components/common/SnapshotBrowser/index.d.ts +11 -0
- package/dist-lib/components/common/SnapshotBrowser/index.d.ts.map +1 -0
- package/dist-lib/components/index.d.ts +12 -0
- package/dist-lib/components/index.d.ts.map +1 -1
- package/dist-lib/components.js +152 -128
- package/dist-lib/components.js.map +1 -1
- package/dist-lib/hooks/usePlanSingleActions.d.ts.map +1 -1
- package/dist-lib/hooks/usePlanSingleActions.js +21 -21
- package/dist-lib/hooks/usePlanSingleActions.js.map +1 -1
- package/dist-lib/services/backups.d.ts +4 -0
- package/dist-lib/services/backups.d.ts.map +1 -1
- package/dist-lib/services/backups.js +34 -25
- package/dist-lib/services/backups.js.map +1 -1
- package/dist-lib/services/settings.d.ts +3 -2
- package/dist-lib/services/settings.d.ts.map +1 -1
- package/dist-lib/services/settings.js +0 -1
- package/dist-lib/services/settings.js.map +1 -1
- package/dist-lib/services.js +113 -112
- package/dist-lib/styles/core-frontend.css +1 -1
- package/dist-lib/utils/index.d.ts +1 -0
- package/dist-lib/utils/index.d.ts.map +1 -1
- package/dist-lib/utils/snapshotDatabase.d.ts +16 -0
- package/dist-lib/utils/snapshotDatabase.d.ts.map +1 -0
- package/dist-lib/utils/snapshotDatabase.js +105 -0
- package/dist-lib/utils/snapshotDatabase.js.map +1 -0
- package/dist-lib/utils.js +24 -22
- package/dist-lib/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/@types/settings.ts +43 -0
- package/src/components/Plan/Backups/Backups.tsx +40 -1
- package/src/components/Plan/PlanSettings/PlanNotificationSettings.tsx +65 -0
- package/src/components/Plan/SnapshotViewer/SnapshotViewer.tsx +344 -0
- package/src/components/Plan/SnapshotViewer/SnapshotViewerFile.tsx +89 -0
- package/src/components/Restore/RestoreFileSelector/RestoreFileSelector.tsx +82 -145
- package/src/components/Restore/RestoredFileBrowser/RestoredFileBrowser.tsx +71 -156
- package/src/components/Settings/IntegrationSettings/IntegrationSettings.module.scss +16 -0
- package/src/components/Settings/IntegrationSettings/IntegrationSettings.tsx +45 -42
- package/src/components/Settings/IntegrationSettings/NtfySettings.tsx +106 -0
- package/src/components/Settings/IntegrationSettings/SMTPSettings.tsx +28 -19
- package/src/components/Settings/IntegrationSettings/ValidateEmailIntegration.tsx +58 -0
- package/src/components/Storage/EditStorage/EditStorage.tsx +1 -1
- package/src/components/common/SnapshotBrowser/SnapshotBrowser.module.scss +376 -0
- package/src/components/common/SnapshotBrowser/SnapshotBrowserDirectories.tsx +84 -0
- package/src/components/common/SnapshotBrowser/SnapshotBrowserFileList.tsx +52 -0
- package/src/components/common/SnapshotBrowser/SnapshotBrowserFileRow.tsx +44 -0
- package/src/components/common/SnapshotBrowser/SnapshotBrowserGoUpRow.tsx +22 -0
- package/src/components/common/SnapshotBrowser/SnapshotBrowserToolbar.tsx +29 -0
- package/src/components/common/SnapshotBrowser/hooks/useSnapshotDatabase.ts +130 -0
- package/src/components/common/SnapshotBrowser/hooks/useSnapshotNavigation.ts +154 -0
- package/src/components/common/SnapshotBrowser/hooks/useSnapshotSort.ts +24 -0
- package/src/components/common/SnapshotBrowser/index.ts +13 -0
- package/src/components/index.ts +15 -0
- package/src/hooks/usePlanSingleActions.tsx +5 -3
- package/src/services/backups.ts +12 -0
- package/src/services/settings.ts +2 -2
- package/src/utils/index.ts +1 -0
- package/src/utils/snapshotDatabase.ts +201 -0
- /package/dist-lib/providers/{azureBlob.png → azureblob.png} +0 -0
- /package/dist-lib/providers/{azureFiles.png → azurefiles.png} +0 -0
- /package/dist-lib/providers/{files.png → filescom.png} +0 -0
- /package/dist-lib/providers/{oracle.png → oracleobjectstorage.png} +0 -0
- /package/dist-lib/providers/{proton.png → protondrive.png} +0 -0
|
@@ -36,3 +36,19 @@
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
@media only screen and (max-width: 768px) {
|
|
41
|
+
.integrations {
|
|
42
|
+
.field {
|
|
43
|
+
width: 100%;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
.integrationSelect {
|
|
47
|
+
width: 100%;
|
|
48
|
+
margin-bottom: 30px;
|
|
49
|
+
|
|
50
|
+
:global([class*='_dropdown_']) {
|
|
51
|
+
width: 100%;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
import classes from './IntegrationSettings.module.scss';
|
|
3
|
-
import Input from '../../common/form/Input/Input';
|
|
4
|
-
import ActionModal from '../../common/ActionModal/ActionModal';
|
|
5
|
-
import { useValidateIntegration } from '../../../services/settings';
|
|
6
3
|
import SMTPSettings from './SMTPSettings';
|
|
4
|
+
import NtfySettings from './NtfySettings';
|
|
5
|
+
import Icon from '../../common/Icon/Icon';
|
|
6
|
+
import Select from '../../common/form/Select/Select';
|
|
7
|
+
import { isMobile } from '../../../utils';
|
|
7
8
|
|
|
8
9
|
interface IntegrationSettingsProps {
|
|
9
10
|
settingsID: number;
|
|
@@ -12,12 +13,9 @@ interface IntegrationSettingsProps {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
const IntegrationSettings = ({ settingsID, settings, onUpdate }: IntegrationSettingsProps) => {
|
|
15
|
-
const [
|
|
16
|
-
const [showEmailTestModal, setShowEmailTestModal] = useState<'' | 'smtp'>('');
|
|
16
|
+
const [tab, setTab] = useState<'smtp' | 'ntfy'>('smtp');
|
|
17
17
|
const integrationSettings = settings?.integration || {};
|
|
18
|
-
const { smtp } = integrationSettings || {};
|
|
19
|
-
|
|
20
|
-
const validationMutation = useValidateIntegration();
|
|
18
|
+
const { smtp, ntfy } = integrationSettings || {};
|
|
21
19
|
|
|
22
20
|
const onIntegrationUpdate = (key: string, intSettings: Record<string, any>) => {
|
|
23
21
|
console.log('onIntegrationUpdate :', key, intSettings);
|
|
@@ -26,42 +24,47 @@ const IntegrationSettings = ({ settingsID, settings, onUpdate }: IntegrationSett
|
|
|
26
24
|
|
|
27
25
|
return (
|
|
28
26
|
<div className={classes.integrations}>
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
message={
|
|
40
|
-
<>
|
|
41
|
-
<Input
|
|
42
|
-
label="Send Test Email to this email"
|
|
43
|
-
full={true}
|
|
44
|
-
fieldValue={testEmail}
|
|
45
|
-
onUpdate={(val) => setTestEmail(val)}
|
|
46
|
-
type="email"
|
|
47
|
-
placeholder="test@test.com"
|
|
48
|
-
/>
|
|
49
|
-
</>
|
|
50
|
-
}
|
|
51
|
-
errorMessage={validationMutation.error?.message}
|
|
52
|
-
successMessage={validationMutation.isSuccess ? 'Test email sent. Integration validated successfully.' : ''}
|
|
53
|
-
closeModal={() => setShowEmailTestModal('')}
|
|
54
|
-
width="400px"
|
|
55
|
-
secondaryAction={{ title: 'Close', action: () => setShowEmailTestModal('') }}
|
|
56
|
-
primaryAction={{
|
|
57
|
-
title: `Send Test Email`,
|
|
58
|
-
type: 'default',
|
|
59
|
-
icon: 'email',
|
|
60
|
-
isPending: validationMutation.isPending,
|
|
61
|
-
action: () => validationMutation.mutate({ settingsID, type: 'smtp', settings: settings, test: { email: testEmail } }),
|
|
62
|
-
}}
|
|
27
|
+
{isMobile() ? (
|
|
28
|
+
<Select
|
|
29
|
+
customClasses={classes.integrationSelect}
|
|
30
|
+
options={[
|
|
31
|
+
{ label: 'SMTP', value: 'smtp', icon: 'email' },
|
|
32
|
+
{ label: 'Ntfy', value: 'ntfy', icon: 'ntfy' },
|
|
33
|
+
]}
|
|
34
|
+
fieldValue={tab}
|
|
35
|
+
full={true}
|
|
36
|
+
onUpdate={(val) => setTab(val as 'smtp' | 'ntfy')}
|
|
63
37
|
/>
|
|
38
|
+
) : (
|
|
39
|
+
<>
|
|
40
|
+
<ul className={classes.tabs}>
|
|
41
|
+
<li className={`${tab === 'smtp' ? classes.tabActive : ''}`} onClick={() => setTab('smtp')}>
|
|
42
|
+
<Icon type="email" size={14} /> SMTP
|
|
43
|
+
{smtp?.connected && <Icon type="check-circle-filled" size={12} />}
|
|
44
|
+
</li>
|
|
45
|
+
<li className={`${tab === 'ntfy' ? classes.tabActive : ''}`} onClick={() => setTab('ntfy')}>
|
|
46
|
+
<Icon type="ntfy" size={14} /> Ntfy
|
|
47
|
+
{ntfy?.connected && <Icon type="check-circle-filled" size={12} />}
|
|
48
|
+
</li>
|
|
49
|
+
</ul>
|
|
50
|
+
</>
|
|
64
51
|
)}
|
|
52
|
+
<div>
|
|
53
|
+
{tab === 'smtp' && (
|
|
54
|
+
<SMTPSettings
|
|
55
|
+
settingsID={settingsID}
|
|
56
|
+
settings={integrationSettings}
|
|
57
|
+
onUpdate={(iSettings) => onIntegrationUpdate('smtp', iSettings)}
|
|
58
|
+
/>
|
|
59
|
+
)}
|
|
60
|
+
{tab === 'ntfy' && (
|
|
61
|
+
<NtfySettings
|
|
62
|
+
settingsID={settingsID}
|
|
63
|
+
settings={integrationSettings}
|
|
64
|
+
onUpdate={(iSettings) => onIntegrationUpdate('ntfy', iSettings)}
|
|
65
|
+
/>
|
|
66
|
+
)}
|
|
67
|
+
</div>
|
|
65
68
|
</div>
|
|
66
69
|
);
|
|
67
70
|
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import classes from './IntegrationSettings.module.scss';
|
|
3
|
+
import { IntegrationSettings, NtfySettingsType } from '../../../@types';
|
|
4
|
+
import Icon from '../../common/Icon/Icon';
|
|
5
|
+
import Select from '../../common/form/Select/Select';
|
|
6
|
+
import Input from '../../common/form/Input/Input';
|
|
7
|
+
import ActionModal from '../../common/ActionModal/ActionModal';
|
|
8
|
+
import { useValidateIntegration } from '../../../services';
|
|
9
|
+
import PasswordField from '../../common/form/PasswordField/PasswordField';
|
|
10
|
+
|
|
11
|
+
interface NtfySettingsProps {
|
|
12
|
+
settingsID: number;
|
|
13
|
+
settings: IntegrationSettings;
|
|
14
|
+
onUpdate: (settings: NtfySettingsType) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const NtfySettings = ({ settingsID, settings, onUpdate }: NtfySettingsProps) => {
|
|
18
|
+
const [ntfySettings, setNtfySettings] = useState<NtfySettingsType>(settings?.ntfy || { authType: 'token', authToken: '', connected: false });
|
|
19
|
+
const [errorFields, setErrorFields] = useState<{ authToken: string }>({ authToken: '' });
|
|
20
|
+
const [showTestModal, setShowTestModal] = useState(false);
|
|
21
|
+
const [testUrl, setTestUrl] = useState('');
|
|
22
|
+
const validationMutation = useValidateIntegration();
|
|
23
|
+
|
|
24
|
+
const authType = ntfySettings.authType || 'token';
|
|
25
|
+
|
|
26
|
+
const updateNtfySettings = (updated: NtfySettingsType) => {
|
|
27
|
+
setNtfySettings(updated);
|
|
28
|
+
onUpdate(updated);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const validateSettings = (e: React.FormEvent) => {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
|
|
34
|
+
const newErrors = { authToken: '' };
|
|
35
|
+
|
|
36
|
+
if (!ntfySettings?.authToken) {
|
|
37
|
+
newErrors.authToken = 'Required';
|
|
38
|
+
}
|
|
39
|
+
setErrorFields(newErrors);
|
|
40
|
+
const hasErrors = Object.values(newErrors).some((error) => error !== '');
|
|
41
|
+
if (!hasErrors) {
|
|
42
|
+
setShowTestModal(true);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div>
|
|
48
|
+
<div className={classes.field}>
|
|
49
|
+
<Select
|
|
50
|
+
label="Auth Type*"
|
|
51
|
+
fieldValue={authType}
|
|
52
|
+
options={[{ label: 'Token', value: 'token' }]}
|
|
53
|
+
onUpdate={(val) => updateNtfySettings({ ...ntfySettings, authType: val })}
|
|
54
|
+
inline={true}
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
<div className={classes.field}>
|
|
58
|
+
<PasswordField
|
|
59
|
+
label="Auth Token*"
|
|
60
|
+
fieldValue={ntfySettings.authToken}
|
|
61
|
+
onUpdate={(val) => updateNtfySettings({ ...ntfySettings, authToken: val })}
|
|
62
|
+
error={errorFields?.authToken}
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
<div className={classes.field}>
|
|
66
|
+
<button className={classes.validateBtn} onClick={validateSettings} type="button">
|
|
67
|
+
<Icon type="check" size={10} /> {ntfySettings.connected ? 'Re-validate Ntfy' : 'Validate Ntfy'}
|
|
68
|
+
</button>
|
|
69
|
+
</div>
|
|
70
|
+
{showTestModal && (
|
|
71
|
+
<ActionModal
|
|
72
|
+
title={`Test Ntfy Integration`}
|
|
73
|
+
message={
|
|
74
|
+
<>
|
|
75
|
+
<Input
|
|
76
|
+
label="Send Test Notification to this topic"
|
|
77
|
+
full={true}
|
|
78
|
+
inline={false}
|
|
79
|
+
fieldValue={testUrl}
|
|
80
|
+
onUpdate={(val) => setTestUrl(val)}
|
|
81
|
+
type="text"
|
|
82
|
+
placeholder="test/topic url. Eg: https://ntfy.sh/testtopic"
|
|
83
|
+
/>
|
|
84
|
+
</>
|
|
85
|
+
}
|
|
86
|
+
errorMessage={validationMutation.error?.message}
|
|
87
|
+
successMessage={validationMutation.isSuccess ? 'Test notification sent. Integration validated successfully.' : ''}
|
|
88
|
+
closeModal={() => setShowTestModal(false)}
|
|
89
|
+
width="400px"
|
|
90
|
+
secondaryAction={{ title: 'Close', action: () => setShowTestModal(false) }}
|
|
91
|
+
primaryAction={{
|
|
92
|
+
title: `Send Test Notification`,
|
|
93
|
+
type: 'default',
|
|
94
|
+
icon: 'send',
|
|
95
|
+
isPending: validationMutation.isPending,
|
|
96
|
+
action: () =>
|
|
97
|
+
testUrl &&
|
|
98
|
+
validationMutation.mutate({ settingsID, type: 'ntfy', settings: { ...settings, ntfy: ntfySettings }, test: { url: testUrl } }),
|
|
99
|
+
}}
|
|
100
|
+
/>
|
|
101
|
+
)}
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export default NtfySettings;
|
|
@@ -3,42 +3,47 @@ import Input from '../../common/form/Input/Input';
|
|
|
3
3
|
import Icon from '../../common/Icon/Icon';
|
|
4
4
|
import { isValidEmail } from '../../../utils/helpers';
|
|
5
5
|
import { SmtpSettingsType } from '../../../@types/settings';
|
|
6
|
+
import { IntegrationSettings } from '../../../@types';
|
|
6
7
|
import classes from './IntegrationSettings.module.scss';
|
|
8
|
+
import ValidateEmailIntegration from './ValidateEmailIntegration';
|
|
7
9
|
|
|
8
10
|
interface SMTPSettingsProps {
|
|
9
|
-
|
|
11
|
+
settingsID: number;
|
|
12
|
+
settings: IntegrationSettings;
|
|
10
13
|
onUpdate: (settings: SmtpSettingsType) => void;
|
|
11
|
-
showTestModal: (type: 'smtp') => void;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
const SMTPSettings = ({ settings, onUpdate
|
|
16
|
+
const SMTPSettings = ({ settingsID, settings, onUpdate }: SMTPSettingsProps) => {
|
|
17
|
+
const [showTestModal, setShowTestModal] = useState(false);
|
|
15
18
|
const [errorFields, setErrorFields] = useState<{ server: string; port: string; senderEmail: string }>({
|
|
16
19
|
server: '',
|
|
17
20
|
port: '',
|
|
18
21
|
senderEmail: '',
|
|
19
22
|
});
|
|
20
23
|
|
|
24
|
+
const smtpSettings = settings?.smtp || { server: '', port: 587, senderEmail: '', username: '', password: '', connected: false };
|
|
25
|
+
|
|
21
26
|
const validateSettings = (e: React.FormEvent) => {
|
|
22
27
|
e.preventDefault();
|
|
23
28
|
|
|
24
29
|
const newErrors = { server: '', port: '', senderEmail: '' };
|
|
25
30
|
|
|
26
|
-
if (!
|
|
31
|
+
if (!smtpSettings?.server) {
|
|
27
32
|
newErrors.server = 'Server is required';
|
|
28
33
|
}
|
|
29
|
-
if (!
|
|
34
|
+
if (!smtpSettings?.port) {
|
|
30
35
|
newErrors.port = 'Port is required';
|
|
31
36
|
}
|
|
32
|
-
if (!
|
|
37
|
+
if (!smtpSettings?.senderEmail) {
|
|
33
38
|
newErrors.senderEmail = 'Sender Email is required';
|
|
34
|
-
} else if (!isValidEmail(
|
|
39
|
+
} else if (!isValidEmail(smtpSettings.senderEmail)) {
|
|
35
40
|
newErrors.senderEmail = 'Invalid email';
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
setErrorFields(newErrors);
|
|
39
44
|
const hasErrors = Object.values(newErrors).some((error) => error !== '');
|
|
40
45
|
if (!hasErrors) {
|
|
41
|
-
|
|
46
|
+
setShowTestModal(true);
|
|
42
47
|
}
|
|
43
48
|
};
|
|
44
49
|
|
|
@@ -47,16 +52,16 @@ const SMTPSettings = ({ settings, onUpdate, showTestModal }: SMTPSettingsProps)
|
|
|
47
52
|
<div className={classes.field}>
|
|
48
53
|
<Input
|
|
49
54
|
label="SMTP Server*"
|
|
50
|
-
fieldValue={(
|
|
51
|
-
onUpdate={(val) => onUpdate({ ...
|
|
55
|
+
fieldValue={(smtpSettings?.server || '') as string}
|
|
56
|
+
onUpdate={(val) => onUpdate({ ...smtpSettings, server: val })}
|
|
52
57
|
error={errorFields?.server}
|
|
53
58
|
/>
|
|
54
59
|
</div>
|
|
55
60
|
<div className={classes.field}>
|
|
56
61
|
<Input
|
|
57
62
|
label="SMTP PORT*"
|
|
58
|
-
fieldValue={(
|
|
59
|
-
onUpdate={(val) => onUpdate({ ...
|
|
63
|
+
fieldValue={(smtpSettings?.port || '') as string}
|
|
64
|
+
onUpdate={(val) => onUpdate({ ...smtpSettings, port: parseInt(val, 10) })}
|
|
60
65
|
error={errorFields?.port}
|
|
61
66
|
/>
|
|
62
67
|
</div>
|
|
@@ -64,32 +69,36 @@ const SMTPSettings = ({ settings, onUpdate, showTestModal }: SMTPSettingsProps)
|
|
|
64
69
|
<Input
|
|
65
70
|
label="Sender Email*"
|
|
66
71
|
type="email"
|
|
67
|
-
fieldValue={(
|
|
68
|
-
onUpdate={(val) => onUpdate({ ...
|
|
72
|
+
fieldValue={(smtpSettings?.senderEmail || '') as string}
|
|
73
|
+
onUpdate={(val) => onUpdate({ ...smtpSettings, senderEmail: val })}
|
|
69
74
|
error={errorFields?.senderEmail}
|
|
70
75
|
/>
|
|
71
76
|
</div>
|
|
72
77
|
<div className={classes.field}>
|
|
73
78
|
<Input
|
|
74
79
|
label="SMTP Username"
|
|
75
|
-
fieldValue={(
|
|
76
|
-
onUpdate={(val) => onUpdate({ ...
|
|
80
|
+
fieldValue={(smtpSettings?.username || '') as string}
|
|
81
|
+
onUpdate={(val) => onUpdate({ ...smtpSettings, username: val })}
|
|
77
82
|
/>
|
|
78
83
|
</div>
|
|
79
84
|
<div className={classes.field}>
|
|
80
85
|
<Input
|
|
81
86
|
label="SMTP Password"
|
|
82
|
-
fieldValue={(
|
|
87
|
+
fieldValue={(smtpSettings?.password || '') as string}
|
|
83
88
|
type="password"
|
|
84
|
-
onUpdate={(val) => onUpdate({ ...
|
|
89
|
+
onUpdate={(val) => onUpdate({ ...smtpSettings, password: val })}
|
|
85
90
|
/>
|
|
86
91
|
</div>
|
|
87
92
|
|
|
88
93
|
<div className={classes.field}>
|
|
89
94
|
<button className={classes.validateBtn} onClick={validateSettings} type="button">
|
|
90
|
-
<Icon type="check" size={10} /> {
|
|
95
|
+
<Icon type="check" size={10} /> {smtpSettings?.connected ? 'Re-validate SMTP' : 'Validate SMTP'}
|
|
91
96
|
</button>
|
|
92
97
|
</div>
|
|
98
|
+
|
|
99
|
+
{showTestModal && (
|
|
100
|
+
<ValidateEmailIntegration settingsID={settingsID} settings={settings} integrationType="smtp" onClose={() => setShowTestModal(false)} />
|
|
101
|
+
)}
|
|
93
102
|
</div>
|
|
94
103
|
);
|
|
95
104
|
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import Input from '../../common/form/Input/Input';
|
|
3
|
+
import ActionModal from '../../common/ActionModal/ActionModal';
|
|
4
|
+
import { useValidateIntegration } from '../../../services';
|
|
5
|
+
import { INTEGRATIONS_AVAILABLE, IntegrationSettings, IntegrationTypes } from '../../../@types';
|
|
6
|
+
|
|
7
|
+
interface ValidateEmailIntegrationProps {
|
|
8
|
+
settingsID: number;
|
|
9
|
+
settings: IntegrationSettings;
|
|
10
|
+
integrationType: IntegrationTypes;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const ValidateEmailIntegration = ({ settingsID, settings, integrationType, onClose }: ValidateEmailIntegrationProps) => {
|
|
15
|
+
const [testEmail, setTestEmail] = useState('');
|
|
16
|
+
const validationMutation = useValidateIntegration();
|
|
17
|
+
const integrationName = INTEGRATIONS_AVAILABLE[integrationType as IntegrationTypes].name;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<ActionModal
|
|
21
|
+
title={`Test ${integrationName} Integration`}
|
|
22
|
+
message={
|
|
23
|
+
<>
|
|
24
|
+
<Input
|
|
25
|
+
label="Send Test Email to this email"
|
|
26
|
+
full={true}
|
|
27
|
+
inline={false}
|
|
28
|
+
fieldValue={testEmail}
|
|
29
|
+
onUpdate={(val) => setTestEmail(val)}
|
|
30
|
+
type="email"
|
|
31
|
+
placeholder="test@test.com"
|
|
32
|
+
/>
|
|
33
|
+
</>
|
|
34
|
+
}
|
|
35
|
+
errorMessage={validationMutation.error?.message}
|
|
36
|
+
successMessage={validationMutation.isSuccess ? `Test email sent. ${integrationName} validated successfully.` : ''}
|
|
37
|
+
closeModal={onClose}
|
|
38
|
+
width="400px"
|
|
39
|
+
secondaryAction={{ title: 'Close', action: onClose }}
|
|
40
|
+
primaryAction={{
|
|
41
|
+
title: 'Send Test Email',
|
|
42
|
+
type: 'default',
|
|
43
|
+
icon: 'email',
|
|
44
|
+
isPending: validationMutation.isPending,
|
|
45
|
+
action: () =>
|
|
46
|
+
testEmail &&
|
|
47
|
+
validationMutation.mutate({
|
|
48
|
+
settingsID,
|
|
49
|
+
type: integrationType,
|
|
50
|
+
settings: { ...settings },
|
|
51
|
+
test: { email: testEmail },
|
|
52
|
+
}),
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default ValidateEmailIntegration;
|
|
@@ -39,7 +39,7 @@ const EditStorage = ({ close, storage }: EditStorageProps) => {
|
|
|
39
39
|
storage.storageFields.forEach((field: storageOptionField) => {
|
|
40
40
|
if (field.required) {
|
|
41
41
|
(groupedFields.required as storageOptionField[]).push(field);
|
|
42
|
-
} else {
|
|
42
|
+
} else if (!field.authFieldType) {
|
|
43
43
|
(groupedFields.optional as storageOptionField[]).push(field);
|
|
44
44
|
}
|
|
45
45
|
});
|