795 lines
33 KiB
JavaScript
795 lines
33 KiB
JavaScript
const Editor = {
|
|
oninit(vnode) {
|
|
// Props
|
|
this.isEdit = vnode.attrs.isEdit || false;
|
|
this.isAdd = vnode.attrs.isAdd || false;
|
|
this.isPublic = vnode.attrs.isPublic || false;
|
|
this.logRequest = vnode.attrs.logRequest || false;
|
|
this.logResponse = vnode.attrs.logResponse || false;
|
|
this.runtime = vnode.attrs.runtime || "node"; // Add runtime
|
|
|
|
// Only controls whether the name/version is shown (left side of header),
|
|
// but we still always show the Execute button on the right side.
|
|
this.showHeader = vnode.attrs.showHeader !== false; // default true
|
|
|
|
// New props for showing/hiding individual settings
|
|
this.showPublicToggle = vnode.attrs.showPublicToggle !== false; // default true
|
|
this.showLogRequestToggle = vnode.attrs.showLogRequestToggle !== false; // default true
|
|
this.showLogResponseToggle = vnode.attrs.showLogResponseToggle !== false; // default true
|
|
this.showSaveButton = vnode.attrs.showSaveButton !== false; // default true
|
|
|
|
// New prop to control entire settings panel visibility
|
|
this.showFunctionSettings = vnode.attrs.showFunctionSettings !== false; // default true
|
|
|
|
// Name + version
|
|
this.name = vnode.attrs.name || "foo";
|
|
this.versionNumber = vnode.attrs.versionNumber || "1";
|
|
this.nameEditing = false;
|
|
|
|
// Editor defaults
|
|
this.jsValue = vnode.attrs.jsValue || "";
|
|
this.jsonValue = vnode.attrs.jsonValue || "{}";
|
|
|
|
// Execute endpoint
|
|
this.executeUrl = vnode.attrs.executeUrl;
|
|
|
|
// State for environment toggle, fetch results, etc.
|
|
this.showEnvironment = false;
|
|
this.loading = false;
|
|
this.error = null;
|
|
this.response = null; // JSON from server
|
|
this.responseRaw = ""; // Raw text from server
|
|
this.responseTime = 0;
|
|
this.responseSize = 0;
|
|
|
|
// URL props
|
|
this.saveUrl = vnode.attrs.saveUrl;
|
|
|
|
// Separate loading states for each button
|
|
this.executeLoading = false;
|
|
this.saveLoading = false;
|
|
|
|
// New prop for showing/hiding delete button
|
|
this.showDeleteButton = vnode.attrs.showDeleteButton !== false; // default true
|
|
|
|
// Delete endpoint
|
|
this.deleteUrl = vnode.attrs.deleteUrl;
|
|
|
|
this.dashboardUrl = vnode.attrs.dashboardUrl;
|
|
|
|
// New timer-specific props
|
|
this.isTimer = vnode.attrs.isTimer || false;
|
|
this.triggerType = vnode.attrs.triggerType || "interval"; // 'interval' or 'date'
|
|
this.frequencyMinutes = vnode.attrs.frequencyMinutes || 60;
|
|
this.runDate = vnode.attrs.runDate || "";
|
|
|
|
// Show timer settings panel
|
|
this.showTimerSettings = vnode.attrs.showTimerSettings === true; // default false
|
|
|
|
this.cancelUrl = vnode.attrs.cancelUrl || "/dashboard/http_functions";
|
|
|
|
// Add enabled property for timer functions
|
|
this.isEnabled = vnode.attrs.isEnabled !== false; // default true
|
|
|
|
// New state for AI generation
|
|
this.naturalLanguageQuery = "";
|
|
this.generateLoading = false;
|
|
this.showNaturalLanguageQuery = false;
|
|
this.generateUrl = vnode.attrs.generateUrl;
|
|
},
|
|
|
|
oncreate() {
|
|
// Initialize top JS editor
|
|
this.editorJS = ace.edit("js-editor");
|
|
this.editorJS.setOptions({ maxLines: 100 });
|
|
this.editorJS.setTheme("ace/theme/github_dark");
|
|
this.editorJS.session.setMode("ace/mode/javascript");
|
|
this.editorJS.setValue(this.jsValue, -1);
|
|
|
|
this.editorJS.session.on("change", () => {
|
|
this.jsValue = this.editorJS.getValue();
|
|
m.redraw();
|
|
});
|
|
|
|
// Initialize bottom JSON editor
|
|
this.editorJSON = ace.edit("json-editor");
|
|
this.editorJSON.setOptions({ maxLines: 100 });
|
|
this.editorJSON.setTheme("ace/theme/github_dark");
|
|
this.editorJSON.session.setMode("ace/mode/json");
|
|
this.editorJSON.setValue(this.jsonValue, -1);
|
|
|
|
this.editorJSON.session.on("change", () => {
|
|
this.jsonValue = this.editorJSON.getValue();
|
|
m.redraw();
|
|
});
|
|
},
|
|
|
|
async execute() {
|
|
this.executeLoading = true;
|
|
this.error = null;
|
|
this.response = null;
|
|
this.responseRaw = "";
|
|
this.responseSize = 0;
|
|
this.responseTime = 0;
|
|
|
|
const startTime = Date.now();
|
|
try {
|
|
const code = this.editorJS.getValue();
|
|
const environment_info = this.editorJSON.getValue();
|
|
|
|
const resp = await fetch(this.executeUrl, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
code,
|
|
environment_info,
|
|
runtime: this.runtime,
|
|
}),
|
|
});
|
|
if (!resp.ok) {
|
|
throw new Error(`HTTP error! status: ${resp.status}`);
|
|
}
|
|
|
|
this.responseRaw = await resp.text();
|
|
this.responseSize = new Blob([this.responseRaw]).size;
|
|
this.response = JSON.parse(this.responseRaw);
|
|
this.responseTime = Date.now() - startTime;
|
|
} catch (err) {
|
|
this.error = err;
|
|
} finally {
|
|
this.executeLoading = false;
|
|
m.redraw();
|
|
}
|
|
},
|
|
|
|
async save() {
|
|
this.saveLoading = true;
|
|
this.error = null;
|
|
|
|
try {
|
|
let payload = {
|
|
name: this.name,
|
|
script_content: this.jsValue,
|
|
environment_info: this.jsonValue,
|
|
is_public: this.isPublic,
|
|
log_request: this.logRequest,
|
|
log_response: this.logResponse,
|
|
runtime: this.runtime,
|
|
};
|
|
|
|
// Create payload based on whether this is a timer function
|
|
payload = this.isTimer
|
|
? {
|
|
name: this.name,
|
|
script_content: this.jsValue,
|
|
environment_info: this.jsonValue,
|
|
trigger_type: this.triggerType,
|
|
frequency_minutes:
|
|
this.triggerType === "interval"
|
|
? parseInt(this.frequencyMinutes)
|
|
: null,
|
|
run_date: this.triggerType === "date" ? this.runDate : null,
|
|
is_enabled: this.isEnabled, // Add enabled status to payload
|
|
}
|
|
: {
|
|
name: this.name,
|
|
script_content: this.jsValue,
|
|
environment_info: this.jsonValue,
|
|
is_public: this.isPublic,
|
|
log_request: this.logRequest,
|
|
log_response: this.logResponse,
|
|
runtime: this.runtime,
|
|
};
|
|
|
|
const response = await m.request({
|
|
method: "POST",
|
|
url: this.saveUrl,
|
|
body: payload,
|
|
});
|
|
|
|
if (response.status === "success") {
|
|
if (this.isAdd) {
|
|
window.location.href = this.dashboardUrl;
|
|
} else {
|
|
// Increment version number after successful save
|
|
this.versionNumber = (parseInt(this.versionNumber) + 1).toString();
|
|
}
|
|
Alert.show(
|
|
response.message || "Function saved successfully!",
|
|
"success"
|
|
);
|
|
} else {
|
|
Alert.show(response.message || "Error saving function", "error");
|
|
this.error = new Error(response.message);
|
|
}
|
|
} catch (err) {
|
|
Alert.show(err?.response.message || "Error saving function", "error");
|
|
this.error = err?.response;
|
|
} finally {
|
|
this.saveLoading = false;
|
|
m.redraw();
|
|
}
|
|
},
|
|
|
|
async delete() {
|
|
if (!confirm("Are you sure you want to delete this function?")) {
|
|
return;
|
|
}
|
|
|
|
this.deleteLoading = true;
|
|
this.error = null;
|
|
|
|
try {
|
|
const response = await m.request({
|
|
method: "DELETE",
|
|
url: this.deleteUrl,
|
|
});
|
|
|
|
if (response.status === "success") {
|
|
Alert.show(
|
|
response.message || "Function deleted successfully!",
|
|
"success"
|
|
);
|
|
// Optionally redirect to a different page after deletion
|
|
window.location.href = this.cancelUrl;
|
|
} else {
|
|
Alert.show(response.message || "Error deleting function", "error");
|
|
this.error = new Error(response.message);
|
|
}
|
|
} catch (err) {
|
|
Alert.show(err.message || "Error deleting function", "error");
|
|
this.error = err;
|
|
} finally {
|
|
this.deleteLoading = false;
|
|
m.redraw();
|
|
}
|
|
},
|
|
|
|
async generateWithAI() {
|
|
this.generateLoading = true;
|
|
this.error = null;
|
|
m.redraw();
|
|
|
|
try {
|
|
const resp = await m.request({
|
|
method: "POST",
|
|
url: this.generateUrl,
|
|
body: { natural_query: this.naturalLanguageQuery },
|
|
});
|
|
|
|
if (resp.script_content) {
|
|
this.editorJS.setValue(resp.script_content, -1);
|
|
} else if (resp.error) {
|
|
throw new Error(resp.error);
|
|
}
|
|
} catch (err) {
|
|
this.error = err;
|
|
} finally {
|
|
this.generateLoading = false;
|
|
m.redraw();
|
|
}
|
|
},
|
|
|
|
view() {
|
|
return m("div", { class: "" }, [
|
|
/* ─────────────────────────────────────────────────────────────────
|
|
HEADER BAR
|
|
─────────────────────────────────────────────────────────────────*/
|
|
m(
|
|
"div",
|
|
{
|
|
class:
|
|
"flex items-center justify-between p-2 border-b border-gray-200 dark:border-gray-800",
|
|
},
|
|
[
|
|
// Left side: name/version OR add input (shown only if showHeader==true)
|
|
this.showHeader
|
|
? m("div", { class: "flex space-x-2" }, [
|
|
// If editing existing function
|
|
this.isEdit
|
|
? m(
|
|
"div",
|
|
{
|
|
class:
|
|
"inline-flex items-center space-x-1 h-10 py-2 text-gray-600 dark:text-gray-400 text-md font-medium cursor-pointer",
|
|
},
|
|
[
|
|
m("span", { class: "inline-flex items-center" }, [
|
|
!this.nameEditing
|
|
? m(
|
|
"span",
|
|
{
|
|
class: "font-mono",
|
|
onclick: () => (this.nameEditing = true),
|
|
},
|
|
this.name
|
|
)
|
|
: m("input", {
|
|
class:
|
|
"bg-gray-50 border border-gray-300 text-sm rounded-lg p-1.5 dark:bg-gray-700 dark:border-gray-600",
|
|
value: this.name,
|
|
oninput: (e) => (this.name = e.target.value),
|
|
onblur: () => (this.nameEditing = false),
|
|
autofocus: true,
|
|
}),
|
|
|
|
// Pencil icon
|
|
m(
|
|
"svg",
|
|
{
|
|
xmlns: "http://www.w3.org/2000/svg",
|
|
fill: "none",
|
|
viewBox: "0 0 24 24",
|
|
"stroke-width": "1.5",
|
|
stroke: "currentColor",
|
|
class: "w-5 h-5",
|
|
onclick: () =>
|
|
(this.nameEditing = !this.nameEditing),
|
|
},
|
|
m("path", {
|
|
"stroke-linecap": "round",
|
|
"stroke-linejoin": "round",
|
|
d: "m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10",
|
|
})
|
|
),
|
|
]),
|
|
// Version
|
|
m(
|
|
"span",
|
|
{
|
|
class:
|
|
"bg-blue-500 text-white text-xs font-semibold px-2 py-1 rounded ml-2",
|
|
},
|
|
`v${this.versionNumber}`
|
|
),
|
|
]
|
|
)
|
|
: null,
|
|
|
|
// If adding a new function
|
|
this.isAdd
|
|
? m("div", { class: "w-full" }, [
|
|
m(
|
|
"label",
|
|
{ class: "block mb-2 text-sm font-medium" },
|
|
"Function name"
|
|
),
|
|
m("input", {
|
|
type: "text",
|
|
class: "bg-gray-50 border w-full p-2.5 rounded-lg",
|
|
placeholder: "foo",
|
|
required: true,
|
|
value: this.name,
|
|
oninput: (e) => (this.name = e.target.value),
|
|
}),
|
|
])
|
|
: null,
|
|
])
|
|
: m("div"), // If header is hidden, left side is empty
|
|
|
|
// Right side: always show spinner or execute button
|
|
m("div", { class: "flex items-center space-x-3" }, [
|
|
this.executeLoading
|
|
? m("div", {
|
|
class:
|
|
"animate-spin h-6 w-6 border-4 border-green-300 border-t-transparent rounded-full",
|
|
})
|
|
: m(
|
|
"button",
|
|
{
|
|
class: "p-2 rounded-full hover:bg-gray-200 text-green-700",
|
|
onclick: () => this.execute(),
|
|
title: "Execute",
|
|
},
|
|
m(
|
|
"svg",
|
|
{
|
|
xmlns: "http://www.w3.org/2000/svg",
|
|
fill: "none",
|
|
viewBox: "0 0 24 24",
|
|
"stroke-width": "1.5",
|
|
stroke: "currentColor",
|
|
class: "w-6 h-6",
|
|
},
|
|
m("path", {
|
|
"stroke-linecap": "round",
|
|
"stroke-linejoin": "round",
|
|
d: "M5.25 5.25 19.5 12 5.25 18.75 5.25 5.25z",
|
|
})
|
|
)
|
|
),
|
|
]),
|
|
]
|
|
),
|
|
|
|
/* ─────────────────────────────────────────────────────────────────
|
|
AI Generation
|
|
─────────────────────────────────────────────────────────────────*/
|
|
m("div", { class: "p-2 border-b border-gray-200 dark:border-gray-800" }, [
|
|
m(
|
|
"button",
|
|
{
|
|
class: "text-sm text-blue-500 hover:underline",
|
|
onclick: () =>
|
|
(this.showNaturalLanguageQuery = !this.showNaturalLanguageQuery),
|
|
},
|
|
"Generate with AI"
|
|
),
|
|
|
|
this.showNaturalLanguageQuery &&
|
|
m("div", { class: "mt-2" }, [
|
|
m("textarea", {
|
|
class:
|
|
"w-full p-2 border rounded bg-gray-50 dark:bg-gray-700 dark:border-gray-600",
|
|
rows: 3,
|
|
placeholder:
|
|
"Enter a description of what you want this function to do...",
|
|
oninput: (e) => (this.naturalLanguageQuery = e.target.value),
|
|
value: this.naturalLanguageQuery,
|
|
}),
|
|
m(
|
|
"button",
|
|
{
|
|
class:
|
|
"mt-2 px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 disabled:opacity-50",
|
|
onclick: () => this.generateWithAI(),
|
|
disabled: this.generateLoading,
|
|
},
|
|
this.generateLoading
|
|
? m("div", {
|
|
class:
|
|
"animate-spin h-4 w-4 border-2 border-white border-t-transparent rounded-full",
|
|
})
|
|
: "Generate"
|
|
),
|
|
]),
|
|
]),
|
|
|
|
/* ─────────────────────────────────────────────────────────────────
|
|
JS Editor
|
|
─────────────────────────────────────────────────────────────────*/
|
|
m("div", { id: "js-editor", class: "rounded shadow h-64" }),
|
|
|
|
/* ─────────────────────────────────────────────────────────────────
|
|
Environment Toggle
|
|
─────────────────────────────────────────────────────────────────*/
|
|
m(
|
|
"div",
|
|
{ class: "flex space-x-2 border-b border-gray-200 justify-between" },
|
|
[
|
|
m(
|
|
"button",
|
|
{
|
|
class:
|
|
"inline-flex items-center px-4 py-2 h-10 text-gray-600 hover:bg-accent hover:text-accent-foreground",
|
|
onclick: () => (this.showEnvironment = !this.showEnvironment),
|
|
},
|
|
[
|
|
m(
|
|
"svg",
|
|
{
|
|
xmlns: "http://www.w3.org/2000/svg",
|
|
fill: "none",
|
|
viewBox: "0 0 24 24",
|
|
"stroke-width": "1.5",
|
|
stroke: "currentColor",
|
|
class: "w-4 h-4",
|
|
},
|
|
m("path", {
|
|
"stroke-linecap": "round",
|
|
"stroke-linejoin": "round",
|
|
d: "M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125",
|
|
})
|
|
),
|
|
m("span", { class: "ml-1" }, "Environment"),
|
|
]
|
|
),
|
|
m("div", { class: "flex-auto" }),
|
|
]
|
|
),
|
|
|
|
/* ─────────────────────────────────────────────────────────────────
|
|
JSON Editor
|
|
─────────────────────────────────────────────────────────────────*/
|
|
m("div", { id: "json-editor", class: "rounded shadow h-64" }),
|
|
|
|
/* ─────────────────────────────────────────────────────────────────
|
|
Hidden fields (if needed for forms)
|
|
─────────────────────────────────────────────────────────────────*/
|
|
m("input", { type: "hidden", name: "script", value: this.jsValue }),
|
|
m("input", {
|
|
type: "hidden",
|
|
name: "environment",
|
|
value: this.jsonValue,
|
|
}),
|
|
|
|
/* ─────────────────────────────────────────────────────────────────
|
|
Loading & Error
|
|
─────────────────────────────────────────────────────────────────*/
|
|
this.error &&
|
|
m(
|
|
"div",
|
|
{ class: "mt-2 p-2 text-red-600 font-semibold" },
|
|
`Error: ${this.error.message}`
|
|
),
|
|
|
|
// Function settings panel
|
|
this.showFunctionSettings &&
|
|
m("div", { class: "bg-gray-100 dark:bg-gray-800 p-4 border-b" }, [
|
|
// Settings group
|
|
m("div", { class: "flex flex-col space-y-4" }, [
|
|
// Toggles group
|
|
m("div", { class: "flex flex-wrap gap-6" }, [
|
|
// Runtime dropdown
|
|
m("div", { class: "flex flex-col" }, [
|
|
m(
|
|
"label",
|
|
{
|
|
for: "runtime-select",
|
|
class: "mb-2 text-sm font-medium",
|
|
},
|
|
"Runtime"
|
|
),
|
|
m(
|
|
"select",
|
|
{
|
|
id: "runtime-select",
|
|
class:
|
|
"bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500",
|
|
onchange: (e) => (this.runtime = e.target.value),
|
|
},
|
|
[
|
|
m(
|
|
"option",
|
|
{ value: "node", selected: this.runtime === "node" },
|
|
"Node.js"
|
|
),
|
|
m(
|
|
"option",
|
|
{ value: "deno", selected: this.runtime === "deno" },
|
|
"Deno"
|
|
),
|
|
]
|
|
),
|
|
]),
|
|
|
|
// Public/Private toggle
|
|
this.showPublicToggle &&
|
|
m(
|
|
"label",
|
|
{
|
|
class:
|
|
"flex items-center space-x-3 text-sm text-gray-600 dark:text-gray-300 cursor-pointer",
|
|
},
|
|
[
|
|
m("div", { class: "relative" }, [
|
|
m("input[type=checkbox]", {
|
|
class: "sr-only peer",
|
|
checked: this.isPublic,
|
|
onchange: (e) => (this.isPublic = e.target.checked),
|
|
}),
|
|
m("div", {
|
|
class:
|
|
"w-11 h-6 bg-gray-200 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600",
|
|
}),
|
|
]),
|
|
m("span", "Public Function"),
|
|
]
|
|
),
|
|
|
|
// Log Request toggle
|
|
this.showLogRequestToggle &&
|
|
m(
|
|
"label",
|
|
{
|
|
class:
|
|
"flex items-center space-x-3 text-sm text-gray-600 dark:text-gray-300 cursor-pointer",
|
|
},
|
|
[
|
|
m("div", { class: "relative" }, [
|
|
m("input[type=checkbox]", {
|
|
class: "sr-only peer",
|
|
checked: this.logRequest,
|
|
onchange: (e) => (this.logRequest = e.target.checked),
|
|
}),
|
|
m("div", {
|
|
class:
|
|
"w-11 h-6 bg-gray-200 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600",
|
|
}),
|
|
]),
|
|
m("span", "Log Requests"),
|
|
]
|
|
),
|
|
|
|
// Log Response toggle
|
|
this.showLogResponseToggle &&
|
|
m(
|
|
"label",
|
|
{
|
|
class:
|
|
"flex items-center space-x-3 text-sm text-gray-600 dark:text-gray-300 cursor-pointer",
|
|
},
|
|
[
|
|
m("div", { class: "relative" }, [
|
|
m("input[type=checkbox]", {
|
|
class: "sr-only peer",
|
|
checked: this.logResponse,
|
|
onchange: (e) => (this.logResponse = e.target.checked),
|
|
}),
|
|
m("div", {
|
|
class:
|
|
"w-11 h-6 bg-gray-200 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600",
|
|
}),
|
|
]),
|
|
m("span", "Log Responses"),
|
|
]
|
|
),
|
|
]),
|
|
|
|
// Timer settings (shown only if isTimer is true)
|
|
this.isTimer &&
|
|
this.showTimerSettings && [
|
|
// Enabled toggle
|
|
m(
|
|
"label",
|
|
{
|
|
class:
|
|
"flex items-center space-x-3 text-sm text-gray-600 dark:text-gray-300 cursor-pointer mt-4",
|
|
},
|
|
[
|
|
m("div", { class: "relative" }, [
|
|
m("input[type=checkbox]", {
|
|
class: "sr-only peer",
|
|
checked: this.isEnabled,
|
|
onchange: (e) => (this.isEnabled = e.target.checked),
|
|
}),
|
|
m("div", {
|
|
class:
|
|
"w-11 h-6 bg-gray-200 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600",
|
|
}),
|
|
]),
|
|
m("span", "Enabled"),
|
|
]
|
|
),
|
|
|
|
// Timer settings group
|
|
m("div", { class: "grid grid-cols-2 gap-4 mt-4" }, [
|
|
// Trigger Type Selection
|
|
m("div", { class: "flex flex-col space-y-2" }, [
|
|
m(
|
|
"label",
|
|
{
|
|
class:
|
|
"text-sm font-medium text-gray-700 dark:text-gray-300",
|
|
},
|
|
"Trigger Type"
|
|
),
|
|
m(
|
|
"select",
|
|
{
|
|
class:
|
|
"bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg px-3 py-2",
|
|
value: this.triggerType,
|
|
onchange: (e) => (this.triggerType = e.target.value),
|
|
},
|
|
[
|
|
m("option", { value: "interval" }, "Interval"),
|
|
m("option", { value: "date" }, "Specific Date"),
|
|
]
|
|
),
|
|
]),
|
|
|
|
// Interval Settings or Date Settings based on triggerType
|
|
this.triggerType === "interval"
|
|
? m("div", { class: "flex flex-col space-y-2" }, [
|
|
m(
|
|
"label",
|
|
{
|
|
class:
|
|
"text-sm font-medium text-gray-700 dark:text-gray-300",
|
|
},
|
|
"Frequency (minutes)"
|
|
),
|
|
m("input[type=number]", {
|
|
class:
|
|
"bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg px-3 py-2",
|
|
value: this.frequencyMinutes,
|
|
min: 1,
|
|
onchange: (e) =>
|
|
(this.frequencyMinutes = e.target.value),
|
|
}),
|
|
])
|
|
: m("div", { class: "flex flex-col space-y-2" }, [
|
|
m(
|
|
"label",
|
|
{
|
|
class:
|
|
"text-sm font-medium text-gray-700 dark:text-gray-300",
|
|
},
|
|
"Run Date"
|
|
),
|
|
m("input[type=datetime-local]", {
|
|
class:
|
|
"bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg px-3 py-2",
|
|
value: this.runDate,
|
|
onchange: (e) => (this.runDate = e.target.value),
|
|
}),
|
|
]),
|
|
]),
|
|
],
|
|
|
|
// Actions group
|
|
m(
|
|
"div",
|
|
{ class: "flex items-center justify-end space-x-3 pt-2" },
|
|
[
|
|
// Save button
|
|
this.showSaveButton &&
|
|
m(
|
|
"button",
|
|
{
|
|
class:
|
|
"px-4 py-2 bg-blue-500 text-white text-sm font-medium rounded-lg hover:bg-blue-600 transition-colors flex items-center space-x-2 disabled:opacity-50",
|
|
onclick: () => this.save(),
|
|
disabled: this.saveLoading,
|
|
},
|
|
[
|
|
this.saveLoading &&
|
|
m("div", {
|
|
class:
|
|
"animate-spin h-4 w-4 border-2 border-white border-t-transparent rounded-full",
|
|
}),
|
|
m(
|
|
"span",
|
|
this.saveLoading ? "Saving..." : "Save Function"
|
|
),
|
|
]
|
|
),
|
|
|
|
// Delete button
|
|
this.showDeleteButton &&
|
|
m(
|
|
"button",
|
|
{
|
|
class:
|
|
"px-4 py-2 bg-white text-red-600 text-sm font-medium border border-red-200 rounded-lg hover:bg-red-50 transition-colors flex items-center space-x-2 disabled:opacity-50",
|
|
onclick: () => this.delete(),
|
|
disabled: this.deleteLoading,
|
|
},
|
|
[
|
|
this.deleteLoading &&
|
|
m("div", {
|
|
class:
|
|
"animate-spin h-4 w-4 border-2 border-red-600 border-t-transparent rounded-full",
|
|
}),
|
|
m(
|
|
"span",
|
|
this.deleteLoading ? "Deleting..." : "Delete Function"
|
|
),
|
|
]
|
|
),
|
|
]
|
|
),
|
|
]),
|
|
]),
|
|
|
|
/* ─────────────────────────────────────────────────────────────────
|
|
ResponseView (child) if needed
|
|
─────────────────────────────────────────────────────────────────*/
|
|
!this.executeLoading &&
|
|
!this.error &&
|
|
this.response &&
|
|
m(ResponseView, {
|
|
response: this.response,
|
|
responseTime: this.responseTime,
|
|
responseSize: this.responseSize,
|
|
envEditorValue: this.jsonValue,
|
|
isTimer: this.isTimer,
|
|
onClose: () => {
|
|
this.response = null;
|
|
},
|
|
}),
|
|
]);
|
|
},
|
|
};
|