improve: change db schema for settings

This commit is contained in:
h z
2025-03-20 13:58:24 +00:00
parent 2c330904e4
commit dc0ff3b406
7 changed files with 658 additions and 389 deletions

View File

@@ -1,363 +1,71 @@
import React, { useState, useEffect } from "react";
import {
useCreateWebhookSetting,
useUpdateWebhookSetting,
useWebhookSettingByPathId,
useWebhooks,
useCreateWebhook,
useUpdateWebhook,
useDeleteWebhook
} from "../../utils/webhook-queries";
import {useUpdatePath} from "../../utils/path-queries";
import {useCreatePathSetting, usePathSetting} from "../../utils/setting-queries";
import WebhookSettingPanel from "../Settings/PathSettings/WebhookSettingPanel";
import React, {useState} from "react";
const PathSettingModal = ({ isOpen, path, onClose }) => {
const {data: pathSetting, isLoading: isPathSettingLoading} = usePathSetting(path?.setting_id || 0);
const createPathSetting = useCreatePathSetting();
const updatePath = useUpdatePath();
const PathSettingModal = ({ pathId, isOpen, onClose }) => {
const { data: setting } = useWebhookSettingByPathId(pathId);
const { data: webhooks } = useWebhooks();
const createWebhookSetting = useCreateWebhookSetting();
const updateWebhookSetting = useUpdateWebhookSetting();
const createWebhook = useCreateWebhook();
const updateWebhook = useUpdateWebhook();
const deleteWebhook = useDeleteWebhook();
const [url, setUrl] = useState("");
const [enabled, setEnabled] = useState(false);
const [webhookId, setWebhookId] = useState(-1);
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 [triggerEvents, setTriggerEvents] = useState(0);
const [isRecursive, setIsRecursive] = useState(false);
const [additionalHeaders, setAdditionalHeaders] = useState({});
const [headerList, setHeaderList] = useState([]);
const handleTriggerEventsUpdate = (eventType, isChecked) => {
setTriggerEvents((prevEvents) => {
let newEvents = prevEvents;
switch (eventType) {
case "isOnMarkdownCreated":
newEvents = isChecked ? (newEvents | 1) : (newEvents & ~1);
break;
case "isOnMarkdownUpdated":
newEvents = isChecked ? (newEvents | 2) : (newEvents & ~2);
break;
case "isOnMarkdownDeleted":
newEvents = isChecked ? (newEvents | 4) : (newEvents & ~4);
break;
case "isOnPathCreated":
newEvents = isChecked ? (newEvents | 8) : (newEvents & ~8);
break;
case "isOnPathUpdated":
newEvents = isChecked ? (newEvents | 16) : (newEvents & ~16);
break;
case "isOnPathDeleted":
newEvents = isChecked ? (newEvents | 32) : (newEvents & ~32);
break;
default:
break;
const [activeTab, setActiveTab] = useState("webhook");
const handleCreatePathSetting = () => {
createPathSetting.mutate({}, {
onSuccess: (res) => {
updatePath.mutate({id: path.id, data: {setting_id: res.id}});
}
return newEvents;
});
};
const assignFromTriggerEvents = (events) => {
setIsOnMarkdownCreated((events & 1) > 0);
setIsOnMarkdownUpdated((events & 2) > 0);
setIsOnMarkdownDeleted((events & 4) > 0);
setIsOnPathCreated((events & 8) > 0);
setIsOnPathUpdated((events & 16) > 0);
setIsOnPathDeleted((events & 32) > 0);
};
useEffect(() => {
if (setting && webhooks) {
setEnabled(setting.enabled);
setWebhookId(setting.webhook_id || -1);
const selectedWebhook = webhooks?.find(hook => hook.id === setting.webhook_id);
if (selectedWebhook) {
setUrl(selectedWebhook.hook_url);
}
setTriggerEvents(setting.on_events);
assignFromTriggerEvents(setting.on_events);
setIsRecursive(setting.recursive);
try{
const headers = setting.additional_header ?
JSON.parse(setting.additional_header) : {};
setAdditionalHeaders(headers);
setHeaderList(Object.entries(headers).map(([key, value]) => ({key, value })));
} catch(err) {
setAdditionalHeaders({});
setHeaderList([]);
}
} else {
setUrl("");
setEnabled(false);
setWebhookId(-1);
setTriggerEvents(0);
assignFromTriggerEvents(0);
setIsRecursive(false);
setAdditionalHeaders({});
setHeaderList([]);
}
}, [setting, webhooks]);
const handleSave = () => {
const payload = {
path_id: pathId,
webhook_id: webhookId,
enabled,
on_events: triggerEvents,
recursive: isRecursive,
additional_header: JSON.stringify(additionalHeaders),
};
console.log(payload);
if (!setting) {
createWebhookSetting.mutate(payload, {
onSuccess: () => alert("Webhook setting created successfully"),
onError: () => alert("Webhook setting creation failed"),
});
} else {
updateWebhookSetting.mutate({ id: setting.id, data: payload }, {
onSuccess: () => alert("Webhook setting updated successfully"),
onError: () => alert("Webhook setting update failed"),
});
}
onClose();
};
const handleCreateWebhook = () => {
const newUrl = prompt("Enter new webhook URL");
if (newUrl) {
createWebhook.mutate(newUrl, {
onSuccess: () => alert("Webhook created successfully"),
onError: () => alert("Webhook creation failed"),
});
}
};
const handleUpdateWebhook = () => {
const newUrl = prompt("Enter new webhook URL", url);
if (newUrl && webhookId !== -1) {
updateWebhook.mutate({ id: webhookId, data: { hook_url: newUrl } }, {
onSuccess: () => alert("Webhook updated successfully"),
onError: () => alert("Webhook update failed"),
});
}
};
const handleDeleteWebhook = () => {
if (webhookId !== -1 && window.confirm("Are you sure you want to delete this webhook?")) {
deleteWebhook.mutate(webhookId, {
onSuccess: () => alert("Webhook deleted successfully"),
onError: () => alert("Webhook deletion failed"),
});
}
};
const handleApplyHeaders = () => {
const newHeaders = {};
headerList.forEach(({ key, value }) => {
if (key.trim()) newHeaders[key] = value;
});
setAdditionalHeaders(newHeaders);
};
const handleHeaderChange = (index, field, value) => {
const updatedHeaders = [...headerList];
updatedHeaders[index][field] = value;
setHeaderList(updatedHeaders);
};
const handleAddHeader = () => {
setHeaderList([...headerList, { key: "", value: "" }])
};
if(isPathSettingLoading)
return <p>Loading...</p>
return (
<div className={`modal ${isOpen ? "is-active" : ""}`}>
<div className="modal-background"></div>
<div className="modal-card">
<div className="modal-background" onClick={onClose}></div>
<div className="modal-card" style={{width: "60vw"}}>
<header className="modal-card-head">
<p className="modal-card-title">Webhook Settings</p>
<button className="delete" aria-label="close" onClick={onClose}></button>
<p className="modal-card-title">Path Settings</p>
<button type="button" className="delete" aria-label="close" onClick={onClose} />
</header>
<section className="modal-card-body">
<form>
<div className="field">
<label className="label">Webhook URL</label>
<div className="field has-addons">
<div className="control is-expanded">
<div className="select is-fullwidth">
<select
value={url}
onChange={(e) => {
setUrl(e.target.value);
const selectedWebhook = webhooks?.find(h => h.hook_url === e.target.value);
setWebhookId(selectedWebhook?.id || -1);
}}
>
<option value="">Select a webhook</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>
{webhookId !== -1 && (
<div className="buttons">
<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 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) => {
setIsOnMarkdownCreated(e.target.checked);
handleTriggerEventsUpdate("isOnMarkdownCreated", e.target.checked);
}}
/>
Markdown Created
</label>
<br />
<label className="checkbox">
<input
type="checkbox"
checked={isOnMarkdownUpdated}
onChange={(e) => {
setIsOnMarkdownUpdated(e.target.checked);
handleTriggerEventsUpdate("isOnMarkdownUpdated", e.target.checked);
}}
/>
Markdown Updated
</label>
<br />
<label className="checkbox">
<input
type="checkbox"
checked={isOnMarkdownDeleted}
onChange={(e) => {
setIsOnMarkdownDeleted(e.target.checked);
handleTriggerEventsUpdate("isOnMarkdownDeleted", e.target.checked);
}}
/>
Markdown Deleted
</label>
</div>
<div className="column">
<label className="checkbox">
<input
type="checkbox"
checked={isOnPathCreated}
onChange={(e) => {
setIsOnPathCreated(e.target.checked);
handleTriggerEventsUpdate("isOnPathCreated", e.target.checked);
}}
/>
Path Created
</label>
<br />
<label className="checkbox">
<input
type="checkbox"
checked={isOnPathUpdated}
onChange={(e) => {
setIsOnPathUpdated(e.target.checked);
handleTriggerEventsUpdate("isOnPathUpdated", e.target.checked);
}}
/>
Path Updated
</label>
<br />
<label className="checkbox">
<input
type="checkbox"
checked={isOnPathDeleted}
onChange={(e) => {
setIsOnPathDeleted(e.target.checked);
handleTriggerEventsUpdate("isOnPathDeleted", 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="checkbox">Additional Headers</label>
<div className="box">
{headerList.map((header, index) => (
<div className="columns" key={index}>
<div className="column">
<input
type="text"
className="input"
placeholder="key"
value={header.key}
onChange={(e) => {handleHeaderChange(index, "key", e.target.value)}}
/>
</div>
<div className="column">
<input
type="text"
className="input"
placeholder="value"
value={header.value}
onChange={(e) => handleHeaderChange(index, "value", e.target.value)}
/>
</div>
</div>
))}
<button type="button" className="button is-small is-info" onClick={handleAddHeader}>Add Header</button>
<button type="button" className="button is-small is-success" onClick={handleApplyHeaders}>Apply</button>
</div>
</div>
{!pathSetting && !isPathSettingLoading ? (
<section className="modal-card-body">
<button
type="button"
className="button is-primary"
onClick={handleCreatePathSetting}
>
Create Path Setting
</button>
</section>
) : (
<section className="modal-card-body">
<div className="tabs">
<ul>
<li className={activeTab === "webhook" ? "is-active" : ""}>
<a onClick={() => setActiveTab("webhook")}>Webhook</a>
</li>
<li className={activeTab === "template" ? "is-active" : ""}>
<a onClick={() => setActiveTab("template")}>Template</a>
</li>
</ul>
</div>
</form>
</section>
<footer className="modal-card-foot">
<button className="button is-success" type="button" onClick={handleSave}>Save</button>
<button className="button" onClick={onClose}>Cancel</button>
</footer>
{activeTab === "webhook" && (
<WebhookSettingPanel
pathSetting={pathSetting}
onClose={onClose}
/>
)}
{activeTab === "template" && (
<div></div>
)}
</section>
)}
</div>
</div>
);
};
export default PathSettingModal;