Skip to content

Commit d174734

Browse files
committed
feat: complete push notification panel integration and data mapping
- Fix push notification panel visibility by adding to SettingsNavigation and SettingsPage routing - Add comprehensive data transformation logic in useGenericSettings for nested-to-flat field mapping - Fix field naming consistency between PushNotificationSettings and PushNotificationPanel components - Add missing service_batch_size field to complete backend field coverage - Implement bidirectional data transformation for proper save/load functionality - Update settings types to include push_notifications group - Complete integration of all push notification configuration fields: * Main: enabled * Service: worker_count, queue_size, batch_size, retry_attempts, retry_delay * APNs: enabled, key_path, key_id, team_id, bundle_id, production * FCM: enabled, credentials_path, project_id Resolves panel visibility issues and ensures proper data flow between frontend and backend.
1 parent 5c8b3b2 commit d174734

File tree

7 files changed

+271
-161
lines changed

7 files changed

+271
-161
lines changed

src/components/settings/PushNotificationSettings.tsx

Lines changed: 71 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ const PushNotificationSettings: React.FC = () => {
113113
style={{ marginBottom: 16 }}
114114
>
115115
<Form.Item
116-
name={['service', 'worker_count']}
116+
name="service_worker_count"
117117
label={
118118
<span>
119119
Worker Count&nbsp;
@@ -127,16 +127,16 @@ const PushNotificationSettings: React.FC = () => {
127127
{ type: 'number', min: 1, max: 100, message: 'Worker count must be between 1 and 100' }
128128
]}
129129
>
130-
<InputNumber
131-
placeholder="Enter worker count"
130+
<InputNumber
131+
placeholder="Enter worker count"
132132
style={{ width: '100%' }}
133133
min={1}
134134
max={100}
135135
/>
136136
</Form.Item>
137137

138138
<Form.Item
139-
name={['service', 'queue_size']}
139+
name="service_queue_size"
140140
label={
141141
<span>
142142
Queue Size&nbsp;
@@ -150,16 +150,16 @@ const PushNotificationSettings: React.FC = () => {
150150
{ type: 'number', min: 100, max: 10000, message: 'Queue size must be between 100 and 10000' }
151151
]}
152152
>
153-
<InputNumber
154-
placeholder="Enter queue size"
153+
<InputNumber
154+
placeholder="Enter queue size"
155155
style={{ width: '100%' }}
156156
min={100}
157157
max={10000}
158158
/>
159159
</Form.Item>
160160

161161
<Form.Item
162-
name={['service', 'retry_max_attempts']}
162+
name="service_retry_attempts"
163163
label={
164164
<span>
165165
Max Retry Attempts&nbsp;
@@ -173,16 +173,16 @@ const PushNotificationSettings: React.FC = () => {
173173
{ type: 'number', min: 1, max: 10, message: 'Max retry attempts must be between 1 and 10' }
174174
]}
175175
>
176-
<InputNumber
177-
placeholder="Enter max retry attempts"
176+
<InputNumber
177+
placeholder="Enter max retry attempts"
178178
style={{ width: '100%' }}
179179
min={1}
180180
max={10}
181181
/>
182182
</Form.Item>
183183

184184
<Form.Item
185-
name={['service', 'retry_base_delay']}
185+
name="service_retry_delay"
186186
label={
187187
<span>
188188
Retry Base Delay&nbsp;
@@ -193,17 +193,40 @@ const PushNotificationSettings: React.FC = () => {
193193
}
194194
rules={[
195195
{ required: true, message: 'Please enter retry base delay' },
196-
{
197-
pattern: /^\d+[a-zA-Z]+$/,
198-
message: 'Invalid duration format. Use Go duration format (e.g., "1s", "500ms", "2m")'
196+
{
197+
pattern: /^\d+[a-zA-Z]+$/,
198+
message: 'Invalid duration format. Use Go duration format (e.g., "1s", "500ms", "2m")'
199199
}
200200
]}
201201
>
202-
<Input
203-
placeholder="e.g., 1s, 500ms, 2m"
202+
<Input
203+
placeholder="e.g., 1s, 500ms, 2m"
204204
prefix={<SettingOutlined />}
205205
/>
206206
</Form.Item>
207+
208+
<Form.Item
209+
name="service_batch_size"
210+
label={
211+
<span>
212+
Batch Size&nbsp;
213+
<Tooltip title="Number of notifications to process in each batch (1-1000)">
214+
<QuestionCircleOutlined />
215+
</Tooltip>
216+
</span>
217+
}
218+
rules={[
219+
{ required: true, message: 'Please enter batch size' },
220+
{ type: 'number', min: 1, max: 1000, message: 'Batch size must be between 1 and 1000' }
221+
]}
222+
>
223+
<InputNumber
224+
placeholder="Enter batch size"
225+
style={{ width: '100%' }}
226+
min={1}
227+
max={1000}
228+
/>
229+
</Form.Item>
207230
</Card>
208231

209232
{/* APNs Configuration */}
@@ -217,7 +240,7 @@ const PushNotificationSettings: React.FC = () => {
217240
style={{ marginBottom: 16 }}
218241
>
219242
<Form.Item
220-
name={['apns', 'enabled']}
243+
name="apns_enabled"
221244
label={
222245
<span>
223246
Enable APNs&nbsp;
@@ -232,7 +255,7 @@ const PushNotificationSettings: React.FC = () => {
232255
</Form.Item>
233256

234257
<Form.Item
235-
name={['apns', 'key_file']}
258+
name="apns_key_path"
236259
label={
237260
<span>
238261
APNs Key File Path&nbsp;
@@ -242,20 +265,20 @@ const PushNotificationSettings: React.FC = () => {
242265
</span>
243266
}
244267
rules={[
245-
{
246-
required: form.getFieldValue(['apns', 'enabled']),
247-
message: 'Please enter APNs key file path when APNs is enabled'
268+
{
269+
required: form.getFieldValue('apns_enabled'),
270+
message: 'Please enter APNs key file path when APNs is enabled'
248271
}
249272
]}
250273
>
251-
<Input
252-
placeholder="path/to/apns-key.p8"
274+
<Input
275+
placeholder="path/to/apns-key.p8"
253276
prefix={<FileTextOutlined />}
254277
/>
255278
</Form.Item>
256279

257280
<Form.Item
258-
name={['apns', 'key_id']}
281+
name="apns_key_id"
259282
label={
260283
<span>
261284
APNs Key ID&nbsp;
@@ -265,22 +288,22 @@ const PushNotificationSettings: React.FC = () => {
265288
</span>
266289
}
267290
rules={[
268-
{
269-
required: form.getFieldValue(['apns', 'enabled']),
270-
message: 'Please enter APNs key ID when APNs is enabled'
291+
{
292+
required: form.getFieldValue('apns_enabled'),
293+
message: 'Please enter APNs key ID when APNs is enabled'
271294
},
272295
{ len: 10, message: 'APNs Key ID must be exactly 10 characters' }
273296
]}
274297
>
275-
<Input
276-
placeholder="YOUR_KEY_ID"
298+
<Input
299+
placeholder="YOUR_KEY_ID"
277300
prefix={<KeyOutlined />}
278301
maxLength={10}
279302
/>
280303
</Form.Item>
281304

282305
<Form.Item
283-
name={['apns', 'team_id']}
306+
name="apns_team_id"
284307
label={
285308
<span>
286309
Team ID&nbsp;
@@ -290,22 +313,22 @@ const PushNotificationSettings: React.FC = () => {
290313
</span>
291314
}
292315
rules={[
293-
{
294-
required: form.getFieldValue(['apns', 'enabled']),
295-
message: 'Please enter Team ID when APNs is enabled'
316+
{
317+
required: form.getFieldValue('apns_enabled'),
318+
message: 'Please enter Team ID when APNs is enabled'
296319
},
297320
{ len: 10, message: 'Team ID must be exactly 10 characters' }
298321
]}
299322
>
300-
<Input
301-
placeholder="YOUR_TEAM_ID"
323+
<Input
324+
placeholder="YOUR_TEAM_ID"
302325
prefix={<KeyOutlined />}
303326
maxLength={10}
304327
/>
305328
</Form.Item>
306329

307330
<Form.Item
308-
name={['apns', 'topic']}
331+
name="apns_bundle_id"
309332
label={
310333
<span>
311334
App Bundle Identifier&nbsp;
@@ -315,20 +338,20 @@ const PushNotificationSettings: React.FC = () => {
315338
</span>
316339
}
317340
rules={[
318-
{
319-
required: form.getFieldValue(['apns', 'enabled']),
320-
message: 'Please enter app bundle identifier when APNs is enabled'
341+
{
342+
required: form.getFieldValue('apns_enabled'),
343+
message: 'Please enter app bundle identifier when APNs is enabled'
321344
}
322345
]}
323346
>
324-
<Input
325-
placeholder="com.your.app"
347+
<Input
348+
placeholder="com.your.app"
326349
prefix={<AppleOutlined />}
327350
/>
328351
</Form.Item>
329352

330353
<Form.Item
331-
name={['apns', 'production']}
354+
name="apns_production"
332355
label={
333356
<span>
334357
Production Mode&nbsp;
@@ -354,7 +377,7 @@ const PushNotificationSettings: React.FC = () => {
354377
style={{ marginBottom: 16 }}
355378
>
356379
<Form.Item
357-
name={['fcm', 'enabled']}
380+
name="fcm_enabled"
358381
label={
359382
<span>
360383
Enable FCM&nbsp;
@@ -369,7 +392,7 @@ const PushNotificationSettings: React.FC = () => {
369392
</Form.Item>
370393

371394
<Form.Item
372-
name={['fcm', 'credentials_file']}
395+
name="fcm_credentials_path"
373396
label={
374397
<span>
375398
FCM Credentials File Path&nbsp;
@@ -379,14 +402,14 @@ const PushNotificationSettings: React.FC = () => {
379402
</span>
380403
}
381404
rules={[
382-
{
383-
required: form.getFieldValue(['fcm', 'enabled']),
384-
message: 'Please enter FCM credentials file path when FCM is enabled'
405+
{
406+
required: form.getFieldValue('fcm_enabled'),
407+
message: 'Please enter FCM credentials file path when FCM is enabled'
385408
}
386409
]}
387410
>
388-
<Input
389-
placeholder="path/to/fcm-credentials.json"
411+
<Input
412+
placeholder="path/to/fcm-credentials.json"
390413
prefix={<FileTextOutlined />}
391414
/>
392415
</Form.Item>

src/components/settings/SettingsNavigation.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
InfoCircleOutlined,
1212
WalletOutlined,
1313
GlobalOutlined,
14+
BellOutlined,
1415
} from '@ant-design/icons';
1516

1617
const { Panel } = Collapse;
@@ -86,6 +87,12 @@ const settingsTabs: SettingsTab[] = [
8687
icon: <RobotOutlined className="item-icon" />,
8788
path: '/settings/ollama'
8889
},
90+
{
91+
key: 'push_notifications',
92+
label: 'Push Notifications',
93+
icon: <BellOutlined className="item-icon" />,
94+
path: '/settings/push-notifications'
95+
},
8996
{
9097
key: 'relay_info',
9198
label: 'Relay Info',

src/components/settings/SettingsPage.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
InfoCircleOutlined,
1010
WalletOutlined,
1111
GlobalOutlined,
12+
BellOutlined,
1213
DownOutlined,
1314
RightOutlined
1415
} from '@ant-design/icons';
@@ -18,6 +19,7 @@ import OllamaSettings from './OllamaSettings';
1819
import WalletSettings from './WalletSettings';
1920
import GeneralSettings from './GeneralSettings';
2021
import RelayInfoSettings from './RelayInfoSettings';
22+
import PushNotificationSettings from './PushNotificationSettings';
2123

2224
const SettingsContainer = styled.div`
2325
width: 100%;
@@ -160,6 +162,13 @@ const SettingsPage: React.FC = () => {
160162
icon: <RobotOutlined />,
161163
component: <OllamaSettings />
162164
},
165+
{
166+
key: 'push_notifications',
167+
path: '/settings/push-notifications',
168+
label: 'Push Notifications',
169+
icon: <BellOutlined />,
170+
component: <PushNotificationSettings />
171+
},
163172
{
164173
key: 'relay_info',
165174
path: '/settings/relay-info',

src/components/settings/layouts/AdvancedSettingsLayout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const AdvancedSettingsLayout: React.FC<AdvancedSettingsLayoutProps> = ({
3535
}) => {
3636
const [saveLoading, setSaveLoading] = useState(false);
3737
const [resetLoading, setResetLoading] = useState(false);
38-
const [activeKeys, setActiveKeys] = useState<string[]>(['general', 'image-moderation']);
38+
const [activeKeys, setActiveKeys] = useState<string[]>(['general', 'image-moderation', 'push-notifications']);
3939

4040
// Use the generic settings hook to handle saving all settings
4141
const {

0 commit comments

Comments
 (0)