Merge pull request 'feat(ui): 배치 작업 목록 한글 표시명 추가 (#40)' (#43) from feature/ISSUE-40-job-display-name into develop
This commit is contained in:
커밋
a9e8df7e89
@ -28,6 +28,7 @@
|
|||||||
- 배치 작업 목록 UX 개선: 상태 필터, 카드/테이블 뷰, 정렬, 실행 중 강조 (#33)
|
- 배치 작업 목록 UX 개선: 상태 필터, 카드/테이블 뷰, 정렬, 실행 중 강조 (#33)
|
||||||
- 재시도 초과 레코드 초기화 API/UI 추가
|
- 재시도 초과 레코드 초기화 API/UI 추가
|
||||||
- IMO 기반 Risk 상세 조회 bypass API 추가 (#39)
|
- IMO 기반 Risk 상세 조회 bypass API 추가 (#39)
|
||||||
|
- 배치 작업 목록 한글 표시명 추가 (#40)
|
||||||
|
|
||||||
### 수정
|
### 수정
|
||||||
- 자동 재수집 JobParameter 오버플로우 수정 (VARCHAR 2500 제한 해결)
|
- 자동 재수집 JobParameter 오버플로우 수정 (VARCHAR 2500 제한 해결)
|
||||||
|
|||||||
@ -235,6 +235,7 @@ export interface LastExecution {
|
|||||||
|
|
||||||
export interface JobDetailDto {
|
export interface JobDetailDto {
|
||||||
jobName: string;
|
jobName: string;
|
||||||
|
displayName: string | null;
|
||||||
lastExecution: LastExecution | null;
|
lastExecution: LastExecution | null;
|
||||||
scheduleCron: string | null;
|
scheduleCron: string | null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,9 +75,16 @@ export default function Jobs() {
|
|||||||
|
|
||||||
usePoller(loadJobs, POLLING_INTERVAL);
|
usePoller(loadJobs, POLLING_INTERVAL);
|
||||||
|
|
||||||
|
/** displayName 우선, 없으면 jobName */
|
||||||
|
const getJobLabel = useCallback((job: JobDetailDto) => job.displayName || job.jobName, []);
|
||||||
|
|
||||||
const statusCounts = useMemo(() => {
|
const statusCounts = useMemo(() => {
|
||||||
const searchFiltered = searchTerm.trim()
|
const searchFiltered = searchTerm.trim()
|
||||||
? jobs.filter((job) => job.jobName.toLowerCase().includes(searchTerm.toLowerCase()))
|
? jobs.filter((job) => {
|
||||||
|
const term = searchTerm.toLowerCase();
|
||||||
|
return job.jobName.toLowerCase().includes(term)
|
||||||
|
|| (job.displayName?.toLowerCase().includes(term) ?? false);
|
||||||
|
})
|
||||||
: jobs;
|
: jobs;
|
||||||
|
|
||||||
return STATUS_TABS.reduce<Record<StatusFilterKey, number>>(
|
return STATUS_TABS.reduce<Record<StatusFilterKey, number>>(
|
||||||
@ -94,14 +101,17 @@ export default function Jobs() {
|
|||||||
|
|
||||||
if (searchTerm.trim()) {
|
if (searchTerm.trim()) {
|
||||||
const term = searchTerm.toLowerCase();
|
const term = searchTerm.toLowerCase();
|
||||||
result = result.filter((job) => job.jobName.toLowerCase().includes(term));
|
result = result.filter((job) =>
|
||||||
|
job.jobName.toLowerCase().includes(term)
|
||||||
|
|| (job.displayName?.toLowerCase().includes(term) ?? false),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = result.filter((job) => matchesStatusFilter(job, statusFilter));
|
result = result.filter((job) => matchesStatusFilter(job, statusFilter));
|
||||||
|
|
||||||
result = [...result].sort((a, b) => {
|
result = [...result].sort((a, b) => {
|
||||||
if (sortKey === 'name') {
|
if (sortKey === 'name') {
|
||||||
return a.jobName.localeCompare(b.jobName);
|
return getJobLabel(a).localeCompare(getJobLabel(b));
|
||||||
}
|
}
|
||||||
if (sortKey === 'recent') {
|
if (sortKey === 'recent') {
|
||||||
const aTime = a.lastExecution?.startTime ? new Date(a.lastExecution.startTime).getTime() : 0;
|
const aTime = a.lastExecution?.startTime ? new Date(a.lastExecution.startTime).getTime() : 0;
|
||||||
@ -302,9 +312,14 @@ export default function Jobs() {
|
|||||||
${isRunning ? 'border-l-4 border-emerald-500' : ''}`}
|
${isRunning ? 'border-l-4 border-emerald-500' : ''}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between mb-3">
|
<div className="flex items-start justify-between mb-3">
|
||||||
<h3 className="text-sm font-semibold text-wing-text break-all leading-tight">
|
<div>
|
||||||
{job.jobName}
|
<h3 className="text-sm font-semibold text-wing-text break-all leading-tight">
|
||||||
</h3>
|
{getJobLabel(job)}
|
||||||
|
</h3>
|
||||||
|
{job.displayName && (
|
||||||
|
<p className="text-xs text-wing-muted mt-0.5">{job.jobName}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="flex items-center gap-2 ml-2 shrink-0">
|
<div className="flex items-center gap-2 ml-2 shrink-0">
|
||||||
{isRunning && (
|
{isRunning && (
|
||||||
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
|
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
|
||||||
@ -421,7 +436,12 @@ export default function Jobs() {
|
|||||||
{isRunning && (
|
{isRunning && (
|
||||||
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse shrink-0" />
|
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse shrink-0" />
|
||||||
)}
|
)}
|
||||||
{job.jobName}
|
<div>
|
||||||
|
<span>{getJobLabel(job)}</span>
|
||||||
|
{job.displayName && (
|
||||||
|
<p className="text-xs text-wing-muted font-normal">{job.jobName}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-3">
|
<td className="px-4 py-3">
|
||||||
@ -489,7 +509,7 @@ export default function Jobs() {
|
|||||||
>
|
>
|
||||||
<h3 className="text-lg font-semibold text-wing-text mb-2">작업 실행 확인</h3>
|
<h3 className="text-lg font-semibold text-wing-text mb-2">작업 실행 확인</h3>
|
||||||
<p className="text-wing-muted text-sm mb-4">
|
<p className="text-wing-muted text-sm mb-4">
|
||||||
"{targetJob}" 작업을 실행하시겠습니까?
|
"{jobs.find((j) => j.jobName === targetJob)?.displayName || targetJob}" 작업을 실행하시겠습니까?
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="flex justify-end gap-3 mt-6">
|
<div className="flex justify-end gap-3 mt-6">
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import java.time.LocalDateTime;
|
|||||||
public class JobDetailDto {
|
public class JobDetailDto {
|
||||||
|
|
||||||
private String jobName;
|
private String jobName;
|
||||||
|
private String displayName;
|
||||||
private LastExecution lastExecution;
|
private LastExecution lastExecution;
|
||||||
private String scheduleCron;
|
private String scheduleCron;
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,40 @@ import java.util.stream.Collectors;
|
|||||||
@Service
|
@Service
|
||||||
public class BatchService {
|
public class BatchService {
|
||||||
|
|
||||||
|
/** Job Bean 이름 → 한글 표시명 매핑 */
|
||||||
|
private static final Map<String, String> JOB_DISPLAY_NAMES = Map.ofEntries(
|
||||||
|
// AIS
|
||||||
|
Map.entry("aisTargetImportJob", "AIS 선박위치 수집(1분 주기)"),
|
||||||
|
Map.entry("aisTargetDbSyncJob", "AIS 선박위치 DB 적재(15분 주기)"),
|
||||||
|
// 공통코드
|
||||||
|
Map.entry("FlagCodeImportJob", "선박 국가코드 수집"),
|
||||||
|
Map.entry("Stat5CodeImportJob", "선박 유형코드 수집"),
|
||||||
|
// Compliance
|
||||||
|
Map.entry("ComplianceImportRangeJob", "선박 제재 정보 수집"),
|
||||||
|
Map.entry("CompanyComplianceImportRangeJob", "회사 제재 정보 수집"),
|
||||||
|
// Event
|
||||||
|
Map.entry("EventImportJob", "해양 사건/사고 수집"),
|
||||||
|
// Port
|
||||||
|
Map.entry("PortImportJob", "항구 시설 수집"),
|
||||||
|
// Movement
|
||||||
|
Map.entry("AnchorageCallsRangeImportJob", "정박지 기항 이력 수집"),
|
||||||
|
Map.entry("BerthCallsRangeImportJob", "선석 기항 이력 수집"),
|
||||||
|
Map.entry("CurrentlyAtRangeImportJob", "현재 위치 이력 수집"),
|
||||||
|
Map.entry("DestinationsRangeImportJob", "목적지 이력 수집"),
|
||||||
|
Map.entry("PortCallsRangeImportJob", "항구 기항 이력 수집"),
|
||||||
|
Map.entry("STSOperationRangeImportJob", "STS 작업 이력 수집"),
|
||||||
|
Map.entry("TerminalCallsRangeImportJob", "터미널 기항 이력 수집"),
|
||||||
|
Map.entry("TransitsRangeImportJob", "항해 이력 수집"),
|
||||||
|
// PSC
|
||||||
|
Map.entry("PSCDetailImportJob", "PSC 선박 검사 수집"),
|
||||||
|
// Risk
|
||||||
|
Map.entry("RiskRangeImportJob", "선박 위험지표 수집"),
|
||||||
|
// Ship
|
||||||
|
Map.entry("ShipDetailUpdateJob", "선박 제원정보 수집"),
|
||||||
|
// Infra
|
||||||
|
Map.entry("partitionManagerJob", "AIS 파티션 테이블 생성/관리")
|
||||||
|
);
|
||||||
|
|
||||||
private final JobLauncher jobLauncher;
|
private final JobLauncher jobLauncher;
|
||||||
private final JobExplorer jobExplorer;
|
private final JobExplorer jobExplorer;
|
||||||
private final JobOperator jobOperator;
|
private final JobOperator jobOperator;
|
||||||
@ -852,6 +886,7 @@ public class BatchService {
|
|||||||
|
|
||||||
return JobDetailDto.builder()
|
return JobDetailDto.builder()
|
||||||
.jobName(jobName)
|
.jobName(jobName)
|
||||||
|
.displayName(JOB_DISPLAY_NAMES.get(jobName))
|
||||||
.lastExecution(lastExec)
|
.lastExecution(lastExec)
|
||||||
.scheduleCron(cronMap.get(jobName))
|
.scheduleCron(cronMap.get(jobName))
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user