1import { j as createSignal, B as createEffect, a as createComponent, N as Suspense, V as Typography, E as Box, Q as Stack, a5 as Card, a8 as CardContent, ag as FormControl, ah as InputLabel, ai as Select, aj as MenuItem, F as For, w as memo, ak as TableContainer, al as Table, am as TableHead, an as TableRow, ao as TableCell, ap as TableBody, S as Show, J as CircularProgress, X as Chip, G as Slide, Y as Paper, R as TextField } from "./suid-material-beZszf02.js"; 2import { A as Add, V as Visibility, D as Delete } from "./suid-icons-BVoj-b7W.js"; 3import { u as useAuth, a as useNavigate, c as useToast, A as AppButton, d as apiClient } from "./index-D967GsUD.js"; 4import { A as AppIconButton } from "./AppIconButton-D7UwNbyJ.js"; 5import { N as Nav } from "./Nav-CablUE1w.js"; 6import "./browser.umd-YwivngSI.js"; 7import "./logo-CkfnQ46G.js"; 8function ContentDocListPage() { 9 const { 10 user 11 } = useAuth(); 12 const navigate = useNavigate(); 13 const toast = useToast(); 14 const [contentDocs, setContentDocs] = createSignal([]); 15 const [loading, setLoading] = createSignal(true); 16 const [filterType, setFilterType] = createSignal(""); 17 const [filterStatus, setFilterStatus] = createSignal(""); 18 const [selectedDocId, setSelectedDocId] = createSignal(null); 19 const [editingDoc, setEditingDoc] = createSignal(null); 20 const loadContentDocs = async () => { 21 setLoading(true); 22 try { 23 const params = new URLSearchParams(); 24 if (filterType()) params.append("type", filterType()); 25 const type = params.get("type") || void 0; 26 const result = await apiClient.contentDocs.list(type); 27 setContentDocs(result.contentDocs || []); 28 } catch (error) { 29 console.error("Error loading content docs:", error); 30 } finally { 31 setLoading(false); 32 } 33 }; 34 createEffect(() => { 35 loadContentDocs(); 36 }); 37 const handleDelete = async (id) => { 38 if (!confirm("Are you sure you want to delete this content template?")) { 39 return; 40 } 41 try { 42 await apiClient.contentDocs.remove(id); 43 await loadContentDocs(); 44 } catch (error) { 45 console.error("Error deleting content doc:", error); 46 toast.showToast("error", "Failed to delete content template"); 47 } 48 }; 49 const handleDuplicate = async (contentDoc) => { 50 try { 51 const duplicate = { 52 ...contentDoc, 53 _id: void 0, 54 version: incrementVersion(contentDoc.version), 55 status: "draft" 56 }; 57 const result = await apiClient.contentDocs.create(duplicate); 58 navigate(`/content-docs/${result.contentDoc._id}`); 59 } catch (error) { 60 console.error("Error duplicating content doc:", error); 61 toast.showToast("error", "Failed to duplicate content template"); 62 } 63 }; 64 const incrementVersion = (version) => { 65 const parts = version.split("."); 66 if (parts.length !== 3) return version; 67 const year = parts[0];
68 const month = parts[1]; 69 const patch = parseInt(parts[2], 10); 70 if (isNaN(patch)) return version; 71 const newPatch = patch + 1; 72 return `${year}.${month}.${newPatch.toString().padStart(3, "0")}`; 73 }; 74 const filteredDocs = () => { 75 let docs = contentDocs(); 76 if (filterType()) { 77 docs = docs.filter((doc) => doc.type === filterType()); 78 } 79 if (filterStatus()) { 80 docs = docs.filter((doc) => doc.status === filterStatus()); 81 } 82 return docs; 83 }; 84 const uniqueTypes = () => { 85 const types = new Set(contentDocs().map((doc) => doc.type)); 86 return Array.from(types).sort(); 87 }; 88 const formatDate = (date) => { 89 return new Date(date).toLocaleDateString(); 90 }; 91 const handleRowClick = (doc) => { 92 var _a; 93 const docId = (_a = doc._id) == null ? void 0 : _a.toString(); 94 if (selectedDocId() === docId) { 95 setSelectedDocId(null); 96 setEditingDoc(null); 97 } else { 98 setSelectedDocId(docId || null); 99 setEditingDoc(doc); 100 } 101 }; 102 const handleSaveEdit = async () => { 103 const doc = editingDoc(); 104 if (!doc) return; 105 try { 106 await apiClient.contentDocs.update(String(doc._id), doc); 107 await loadContentDocs(); 108 setSelectedDocId(null); 109 setEditingDoc(null); 110 } catch (error) { 111 console.error("Error updating content doc:", error); 112 toast.showToast("error", "Failed to update content template"); 113 } 114 }; 115 const handleCancelEdit = () => { 116 setSelectedDocId(null); 117 setEditingDoc(null); 118 }; 119 return createComponent(Box, { 120 get children() { 121 return [createComponent(Suspense, { 122 get fallback() { 123 return createComponent(Typography, { 124 variant: "h3", 125 color: "text.white", 126 children: "Loading..." 127 }); 128 }, 129 get children() { 130 return createComponent(Nav, { 131 title: "Content Templates", 132 user 133 }); 134 } 135 }), createComponent(Box, { 136 sx: { 137 margin: "3rem" 138 }, 139 get children() { 140 return createComponent(Box, { 141 sx: { 142 p: 3 143 }, 144 get children() { 145 return [createComponent(Stack, { 146 direction: "row", 147 justifyContent: "space-between", 148 alignItems: "center", 149 sx: { 150 mb: 3, 151 marginBottom: "1rem" 152 }, 153 get children() { 154 return createComponent(Typography, { 155 variant: "h4", 156 color: "white", 157 children: "Content Templates" 158 }); 159 } 160 }), createComponent(Card, { 161 sx: { 162 mb: 3 163 }, 164 get children() { 165 return createComponent(CardContent, { 166 get children() { 167 return createComponent(Stack, { 168 direction: "row", 169 spacing: 2, 170 alignItems: "center", 171 get children() { 172 return [createComponent(FormControl, { 173 sx: { 174 minWidth: 150 175 }, 176 get children() { 177 return [createComponent(InputLabel, { 178 children: "Type" 179 }), createComponent(Select, { 180 get value() { 181 return filterType(); 182 }, 183 onChange: (e) => setFilterType(e.target.value), 184 label: "Type", 185 get children() { 186 return [createComponent(MenuItem, { 187 value: "", 188 children: "All Types" 189 }), createComponent(For, { 190 get each() { 191 return uniqueTypes(); 192 }, 193 children: (type) => createComponent(MenuItem, { 194 value: type, 195 children: type 196 }) 197 })]; 198 } 199 })]; 200 } 201 }), createComponent(FormControl, { 202 sx: { 203 minWidth: 150 204 }, 205 get children() { 206 return [createComponent(InputLabel, { 207 children: "Status" 208 }), createComponent(Select, { 209 get value() { 210 return filterStatus(); 211 }, 212 onChange: (e) => setFilterStatus(e.target.value), 213 label: "Status", 214 get children() { 215 return [createComponent(MenuItem, { 216 value: "", 217 children: "All Statuses" 218 }), createComponent(MenuItem, { 219 value: "draft", 220 children: "Draft" 221 }), createComponent(MenuItem, { 222 value: "published", 223 children: "Published" 224 })]; 225 } 226 })]; 227 } 228 }), createComponent(Typography, { 229 variant: "body2", 230 color: "text.secondary", 231 get children() { 232 return [memo(() => filteredDocs().length), " templates"]; 233 } 234 }), createComponent(AppButton, { 235 intent: "primary", 236 get startIcon() { 237 return createComponent(Add, {}); 238 }, 239 onClick: () => navigate("/content-docs/new"), 240 children: "Create New Template" 241 })]; 242 } 243 }); 244 } 245 }); 246 } 247 }), createComponent(Card, { 248 get children() { 249 return createComponent(TableContainer, { 250 get children() { 251 return createComponent(Table, { 252 get children() { 253 return [createComponent(TableHead, { 254 get children() { 255 return createComponent(TableRow, { 256 get children() { 257 return [createComponent(TableCell, { 258 children: "Type" 259 }), createComponent(TableCell, { 260 children: "Version" 261 }), createComponent(TableCell, { 262 children: "Status" 263 }), createComponent(TableCell, { 264 children: "Updated" 265 }), createComponent(TableCell, { 266 children: "Actions" 267 })]; 268 } 269 }); 270 } 271 }), createComponent(TableBody, { 272 get children() { 273 return createComponent(Show, { 274 get when() { 275 return loading(); 276 }, 277 get fallback() { 278 return createComponent(For, { 279 get each() { 280 return filteredDocs(); 281 }, 282 children: (doc) => [createComponent(TableRow, { 283 hover: true, 284 onClick: () => handleRowClick(doc), 285 get sx() { 286 var _a; 287 return { 288 cursor: "pointer", 289 backgroundColor: selectedDocId() === ((_a = doc._id) == null ? void 0 : _a.toString()) ? "action.selected" : "
289inherit" 290 }; 291 }, 292 get children() { 293 return [createComponent(TableCell, { 294 get children() { 295 return createComponent(Typography, { 296 variant: "body2", 297 sx: { 298 fontFamily: "monospace" 299 }, 300 get children() { 301 return doc.type; 302 } 303 }); 304 } 305 }), createComponent(TableCell, { 306 get children() { 307 return createComponent(Typography, { 308 variant: "body2", 309 get children() { 310 return doc.version; 311 } 312 }); 313 } 314 }), createComponent(TableCell, { 315 get children() { 316 return createComponent(Chip, { 317 get label() { 318 return doc.status; 319 }, 320 get color() { 321 return doc.status === "published" ? "success" : "default"; 322 }, 323 size: "small" 324 }); 325 } 326 }), createComponent(TableCell, { 327 get children() { 328 return createComponent(Typography, { 329 variant: "body2", 330 get children() { 331 return formatDate(doc.updatedAt || doc.createdAt || ""); 332 } 333 }); 334 } 335 }), createComponent(TableCell, { 336 get children() { 337 return createComponent(Stack, { 338 direction: "row", 339 spacing: 0.5, 340 get children() { 341 return [createComponent(AppIconButton, { 342 size: "small", 343 onClick: (e) => { 344 e.stopPropagation(); 345 navigate(`/content-docs/${doc._id}`); 346 }, 347 title: "Open Full Editor", 348 sx: { 349 color: "primary.main" 350 }, 351 get children() { 352 return createComponent(Visibility, {}); 353 } 354 }), createComponent(AppIconButton, { 355 size: "small", 356 onClick: (e) => { 357 e.stopPropagation(); 358 handleDuplicate(doc); 359 }, 360 title: "Duplicate", 361 sx: { 362 color: "primary.main" 363 }, 364 get children() { 365 return createComponent(Add, {}); 366 } 367 }), createComponent(Show, { 368 get when() { 369 return doc.status === "draft"; 370 }, 371 get children() { 372 return createComponent(AppIconButton, { 373 size: "small", 374 onClick: (e) => { 375 var _a; 376 e.stopPropagation(); 377 handleDelete(((_a = doc._id) == null ? void 0 : _a.toString()) || ""); 378 }, 379 title: "Delete", 380 color: "error", 381 get children() { 382 return createComponent(Delete, {}); 383 } 384 }); 385 } 386 })]; 387 } 388 }); 389 } 390 })]; 391 } 392 }), createComponent(TableRow, { 393 get children() { 394 return createComponent(TableCell, { 395 colSpan: 5, 396 sx: { 397 p: 0, 398 border: "none" 399 }, 400 get children() { 401 return createComponent(Slide, { 402 direction: "down", 403 get ["in"]() { 404 var _a; 405 return selectedDocId() === ((_a = doc._id) == null ? void 0 : _a.toString()); 406 }, 407 mountOnEnter: true, 408 unmountOnExit: true, 409 get children() { 410 return createComponent(Paper, { 411 elevation: 2, 412 sx: { 413 m: 1, 414 p: 2 415 }, 416 get children() { 417 return [createComponent(Typography, { 418 variant: "h6", 419 sx: { 420 mb: 2 421 }, 422 get children() { 423 return ["Quick Edit: ", memo(() => doc.type), " v", memo(() => doc.version)]; 424 } 425 }), createComponent(Stack, { 426 spacing: 2, 427 get children() { 428 return [createComponent(Stack, { 429 direction: "row", 430 spacing: 2, 431 get children() { 432 return [createComponent(TextField, { 433 label: "Type", 434 get value() { 435 var _a; 436 return ((_a = editingDoc()) == null ? void 0 : _a.type) || ""; 437 }, 438 onChange: (e) =>
438 setEditingDoc((prev) => prev ? { 439 ...prev, 440 type: e.target.value 441 } : null), 442 size: "small", 443 sx: { 444 minWidth: 150 445 } 446 }), createComponent(TextField, { 447 label: "Version", 448 get value() { 449 var _a; 450 return ((_a = editingDoc()) == null ? void 0 : _a.version) || ""; 451 }, 452 onChange: (e) => setEditingDoc((prev) => prev ? { 453 ...prev, 454 version: e.target.value 455 } : null),
456 size: "small", 457 sx: { 458 minWidth: 120 459 } 460 }), createComponent(FormControl, { 461 size: "small", 462 sx: { 463 minWidth: 120 464 }, 465 get children() { 466 return [createComponent(InputLabel, { 467 children: "Status" 468 }), createComponent(Select, { 469 get value() { 470 var _a; 471 return ((_a = editingDoc()) == null ? void 0 : _a.status) || "draft"; 472 }, 473 onChange: (e) => setEditingDoc((prev) => prev ? { 474 ...prev, 475 status: e.target.value 476 } : null),
477 label: "Status", 478 get children() { 479 return [createComponent(MenuItem, { 480 value: "draft", 481 children: "Draft" 482 }), createComponent(MenuItem, { 483 value: "published", 484 children: "Published" 485 })]; 486 } 487 })]; 488 } 489 })]; 490 } 491 }), createComponent(Stack, { 492 direction: "row", 493 spacing: 2, 494 justifyContent: "flex-end", 495 get children() { 496 return [createComponent(AppButton, { 497 intent: "secondary", 498 onClick: handleCancelEdit, 499 children: "Cancel" 500 }), createComponent(AppButton, { 501 intent: "primary", 502 onClick: handleSaveEdit, 503 children: "Save" 504 })]; 505 } 506 })]; 507 } 508 })]; 509 } 510 }); 511 } 512 }); 513 } 514 }); 515 } 516 })] 517 }); 518 }, 519 get children() { 520 return createComponent(TableRow, { 521 get children() { 522 return createComponent(TableCell, { 523 colSpan: 5, 524 sx: { 525 textAlign: "center", 526 py: 4 527 }, 528 get children() { 529 return createComponent(CircularProgress, {}); 530 } 531 }); 532 } 533 }); 534 } 535 }); 536 } 537 })]; 538 } 539 }); 540 } 541 }); 542 } 543 })]; 544 } 545 }); 546 } 547 })]; 548 } 549 }); 550} 551export { 552 ContentDocListPage as default 553};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.