This commit is contained in:
mindol1004
2024-09-13 15:54:19 +09:00
parent ea69accedc
commit 4bfda23a47
16 changed files with 257 additions and 3513 deletions

View File

@@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.spring.domain.schedule.dto.ReScheduleJobRequest;
@@ -29,8 +30,11 @@ public class ScheduleJobApi {
private final ScheduleControlService scheduleControlService;
@GetMapping
public List<ScheduleJobResponse> getAllJobs() {
return findScheduleJobService.getAllJobs();
public List<ScheduleJobResponse> getAllJobs(
@RequestParam(required = false) String groupName,
@RequestParam(required = false) String jobName
) {
return findScheduleJobService.getAllJobs(groupName, jobName);
}
@GetMapping("/groups")

View File

@@ -12,7 +12,7 @@ public class ScheduleJobResponse {
private final String name; // 작업의 이름
private final String group; // 작업이 속한 그룹의 이름
private final String description; // 작업에 대한 설명 (JobDetail에서 제공)
private final String schedule; // 다음 실행 시간 (Trigger에서 제공)
private final String cronExpression; // cron
private final String status; // 현재 트리거의 상태 (TriggerState에서 제공)
private final String jobClass; // 작업의 클래스 이름 (JobDetail에서 제공)
private final String jobDataMap; // 작업에 대한 데이터 맵 (JobDetail에서 제공, 직렬화된 형태로 저장)

View File

@@ -6,9 +6,11 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
@@ -27,47 +29,85 @@ public class FindScheduleJobService {
private final Scheduler scheduler;
public List<ScheduleJobResponse> getAllJobs() {
public List<ScheduleJobResponse> getAllJobs(String groupName, String jobName) {
try {
return scheduler.getJobGroupNames().stream()
.flatMap(groupName -> {
try {
return scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName)).stream();
} catch (SchedulerException e) {
return Stream.empty();
}
})
.map(jobKey -> {
try {
return createSchedule(jobKey);
} catch (SchedulerException e) {
return null;
}
})
return getFilteredJobKeys(groupName, jobName)
.map(this::createScheduleSafely)
.filter(Objects::nonNull)
.collect(Collectors.toList());
} catch (SchedulerException e) {
return Collections.emptyList();
}
}
private Stream<JobKey> getFilteredJobKeys(String groupName, String jobName) throws SchedulerException {
return scheduler.getJobGroupNames().stream()
.filter(group -> isGroupMatched(group, groupName))
.flatMap(this::getJobKeysForGroup)
.filter(jobKey -> isJobMatched(jobKey, jobName));
}
private boolean isGroupMatched(String group, String groupName) {
return groupName == null || groupName.isEmpty() || group.equals(groupName);
}
private Stream<JobKey> getJobKeysForGroup(String group) {
try {
return scheduler.getJobKeys(GroupMatcher.jobGroupEquals(group)).stream();
} catch (SchedulerException e) {
return Stream.empty();
}
}
private boolean isJobMatched(JobKey jobKey, String jobName) {
return jobName == null || jobName.isEmpty() || jobKey.getName().equals(jobName);
}
private ScheduleJobResponse createScheduleSafely(JobKey jobKey) {
try {
return createSchedule(jobKey);
} catch (SchedulerException e) {
return null;
}
}
private ScheduleJobResponse createSchedule(JobKey jobKey) throws SchedulerException {
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
Trigger trigger = scheduler.getTriggersOfJob(jobKey).stream().findFirst().orElse(null);
Optional<Trigger> trigger = Optional.ofNullable(scheduler.getTriggersOfJob(jobKey).stream().findFirst().orElse(null));
return new ScheduleJobResponse(
jobKey.getName(),
jobKey.getGroup(),
jobDetail.getDescription(),
trigger != null ? trigger.getNextFireTime().toString() : "N/A",
trigger != null ? scheduler.getTriggerState(trigger.getKey()).name() : "UNKNOWN",
getCronExpression(trigger),
getTriggerState(trigger),
jobDetail.getJobClass().getName(),
jobDetail.getJobDataMap().toString(),
trigger != null ? trigger.getClass().getSimpleName() : "UNKNOWN",
trigger != null ? convertToLocalDateTime(trigger.getNextFireTime()) : null,
trigger != null ? convertToLocalDateTime(trigger.getPreviousFireTime()) : null
trigger.map(t -> t.getClass().getSimpleName()).orElse("UNKNOWN"),
trigger.map(Trigger::getNextFireTime).map(this::convertToLocalDateTime).orElse(null),
trigger.map(Trigger::getPreviousFireTime).map(this::convertToLocalDateTime).orElse(null)
);
}
private String getTriggerState(Optional<Trigger> trigger) {
return trigger.map(t -> {
try {
return scheduler.getTriggerState(t.getKey()).name();
} catch (SchedulerException e) {
return "UNKNOWN";
}
}).orElse("UNKNOWN");
}
private String getCronExpression(Optional<Trigger> trigger) {
return trigger.map(t -> {
if (t instanceof CronTrigger) {
return ((CronTrigger) t).getCronExpression();
}
return t.getScheduleBuilder().toString();
}).orElse("N/A");
}
private LocalDateTime convertToLocalDateTime(Date date) {
if (date == null) return null;
return date.toInstant()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -426,7 +426,6 @@ h6 {
}
.header .search-form input {
border: 0;
font-size: 14px;
color: #012970;
border: 1px solid rgba(1, 41, 112, 0.2);
@@ -736,7 +735,6 @@ h6 {
font-size: 14px;
font-weight: 600;
color: #012970;
transition: 0.3;
padding: 10px 0 10px 40px;
transition: 0.3s;
}
@@ -1133,7 +1131,6 @@ h6 {
border-radius: 0;
box-shadow: none;
font-size: 14px;
border-radius: 0;
}
.contact .php-email-form input:focus,
@@ -1230,4 +1227,4 @@ h6 {
text-align: center;
font-size: 13px;
color: #012970;
}
}

View File

@@ -1,7 +1,7 @@
import apiClient from '../common/axios-instance.js';
export const getAllJobs = async () => {
const response = await apiClient.get('/api/schedule');
export const getAllJobs = async (searchParams) => {
const response = await apiClient.get('/api/schedule', { params: searchParams });
return response.data;
}

View File

@@ -0,0 +1,65 @@
import {getAllJobs} from '../../apis/schedule-api.js';
document.addEventListener('DOMContentLoaded', () => {
const searchForm = document.getElementById('searchForm');
const tableBody = document.querySelector('tbody');
searchForm.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(searchForm);
const searchParams = new URLSearchParams(formData);
const response = await getAllJobs(searchParams);
updateTable(response.data);
});
function updateTable(jobs) {
tableBody.innerHTML = '';
jobs.forEach(job => {
const row = `
<tr>
<td>${job.group}</td>
<td>${job.name}</td>
<td>${job.description || '-'}</td>
<td>${job.cronExpression}</td>
<td>${formatDateTime(job.nextFireTime)}</td>
<td>${formatDateTime(job.previousFireTime)}</td>
<td class="text-center">
<span class="badge ${getStatusBadgeClass(job.status)} w-100 py-2">${job.status}</span>
</td>
<td class="text-center">
<span class="badge bg-secondary w-100 py-2"><i class="bi bi-eye"></i> 상세</span>
</td>
</tr>
`;
tableBody.insertAdjacentHTML('beforeend', row);
});
}
function formatDateTime(dateTimeString) {
if (!dateTimeString) return '-';
const date = new Date(dateTimeString);
return date.toLocaleString('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
function getStatusBadgeClass(status) {
switch (status) {
case 'NORMAL':
return 'bg-success';
case 'PAUSED':
return 'bg-warning';
case 'COMPLETE':
return 'bg-info';
case 'ERROR':
return 'bg-danger';
default:
return 'bg-secondary';
}
}
});

View File

@@ -1,3 +1,4 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:fragment="config" lang="ko" xml:lang="ko">
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
<link rel="stylesheet" th:href="@{/css/bootstrap-icons.css}">

View File

@@ -1,3 +1,4 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:fragment="footer" lang="ko" xml:lang="ko">
<footer class="bg-light text-center p-3">
<p>회사 정보: © 2023 회사명. 모든 권리 보유.</p>

View File

@@ -3,227 +3,30 @@
<header id="header" class="header fixed-top d-flex align-items-center">
<div class="d-flex align-items-center justify-content-between">
<a href="index.html" class="logo d-flex align-items-center">
<img src="assets/img/logo.png" alt="">
<span class="d-none d-lg-block">NiceAdmin</span>
</a>
<i class="bi bi-list toggle-sidebar-btn"></i>
</div><!-- End Logo -->
</div>
<div class="search-bar">
<form class="search-form d-flex align-items-center" method="POST" action="#">
<input type="text" name="query" placeholder="Search" title="Enter search keyword">
<button type="submit" title="Search"><i class="bi bi-search"></i></button>
</form>
</div><!-- End Search Bar -->
</div>
<nav class="header-nav ms-auto">
<ul class="d-flex align-items-center">
<li class="nav-item d-block d-lg-none">
<a class="nav-link nav-icon search-bar-toggle " href="#">
<i class="bi bi-search"></i>
</a>
</li><!-- End Search Icon-->
<li class="nav-item dropdown">
<a class="nav-link nav-icon" href="#" data-bs-toggle="dropdown">
<i class="bi bi-bell"></i>
<span class="badge bg-primary badge-number">4</span>
</a><!-- End Notification Icon -->
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow notifications">
<li class="dropdown-header">
You have 4 new notifications
<a href="#"><span class="badge rounded-pill bg-primary p-2 ms-2">View all</span></a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="bi bi-exclamation-circle text-warning"></i>
<div>
<h4>Lorem Ipsum</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>30 min. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="bi bi-x-circle text-danger"></i>
<div>
<h4>Atque rerum nesciunt</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>1 hr. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="bi bi-check-circle text-success"></i>
<div>
<h4>Sit rerum fuga</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>2 hrs. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="bi bi-info-circle text-primary"></i>
<div>
<h4>Dicta reprehenderit</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>4 hrs. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-footer">
<a href="#">Show all notifications</a>
</li>
</ul><!-- End Notification Dropdown Items -->
</li><!-- End Notification Nav -->
<li class="nav-item dropdown">
<a class="nav-link nav-icon" href="#" data-bs-toggle="dropdown">
<i class="bi bi-chat-left-text"></i>
<span class="badge bg-success badge-number">3</span>
</a><!-- End Messages Icon -->
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow messages">
<li class="dropdown-header">
You have 3 new messages
<a href="#"><span class="badge rounded-pill bg-primary p-2 ms-2">View all</span></a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="message-item">
<a href="#">
<img src="assets/img/messages-1.jpg" alt="" class="rounded-circle">
<div>
<h4>Maria Hudson</h4>
<p>Velit asperiores et ducimus soluta repudiandae labore officia est ut...</p>
<p>4 hrs. ago</p>
</div>
<li class="nav-item d-block d-lg-none">
<a class="nav-link nav-icon search-bar-toggle " href="#">
<i class="bi bi-search"></i>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="message-item">
<a href="#">
<img src="assets/img/messages-2.jpg" alt="" class="rounded-circle">
<div>
<h4>Anna Nelson</h4>
<p>Velit asperiores et ducimus soluta repudiandae labore officia est ut...</p>
<p>6 hrs. ago</p>
</div>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="message-item">
<a href="#">
<img src="assets/img/messages-3.jpg" alt="" class="rounded-circle">
<div>
<h4>David Muldon</h4>
<p>Velit asperiores et ducimus soluta repudiandae labore officia est ut...</p>
<p>8 hrs. ago</p>
</div>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-footer">
<a href="#">Show all messages</a>
</li>
</ul><!-- End Messages Dropdown Items -->
</li><!-- End Messages Nav -->
</li>
<li class="nav-item dropdown pe-3">
<a class="nav-link nav-profile d-flex align-items-center pe-0" href="#" data-bs-toggle="dropdown">
<img src="assets/img/profile-img.jpg" alt="Profile" class="rounded-circle">
<span class="d-none d-md-block dropdown-toggle ps-2">K. Anderson</span>
</a><!-- End Profile Iamge Icon -->
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow profile">
<li class="dropdown-header">
<h6>Kevin Anderson</h6>
<span>Web Designer</span>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item d-flex align-items-center" href="users-profile.html">
<i class="bi bi-person"></i>
<span>My Profile</span>
<a class="nav-link nav-profile d-flex align-items-center pe-0" href="#" data-bs-toggle="dropdown">
<img src="/images/user-id.png" alt="Profile" class="rounded-circle">
<span class="d-none d-md-block dropdown-toggle ps-2">K. Anderson</span>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item d-flex align-items-center" href="users-profile.html">
<i class="bi bi-gear"></i>
<span>Account Settings</span>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item d-flex align-items-center" href="pages-faq.html">
<i class="bi bi-question-circle"></i>
<span>Need Help?</span>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item d-flex align-items-center" href="#">
<i class="bi bi-box-arrow-right"></i>
<span>Sign Out</span>
</a>
</li>
</ul><!-- End Profile Dropdown Items -->
</li><!-- End Profile Nav -->
</li>
</ul>
</nav><!-- End Icons Navigation -->
</header><!-- End Header -->
</nav>
</header>
</html>

View File

@@ -1,237 +1,45 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:fragment="sidebar" lang="ko" xml:lang="ko">
<aside id="sidebar" class="sidebar">
<ul class="sidebar-nav" id="sidebar-nav">
<li class="nav-item">
<a class="nav-link " href="index.html">
<i class="bi bi-grid"></i>
<span>Dashboard</span>
</a>
</li><!-- End Dashboard Nav -->
<a class="nav-link " href="index.html"><i class="bi bi-grid"></i><span>Dashboard</span></a>
</li>
<li class="nav-item">
<a class="nav-link " href="index.html"><i class="bi bi-grid"></i><span>Quartz Job</span></a>
</li>
<li class="nav-item">
<a class="nav-link " href="index.html"><i class="bi bi-grid"></i><span>CronTrigger</span></a>
</li>
<li class="nav-item">
<a class="nav-link " href="index.html"><i class="bi bi-grid"></i><span>SimpleTrigger</span></a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" data-bs-target="#components-nav" data-bs-toggle="collapse" href="#">
<i class="bi bi-menu-button-wide"></i><span>Components</span><i class="bi bi-chevron-down ms-auto"></i>
<i class="bi bi-menu-button-wide"></i><span>Schedule</span><i class="bi bi-chevron-down ms-auto"></i>
</a>
<ul id="components-nav" class="nav-content collapse " data-bs-parent="#sidebar-nav">
<li>
<a href="components-alerts.html">
<i class="bi bi-circle"></i><span>Alerts</span>
</a>
</li>
<li>
<a href="components-accordion.html">
<i class="bi bi-circle"></i><span>Accordion</span>
</a>
</li>
<li>
<a href="components-badges.html">
<i class="bi bi-circle"></i><span>Badges</span>
</a>
</li>
<li>
<a href="components-breadcrumbs.html">
<i class="bi bi-circle"></i><span>Breadcrumbs</span>
</a>
</li>
<li>
<a href="components-buttons.html">
<i class="bi bi-circle"></i><span>Buttons</span>
</a>
</li>
<li>
<a href="components-cards.html">
<i class="bi bi-circle"></i><span>Cards</span>
</a>
</li>
<li>
<a href="components-carousel.html">
<i class="bi bi-circle"></i><span>Carousel</span>
</a>
</li>
<li>
<a href="components-list-group.html">
<i class="bi bi-circle"></i><span>List group</span>
</a>
</li>
<li>
<a href="components-modal.html">
<i class="bi bi-circle"></i><span>Modal</span>
</a>
</li>
<li>
<a href="components-tabs.html">
<i class="bi bi-circle"></i><span>Tabs</span>
</a>
</li>
<li>
<a href="components-pagination.html">
<i class="bi bi-circle"></i><span>Pagination</span>
</a>
</li>
<li>
<a href="components-progress.html">
<i class="bi bi-circle"></i><span>Progress</span>
</a>
</li>
<li>
<a href="components-spinners.html">
<i class="bi bi-circle"></i><span>Spinners</span>
</a>
</li>
<li>
<a href="components-tooltips.html">
<i class="bi bi-circle"></i><span>Tooltips</span>
</a>
</li>
<li>
<a href="components-alerts.html"><i class="bi bi-circle"></i><span>Alerts</span></a>
</li>
<li>
<a href="components-accordion.html"><i class="bi bi-circle"></i><span>Accordion</span></a>
</li>
</ul>
</li><!-- End Components Nav -->
<li class="nav-item">
<a class="nav-link collapsed" data-bs-target="#forms-nav" data-bs-toggle="collapse" href="#">
<i class="bi bi-journal-text"></i><span>Forms</span><i class="bi bi-chevron-down ms-auto"></i>
</a>
<ul id="forms-nav" class="nav-content collapse " data-bs-parent="#sidebar-nav">
<li>
<a href="forms-elements.html">
<i class="bi bi-circle"></i><span>Form Elements</span>
</a>
</li>
<li>
<a href="forms-layouts.html">
<i class="bi bi-circle"></i><span>Form Layouts</span>
</a>
</li>
<li>
<a href="forms-editors.html">
<i class="bi bi-circle"></i><span>Form Editors</span>
</a>
</li>
<li>
<a href="forms-validation.html">
<i class="bi bi-circle"></i><span>Form Validation</span>
</a>
</li>
</ul>
</li><!-- End Forms Nav -->
<li class="nav-item">
<a class="nav-link collapsed" data-bs-target="#tables-nav" data-bs-toggle="collapse" href="#">
<i class="bi bi-layout-text-window-reverse"></i><span>Tables</span><i class="bi bi-chevron-down ms-auto"></i>
</a>
<ul id="tables-nav" class="nav-content collapse " data-bs-parent="#sidebar-nav">
<li>
<a href="tables-general.html">
<i class="bi bi-circle"></i><span>General Tables</span>
</a>
</li>
<li>
<a href="tables-data.html">
<i class="bi bi-circle"></i><span>Data Tables</span>
</a>
</li>
</ul>
</li><!-- End Tables Nav -->
</li>
<li class="nav-item">
<a class="nav-link collapsed" data-bs-target="#charts-nav" data-bs-toggle="collapse" href="#">
<i class="bi bi-bar-chart"></i><span>Charts</span><i class="bi bi-chevron-down ms-auto"></i>
<i class="bi bi-bar-chart"></i><span>Charts</span><i class="bi bi-chevron-down ms-auto"></i>
</a>
<ul id="charts-nav" class="nav-content collapse " data-bs-parent="#sidebar-nav">
<li>
<a href="charts-chartjs.html">
<i class="bi bi-circle"></i><span>Chart.js</span>
</a>
</li>
<li>
<a href="charts-apexcharts.html">
<i class="bi bi-circle"></i><span>ApexCharts</span>
</a>
</li>
<li>
<a href="charts-echarts.html">
<i class="bi bi-circle"></i><span>ECharts</span>
</a>
</li>
<li>
<a href="charts-chartjs.html"><i class="bi bi-circle"></i><span>Chart.js</span></a>
</li>
<li>
<a href="charts-apexcharts.html"><i class="bi bi-circle"></i><span>ApexCharts</span></a>
</li>
</ul>
</li><!-- End Charts Nav -->
<li class="nav-item">
<a class="nav-link collapsed" data-bs-target="#icons-nav" data-bs-toggle="collapse" href="#">
<i class="bi bi-gem"></i><span>Icons</span><i class="bi bi-chevron-down ms-auto"></i>
</a>
<ul id="icons-nav" class="nav-content collapse " data-bs-parent="#sidebar-nav">
<li>
<a href="icons-bootstrap.html">
<i class="bi bi-circle"></i><span>Bootstrap Icons</span>
</a>
</li>
<li>
<a href="icons-remix.html">
<i class="bi bi-circle"></i><span>Remix Icons</span>
</a>
</li>
<li>
<a href="icons-boxicons.html">
<i class="bi bi-circle"></i><span>Boxicons</span>
</a>
</li>
</ul>
</li><!-- End Icons Nav -->
<li class="nav-heading">Pages</li>
<li class="nav-item">
<a class="nav-link collapsed" href="users-profile.html">
<i class="bi bi-person"></i>
<span>Profile</span>
</a>
</li><!-- End Profile Page Nav -->
<li class="nav-item">
<a class="nav-link collapsed" href="pages-faq.html">
<i class="bi bi-question-circle"></i>
<span>F.A.Q</span>
</a>
</li><!-- End F.A.Q Page Nav -->
<li class="nav-item">
<a class="nav-link collapsed" href="pages-contact.html">
<i class="bi bi-envelope"></i>
<span>Contact</span>
</a>
</li><!-- End Contact Page Nav -->
<li class="nav-item">
<a class="nav-link collapsed" href="pages-register.html">
<i class="bi bi-card-list"></i>
<span>Register</span>
</a>
</li><!-- End Register Page Nav -->
<li class="nav-item">
<a class="nav-link collapsed" href="pages-login.html">
<i class="bi bi-box-arrow-in-right"></i>
<span>Login</span>
</a>
</li><!-- End Login Page Nav -->
<li class="nav-item">
<a class="nav-link collapsed" href="pages-error-404.html">
<i class="bi bi-dash-circle"></i>
<span>Error 404</span>
</a>
</li><!-- End Error 404 Page Nav -->
<li class="nav-item">
<a class="nav-link collapsed" href="pages-blank.html">
<i class="bi bi-file-earmark"></i>
<span>Blank</span>
</a>
</li><!-- End Blank Page Nav -->
</li>
</ul>
</aside><!-- End Sidebar-->
</aside>
</html>

View File

@@ -6,53 +6,6 @@
<body>
<div th:replace="fragments/header::header"></div>
<div th:replace="fragments/left::sidebar"></div>
<main class="col-md-9 ml-sm-auto col-lg-10 px-4" id="main">
<h1 class="mt-5 pagetitle">스케줄 관리</h1>
<div class="mt-4">
<form action="/api/schedule/search" method="get" class="form-inline">
<div class="form-group mb-2">
<label for="groupName" class="sr-only">그룹명</label>
<input type="text" class="form-control" id="groupName" name="groupName" placeholder="그룹명 입력">
</div>
<div class="form-group mb-2 mx-2">
<label for="jobName" class="sr-only">작업명</label>
<input type="text" class="form-control" id="jobName" name="jobName" placeholder="작업명 입력">
</div>
<div class="form-group mb-2 mx-2">
<label for="status" class="sr-only">상태</label>
<select class="form-control" id="status" name="status">
<option value="">모두</option>
<option value="ACTIVE">활성</option>
<option value="PAUSED">일시 정지</option>
</select>
</div>
<button type="submit" class="btn btn-primary mb-2">검색</button>
</form>
</div>
<h2 class="mt-4">모든 작업</h2>
<table class="table">
<thead>
<tr>
<th>작업 이름</th>
<th>그룹 이름</th>
<th>상태</th>
<th>작업 조작</th>
</tr>
</thead>
<tbody>
<tr th:each="job : ${jobs}">
<td th:text="${job.name}"></td>
<td th:text="${job.group}"></td>
<td th:text="${job.status}"></td>
<td>
<button class="btn btn-warning" th:onclick="'pauseJob(\'' + ${job.group} + '\', \'' + ${job.name} + '\')'">일시 정지</button>
<button class="btn btn-success" th:onclick="'resumeJob(\'' + ${job.group} + '\', \'' + ${job.name} + '\')'">재개</button>
<button class="btn btn-danger" th:onclick="'triggerJob(\'' + ${job.group} + '\', \'' + ${job.name} + '\')'">트리거</button>
</td>
</tr>
</tbody>
</table>
</main>
<div layout:fragment="content"></div>
</body>
</html>

View File

@@ -1,57 +1,88 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layouts/layout}" lang="ko" xml:lang="ko">
layout:decorate="~{layouts/layout}"
layout:fragment="content" lang="ko" xml:lang="ko">
<head>
<title>Schedule - List</title>
</head>
<body>
<h1 class="mt-5">스케줄 관리</h1>
<div class="mt-4">
<form action="/api/schedule/search" method="get">
<div class="form-row">
<div class="form-group col-md-4">
<label for="groupName">그룹명</label>
<input type="text" class="form-control" id="groupName" name="groupName" placeholder="그룹명 입력">
<main id="main" class="main">
<div class="pagetitle">
<div class="row align-items-center">
<div class="col">
<h1><i class="bi bi-calendar3"></i> 스케줄 목록</h1>
</div>
<div class="form-group col-md-4">
<label for="jobName">작업명</label>
<input type="text" class="form-control" id="jobName" name="jobName" placeholder="작업명 입력">
</div>
<div class="form-group col-md-4">
<label for="status">상태</label>
<select class="form-control" id="status" name="status">
<option value="">모두</option>
<option value="ACTIVE">활성</option>
<option value="PAUSED">일시 정지</option>
</select>
<div class="col-auto">
<nav>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="index.html"></a></li>
<li class="breadcrumb-item active">스케줄</li>
</ol>
</nav>
</div>
</div>
<button type="submit" class="btn btn-primary">검색</button>
</form>
</div>
<h2 class="mt-4">모든 작업</h2>
<table class="table">
<thead>
<tr>
<th>작업 이름</th>
<th>그룹 이름</th>
<th>상태</th>
<th>작업 조작</th>
</tr>
</thead>
<tbody>
<tr th:each="job : ${jobs}">
<td th:text="${job.name}"></td>
<td th:text="${job.group}"></td>
<td th:text="${job.status}"></td>
<td>
<button class="btn btn-warning" th:onclick="'pauseJob(\'' + ${job.group} + '\', \'' + ${job.name} + '\')'">일시 정지</button>
<button class="btn btn-success" th:onclick="'resumeJob(\'' + ${job.group} + '\', \'' + ${job.name} + '\')'">재개</button>
<button class="btn btn-danger" th:onclick="'triggerJob(\'' + ${job.group} + '\', \'' + ${job.name} + '\')'">트리거</button>
</td>
</tr>
</tbody>
</table>
</div>
<section class="section">
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<h5 class="card-title">
<i class="bi bi-search"></i> 스케줄 검색
</h5>
<form id="searchForm" class="row g-3">
<div class="col-md-5">
<div class="form-floating">
<input type="text" class="form-control" id="groupName" name="groupName" placeholder="그룹명">
<label for="groupName"><i class="bi bi-people"></i> 그룹명</label>
</div>
</div>
<div class="col-md-5">
<div class="form-floating">
<input type="text" class="form-control" id="jobName" name="jobName" placeholder="잡 이름">
<label for="jobName"><i class="bi bi-briefcase"></i> 잡 이름</label>
</div>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary h-100 w-100">
<i class="bi bi-search"></i> 검색
</button>
</div>
</form>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title">
<i class="bi bi-list-ul"></i> 스케줄 목록
</h5>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th class="col-1 text-nowrap"><i class="bi bi-people"></i> 그룹</th>
<th class="col-1 text-nowrap"><i class="bi bi-briefcase"></i> 잡 이름</th>
<th class="col-2 text-nowrap"><i class="bi bi-info-circle"></i> 설명</th>
<th class="col-2 text-nowrap"><i class="bi bi-calendar-event"></i> 스케줄</th>
<th class="col-2 text-nowrap"><i class="bi bi-clock"></i> 다음 실행</th>
<th class="col-2 text-nowrap"><i class="bi bi-clock-history"></i> 이전 실행</th>
<th class="col-1 text-nowrap"><i class="bi bi-activity"></i> 상태</th>
<th class="col-2 text-nowrap"><i class="bi bi-gear"></i> 액션</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</section>
<script type="module" th:src="@{/js/pages/schedule/schedule-list.js}" defer></script>
</main>
</body>
</html>