You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
5.4 KiB
93 lines
5.4 KiB
|
2 months ago
|
(function () {
|
||
|
|
"use strict";
|
||
|
|
|
||
|
|
const channelPattern = /^CH(?:0[1-9]|[1-3][0-9]|4[0-8])$/;
|
||
|
|
|
||
|
|
function mount(options) {
|
||
|
|
// The API independently enforces log.clear. Audit/link classes have no clear action.
|
||
|
|
if (!["port", "system"].includes(options.kind) || options.role !== "administrator") { return null; }
|
||
|
|
const system = options.kind === "system";
|
||
|
|
const doc = options.document;
|
||
|
|
const select = options.channelField;
|
||
|
|
if (!doc || (!system && !select) || !options.parent) { return null; }
|
||
|
|
let busy = false;
|
||
|
|
let disposed = false;
|
||
|
|
function node(tag, className, text) {
|
||
|
|
const element = doc.createElement(tag);
|
||
|
|
element.className = className;
|
||
|
|
element.textContent = text;
|
||
|
|
return element;
|
||
|
|
}
|
||
|
|
const area = node("section", "port-log-clear", "");
|
||
|
|
area.setAttribute("aria-label", system ? "시스템 로그 관리" : "포트 로그 관리");
|
||
|
|
const copy = node("div", "port-log-clear-copy", "");
|
||
|
|
const target = node("strong", "port-log-clear-target", "");
|
||
|
|
target.setAttribute("role", "status");
|
||
|
|
const scope = node("p", "port-log-clear-scope", "기간·검색 조건·표시 개수와 관계없이 선택한 포트의 저장 로그 전체를 삭제합니다. 새 로그 수집은 계속됩니다.");
|
||
|
|
if (system) { scope.textContent = "기간·검색 조건·표시 개수와 관계없이 일반 시스템 이벤트 전체를 삭제합니다. 감사 로그·포트 로그·포트 상태 이벤트는 보존됩니다."; }
|
||
|
|
scope.id = "port-log-clear-scope";
|
||
|
|
const note = node("p", "port-log-clear-note", "다른 포트와 시스템·감사·포트 상태 이벤트는 유지됩니다. 설정 백업에는 로그 원문이 포함되지 않습니다.");
|
||
|
|
if (system) { note.textContent = "감사 기록은 클리어 후에도 이 화면에 남습니다. 새 시스템 로그는 계속 저장되며, 설정 백업에는 로그 원문이 포함되지 않습니다."; }
|
||
|
|
const button = node("button", "btn danger", "로그 클리어 (삭제)");
|
||
|
|
button.type = "button";
|
||
|
|
button.dataset[system ? "systemLogClear" : "portLogClear"] = "true";
|
||
|
|
button.setAttribute("aria-describedby", scope.id);
|
||
|
|
copy.append(target, scope, note);
|
||
|
|
area.append(copy, button);
|
||
|
|
options.parent.appendChild(area);
|
||
|
|
|
||
|
|
function update() {
|
||
|
|
const channel = system ? "SYSTEM" : select.value;
|
||
|
|
const valid = system || channelPattern.test(channel);
|
||
|
|
button.disabled = busy || disposed || !valid;
|
||
|
|
button.textContent = busy ? "삭제 중..." : "로그 클리어 (삭제)";
|
||
|
|
target.textContent = busy ? "로그를 삭제하고 있습니다." : (valid ? "삭제 대상: " + channel + " · 저장된 통신 로그 전체" : "위 검색 조건에서 포트 1개를 선택하세요.");
|
||
|
|
if (system && !busy) { target.textContent = "삭제 대상: 일반 시스템 이벤트 · 감사 기록 제외"; }
|
||
|
|
area.dataset.ready = String(valid);
|
||
|
|
area.setAttribute("aria-busy", String(busy));
|
||
|
|
}
|
||
|
|
|
||
|
|
async function clear() {
|
||
|
|
// Capture the exact target: changing filters cannot retarget deletion.
|
||
|
|
const channel = system ? "SYSTEM" : select.value;
|
||
|
|
if (busy || disposed || options.isDisposed() || (!system && !channelPattern.test(channel))) { return; }
|
||
|
|
const prompt = system
|
||
|
|
? "일반 시스템 이벤트 전체를 삭제합니다.\n기간·검색 조건·표시 개수와 관계없이 삭제되며 복구할 수 없습니다. 감사 로그·포트 로그·포트 상태 이벤트는 보존됩니다.\n감사 기록은 클리어 후에도 화면에 남습니다. 내보내기는 현재 검색 조건과 표시 개수 범위만 포함합니다.\n계속하려면 SYSTEM을 정확히 입력하세요."
|
||
|
|
: channel + "의 저장된 포트 로그 전체를 삭제합니다.\n기간·검색 조건·표시 개수와 관계없이 RX/TX·명령·세션 기록이 삭제되며 복구할 수 없습니다.\n필요한 기록은 먼저 내보내세요. 내보내기에는 현재 검색 조건과 표시 개수 제한이 적용됩니다. 설정 백업에는 로그 원문이 포함되지 않습니다.\n다른 포트와 시스템·감사·포트 상태 이벤트는 유지됩니다. 새 로그 수집은 계속됩니다.\n계속하려면 " + channel + "을 정확히 입력하세요.";
|
||
|
|
const confirmation = options.confirm(prompt);
|
||
|
|
if (confirmation !== channel || disposed || options.isDisposed()) { return; }
|
||
|
|
busy = true;
|
||
|
|
update();
|
||
|
|
options.onBusy();
|
||
|
|
try {
|
||
|
|
const result = await options.send(system ? { confirmation: confirmation } : { channel: channel, confirmation: confirmation });
|
||
|
|
if (!disposed && !options.isDisposed()) { options.onSuccess(channel, result); }
|
||
|
|
} catch (error) {
|
||
|
|
if (!disposed && !options.isDisposed()) { options.onError(error); }
|
||
|
|
} finally {
|
||
|
|
busy = false;
|
||
|
|
update();
|
||
|
|
// Release page-level refresh guards even after navigation.
|
||
|
|
await options.onSettled();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
select?.addEventListener("change", update);
|
||
|
|
button.addEventListener("click", clear);
|
||
|
|
update();
|
||
|
|
return {
|
||
|
|
update: update,
|
||
|
|
dispose: function () {
|
||
|
|
disposed = true;
|
||
|
|
select?.removeEventListener("change", update);
|
||
|
|
button.removeEventListener("click", clear);
|
||
|
|
update();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
const api = { mount: mount };
|
||
|
|
if (typeof module !== "undefined" && module.exports) { module.exports = api; }
|
||
|
|
if (typeof window !== "undefined") { window.teraPortLogClear = api; }
|
||
|
|
}());
|