@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.
Files changed (143) hide show
  1. package/dist-lib/@types/index.js +4 -1
  2. package/dist-lib/@types/index.js.map +1 -1
  3. package/dist-lib/@types/settings.d.ts +14 -0
  4. package/dist-lib/@types/settings.d.ts.map +1 -1
  5. package/dist-lib/@types/settings.js +34 -0
  6. package/dist-lib/@types/settings.js.map +1 -0
  7. package/dist-lib/components/Plan/Backups/Backups.d.ts.map +1 -1
  8. package/dist-lib/components/Plan/Backups/Backups.js +189 -159
  9. package/dist-lib/components/Plan/Backups/Backups.js.map +1 -1
  10. package/dist-lib/components/Plan/PlanSettings/PlanNotificationSettings.d.ts.map +1 -1
  11. package/dist-lib/components/Plan/PlanSettings/PlanNotificationSettings.js +148 -90
  12. package/dist-lib/components/Plan/PlanSettings/PlanNotificationSettings.js.map +1 -1
  13. package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewer.d.ts +32 -0
  14. package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewer.d.ts.map +1 -0
  15. package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewer.js +252 -0
  16. package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewer.js.map +1 -0
  17. package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewerFile.d.ts +23 -0
  18. package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewerFile.d.ts.map +1 -0
  19. package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewerFile.js +72 -0
  20. package/dist-lib/components/Plan/SnapshotViewer/SnapshotViewerFile.js.map +1 -0
  21. package/dist-lib/components/Restore/RestoreFileSelector/RestoreFileSelector.d.ts.map +1 -1
  22. package/dist-lib/components/Restore/RestoreFileSelector/RestoreFileSelector.js +188 -198
  23. package/dist-lib/components/Restore/RestoreFileSelector/RestoreFileSelector.js.map +1 -1
  24. package/dist-lib/components/Restore/RestoreFileSelector/RestoreFileSelector.module.scss.js +20 -64
  25. package/dist-lib/components/Restore/RestoreFileSelector/RestoreFileSelector.module.scss.js.map +1 -1
  26. package/dist-lib/components/Restore/RestoredFileBrowser/RestoredFileBrowser.d.ts.map +1 -1
  27. package/dist-lib/components/Restore/RestoredFileBrowser/RestoredFileBrowser.js +125 -159
  28. package/dist-lib/components/Restore/RestoredFileBrowser/RestoredFileBrowser.js.map +1 -1
  29. package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.d.ts.map +1 -1
  30. package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.js +52 -47
  31. package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.js.map +1 -1
  32. package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.module.scss.js +12 -6
  33. package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.module.scss.js.map +1 -1
  34. package/dist-lib/components/Settings/IntegrationSettings/NtfySettings.d.ts +9 -0
  35. package/dist-lib/components/Settings/IntegrationSettings/NtfySettings.d.ts.map +1 -0
  36. package/dist-lib/components/Settings/IntegrationSettings/NtfySettings.js +79 -0
  37. package/dist-lib/components/Settings/IntegrationSettings/NtfySettings.js.map +1 -0
  38. package/dist-lib/components/Settings/IntegrationSettings/SMTPSettings.d.ts +4 -3
  39. package/dist-lib/components/Settings/IntegrationSettings/SMTPSettings.d.ts.map +1 -1
  40. package/dist-lib/components/Settings/IntegrationSettings/SMTPSettings.js +37 -35
  41. package/dist-lib/components/Settings/IntegrationSettings/SMTPSettings.js.map +1 -1
  42. package/dist-lib/components/Settings/IntegrationSettings/ValidateEmailIntegration.d.ts +10 -0
  43. package/dist-lib/components/Settings/IntegrationSettings/ValidateEmailIntegration.d.ts.map +1 -0
  44. package/dist-lib/components/Settings/IntegrationSettings/ValidateEmailIntegration.js +49 -0
  45. package/dist-lib/components/Settings/IntegrationSettings/ValidateEmailIntegration.js.map +1 -0
  46. package/dist-lib/components/Storage/EditStorage/EditStorage.js +10 -10
  47. package/dist-lib/components/Storage/EditStorage/EditStorage.js.map +1 -1
  48. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowser.module.scss.js +74 -0
  49. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowser.module.scss.js.map +1 -0
  50. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserDirectories.d.ts +17 -0
  51. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserDirectories.d.ts.map +1 -0
  52. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserDirectories.js +57 -0
  53. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserDirectories.js.map +1 -0
  54. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileList.d.ts +18 -0
  55. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileList.d.ts.map +1 -0
  56. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileList.js +24 -0
  57. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileList.js.map +1 -0
  58. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileRow.d.ts +18 -0
  59. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileRow.d.ts.map +1 -0
  60. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileRow.js +37 -0
  61. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserFileRow.js.map +1 -0
  62. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserGoUpRow.d.ts +9 -0
  63. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserGoUpRow.d.ts.map +1 -0
  64. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserGoUpRow.js +15 -0
  65. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserGoUpRow.js.map +1 -0
  66. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserToolbar.d.ts +11 -0
  67. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserToolbar.d.ts.map +1 -0
  68. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserToolbar.js +18 -0
  69. package/dist-lib/components/common/SnapshotBrowser/SnapshotBrowserToolbar.js.map +1 -0
  70. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotDatabase.d.ts +12 -0
  71. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotDatabase.d.ts.map +1 -0
  72. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotDatabase.js +70 -0
  73. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotDatabase.js.map +1 -0
  74. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotNavigation.d.ts +22 -0
  75. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotNavigation.d.ts.map +1 -0
  76. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotNavigation.js +79 -0
  77. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotNavigation.js.map +1 -0
  78. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotSort.d.ts +6 -0
  79. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotSort.d.ts.map +1 -0
  80. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotSort.js +18 -0
  81. package/dist-lib/components/common/SnapshotBrowser/hooks/useSnapshotSort.js.map +1 -0
  82. package/dist-lib/components/common/SnapshotBrowser/index.d.ts +11 -0
  83. package/dist-lib/components/common/SnapshotBrowser/index.d.ts.map +1 -0
  84. package/dist-lib/components/index.d.ts +12 -0
  85. package/dist-lib/components/index.d.ts.map +1 -1
  86. package/dist-lib/components.js +152 -128
  87. package/dist-lib/components.js.map +1 -1
  88. package/dist-lib/hooks/usePlanSingleActions.d.ts.map +1 -1
  89. package/dist-lib/hooks/usePlanSingleActions.js +21 -21
  90. package/dist-lib/hooks/usePlanSingleActions.js.map +1 -1
  91. package/dist-lib/services/backups.d.ts +4 -0
  92. package/dist-lib/services/backups.d.ts.map +1 -1
  93. package/dist-lib/services/backups.js +34 -25
  94. package/dist-lib/services/backups.js.map +1 -1
  95. package/dist-lib/services/settings.d.ts +3 -2
  96. package/dist-lib/services/settings.d.ts.map +1 -1
  97. package/dist-lib/services/settings.js +0 -1
  98. package/dist-lib/services/settings.js.map +1 -1
  99. package/dist-lib/services.js +113 -112
  100. package/dist-lib/styles/core-frontend.css +1 -1
  101. package/dist-lib/utils/index.d.ts +1 -0
  102. package/dist-lib/utils/index.d.ts.map +1 -1
  103. package/dist-lib/utils/snapshotDatabase.d.ts +16 -0
  104. package/dist-lib/utils/snapshotDatabase.d.ts.map +1 -0
  105. package/dist-lib/utils/snapshotDatabase.js +105 -0
  106. package/dist-lib/utils/snapshotDatabase.js.map +1 -0
  107. package/dist-lib/utils.js +24 -22
  108. package/dist-lib/utils.js.map +1 -1
  109. package/package.json +1 -1
  110. package/src/@types/settings.ts +43 -0
  111. package/src/components/Plan/Backups/Backups.tsx +40 -1
  112. package/src/components/Plan/PlanSettings/PlanNotificationSettings.tsx +65 -0
  113. package/src/components/Plan/SnapshotViewer/SnapshotViewer.tsx +344 -0
  114. package/src/components/Plan/SnapshotViewer/SnapshotViewerFile.tsx +89 -0
  115. package/src/components/Restore/RestoreFileSelector/RestoreFileSelector.tsx +82 -145
  116. package/src/components/Restore/RestoredFileBrowser/RestoredFileBrowser.tsx +71 -156
  117. package/src/components/Settings/IntegrationSettings/IntegrationSettings.module.scss +16 -0
  118. package/src/components/Settings/IntegrationSettings/IntegrationSettings.tsx +45 -42
  119. package/src/components/Settings/IntegrationSettings/NtfySettings.tsx +106 -0
  120. package/src/components/Settings/IntegrationSettings/SMTPSettings.tsx +28 -19
  121. package/src/components/Settings/IntegrationSettings/ValidateEmailIntegration.tsx +58 -0
  122. package/src/components/Storage/EditStorage/EditStorage.tsx +1 -1
  123. package/src/components/common/SnapshotBrowser/SnapshotBrowser.module.scss +376 -0
  124. package/src/components/common/SnapshotBrowser/SnapshotBrowserDirectories.tsx +84 -0
  125. package/src/components/common/SnapshotBrowser/SnapshotBrowserFileList.tsx +52 -0
  126. package/src/components/common/SnapshotBrowser/SnapshotBrowserFileRow.tsx +44 -0
  127. package/src/components/common/SnapshotBrowser/SnapshotBrowserGoUpRow.tsx +22 -0
  128. package/src/components/common/SnapshotBrowser/SnapshotBrowserToolbar.tsx +29 -0
  129. package/src/components/common/SnapshotBrowser/hooks/useSnapshotDatabase.ts +130 -0
  130. package/src/components/common/SnapshotBrowser/hooks/useSnapshotNavigation.ts +154 -0
  131. package/src/components/common/SnapshotBrowser/hooks/useSnapshotSort.ts +24 -0
  132. package/src/components/common/SnapshotBrowser/index.ts +13 -0
  133. package/src/components/index.ts +15 -0
  134. package/src/hooks/usePlanSingleActions.tsx +5 -3
  135. package/src/services/backups.ts +12 -0
  136. package/src/services/settings.ts +2 -2
  137. package/src/utils/index.ts +1 -0
  138. package/src/utils/snapshotDatabase.ts +201 -0
  139. /package/dist-lib/providers/{azureBlob.png → azureblob.png} +0 -0
  140. /package/dist-lib/providers/{azureFiles.png → azurefiles.png} +0 -0
  141. /package/dist-lib/providers/{files.png → filescom.png} +0 -0
  142. /package/dist-lib/providers/{oracle.png → oracleobjectstorage.png} +0 -0
  143. /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 [testEmail, setTestEmail] = useState('');
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
- <div>
30
- <SMTPSettings
31
- settings={smtp}
32
- onUpdate={(iSettings) => onIntegrationUpdate('smtp', iSettings)}
33
- showTestModal={(type) => setShowEmailTestModal(type)}
34
- />
35
- </div>
36
- {showEmailTestModal && (
37
- <ActionModal
38
- title={`Test SMTP Integration`}
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
- settings: SmtpSettingsType;
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, showTestModal }: SMTPSettingsProps) => {
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 (!settings?.server) {
31
+ if (!smtpSettings?.server) {
27
32
  newErrors.server = 'Server is required';
28
33
  }
29
- if (!settings?.port) {
34
+ if (!smtpSettings?.port) {
30
35
  newErrors.port = 'Port is required';
31
36
  }
32
- if (!settings?.senderEmail) {
37
+ if (!smtpSettings?.senderEmail) {
33
38
  newErrors.senderEmail = 'Sender Email is required';
34
- } else if (!isValidEmail(settings.senderEmail)) {
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
- showTestModal('smtp');
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={(settings?.server || '') as string}
51
- onUpdate={(val) => onUpdate({ ...settings, server: val })}
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={(settings?.port || '') as string}
59
- onUpdate={(val) => onUpdate({ ...settings, port: parseInt(val, 10) })}
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={(settings?.senderEmail || '') as string}
68
- onUpdate={(val) => onUpdate({ ...settings, senderEmail: val })}
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={(settings?.username || '') as string}
76
- onUpdate={(val) => onUpdate({ ...settings, username: val })}
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={(settings?.password || '') as string}
87
+ fieldValue={(smtpSettings?.password || '') as string}
83
88
  type="password"
84
- onUpdate={(val) => onUpdate({ ...settings, password: val })}
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} /> {settings?.connected ? 'Re-validate SMTP' : 'Validate SMTP'}
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
  });