Webhookの編集をモーダル化
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# CertRemind 開発進捗
|
||||
|
||||
最終更新: 2026-05-25
|
||||
最終更新: 2026-05-27
|
||||
|
||||
## 現在の実装状況
|
||||
|
||||
@@ -244,7 +244,7 @@ pnpm monitor:worker
|
||||
- 確認ダイアログ付き履歴削除
|
||||
- 通知方法管理画面
|
||||
- Webhook 登録
|
||||
- Webhook 編集
|
||||
- モーダルでの Webhook 編集
|
||||
- 確認ダイアログ付き Webhook 削除
|
||||
- ブラウザ Push 通知の許可状態表示
|
||||
- 現在のブラウザの Push 登録状態表示
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
import { ArrowLeft, BellOff, BellRing, Link, Pencil, Plus, Trash2 } from 'lucide-react';
|
||||
import { request } from '../api/client.js';
|
||||
import { ConfirmDialog } from '../components/ConfirmDialog.jsx';
|
||||
@@ -56,7 +57,9 @@ export function NotificationMethodsView({ onBack }) {
|
||||
const [vapidPublicKey, setVapidPublicKey] = useState('');
|
||||
const [currentPushStatus, setCurrentPushStatus] = useState('unchecked');
|
||||
const [form, setForm] = useState({ alias: '', url: '' });
|
||||
const [editingId, setEditingId] = useState('');
|
||||
const [editingWebhook, setEditingWebhook] = useState(null);
|
||||
const [editForm, setEditForm] = useState({ alias: '', url: '' });
|
||||
const [editDialogOpen, setEditDialogOpen] = useState(false);
|
||||
const [permission, setPermission] = useState(
|
||||
typeof Notification === 'undefined' ? 'unsupported' : Notification.permission,
|
||||
);
|
||||
@@ -121,19 +124,12 @@ export function NotificationMethodsView({ onBack }) {
|
||||
setBusy(true);
|
||||
try {
|
||||
validateWebhookForm(form);
|
||||
const endpoint = editingId
|
||||
? `/api/notification-methods/webhooks/${editingId}`
|
||||
: '/api/notification-methods/webhooks';
|
||||
await request(endpoint, {
|
||||
method: editingId ? 'PATCH' : 'POST',
|
||||
await request('/api/notification-methods/webhooks', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ alias: form.alias.trim(), url: form.url.trim() }),
|
||||
});
|
||||
setForm({ alias: '', url: '' });
|
||||
setEditingId('');
|
||||
showToast({
|
||||
type: 'success',
|
||||
message: editingId ? 'Webhookを更新しました' : 'Webhookを登録しました',
|
||||
});
|
||||
showToast({ type: 'success', message: 'Webhookを登録しました' });
|
||||
await loadMethods();
|
||||
} catch (err) {
|
||||
showToast({ type: 'error', message: err.message });
|
||||
@@ -143,8 +139,38 @@ export function NotificationMethodsView({ onBack }) {
|
||||
}
|
||||
|
||||
function startEdit(webhook) {
|
||||
setEditingId(webhook.notificationMethodId);
|
||||
setForm({ alias: webhook.alias, url: webhook.url });
|
||||
setEditingWebhook(webhook);
|
||||
setEditForm({ alias: webhook.alias, url: webhook.url });
|
||||
setEditDialogOpen(true);
|
||||
}
|
||||
|
||||
function handleEditDialogOpenChange(open) {
|
||||
setEditDialogOpen(open);
|
||||
if (!open) {
|
||||
setEditingWebhook(null);
|
||||
setEditForm({ alias: '', url: '' });
|
||||
}
|
||||
}
|
||||
|
||||
async function submitWebhookEdit(event) {
|
||||
event.preventDefault();
|
||||
if (!editingWebhook) return;
|
||||
|
||||
setBusy(true);
|
||||
try {
|
||||
validateWebhookForm(editForm);
|
||||
await request(`/api/notification-methods/webhooks/${editingWebhook.notificationMethodId}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify({ alias: editForm.alias.trim(), url: editForm.url.trim() }),
|
||||
});
|
||||
showToast({ type: 'success', message: 'Webhookを更新しました' });
|
||||
handleEditDialogOpenChange(false);
|
||||
await loadMethods();
|
||||
} catch (err) {
|
||||
showToast({ type: 'error', message: err.message });
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteWebhook(methodId) {
|
||||
@@ -273,11 +299,50 @@ export function NotificationMethodsView({ onBack }) {
|
||||
</Field>
|
||||
<button className="primary" disabled={busy}>
|
||||
<Plus aria-hidden="true" size={18} />
|
||||
{editingId ? '更新' : '登録'}
|
||||
登録
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<Dialog.Root open={editDialogOpen} onOpenChange={handleEditDialogOpenChange}>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay className="dialog-overlay" />
|
||||
<Dialog.Content className="dialog-content">
|
||||
<Dialog.Title className="dialog-title">Webhookを編集</Dialog.Title>
|
||||
<form className="dialog-form" onSubmit={submitWebhookEdit}>
|
||||
<Field label="エイリアス名">
|
||||
<input
|
||||
value={editForm.alias}
|
||||
onChange={(event) => setEditForm({ ...editForm, alias: event.target.value })}
|
||||
placeholder="Slack 通知"
|
||||
maxLength="120"
|
||||
required
|
||||
/>
|
||||
</Field>
|
||||
<Field label="URL">
|
||||
<input
|
||||
value={editForm.url}
|
||||
onChange={(event) => setEditForm({ ...editForm, url: event.target.value })}
|
||||
placeholder="https://hooks.slack.com/services/..."
|
||||
maxLength="2048"
|
||||
required
|
||||
/>
|
||||
</Field>
|
||||
<div className="dialog-actions">
|
||||
<Dialog.Close asChild>
|
||||
<button className="secondary" type="button">
|
||||
キャンセル
|
||||
</button>
|
||||
</Dialog.Close>
|
||||
<button className="primary" disabled={busy || !editingWebhook}>
|
||||
更新
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root>
|
||||
|
||||
<section className="panel">
|
||||
<h2>登録済みWebhook</h2>
|
||||
<div className="method-list">
|
||||
|
||||
Reference in New Issue
Block a user