@getcatalystiq/agent-plane-ui 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/code-editor-E7L6Y3LM.js +35 -0
- package/dist/code-editor-ZD5ZILTM.cjs +41 -0
- package/dist/index.cjs +489 -239
- package/dist/index.d.cts +1 -7
- package/dist/index.d.ts +1 -7
- package/dist/index.js +490 -240
- package/package.json +22 -2
package/dist/index.cjs
CHANGED
|
@@ -3099,129 +3099,389 @@ function AgentConnectorsManager({ agentId, toolkits: initialToolkits, composioAl
|
|
|
3099
3099
|
)
|
|
3100
3100
|
] });
|
|
3101
3101
|
}
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
const
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3102
|
+
var CodeEditor = React3.lazy(() => import('./code-editor-ZD5ZILTM.cjs'));
|
|
3103
|
+
function buildTree(files) {
|
|
3104
|
+
const rootFiles = [];
|
|
3105
|
+
const dirMap = /* @__PURE__ */ new Map();
|
|
3106
|
+
function ensureDir(dirPath) {
|
|
3107
|
+
const existing = dirMap.get(dirPath);
|
|
3108
|
+
if (existing) return existing;
|
|
3109
|
+
const parts = dirPath.split("/");
|
|
3110
|
+
const node = {
|
|
3111
|
+
name: parts[parts.length - 1],
|
|
3112
|
+
fullPath: dirPath,
|
|
3113
|
+
children: [],
|
|
3114
|
+
files: []
|
|
3115
|
+
};
|
|
3116
|
+
dirMap.set(dirPath, node);
|
|
3117
|
+
if (parts.length > 1) {
|
|
3118
|
+
const parentPath = parts.slice(0, -1).join("/");
|
|
3119
|
+
const parent = ensureDir(parentPath);
|
|
3120
|
+
if (!parent.children.some((c) => c.fullPath === dirPath)) {
|
|
3121
|
+
parent.children.push(node);
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
return node;
|
|
3125
|
+
}
|
|
3126
|
+
for (const file of files) {
|
|
3127
|
+
const slashIdx = file.path.lastIndexOf("/");
|
|
3128
|
+
if (slashIdx === -1) {
|
|
3129
|
+
rootFiles.push(file);
|
|
3130
|
+
} else {
|
|
3131
|
+
const dirPath = file.path.slice(0, slashIdx);
|
|
3132
|
+
const dir = ensureDir(dirPath);
|
|
3133
|
+
dir.files.push(file);
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
const topLevel = [];
|
|
3137
|
+
for (const node of dirMap.values()) {
|
|
3138
|
+
if (!node.fullPath.includes("/")) {
|
|
3139
|
+
topLevel.push(node);
|
|
3140
|
+
}
|
|
3141
|
+
}
|
|
3142
|
+
function sortNode(node) {
|
|
3143
|
+
node.children.sort((a, b) => a.name.localeCompare(b.name));
|
|
3144
|
+
node.files.sort((a, b) => a.path.localeCompare(b.path));
|
|
3145
|
+
node.children.forEach(sortNode);
|
|
3146
|
+
}
|
|
3147
|
+
topLevel.forEach(sortNode);
|
|
3148
|
+
topLevel.sort((a, b) => a.name.localeCompare(b.name));
|
|
3149
|
+
rootFiles.sort((a, b) => a.path.localeCompare(b.path));
|
|
3150
|
+
return { rootFiles, rootDirs: topLevel };
|
|
3151
|
+
}
|
|
3152
|
+
function collectAllDirPaths(nodes) {
|
|
3153
|
+
const paths = /* @__PURE__ */ new Set();
|
|
3154
|
+
function walk(node) {
|
|
3155
|
+
paths.add(node.fullPath);
|
|
3156
|
+
node.children.forEach(walk);
|
|
3157
|
+
}
|
|
3158
|
+
nodes.forEach(walk);
|
|
3159
|
+
return paths;
|
|
3160
|
+
}
|
|
3161
|
+
function FileTreeEditor({
|
|
3162
|
+
initialFiles,
|
|
3163
|
+
onSave,
|
|
3164
|
+
onChange,
|
|
3165
|
+
readOnly = false,
|
|
3166
|
+
hideSave = false,
|
|
3167
|
+
title = "Files",
|
|
3168
|
+
saveLabel = "Save",
|
|
3169
|
+
addFolderLabel = "Folder",
|
|
3170
|
+
newFileTemplate = { filename: "SKILL.md", content: "---\nname: New Skill\ndescription: Describe when this skill should be triggered\n---\n\n# Instructions\n\nDescribe what this skill does...\n" },
|
|
3171
|
+
savedVersion
|
|
3172
|
+
}) {
|
|
3113
3173
|
const [files, setFiles] = React3.useState(initialFiles);
|
|
3114
|
-
const [selectedPath, setSelectedPath] = React3.useState(
|
|
3174
|
+
const [selectedPath, setSelectedPath] = React3.useState(
|
|
3175
|
+
initialFiles.length > 0 ? initialFiles[0].path : null
|
|
3176
|
+
);
|
|
3115
3177
|
const [saving, setSaving] = React3.useState(false);
|
|
3116
|
-
const [
|
|
3178
|
+
const [expanded, setExpanded] = React3.useState(() => {
|
|
3179
|
+
const { rootDirs } = buildTree(initialFiles);
|
|
3180
|
+
return collectAllDirPaths(rootDirs);
|
|
3181
|
+
});
|
|
3182
|
+
const [showAddFolder, setShowAddFolder] = React3.useState(false);
|
|
3183
|
+
const [newFolderName, setNewFolderName] = React3.useState("");
|
|
3184
|
+
const [addingFileInDir, setAddingFileInDir] = React3.useState(null);
|
|
3117
3185
|
const [newFileName, setNewFileName] = React3.useState("");
|
|
3186
|
+
const [savedSnapshot, setSavedSnapshot] = React3.useState(() => JSON.stringify(initialFiles));
|
|
3187
|
+
React3.useEffect(() => {
|
|
3188
|
+
const snap = JSON.stringify(initialFiles);
|
|
3189
|
+
setSavedSnapshot(snap);
|
|
3190
|
+
setFiles(initialFiles);
|
|
3191
|
+
const { rootDirs } = buildTree(initialFiles);
|
|
3192
|
+
setExpanded(collectAllDirPaths(rootDirs));
|
|
3193
|
+
}, [initialFiles]);
|
|
3194
|
+
React3.useEffect(() => {
|
|
3195
|
+
if (savedVersion !== void 0 && savedVersion > 0) {
|
|
3196
|
+
setSavedSnapshot(JSON.stringify(files));
|
|
3197
|
+
}
|
|
3198
|
+
}, [savedVersion]);
|
|
3199
|
+
const onChangeRef = React3.useRef(onChange);
|
|
3200
|
+
onChangeRef.current = onChange;
|
|
3201
|
+
React3.useEffect(() => {
|
|
3202
|
+
if (onChangeRef.current && JSON.stringify(files) !== savedSnapshot) {
|
|
3203
|
+
onChangeRef.current(files);
|
|
3204
|
+
}
|
|
3205
|
+
}, [files, savedSnapshot]);
|
|
3118
3206
|
const isDirty = React3.useMemo(
|
|
3119
|
-
() => JSON.stringify(files) !==
|
|
3120
|
-
[files,
|
|
3207
|
+
() => JSON.stringify(files) !== savedSnapshot,
|
|
3208
|
+
[files, savedSnapshot]
|
|
3209
|
+
);
|
|
3210
|
+
const tree = React3.useMemo(() => buildTree(files), [files]);
|
|
3211
|
+
const activeFile = React3.useMemo(
|
|
3212
|
+
() => selectedPath ? files.find((f) => f.path === selectedPath) ?? null : null,
|
|
3213
|
+
[files, selectedPath]
|
|
3121
3214
|
);
|
|
3122
|
-
const
|
|
3123
|
-
|
|
3124
|
-
setFiles((prev) => prev.map((f) => f.path ===
|
|
3215
|
+
const handleEditorChange = React3.useCallback((value) => {
|
|
3216
|
+
if (readOnly || !selectedPath) return;
|
|
3217
|
+
setFiles((prev) => prev.map((f) => f.path === selectedPath ? { ...f, content: value } : f));
|
|
3218
|
+
}, [readOnly, selectedPath]);
|
|
3219
|
+
function toggleExpand(dirPath) {
|
|
3220
|
+
setExpanded((prev) => {
|
|
3221
|
+
const next = new Set(prev);
|
|
3222
|
+
if (next.has(dirPath)) next.delete(dirPath);
|
|
3223
|
+
else next.add(dirPath);
|
|
3224
|
+
return next;
|
|
3225
|
+
});
|
|
3226
|
+
}
|
|
3227
|
+
function addFolder() {
|
|
3228
|
+
const name = newFolderName.trim();
|
|
3229
|
+
if (!name) return;
|
|
3230
|
+
const filePath = `${name}/${newFileTemplate.filename}`;
|
|
3231
|
+
if (files.some((f) => f.path === filePath)) return;
|
|
3232
|
+
const content = newFileTemplate.content.replace("# New", `# ${name}`);
|
|
3233
|
+
setFiles((prev) => [...prev, { path: filePath, content }]);
|
|
3234
|
+
setSelectedPath(filePath);
|
|
3235
|
+
setExpanded((prev) => /* @__PURE__ */ new Set([...prev, name]));
|
|
3236
|
+
setNewFolderName("");
|
|
3237
|
+
setShowAddFolder(false);
|
|
3238
|
+
}
|
|
3239
|
+
function removeDir(dirPath) {
|
|
3240
|
+
const prefix = dirPath + "/";
|
|
3241
|
+
const affectedFiles = files.filter((f) => f.path.startsWith(prefix));
|
|
3242
|
+
if (affectedFiles.length === 0) return;
|
|
3243
|
+
if (!confirm(`Remove "${dirPath}" and all ${affectedFiles.length} file(s)?`)) return;
|
|
3244
|
+
setFiles((prev) => prev.filter((f) => !f.path.startsWith(prefix)));
|
|
3245
|
+
if (selectedPath && selectedPath.startsWith(prefix)) setSelectedPath(null);
|
|
3246
|
+
}
|
|
3247
|
+
function removeFile(filePath) {
|
|
3248
|
+
const fileName = filePath.split("/").pop() ?? filePath;
|
|
3249
|
+
if (!confirm(`Remove file "${fileName}"?`)) return;
|
|
3250
|
+
setFiles((prev) => prev.filter((f) => f.path !== filePath));
|
|
3251
|
+
if (selectedPath === filePath) setSelectedPath(null);
|
|
3125
3252
|
}
|
|
3126
|
-
function
|
|
3253
|
+
function addFileInDir(dirPath) {
|
|
3127
3254
|
const name = newFileName.trim();
|
|
3128
|
-
if (!name
|
|
3129
|
-
const
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3255
|
+
if (!name) return;
|
|
3256
|
+
const filePath = dirPath ? `${dirPath}/${name}` : name;
|
|
3257
|
+
if (files.some((f) => f.path === filePath)) return;
|
|
3258
|
+
setFiles((prev) => [...prev, { path: filePath, content: "" }]);
|
|
3259
|
+
setSelectedPath(filePath);
|
|
3133
3260
|
setNewFileName("");
|
|
3261
|
+
setAddingFileInDir(null);
|
|
3134
3262
|
}
|
|
3135
|
-
function
|
|
3136
|
-
setFiles((prev) => prev.filter((f) => f.path !== path));
|
|
3137
|
-
if (selectedPath === path) {
|
|
3138
|
-
setSelectedPath(files.find((f) => f.path !== path)?.path ?? null);
|
|
3139
|
-
}
|
|
3140
|
-
}
|
|
3141
|
-
const handleSave = React3.useCallback(async () => {
|
|
3263
|
+
async function handleSave() {
|
|
3142
3264
|
setSaving(true);
|
|
3143
3265
|
try {
|
|
3144
|
-
|
|
3145
|
-
for (const file of files) {
|
|
3146
|
-
const slashIdx = file.path.lastIndexOf("/");
|
|
3147
|
-
if (slashIdx === -1) {
|
|
3148
|
-
const existing = folderMap.get("(root)") ?? [];
|
|
3149
|
-
existing.push({ path: file.path, content: file.content });
|
|
3150
|
-
folderMap.set("(root)", existing);
|
|
3151
|
-
} else {
|
|
3152
|
-
const folder = file.path.slice(0, slashIdx);
|
|
3153
|
-
const fileName = file.path.slice(slashIdx + 1);
|
|
3154
|
-
const existing = folderMap.get(folder) ?? [];
|
|
3155
|
-
existing.push({ path: fileName, content: file.content });
|
|
3156
|
-
folderMap.set(folder, existing);
|
|
3157
|
-
}
|
|
3158
|
-
}
|
|
3159
|
-
const skills = Array.from(folderMap.entries()).map(([folder, files2]) => ({ folder, files: files2 }));
|
|
3160
|
-
await client.agents.update(agentId, { skills });
|
|
3161
|
-
onSaved?.();
|
|
3266
|
+
await onSave(files);
|
|
3162
3267
|
} finally {
|
|
3163
3268
|
setSaving(false);
|
|
3164
3269
|
}
|
|
3165
|
-
}
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3170
|
-
/* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", onClick: handleSave, disabled: saving || !isDirty, children: saving ? "Saving..." : "Save Skills" })
|
|
3171
|
-
] }) }),
|
|
3172
|
-
addingFile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
|
|
3173
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3174
|
-
Input,
|
|
3175
|
-
{
|
|
3176
|
-
value: newFileName,
|
|
3177
|
-
onChange: (e) => setNewFileName(e.target.value),
|
|
3178
|
-
placeholder: "folder/SKILL.md",
|
|
3179
|
-
className: "max-w-xs text-sm",
|
|
3180
|
-
onKeyDown: (e) => e.key === "Enter" && addFile()
|
|
3181
|
-
}
|
|
3182
|
-
),
|
|
3183
|
-
/* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", onClick: addFile, children: "Add" }),
|
|
3184
|
-
/* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
|
|
3185
|
-
setAddingFile(false);
|
|
3186
|
-
setNewFileName("");
|
|
3187
|
-
}, children: "Cancel" })
|
|
3188
|
-
] }),
|
|
3189
|
-
files.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: 'No skills defined. Click "Add File" to create a skill.' }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4 min-h-[300px]", children: [
|
|
3190
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-48 shrink-0 border-r border-border pr-3 space-y-1", children: files.map((f) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3270
|
+
}
|
|
3271
|
+
function renderTreeNode(node, depth) {
|
|
3272
|
+
const isExpanded = expanded.has(node.fullPath);
|
|
3273
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3274
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3191
3275
|
"div",
|
|
3192
3276
|
{
|
|
3193
|
-
className:
|
|
3194
|
-
|
|
3277
|
+
className: "flex items-center justify-between cursor-pointer hover:bg-muted/50 py-1 pr-2",
|
|
3278
|
+
style: { paddingLeft: `${depth * 16 + 8}px` },
|
|
3279
|
+
onClick: () => toggleExpand(node.fullPath),
|
|
3195
3280
|
children: [
|
|
3196
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3197
|
-
|
|
3281
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium text-xs truncate flex items-center gap-1", children: [
|
|
3282
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: isExpanded ? "\u25BE" : "\u25B8" }),
|
|
3283
|
+
node.name,
|
|
3284
|
+
"/"
|
|
3285
|
+
] }),
|
|
3286
|
+
!readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3198
3287
|
"button",
|
|
3199
3288
|
{
|
|
3200
|
-
type: "button",
|
|
3201
3289
|
onClick: (e) => {
|
|
3202
3290
|
e.stopPropagation();
|
|
3203
|
-
|
|
3291
|
+
removeDir(node.fullPath);
|
|
3204
3292
|
},
|
|
3205
|
-
className: "
|
|
3293
|
+
className: "text-muted-foreground hover:text-destructive text-xs ml-1 shrink-0",
|
|
3206
3294
|
children: "\xD7"
|
|
3207
3295
|
}
|
|
3208
3296
|
)
|
|
3209
3297
|
]
|
|
3210
|
-
},
|
|
3211
|
-
f.path
|
|
3212
|
-
)) }),
|
|
3213
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: selectedFile ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3214
|
-
Textarea,
|
|
3215
|
-
{
|
|
3216
|
-
value: selectedFile.content,
|
|
3217
|
-
onChange: (e) => updateFileContent(selectedFile.path, e.target.value),
|
|
3218
|
-
className: "h-full min-h-[300px] font-mono text-xs resize-y",
|
|
3219
|
-
placeholder: "Enter skill content..."
|
|
3220
3298
|
}
|
|
3221
|
-
)
|
|
3299
|
+
),
|
|
3300
|
+
isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3301
|
+
node.children.map((child) => renderTreeNode(child, depth + 1)),
|
|
3302
|
+
node.files.map((file) => {
|
|
3303
|
+
const fileName = file.path.split("/").pop() ?? file.path;
|
|
3304
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3305
|
+
"div",
|
|
3306
|
+
{
|
|
3307
|
+
className: `flex items-center justify-between cursor-pointer hover:bg-muted/30 py-1 pr-2 ${selectedPath === file.path ? "bg-primary/10 text-primary" : ""}`,
|
|
3308
|
+
style: { paddingLeft: `${(depth + 1) * 16 + 8}px` },
|
|
3309
|
+
onClick: () => setSelectedPath(file.path),
|
|
3310
|
+
children: [
|
|
3311
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs truncate", children: fileName }),
|
|
3312
|
+
!readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3313
|
+
"button",
|
|
3314
|
+
{
|
|
3315
|
+
onClick: (e) => {
|
|
3316
|
+
e.stopPropagation();
|
|
3317
|
+
removeFile(file.path);
|
|
3318
|
+
},
|
|
3319
|
+
className: "text-muted-foreground hover:text-destructive text-xs ml-1 shrink-0",
|
|
3320
|
+
children: "\xD7"
|
|
3321
|
+
}
|
|
3322
|
+
)
|
|
3323
|
+
]
|
|
3324
|
+
},
|
|
3325
|
+
file.path
|
|
3326
|
+
);
|
|
3327
|
+
}),
|
|
3328
|
+
!readOnly && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { paddingLeft: `${(depth + 1) * 16 + 8}px` }, className: "py-1 pr-2", children: addingFileInDir === node.fullPath ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1", children: [
|
|
3329
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3330
|
+
Input,
|
|
3331
|
+
{
|
|
3332
|
+
value: newFileName,
|
|
3333
|
+
onChange: (e) => setNewFileName(e.target.value),
|
|
3334
|
+
placeholder: "file.md",
|
|
3335
|
+
className: "h-6 text-xs",
|
|
3336
|
+
onKeyDown: (e) => e.key === "Enter" && addFileInDir(node.fullPath),
|
|
3337
|
+
autoFocus: true
|
|
3338
|
+
}
|
|
3339
|
+
),
|
|
3340
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => addFileInDir(node.fullPath), size: "sm", className: "h-6 text-xs px-2", children: "+" })
|
|
3341
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3342
|
+
"button",
|
|
3343
|
+
{
|
|
3344
|
+
onClick: () => {
|
|
3345
|
+
setAddingFileInDir(node.fullPath);
|
|
3346
|
+
setNewFileName("");
|
|
3347
|
+
},
|
|
3348
|
+
className: "text-xs text-primary hover:underline",
|
|
3349
|
+
children: "+ File"
|
|
3350
|
+
}
|
|
3351
|
+
) })
|
|
3352
|
+
] })
|
|
3353
|
+
] }, node.fullPath);
|
|
3354
|
+
}
|
|
3355
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3356
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
|
|
3357
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
3358
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold", children: title }),
|
|
3359
|
+
isDirty && !readOnly && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "destructive", className: "text-xs", children: "Unsaved changes" }),
|
|
3360
|
+
readOnly && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "secondary", className: "text-xs", children: "Read-only" })
|
|
3361
|
+
] }),
|
|
3362
|
+
!readOnly && !hideSave && /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: handleSave, disabled: saving || !isDirty, size: "sm", children: saving ? "Saving..." : saveLabel })
|
|
3363
|
+
] }),
|
|
3364
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4 min-h-[500px]", children: [
|
|
3365
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-64 shrink-0 border border-border rounded-md overflow-hidden", children: [
|
|
3366
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 bg-muted/50 border-b border-border flex items-center justify-between", children: [
|
|
3367
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: title }),
|
|
3368
|
+
!readOnly && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3369
|
+
"button",
|
|
3370
|
+
{
|
|
3371
|
+
onClick: () => setShowAddFolder(!showAddFolder),
|
|
3372
|
+
className: "text-xs text-primary hover:underline",
|
|
3373
|
+
children: [
|
|
3374
|
+
"+ ",
|
|
3375
|
+
addFolderLabel
|
|
3376
|
+
]
|
|
3377
|
+
}
|
|
3378
|
+
)
|
|
3379
|
+
] }),
|
|
3380
|
+
showAddFolder && !readOnly && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 border-b border-border flex gap-1", children: [
|
|
3381
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3382
|
+
Input,
|
|
3383
|
+
{
|
|
3384
|
+
value: newFolderName,
|
|
3385
|
+
onChange: (e) => setNewFolderName(e.target.value),
|
|
3386
|
+
placeholder: "folder-name",
|
|
3387
|
+
className: "h-7 text-xs",
|
|
3388
|
+
onKeyDown: (e) => e.key === "Enter" && addFolder(),
|
|
3389
|
+
autoFocus: true
|
|
3390
|
+
}
|
|
3391
|
+
),
|
|
3392
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: addFolder, size: "sm", className: "h-7 text-xs px-2", children: "Add" })
|
|
3393
|
+
] }),
|
|
3394
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm overflow-y-auto", children: [
|
|
3395
|
+
tree.rootFiles.map((file) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3396
|
+
"div",
|
|
3397
|
+
{
|
|
3398
|
+
className: `flex items-center justify-between cursor-pointer hover:bg-muted/30 py-1 pr-2 ${selectedPath === file.path ? "bg-primary/10 text-primary" : ""}`,
|
|
3399
|
+
style: { paddingLeft: "8px" },
|
|
3400
|
+
onClick: () => setSelectedPath(file.path),
|
|
3401
|
+
children: [
|
|
3402
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs truncate", children: file.path }),
|
|
3403
|
+
!readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3404
|
+
"button",
|
|
3405
|
+
{
|
|
3406
|
+
onClick: (e) => {
|
|
3407
|
+
e.stopPropagation();
|
|
3408
|
+
removeFile(file.path);
|
|
3409
|
+
},
|
|
3410
|
+
className: "text-muted-foreground hover:text-destructive text-xs ml-1 shrink-0",
|
|
3411
|
+
children: "\xD7"
|
|
3412
|
+
}
|
|
3413
|
+
)
|
|
3414
|
+
]
|
|
3415
|
+
},
|
|
3416
|
+
file.path
|
|
3417
|
+
)),
|
|
3418
|
+
tree.rootDirs.map((node) => renderTreeNode(node, 0)),
|
|
3419
|
+
files.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-3 text-xs text-muted-foreground", children: readOnly ? "No files." : `No ${title.toLowerCase()} yet. Add a ${addFolderLabel.toLowerCase()} to get started.` })
|
|
3420
|
+
] })
|
|
3421
|
+
] }),
|
|
3422
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 border border-border rounded-md overflow-hidden", children: activeFile ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col", children: [
|
|
3423
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-1.5 bg-muted/50 border-b border-border text-xs text-muted-foreground", children: activeFile.path }),
|
|
3424
|
+
/* @__PURE__ */ jsxRuntime.jsx(React3.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 animate-pulse bg-muted/50" }), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3425
|
+
CodeEditor,
|
|
3426
|
+
{
|
|
3427
|
+
value: activeFile.content,
|
|
3428
|
+
onChange: handleEditorChange,
|
|
3429
|
+
filename: activeFile.path
|
|
3430
|
+
}
|
|
3431
|
+
) })
|
|
3432
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex items-center justify-center text-muted-foreground text-sm", children: [
|
|
3433
|
+
"Select a file to ",
|
|
3434
|
+
readOnly ? "view" : "edit"
|
|
3435
|
+
] }) })
|
|
3222
3436
|
] })
|
|
3223
3437
|
] });
|
|
3224
3438
|
}
|
|
3439
|
+
function AgentSkillManager({ agentId, initialSkills, onSaved }) {
|
|
3440
|
+
const client = useAgentPlaneClient();
|
|
3441
|
+
const initialFiles = React3.useMemo(
|
|
3442
|
+
() => initialSkills.flatMap(
|
|
3443
|
+
(s) => s.files.map((f) => ({
|
|
3444
|
+
path: s.folder === "(root)" ? f.path : `${s.folder}/${f.path}`,
|
|
3445
|
+
content: f.content
|
|
3446
|
+
}))
|
|
3447
|
+
),
|
|
3448
|
+
[initialSkills]
|
|
3449
|
+
);
|
|
3450
|
+
const handleSave = React3.useCallback(async (files) => {
|
|
3451
|
+
const folderMap = /* @__PURE__ */ new Map();
|
|
3452
|
+
for (const file of files) {
|
|
3453
|
+
const slashIdx = file.path.lastIndexOf("/");
|
|
3454
|
+
if (slashIdx === -1) {
|
|
3455
|
+
const existing = folderMap.get("(root)") ?? [];
|
|
3456
|
+
existing.push({ path: file.path, content: file.content });
|
|
3457
|
+
folderMap.set("(root)", existing);
|
|
3458
|
+
} else {
|
|
3459
|
+
const folder = file.path.slice(0, slashIdx);
|
|
3460
|
+
const fileName = file.path.slice(slashIdx + 1);
|
|
3461
|
+
const existing = folderMap.get(folder) ?? [];
|
|
3462
|
+
existing.push({ path: fileName, content: file.content });
|
|
3463
|
+
folderMap.set(folder, existing);
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
const skills = Array.from(folderMap.entries()).map(([folder, files2]) => ({ folder, files: files2 }));
|
|
3467
|
+
await client.agents.update(agentId, { skills });
|
|
3468
|
+
onSaved?.();
|
|
3469
|
+
}, [agentId, client, onSaved]);
|
|
3470
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3471
|
+
FileTreeEditor,
|
|
3472
|
+
{
|
|
3473
|
+
initialFiles,
|
|
3474
|
+
onSave: handleSave,
|
|
3475
|
+
title: "Skills",
|
|
3476
|
+
saveLabel: "Save Skills",
|
|
3477
|
+
addFolderLabel: "Skill",
|
|
3478
|
+
newFileTemplate: {
|
|
3479
|
+
filename: "SKILL.md",
|
|
3480
|
+
content: "---\nname: New Skill\ndescription: Describe when this skill should be triggered\n---\n\n# Instructions\n\nDescribe what this skill does...\n"
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
);
|
|
3484
|
+
}
|
|
3225
3485
|
function AgentPluginManager({ agentId, initialPlugins, onSaved }) {
|
|
3226
3486
|
const client = useAgentPlaneClient();
|
|
3227
3487
|
const [plugins, setPlugins] = React3.useState(initialPlugins);
|
|
@@ -3377,141 +3637,6 @@ function AgentPluginManager({ agentId, initialPlugins, onSaved }) {
|
|
|
3377
3637
|
] })
|
|
3378
3638
|
] });
|
|
3379
3639
|
}
|
|
3380
|
-
var FREQUENCIES = [
|
|
3381
|
-
{ value: "manual", label: "Manual (no schedule)" },
|
|
3382
|
-
{ value: "hourly", label: "Hourly" },
|
|
3383
|
-
{ value: "daily", label: "Daily" },
|
|
3384
|
-
{ value: "weekdays", label: "Weekdays (Mon-Fri)" },
|
|
3385
|
-
{ value: "weekly", label: "Weekly" }
|
|
3386
|
-
];
|
|
3387
|
-
var DAYS_OF_WEEK = [
|
|
3388
|
-
{ value: 0, label: "Sunday" },
|
|
3389
|
-
{ value: 1, label: "Monday" },
|
|
3390
|
-
{ value: 2, label: "Tuesday" },
|
|
3391
|
-
{ value: 3, label: "Wednesday" },
|
|
3392
|
-
{ value: 4, label: "Thursday" },
|
|
3393
|
-
{ value: 5, label: "Friday" },
|
|
3394
|
-
{ value: 6, label: "Saturday" }
|
|
3395
|
-
];
|
|
3396
|
-
function formatTimeForInput(time) {
|
|
3397
|
-
if (!time) return "09:00";
|
|
3398
|
-
return time.slice(0, 5);
|
|
3399
|
-
}
|
|
3400
|
-
function AgentScheduleForm({ initialSchedules, timezone }) {
|
|
3401
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-muted-foreground/25 p-5", children: [
|
|
3402
|
-
/* @__PURE__ */ jsxRuntime.jsx(SectionHeader, { title: "Schedules", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
3403
|
-
"Timezone: ",
|
|
3404
|
-
timezone
|
|
3405
|
-
] }) }),
|
|
3406
|
-
initialSchedules.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground py-4", children: "No schedules configured." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: initialSchedules.map((schedule) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3407
|
-
ScheduleCard,
|
|
3408
|
-
{
|
|
3409
|
-
schedule,
|
|
3410
|
-
timezone
|
|
3411
|
-
},
|
|
3412
|
-
schedule.id
|
|
3413
|
-
)) })
|
|
3414
|
-
] });
|
|
3415
|
-
}
|
|
3416
|
-
function ScheduleCard({
|
|
3417
|
-
schedule,
|
|
3418
|
-
timezone
|
|
3419
|
-
}) {
|
|
3420
|
-
const [frequency, setFrequency] = React3.useState(schedule.frequency);
|
|
3421
|
-
const [time, setTime] = React3.useState(formatTimeForInput(schedule.time));
|
|
3422
|
-
const [dayOfWeek, setDayOfWeek] = React3.useState(schedule.day_of_week ?? 1);
|
|
3423
|
-
const [prompt, setPrompt] = React3.useState(schedule.prompt ?? "");
|
|
3424
|
-
const [enabled, setEnabled] = React3.useState(schedule.enabled);
|
|
3425
|
-
const [name, setName] = React3.useState(schedule.name ?? "");
|
|
3426
|
-
const showTimePicker = ["daily", "weekdays", "weekly"].includes(frequency);
|
|
3427
|
-
const showDayPicker = frequency === "weekly";
|
|
3428
|
-
const canEnable = frequency !== "manual";
|
|
3429
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded border border-muted-foreground/15 p-4 space-y-3", children: [
|
|
3430
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
3431
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3432
|
-
Input,
|
|
3433
|
-
{
|
|
3434
|
-
value: name,
|
|
3435
|
-
onChange: (e) => setName(e.target.value),
|
|
3436
|
-
placeholder: "Schedule name (optional)",
|
|
3437
|
-
className: "max-w-xs text-sm"
|
|
3438
|
-
}
|
|
3439
|
-
),
|
|
3440
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: canEnable && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [
|
|
3441
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: enabled ? "Enabled" : "Disabled" }),
|
|
3442
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3443
|
-
"button",
|
|
3444
|
-
{
|
|
3445
|
-
type: "button",
|
|
3446
|
-
role: "switch",
|
|
3447
|
-
"aria-checked": enabled,
|
|
3448
|
-
onClick: () => setEnabled(!enabled),
|
|
3449
|
-
className: `relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${enabled ? "bg-primary" : "bg-muted"}`,
|
|
3450
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3451
|
-
"span",
|
|
3452
|
-
{
|
|
3453
|
-
className: `pointer-events-none inline-block h-4 w-4 transform rounded-full bg-background shadow-lg ring-0 transition-transform ${enabled ? "translate-x-4" : "translate-x-0"}`
|
|
3454
|
-
}
|
|
3455
|
-
)
|
|
3456
|
-
}
|
|
3457
|
-
)
|
|
3458
|
-
] }) })
|
|
3459
|
-
] }),
|
|
3460
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
3461
|
-
/* @__PURE__ */ jsxRuntime.jsx(FormField, { label: "Frequency", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3462
|
-
Select,
|
|
3463
|
-
{
|
|
3464
|
-
value: frequency,
|
|
3465
|
-
onChange: (e) => {
|
|
3466
|
-
const newFreq = e.target.value;
|
|
3467
|
-
setFrequency(newFreq);
|
|
3468
|
-
if (newFreq === "manual") setEnabled(false);
|
|
3469
|
-
else setEnabled(true);
|
|
3470
|
-
},
|
|
3471
|
-
children: FREQUENCIES.map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: f.value, children: f.label }, f.value))
|
|
3472
|
-
}
|
|
3473
|
-
) }),
|
|
3474
|
-
showTimePicker && /* @__PURE__ */ jsxRuntime.jsx(FormField, { label: `Time (${timezone})`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3475
|
-
Input,
|
|
3476
|
-
{
|
|
3477
|
-
type: "time",
|
|
3478
|
-
value: time,
|
|
3479
|
-
onChange: (e) => setTime(e.target.value)
|
|
3480
|
-
}
|
|
3481
|
-
) }),
|
|
3482
|
-
showDayPicker && /* @__PURE__ */ jsxRuntime.jsx(FormField, { label: "Day of Week", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3483
|
-
Select,
|
|
3484
|
-
{
|
|
3485
|
-
value: dayOfWeek.toString(),
|
|
3486
|
-
onChange: (e) => setDayOfWeek(parseInt(e.target.value)),
|
|
3487
|
-
children: DAYS_OF_WEEK.map((d) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: d.value, children: d.label }, d.value))
|
|
3488
|
-
}
|
|
3489
|
-
) })
|
|
3490
|
-
] }),
|
|
3491
|
-
frequency !== "manual" && /* @__PURE__ */ jsxRuntime.jsx(FormField, { label: "Prompt", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3492
|
-
Textarea,
|
|
3493
|
-
{
|
|
3494
|
-
value: prompt,
|
|
3495
|
-
onChange: (e) => setPrompt(e.target.value),
|
|
3496
|
-
rows: 3,
|
|
3497
|
-
placeholder: "Enter the prompt to send on each scheduled run...",
|
|
3498
|
-
className: "resize-y min-h-[60px]"
|
|
3499
|
-
}
|
|
3500
|
-
) }),
|
|
3501
|
-
(schedule.last_run_at || schedule.next_run_at) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-6 text-sm text-muted-foreground pt-1", children: [
|
|
3502
|
-
schedule.last_run_at && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3503
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Last run:" }),
|
|
3504
|
-
" ",
|
|
3505
|
-
/* @__PURE__ */ jsxRuntime.jsx(LocalDate, { value: schedule.last_run_at })
|
|
3506
|
-
] }),
|
|
3507
|
-
schedule.next_run_at && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3508
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Next run:" }),
|
|
3509
|
-
" ",
|
|
3510
|
-
/* @__PURE__ */ jsxRuntime.jsx(LocalDate, { value: schedule.next_run_at })
|
|
3511
|
-
] })
|
|
3512
|
-
] })
|
|
3513
|
-
] });
|
|
3514
|
-
}
|
|
3515
3640
|
function AgentRuns({ agentId }) {
|
|
3516
3641
|
const { LinkComponent, basePath } = useNavigation();
|
|
3517
3642
|
const { data, error, isLoading } = useApi(
|
|
@@ -3751,7 +3876,7 @@ function AgentA2aInfo({
|
|
|
3751
3876
|
] })
|
|
3752
3877
|
] });
|
|
3753
3878
|
}
|
|
3754
|
-
function AgentDetailPage({ agentId, a2aBaseUrl, tenantSlug
|
|
3879
|
+
function AgentDetailPage({ agentId, a2aBaseUrl, tenantSlug }) {
|
|
3755
3880
|
const { LinkComponent, basePath } = useNavigation();
|
|
3756
3881
|
const { mutate } = useSWR.useSWRConfig();
|
|
3757
3882
|
const cacheKey = `agent-${agentId}`;
|
|
@@ -3854,16 +3979,6 @@ function AgentDetailPage({ agentId, a2aBaseUrl, tenantSlug, timezone = "UTC" })
|
|
|
3854
3979
|
}
|
|
3855
3980
|
)
|
|
3856
3981
|
},
|
|
3857
|
-
{
|
|
3858
|
-
label: "Schedules",
|
|
3859
|
-
content: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3860
|
-
AgentScheduleForm,
|
|
3861
|
-
{
|
|
3862
|
-
initialSchedules: [],
|
|
3863
|
-
timezone
|
|
3864
|
-
}
|
|
3865
|
-
)
|
|
3866
|
-
},
|
|
3867
3982
|
{
|
|
3868
3983
|
label: "Runs",
|
|
3869
3984
|
content: /* @__PURE__ */ jsxRuntime.jsx(AgentRuns, { agentId: agent.id })
|
|
@@ -3873,6 +3988,141 @@ function AgentDetailPage({ agentId, a2aBaseUrl, tenantSlug, timezone = "UTC" })
|
|
|
3873
3988
|
)
|
|
3874
3989
|
] });
|
|
3875
3990
|
}
|
|
3991
|
+
var FREQUENCIES = [
|
|
3992
|
+
{ value: "manual", label: "Manual (no schedule)" },
|
|
3993
|
+
{ value: "hourly", label: "Hourly" },
|
|
3994
|
+
{ value: "daily", label: "Daily" },
|
|
3995
|
+
{ value: "weekdays", label: "Weekdays (Mon-Fri)" },
|
|
3996
|
+
{ value: "weekly", label: "Weekly" }
|
|
3997
|
+
];
|
|
3998
|
+
var DAYS_OF_WEEK = [
|
|
3999
|
+
{ value: 0, label: "Sunday" },
|
|
4000
|
+
{ value: 1, label: "Monday" },
|
|
4001
|
+
{ value: 2, label: "Tuesday" },
|
|
4002
|
+
{ value: 3, label: "Wednesday" },
|
|
4003
|
+
{ value: 4, label: "Thursday" },
|
|
4004
|
+
{ value: 5, label: "Friday" },
|
|
4005
|
+
{ value: 6, label: "Saturday" }
|
|
4006
|
+
];
|
|
4007
|
+
function formatTimeForInput(time) {
|
|
4008
|
+
if (!time) return "09:00";
|
|
4009
|
+
return time.slice(0, 5);
|
|
4010
|
+
}
|
|
4011
|
+
function AgentScheduleForm({ initialSchedules, timezone }) {
|
|
4012
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-muted-foreground/25 p-5", children: [
|
|
4013
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionHeader, { title: "Schedules", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
4014
|
+
"Timezone: ",
|
|
4015
|
+
timezone
|
|
4016
|
+
] }) }),
|
|
4017
|
+
initialSchedules.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground py-4", children: "No schedules configured." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: initialSchedules.map((schedule) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4018
|
+
ScheduleCard,
|
|
4019
|
+
{
|
|
4020
|
+
schedule,
|
|
4021
|
+
timezone
|
|
4022
|
+
},
|
|
4023
|
+
schedule.id
|
|
4024
|
+
)) })
|
|
4025
|
+
] });
|
|
4026
|
+
}
|
|
4027
|
+
function ScheduleCard({
|
|
4028
|
+
schedule,
|
|
4029
|
+
timezone
|
|
4030
|
+
}) {
|
|
4031
|
+
const [frequency, setFrequency] = React3.useState(schedule.frequency);
|
|
4032
|
+
const [time, setTime] = React3.useState(formatTimeForInput(schedule.time));
|
|
4033
|
+
const [dayOfWeek, setDayOfWeek] = React3.useState(schedule.day_of_week ?? 1);
|
|
4034
|
+
const [prompt, setPrompt] = React3.useState(schedule.prompt ?? "");
|
|
4035
|
+
const [enabled, setEnabled] = React3.useState(schedule.enabled);
|
|
4036
|
+
const [name, setName] = React3.useState(schedule.name ?? "");
|
|
4037
|
+
const showTimePicker = ["daily", "weekdays", "weekly"].includes(frequency);
|
|
4038
|
+
const showDayPicker = frequency === "weekly";
|
|
4039
|
+
const canEnable = frequency !== "manual";
|
|
4040
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded border border-muted-foreground/15 p-4 space-y-3", children: [
|
|
4041
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
4042
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4043
|
+
Input,
|
|
4044
|
+
{
|
|
4045
|
+
value: name,
|
|
4046
|
+
onChange: (e) => setName(e.target.value),
|
|
4047
|
+
placeholder: "Schedule name (optional)",
|
|
4048
|
+
className: "max-w-xs text-sm"
|
|
4049
|
+
}
|
|
4050
|
+
),
|
|
4051
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: canEnable && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [
|
|
4052
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: enabled ? "Enabled" : "Disabled" }),
|
|
4053
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4054
|
+
"button",
|
|
4055
|
+
{
|
|
4056
|
+
type: "button",
|
|
4057
|
+
role: "switch",
|
|
4058
|
+
"aria-checked": enabled,
|
|
4059
|
+
onClick: () => setEnabled(!enabled),
|
|
4060
|
+
className: `relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${enabled ? "bg-primary" : "bg-muted"}`,
|
|
4061
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4062
|
+
"span",
|
|
4063
|
+
{
|
|
4064
|
+
className: `pointer-events-none inline-block h-4 w-4 transform rounded-full bg-background shadow-lg ring-0 transition-transform ${enabled ? "translate-x-4" : "translate-x-0"}`
|
|
4065
|
+
}
|
|
4066
|
+
)
|
|
4067
|
+
}
|
|
4068
|
+
)
|
|
4069
|
+
] }) })
|
|
4070
|
+
] }),
|
|
4071
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
4072
|
+
/* @__PURE__ */ jsxRuntime.jsx(FormField, { label: "Frequency", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4073
|
+
Select,
|
|
4074
|
+
{
|
|
4075
|
+
value: frequency,
|
|
4076
|
+
onChange: (e) => {
|
|
4077
|
+
const newFreq = e.target.value;
|
|
4078
|
+
setFrequency(newFreq);
|
|
4079
|
+
if (newFreq === "manual") setEnabled(false);
|
|
4080
|
+
else setEnabled(true);
|
|
4081
|
+
},
|
|
4082
|
+
children: FREQUENCIES.map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: f.value, children: f.label }, f.value))
|
|
4083
|
+
}
|
|
4084
|
+
) }),
|
|
4085
|
+
showTimePicker && /* @__PURE__ */ jsxRuntime.jsx(FormField, { label: `Time (${timezone})`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4086
|
+
Input,
|
|
4087
|
+
{
|
|
4088
|
+
type: "time",
|
|
4089
|
+
value: time,
|
|
4090
|
+
onChange: (e) => setTime(e.target.value)
|
|
4091
|
+
}
|
|
4092
|
+
) }),
|
|
4093
|
+
showDayPicker && /* @__PURE__ */ jsxRuntime.jsx(FormField, { label: "Day of Week", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4094
|
+
Select,
|
|
4095
|
+
{
|
|
4096
|
+
value: dayOfWeek.toString(),
|
|
4097
|
+
onChange: (e) => setDayOfWeek(parseInt(e.target.value)),
|
|
4098
|
+
children: DAYS_OF_WEEK.map((d) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: d.value, children: d.label }, d.value))
|
|
4099
|
+
}
|
|
4100
|
+
) })
|
|
4101
|
+
] }),
|
|
4102
|
+
frequency !== "manual" && /* @__PURE__ */ jsxRuntime.jsx(FormField, { label: "Prompt", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4103
|
+
Textarea,
|
|
4104
|
+
{
|
|
4105
|
+
value: prompt,
|
|
4106
|
+
onChange: (e) => setPrompt(e.target.value),
|
|
4107
|
+
rows: 3,
|
|
4108
|
+
placeholder: "Enter the prompt to send on each scheduled run...",
|
|
4109
|
+
className: "resize-y min-h-[60px]"
|
|
4110
|
+
}
|
|
4111
|
+
) }),
|
|
4112
|
+
(schedule.last_run_at || schedule.next_run_at) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-6 text-sm text-muted-foreground pt-1", children: [
|
|
4113
|
+
schedule.last_run_at && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4114
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Last run:" }),
|
|
4115
|
+
" ",
|
|
4116
|
+
/* @__PURE__ */ jsxRuntime.jsx(LocalDate, { value: schedule.last_run_at })
|
|
4117
|
+
] }),
|
|
4118
|
+
schedule.next_run_at && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4119
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Next run:" }),
|
|
4120
|
+
" ",
|
|
4121
|
+
/* @__PURE__ */ jsxRuntime.jsx(LocalDate, { value: schedule.next_run_at })
|
|
4122
|
+
] })
|
|
4123
|
+
] })
|
|
4124
|
+
] });
|
|
4125
|
+
}
|
|
3876
4126
|
|
|
3877
4127
|
exports.AdminTable = AdminTable;
|
|
3878
4128
|
exports.AdminTableHead = AdminTableHead;
|