improve: change db schema for settings
This commit is contained in:
433
src/components/Settings/PathSettings/WebhookSettingPanel.js
Normal file
433
src/components/Settings/PathSettings/WebhookSettingPanel.js
Normal file
@@ -0,0 +1,433 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
useWebhookSetting,
|
||||
useCreateWebhookSetting,
|
||||
useUpdateWebhookSetting,
|
||||
useWebhooks,
|
||||
} from "../../../utils/webhook-queries";
|
||||
|
||||
import {
|
||||
useCreateWebhook,
|
||||
useUpdateWebhook,
|
||||
useDeleteWebhook,
|
||||
} from "../../../utils/webhook-queries";
|
||||
import {useUpdatePathSetting} from "../../../utils/setting-queries";
|
||||
|
||||
const WebhookSettingPanel = ({pathSetting, onClose}) => {
|
||||
|
||||
const {data: setting} = useWebhookSetting(pathSetting?.webhook_setting_id || 0);
|
||||
const {data: webhooks, isLoading: isWebhooksLoading} = useWebhooks();
|
||||
|
||||
const createWebhookSetting = useCreateWebhookSetting();
|
||||
const updateWebhookSetting = useUpdateWebhookSetting();
|
||||
|
||||
const createWebhook = useCreateWebhook();
|
||||
const updateWebhook = useUpdateWebhook();
|
||||
const deleteWebhook = useDeleteWebhook();
|
||||
|
||||
const updatePathSetting = useUpdatePathSetting();
|
||||
|
||||
|
||||
const [enabled, setEnabled] = useState(false);
|
||||
const [isRecursive, setIsRecursive] = useState(false);
|
||||
const [onEvents, setOnEvents] = useState(0);
|
||||
const [selectedUrl, setSelectedUrl] = useState("");
|
||||
const [headerList, setHeaderList] = useState([]);
|
||||
const [additionalHeaders, setAdditionalHeaders] = useState({});
|
||||
|
||||
const [isOnMarkdownCreated, setIsOnMarkdownCreated] = useState(false);
|
||||
const [isOnMarkdownUpdated, setIsOnMarkdownUpdated] = useState(false);
|
||||
const [isOnMarkdownDeleted, setIsOnMarkdownDeleted] = useState(false);
|
||||
const [isOnPathCreated, setIsOnPathCreated] = useState(false);
|
||||
const [isOnPathUpdated, setIsOnPathUpdated] = useState(false);
|
||||
const [isOnPathDeleted, setIsOnPathDeleted] = useState(false);
|
||||
|
||||
const assignFromOnEvents = (bits) => {
|
||||
setIsOnMarkdownCreated(!!(bits & 1));
|
||||
setIsOnMarkdownUpdated(!!(bits & 2));
|
||||
setIsOnMarkdownDeleted(!!(bits & 4));
|
||||
setIsOnPathCreated(!!(bits & 8));
|
||||
setIsOnPathUpdated(!!(bits & 16));
|
||||
setIsOnPathDeleted(!!(bits & 32));
|
||||
};
|
||||
|
||||
const handleTriggerEventsUpdate = (eventType, isChecked) => {
|
||||
setOnEvents((prev) => {
|
||||
let nextVal = prev;
|
||||
switch (eventType) {
|
||||
case "MARKDOWN_CREATED":
|
||||
nextVal = isChecked ? nextVal | 1 : nextVal & ~1;
|
||||
setIsOnMarkdownCreated(isChecked);
|
||||
break;
|
||||
case "MARKDOWN_UPDATED":
|
||||
nextVal = isChecked ? nextVal | 2 : nextVal & ~2;
|
||||
setIsOnMarkdownUpdated(isChecked);
|
||||
break;
|
||||
case "MARKDOWN_DELETED":
|
||||
nextVal = isChecked ? nextVal | 4 : nextVal & ~4;
|
||||
setIsOnMarkdownDeleted(isChecked);
|
||||
break;
|
||||
case "PATH_CREATED":
|
||||
nextVal = isChecked ? nextVal | 8 : nextVal & ~8;
|
||||
setIsOnPathCreated(isChecked);
|
||||
break;
|
||||
case "PATH_UPDATED":
|
||||
nextVal = isChecked ? nextVal | 16 : nextVal & ~16;
|
||||
setIsOnPathUpdated(isChecked);
|
||||
break;
|
||||
case "PATH_DELETED":
|
||||
nextVal = isChecked ? nextVal | 32 : nextVal & ~32;
|
||||
setIsOnPathUpdated(isChecked);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nextVal;
|
||||
});
|
||||
};
|
||||
|
||||
const handleCreateWebhookSetting = () => {
|
||||
createWebhookSetting.mutate({}, {
|
||||
onSuccess: (data) => {
|
||||
updatePathSetting.mutate({id: pathSetting.id, data: {webhook_setting_id: data.id}});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (setting && webhooks) {
|
||||
setEnabled(setting.enabled);
|
||||
setIsRecursive(setting.recursive);
|
||||
setOnEvents(setting.on_events);
|
||||
assignFromOnEvents(setting.on_events);
|
||||
|
||||
try {
|
||||
const headers = setting.additional_header
|
||||
? JSON.parse(setting.additional_header)
|
||||
: {};
|
||||
setAdditionalHeaders(headers);
|
||||
setHeaderList(
|
||||
Object.entries(headers).map(([k, v]) => ({ key: k, value: v }))
|
||||
);
|
||||
} catch (err) {
|
||||
setAdditionalHeaders({});
|
||||
setHeaderList([]);
|
||||
}
|
||||
|
||||
const found = webhooks.find((wh) => wh.id === setting.webhook_id);
|
||||
console.log("found", found);
|
||||
console.log("webhooks", webhooks);
|
||||
console.log("setting.webhook_id", setting.webhook_id);
|
||||
setSelectedUrl(found ? found.hook_url : "");
|
||||
} else {
|
||||
setEnabled(false);
|
||||
setIsRecursive(false);
|
||||
setOnEvents(0);
|
||||
assignFromOnEvents(0);
|
||||
setAdditionalHeaders({});
|
||||
setHeaderList([]);
|
||||
setSelectedUrl("");
|
||||
}
|
||||
}, [setting, webhooks]);
|
||||
|
||||
const handleAddHeader = () => {
|
||||
setHeaderList([...headerList, { key: "", value: "" }]);
|
||||
};
|
||||
const handleHeaderChange = (index, field, val) => {
|
||||
const updated = [...headerList];
|
||||
updated[index][field] = val;
|
||||
setHeaderList(updated);
|
||||
};
|
||||
const handleApplyHeaders = () => {
|
||||
const out = {};
|
||||
headerList.forEach(({ key, value }) => {
|
||||
if (key.trim()) out[key] = value;
|
||||
});
|
||||
setAdditionalHeaders(out);
|
||||
};
|
||||
|
||||
const handleCreateWebhook = () => {
|
||||
const newUrl = prompt("Enter the new webhook URL");
|
||||
if (!newUrl) return;
|
||||
createWebhook.mutate(newUrl, {
|
||||
onSuccess: () => alert("Created new Webhook successfully"),
|
||||
onError: () => alert("Failed to create new Webhook"),
|
||||
});
|
||||
};
|
||||
const handleUpdateWebhook = () => {
|
||||
if (!setting || !setting.webhook_id) {
|
||||
alert("No webhook selected. Must pick from dropdown first.");
|
||||
return;
|
||||
}
|
||||
const newUrl = prompt("Enter updated Webhook URL", selectedUrl);
|
||||
if (!newUrl) return;
|
||||
updateWebhook.mutate(
|
||||
{ id: setting.webhook_id, data: { hook_url: newUrl } },
|
||||
{
|
||||
onSuccess: () => alert("Updated Webhook successfully"),
|
||||
onError: () => alert("Failed to update Webhook"),
|
||||
}
|
||||
);
|
||||
};
|
||||
const handleDeleteWebhook = () => {
|
||||
if (!setting || !setting.webhook_id) {
|
||||
alert("No webhook selected to delete");
|
||||
return;
|
||||
}
|
||||
if (!window.confirm("Are you sure?")) return;
|
||||
deleteWebhook.mutate(setting.webhook_id, {
|
||||
onSuccess: () => alert("Deleted Webhook successfully"),
|
||||
onError: () => alert("Failed to delete Webhook"),
|
||||
});
|
||||
};
|
||||
|
||||
const handleSaveWebhookSetting = async () => {
|
||||
const hook = webhooks.find((wh) => wh.hook_url === selectedUrl);
|
||||
const payload = {
|
||||
webhook_id: hook? hook.id : null,
|
||||
recursive: isRecursive,
|
||||
additional_header: JSON.stringify(additionalHeaders),
|
||||
enabled,
|
||||
on_events: onEvents,
|
||||
|
||||
};
|
||||
console.log(webhooks);
|
||||
console.log(payload);
|
||||
if(!setting || !setting.id){
|
||||
createWebhookSetting.mutate(payload, {
|
||||
onSuccess: (res) => {
|
||||
updatePathSetting.mutate({id: pathSetting.id, data: {webhook_setting_id: res.id}},{
|
||||
onSuccess: () => alert("Webhook setting successfully created"),
|
||||
onError: () => alert("Failed to save Webhook"),
|
||||
})
|
||||
},
|
||||
onError: () => alert("Failed to save Webhook"),
|
||||
});
|
||||
} else {
|
||||
updateWebhookSetting.mutate({id: setting.id, data: payload}, {
|
||||
onSuccess: () => alert("Updated Webhook successfully"),
|
||||
onError: () => alert("Failed to update Webhook"),
|
||||
});
|
||||
}
|
||||
onClose();
|
||||
};
|
||||
|
||||
return setting ? (
|
||||
<div className="box" style={{ marginTop: "1rem" }}>
|
||||
<h4 className="title is-5">Webhook Setting</h4>
|
||||
<div className="field">
|
||||
<label className="label">Select or Create a Webhook</label>
|
||||
<div className="field has-addons">
|
||||
<div className="control is-expanded">
|
||||
{isWebhooksLoading ? (
|
||||
<p>Loading...</p>
|
||||
) : (
|
||||
<div className="select is-fullwidth">
|
||||
<select
|
||||
value={selectedUrl}
|
||||
onChange={(e) => setSelectedUrl(e.target.value)}
|
||||
>
|
||||
<option value="">(none)</option>
|
||||
{webhooks.map((hook) => (
|
||||
<option key={hook.id} value={hook.hook_url}>
|
||||
{hook.hook_url}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="control">
|
||||
<button
|
||||
type="button"
|
||||
className="button is-primary"
|
||||
onClick={handleCreateWebhook}
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{setting?.webhook_id && (
|
||||
<div className="buttons" style={{ marginTop: "0.5rem" }}>
|
||||
<button
|
||||
type="button"
|
||||
className="button is-info"
|
||||
onClick={handleUpdateWebhook}
|
||||
>
|
||||
Update Webhook URL
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="button is-danger"
|
||||
onClick={handleDeleteWebhook}
|
||||
>
|
||||
Delete Webhook
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<label className="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={enabled}
|
||||
onChange={(e) => setEnabled(e.target.checked)}
|
||||
/>
|
||||
Enabled
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<label className="label">On Events</label>
|
||||
<div className="box">
|
||||
<div className="columns">
|
||||
<div className="column">
|
||||
<label className="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isOnMarkdownCreated}
|
||||
onChange={(e) =>
|
||||
handleTriggerEventsUpdate("MARKDOWN_CREATED", e.target.checked)
|
||||
}
|
||||
/>
|
||||
Markdown Created
|
||||
</label>
|
||||
<br />
|
||||
<label className="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isOnMarkdownUpdated}
|
||||
onChange={(e) =>
|
||||
handleTriggerEventsUpdate("MARKDOWN_UPDATED", e.target.checked)
|
||||
}
|
||||
/>
|
||||
Markdown Updated
|
||||
</label>
|
||||
<br />
|
||||
<label className="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isOnMarkdownDeleted}
|
||||
onChange={(e) =>
|
||||
handleTriggerEventsUpdate("MARKDOWN_DELETED", e.target.checked)
|
||||
}
|
||||
/>
|
||||
Markdown Deleted
|
||||
</label>
|
||||
</div>
|
||||
<div className="column">
|
||||
<label className="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isOnPathCreated}
|
||||
onChange={(e) =>
|
||||
handleTriggerEventsUpdate("PATH_CREATED", e.target.checked)
|
||||
}
|
||||
/>
|
||||
Path Created
|
||||
</label>
|
||||
<br />
|
||||
<label className="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isOnPathUpdated}
|
||||
onChange={(e) =>
|
||||
handleTriggerEventsUpdate("PATH_UPDATED", e.target.checked)
|
||||
}
|
||||
/>
|
||||
Path Updated
|
||||
</label>
|
||||
<br />
|
||||
<label className="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isOnPathDeleted}
|
||||
onChange={(e) =>
|
||||
handleTriggerEventsUpdate("PATH_DELETED", e.target.checked)
|
||||
}
|
||||
/>
|
||||
Path Deleted
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<label className="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isRecursive}
|
||||
onChange={(e) => setIsRecursive(e.target.checked)}
|
||||
/>
|
||||
Recursive
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<label className="label">Additional Headers</label>
|
||||
<div className="box">
|
||||
{headerList.map((h, idx) => (
|
||||
<div className="columns" key={idx}>
|
||||
<div className="column">
|
||||
<input
|
||||
type="text"
|
||||
className="input"
|
||||
placeholder="key"
|
||||
value={h.key}
|
||||
onChange={(e) => handleHeaderChange(idx, "key", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="column">
|
||||
<input
|
||||
type="text"
|
||||
className="input"
|
||||
placeholder="value"
|
||||
value={h.value}
|
||||
onChange={(e) =>
|
||||
handleHeaderChange(idx, "value", e.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
className="button is-small is-info"
|
||||
onClick={handleAddHeader}
|
||||
>
|
||||
+ Header
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="button is-small is-success"
|
||||
onClick={handleApplyHeaders}
|
||||
style={{ marginLeft: "0.5rem" }}
|
||||
>
|
||||
Apply
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="button is-primary"
|
||||
onClick={handleSaveWebhookSetting}
|
||||
>
|
||||
Save Webhook Setting
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
className="button is-primary"
|
||||
type="button"
|
||||
onClick={handleCreateWebhookSetting}
|
||||
>
|
||||
Create Webhook Setting
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default WebhookSettingPanel
|
||||
Reference in New Issue
Block a user