done dashboard
This commit is contained in:
@@ -14,7 +14,6 @@ Tags Tạo và quản lý các Thẻ (nhãn từ khóa tìm kiếm nhanh).
|
||||
Add New Tải tệp tin mới lên máy chủ.
|
||||
(Done) 4. Pages (Trang) All Pages Quản lý các trang tĩnh (ví dụ: Trang chủ, Trang liên hệ, Giới thiệu bệnh viện, Giờ làm việc...).
|
||||
Add New Tạo trang tĩnh mới.
|
||||
5. Comments (Bình luận) (Không có) Quản lý bình luận của người đọc (Phê duyệt, Trả lời, Đánh dấu Spam, Xóa tạm/Xóa vĩnh viễn).
|
||||
6. Appearance (Giao diện) Themes Cài đặt, kích hoạt hoặc xóa các giao diện hiển thị của website.
|
||||
Customize Chỉnh sửa giao diện trực quan theo thời gian thực (Header, Footer, Colors, Font, v.v.).
|
||||
Widgets Quản lý các khối nội dung ở Sidebar hoặc Footer.
|
||||
@@ -30,7 +29,7 @@ Profile Chỉnh sửa thông tin cá nhân của tài khoản đang đăng nhậ
|
||||
Import / Export Nhập/Xuất toàn bộ bài viết, trang, media sang file .xml để sao lưu hoặc chuyển host.
|
||||
Site Health Kiểm tra sức khỏe hệ thống (phiên bản PHP, MySQL, các lỗi bảo mật).
|
||||
Export / Erase Personal Data Xuất hoặc xóa dữ liệu cá nhân của người dùng để tuân thủ luật bảo mật (GDPR).
|
||||
10. Settings (Cài đặt) General Thiết lập tên website, câu khẩu hiệu, địa chỉ email admin, múi giờ, định dạng ngày tháng.
|
||||
(done) 10. Settings (Cài đặt) General Thiết lập tên website, câu khẩu hiệu, địa chỉ email admin, múi giờ, định dạng ngày tháng.
|
||||
Writing Cấu hình mặc định khi soạn thảo văn bản và gửi bài viết qua email.
|
||||
Reading Thiết lập trang chủ hiển thị, số lượng bài viết tối đa trên một trang blog, chặn công cụ tìm kiếm.
|
||||
Discussion Cấu hình bình luận (yêu cầu phê duyệt, chặn từ ngữ nhạy cảm).
|
||||
|
||||
+76
-1
@@ -1,11 +1,25 @@
|
||||
package com.sisvietnamvn.web.controller.manage;
|
||||
|
||||
import com.sisvietnamvn.web.domain.Post;
|
||||
import com.sisvietnamvn.web.domain.PageStatus;
|
||||
import com.sisvietnamvn.web.repository.PostRepository;
|
||||
import com.sisvietnamvn.web.repository.PageRepository;
|
||||
import com.sisvietnamvn.web.service.PostService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import com.sun.management.OperatingSystemMXBean;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Controller for the admin dashboard index page.
|
||||
* Serves the main "/manage" landing page.
|
||||
@@ -15,8 +29,69 @@ import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
@PreAuthorize("hasAnyAuthority(\"" + AuthoritiesConstants.ADMIN + "\", \"" + AuthoritiesConstants.EDITOR + "\", \"" + AuthoritiesConstants.AUTHOR + "\", \"" + AuthoritiesConstants.CONTRIBUTOR + "\", \"" + AuthoritiesConstants.SUBSCRIBER + "\", \"" + AuthoritiesConstants.USER + "\")")
|
||||
public class ManageDashboardController {
|
||||
|
||||
private final PostRepository postRepository;
|
||||
private final PageRepository pageRepository;
|
||||
private final PostService postService;
|
||||
|
||||
public ManageDashboardController(PostRepository postRepository, PageRepository pageRepository, PostService postService) {
|
||||
this.postRepository = postRepository;
|
||||
this.pageRepository = pageRepository;
|
||||
this.postService = postService;
|
||||
}
|
||||
|
||||
@GetMapping({"", "/"})
|
||||
public String index() {
|
||||
public String index(Model model) {
|
||||
// At a Glance stats
|
||||
long postCount = postRepository.count();
|
||||
long pageCount = pageRepository.count();
|
||||
model.addAttribute("postCount", postCount);
|
||||
model.addAttribute("pageCount", pageCount);
|
||||
|
||||
// Recent Activity (Top 5 posts)
|
||||
List<Post> recentPosts = postRepository.findAllByOrderByCreatedDateDesc().stream()
|
||||
.limit(5)
|
||||
.collect(Collectors.toList());
|
||||
model.addAttribute("recentPosts", recentPosts);
|
||||
|
||||
// Telemetry Stats
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
long totalRam = runtime.totalMemory();
|
||||
long freeRam = runtime.freeMemory();
|
||||
long usedRam = totalRam - freeRam;
|
||||
int ramPercentage = totalRam > 0 ? (int) ((usedRam * 100.0f) / totalRam) : 0;
|
||||
model.addAttribute("ramPercentage", ramPercentage);
|
||||
model.addAttribute("usedRamMb", usedRam / (1024 * 1024));
|
||||
model.addAttribute("totalRamMb", totalRam / (1024 * 1024));
|
||||
|
||||
File root = new File("/");
|
||||
long totalSpace = root.getTotalSpace();
|
||||
long freeSpace = root.getUsableSpace();
|
||||
long usedSpace = totalSpace - freeSpace;
|
||||
int ioPercentage = totalSpace > 0 ? (int) ((usedSpace * 100.0f) / totalSpace) : 0;
|
||||
model.addAttribute("ioPercentage", ioPercentage);
|
||||
model.addAttribute("usedSpaceGb", usedSpace / (1024 * 1024 * 1024));
|
||||
model.addAttribute("totalSpaceGb", totalSpace / (1024 * 1024 * 1024));
|
||||
|
||||
try {
|
||||
OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
|
||||
double cpuLoad = osBean.getCpuLoad(); // returns 0.0 to 1.0. Returns < 0 if not available.
|
||||
int cpuPercentage = cpuLoad >= 0 ? (int) (cpuLoad * 100) : 0;
|
||||
model.addAttribute("cpuPercentage", cpuPercentage);
|
||||
} catch (Exception e) {
|
||||
model.addAttribute("cpuPercentage", 0);
|
||||
}
|
||||
|
||||
return "manage/index";
|
||||
}
|
||||
|
||||
@PostMapping("/quick-draft")
|
||||
public String quickDraft(@RequestParam("title") String title, @RequestParam("content") String content) {
|
||||
Post post = new Post();
|
||||
post.setTitle(title);
|
||||
post.setContent(content);
|
||||
post.setStatus(PageStatus.DRAFT);
|
||||
|
||||
postService.save(post);
|
||||
return "redirect:/manage";
|
||||
}
|
||||
}
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.sisvietnamvn.web.controller.manage;
|
||||
|
||||
import com.sisvietnamvn.web.service.SettingService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Controller for the admin Updates page.
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/manage/updates")
|
||||
@PreAuthorize("hasAnyAuthority(\"" + AuthoritiesConstants.ADMIN + "\", \"" + AuthoritiesConstants.EDITOR + "\")")
|
||||
public class ManageUpdatesController {
|
||||
|
||||
private final SettingService settingService;
|
||||
private static final String LATEST_VERSION = "4.0.7";
|
||||
|
||||
public ManageUpdatesController(SettingService settingService) {
|
||||
this.settingService = settingService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String updates(Model model) {
|
||||
Map<String, String> settings = settingService.getAllAsMap();
|
||||
String currentVersion = settings.getOrDefault("core_version", "4.0.6");
|
||||
|
||||
boolean updateAvailable = !LATEST_VERSION.equals(currentVersion);
|
||||
|
||||
model.addAttribute("coreVersionCurrent", currentVersion);
|
||||
model.addAttribute("coreVersionLatest", LATEST_VERSION);
|
||||
model.addAttribute("coreUpdateAvailable", updateAvailable);
|
||||
|
||||
// Plugin mock logic
|
||||
String pluginSeoVersion = settings.getOrDefault("plugin_seo_version", "1.0.0");
|
||||
model.addAttribute("pluginSeoVersion", pluginSeoVersion);
|
||||
model.addAttribute("pluginSeoUpdateAvailable", !"1.1.2".equals(pluginSeoVersion));
|
||||
|
||||
return "manage/updates";
|
||||
}
|
||||
|
||||
@PostMapping("/core")
|
||||
public String updateCore(RedirectAttributes redirectAttributes) {
|
||||
settingService.setValue("core_version", LATEST_VERSION);
|
||||
redirectAttributes.addFlashAttribute("successMessage", "System successfully updated to version " + LATEST_VERSION);
|
||||
return "redirect:/manage/updates";
|
||||
}
|
||||
|
||||
@PostMapping("/plugins")
|
||||
public String updatePlugins(RedirectAttributes redirectAttributes) {
|
||||
settingService.setValue("plugin_seo_version", "1.1.2");
|
||||
redirectAttributes.addFlashAttribute("successMessage", "Selected plugins successfully updated.");
|
||||
return "redirect:/manage/updates";
|
||||
}
|
||||
}
|
||||
@@ -40,11 +40,19 @@
|
||||
<!-- Divider -->
|
||||
<hr class="sidebar-divider my-0">
|
||||
|
||||
<!-- Nav Item - Dashboard -->
|
||||
<!-- Nav Item - Dashboard Collapse Menu -->
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" th:href="@{/manage}">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseDashboard"
|
||||
aria-expanded="true" aria-controls="collapseDashboard">
|
||||
<i class="fas fa-fw fa-tachometer-alt"></i>
|
||||
<span>Dashboard</span></a>
|
||||
<span>Dashboard</span>
|
||||
</a>
|
||||
<div id="collapseDashboard" class="collapse" aria-labelledby="headingDashboard" data-parent="#accordionSidebar">
|
||||
<div class="bg-white py-2 collapse-inner rounded">
|
||||
<a class="collapse-item" th:href="@{/manage}">Home</a>
|
||||
<a class="collapse-item" th:href="@{/manage/updates}">Updates</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Divider -->
|
||||
|
||||
@@ -11,145 +11,110 @@
|
||||
<!-- Page Heading -->
|
||||
<div class="d-sm-flex align-items-center justify-content-between mb-4">
|
||||
<h1 class="h3 mb-0 text-gray-800">Dashboard</h1>
|
||||
<a href="#" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm"><i
|
||||
class="fas fa-download fa-sm text-white-50"></i> Generate Report</a>
|
||||
</div>
|
||||
|
||||
<!-- Content Row -->
|
||||
<div class="row">
|
||||
|
||||
<!-- Earnings (Monthly) Card Example -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-primary shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
|
||||
Earnings (Monthly)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">$40,000</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-calendar fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Earnings (Annual) Card Example -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-success shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">
|
||||
Earnings (Annual)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">$215,000</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-dollar-sign fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tasks Card Example -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-info shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Tasks
|
||||
</div>
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-auto">
|
||||
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">50%</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="progress progress-sm mr-2">
|
||||
<div class="progress-bar bg-info" role="progressbar"
|
||||
style="width: 50%" aria-valuenow="50" aria-valuemin="0"
|
||||
aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-clipboard-list fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pending Requests Card Example -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-warning shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
|
||||
Pending Requests</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">18</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-comments fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content Row -->
|
||||
<div class="row">
|
||||
|
||||
<!-- Content Column -->
|
||||
<div class="col-lg-12 mb-4">
|
||||
|
||||
<!-- Project Card Example -->
|
||||
<!-- Server Health -->
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Projects</h6>
|
||||
<h6 class="m-0 font-weight-bold text-primary">Site Health & Telemetry</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h4 class="small font-weight-bold">Server Migration <span
|
||||
class="float-right">20%</span></h4>
|
||||
<h4 class="small font-weight-bold">CPU Load <span
|
||||
class="float-right" th:text="${cpuPercentage} + '%'">0%</span></h4>
|
||||
<div class="progress mb-4">
|
||||
<div class="progress-bar bg-danger" role="progressbar" style="width: 20%"
|
||||
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
<div th:class="'progress-bar ' + (${cpuPercentage} > 80 ? 'bg-danger' : (${cpuPercentage} > 50 ? 'bg-warning' : 'bg-success'))"
|
||||
role="progressbar" th:style="'width: ' + ${cpuPercentage} + '%'"
|
||||
th:aria-valuenow="${cpuPercentage}" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<h4 class="small font-weight-bold">Sales Tracking <span
|
||||
class="float-right">40%</span></h4>
|
||||
|
||||
<h4 class="small font-weight-bold">Memory (RAM) <span
|
||||
class="float-right" th:text="${usedRamMb} + ' MB / ' + ${totalRamMb} + ' MB (' + ${ramPercentage} + '%)'">0 MB / 0 MB</span></h4>
|
||||
<div class="progress mb-4">
|
||||
<div class="progress-bar bg-warning" role="progressbar" style="width: 40%"
|
||||
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
<div th:class="'progress-bar ' + (${ramPercentage} > 80 ? 'bg-danger' : (${ramPercentage} > 50 ? 'bg-warning' : 'bg-info'))"
|
||||
role="progressbar" th:style="'width: ' + ${ramPercentage} + '%'"
|
||||
th:aria-valuenow="${ramPercentage}" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<h4 class="small font-weight-bold">Customer Database <span
|
||||
class="float-right">60%</span></h4>
|
||||
|
||||
<h4 class="small font-weight-bold">Disk Space (I/O) <span
|
||||
class="float-right" th:text="${usedSpaceGb} + ' GB / ' + ${totalSpaceGb} + ' GB (' + ${ioPercentage} + '%)'">0 GB / 0 GB</span></h4>
|
||||
<div class="progress mb-4">
|
||||
<div class="progress-bar" role="progressbar" style="width: 60%"
|
||||
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<h4 class="small font-weight-bold">Payout Details <span
|
||||
class="float-right">80%</span></h4>
|
||||
<div class="progress mb-4">
|
||||
<div class="progress-bar bg-info" role="progressbar" style="width: 80%"
|
||||
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<h4 class="small font-weight-bold">Account Setup <span
|
||||
class="float-right">Complete!</span></h4>
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-success" role="progressbar" style="width: 100%"
|
||||
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
<div th:class="'progress-bar ' + (${ioPercentage} > 80 ? 'bg-danger' : (${ioPercentage} > 50 ? 'bg-warning' : 'bg-primary'))"
|
||||
role="progressbar" th:style="'width: ' + ${ioPercentage} + '%'"
|
||||
th:aria-valuenow="${ioPercentage}" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Draft -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Quick Draft</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form th:action="@{/manage/quick-draft}" method="post">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="title" placeholder="Title" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<textarea class="form-control" name="content" rows="4" placeholder="What's on your mind?"></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-outline-primary btn-sm">Save Draft</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 mb-4">
|
||||
<!-- At a Glance -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">At a Glance</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row text-center mb-3">
|
||||
<div class="col-6">
|
||||
<i class="fas fa-file-alt fa-2x text-gray-300 mb-2"></i>
|
||||
<h4 class="h5 text-gray-800"><span th:text="${postCount}">0</span> Posts</h4>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<i class="fas fa-file fa-2x text-gray-300 mb-2"></i>
|
||||
<h4 class="h5 text-gray-800"><span th:text="${pageCount}">0</span> Pages</h4>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-muted text-center mb-0 small">Running Spring Boot 4.0.6 (Java 21)</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Activity -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Recent Activity</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center" th:each="post : ${recentPosts}">
|
||||
<div>
|
||||
<span class="text-muted small mr-2" th:text="${#temporals.format(post.createdDate, 'dd/MM/yyyy HH:mm')}">Date</span>
|
||||
<a th:href="@{/manage/posts/{id}/edit(id=${post.id})}" th:text="${post.title}">Post Title</a>
|
||||
</div>
|
||||
<span class="badge badge-pill"
|
||||
th:classappend="${post.status == 'PUBLISHED' ? 'badge-success' : (post.status == 'DRAFT' ? 'badge-secondary' : 'badge-warning')}"
|
||||
th:text="${post.status}">DRAFT</span>
|
||||
</li>
|
||||
<li class="list-group-item text-muted text-center small" th:if="${#lists.isEmpty(recentPosts)}">
|
||||
No recent activity
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{fragments/manage-layout}">
|
||||
|
||||
<head>
|
||||
<title>System Updates</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div layout:fragment="content">
|
||||
<!-- Page Heading -->
|
||||
<div class="d-sm-flex align-items-center justify-content-between mb-4">
|
||||
<h1 class="h3 mb-0 text-gray-800">System Updates</h1>
|
||||
</div>
|
||||
|
||||
<!-- Success Message -->
|
||||
<div th:if="${successMessage}" class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
<span th:text="${successMessage}"></span>
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Core Update -->
|
||||
<div class="col-lg-12 mb-4">
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary" th:text="${coreUpdateAvailable} ? 'An updated version of the system is available.' : 'You have the latest version of the system.'">An updated version of the system is available.</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Important:</strong> Before updating, please back up your database and files. For help with updates, visit the <a href="#">Updating Documentation</a>.</p>
|
||||
|
||||
<div th:if="${coreUpdateAvailable}" class="alert alert-warning">
|
||||
<strong>Update Available:</strong> You are currently running version <span th:text="${coreVersionCurrent}">X</span>.
|
||||
Version <span th:text="${coreVersionLatest}">Y</span> is available.
|
||||
</div>
|
||||
<div th:unless="${coreUpdateAvailable}" class="alert alert-success">
|
||||
<strong>Up to Date:</strong> You are currently running version <span th:text="${coreVersionCurrent}">X</span>. No core updates are available.
|
||||
</div>
|
||||
|
||||
<form th:action="@{/manage/updates/core}" method="post">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
|
||||
<button type="submit" class="btn btn-primary" th:disabled="${!coreUpdateAvailable}">Update Now</button>
|
||||
</form>
|
||||
<p class="text-muted small mt-2">While your site is being updated, it will be in maintenance mode. As soon as your updates are complete, your site will return to normal.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Plugins Update -->
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Plugins</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p th:if="${pluginSeoUpdateAvailable}">The following plugins have new versions available. Check the ones you want to update and then click "Update Plugins".</p>
|
||||
<p th:unless="${pluginSeoUpdateAvailable}">Your plugins are all up to date.</p>
|
||||
|
||||
<form th:action="@{/manage/updates/plugins}" method="post" th:if="${pluginSeoUpdateAvailable}">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input type="checkbox" checked disabled></th>
|
||||
<th>Plugin Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><input type="checkbox" checked disabled></td>
|
||||
<td><strong>Sample SEO Plugin</strong><br><small>You have version <span th:text="${pluginSeoVersion}">1.0.0</span>. Update to 1.1.2.</small></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="submit" class="btn btn-secondary btn-sm">Update Selected Plugins</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Themes & Translations Update -->
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Themes</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Your themes are all up to date.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Translations</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Your translations are all up to date.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user