zioinfo-mail/zioinfo/js/ui.js
DESKTOP-TKLFCPR\ython e228faabf5 feat(itsm): G-1~G-12 확장 기능 + 하네스/봇/설치스크립트 구현
G-1: 메신저 Webhook Relay + _send_to_room 실제 httpx 호출 구현
G-2: POST /api/tasks/bulk SR 대량작업 엔드포인트 (최대 100건)
G-3: 라이선스 만료 알림 스케줄러 (매일 09:00 KST)
G-4: 체험판 upgrade_banner 필드 + license.py 배너 로직
G-5: core/auto_rca.py + incidents/problem auto-rca 엔드포인트
G-6: core/deploy_impact.py + vibe impact-analysis 엔드포인트
G-7: core/ticket_classifier.py + SR 생성 시 AI 분류 + ai-suggestion API
G-8: VulnPatchRecord 모델 + vuln_scan 패치추적 4개 엔드포인트
G-9: core/jira_sync.py + gateway Jira/Confluence 연동 엔드포인트
G-10: core/push_notify.py + routers/push.py + PushSubscription 모델
G-11: approvals 다중승인 (위임/서명/기한초과/마감연장)
G-12: alembic.ini + migrations/ + cicd/migrate_to_postgres.sh

하네스: guardia-orchestrator 확장기능 Phase 반영
봇명령어: /sr /status /license /bulk 슬래시 명령어 추가
설치스크립트: setup/ (Ubuntu, CentOS, RHEL, Windows) --test 옵션 포함

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:18:52 +09:00

290 lines
6.8 KiB
JavaScript

/*------------------------------------------------------------------------------
* 1. 파일명: ui.js
* 2. 설 명: UI 조절과 관련된 함수를 정의한다.
* 3. 의존성: form.js, ui.js
* 4. 작성자:
* 5. 작성일: 2006.10.17.
-----------------------------------------------------------------------------*/
/* 2007.05.10
* Object(버튼)의 클래스를 토글로 normal과 over로 바꿔준다.
*/
function toggleButtonClassName(btnElement) {
var normalClassName = "normal";
var overClassName = "over";
if (btnElement.className == normalClassName) {
Element.removeClassName(btnElement, normalClassName);
Element.addClassName(btnElement, overClassName);
} else if (btnElement.className == overClassName){
Element.removeClassName(btnElement, overClassName);
Element.addClassName(btnElement, normalClassName);
}
}
// 목록에서 선택된 요소의 하이라이트 색상
var SELECTED_BG_COLOR = "#99CCFF";
/**
* 해당 object의 자식 노드의 스타일을 모두 지정 색상으로 바꾼다.
*
*/
function changeAllChildNodesColor(obj, color) {
if (obj != null) {
var size = obj.childNodes.length;
for (i = 0; i < size; i++) {
var childEl = obj.childNodes[i]; // Not Recursive!
try {
childEl.style.background = color;
} catch (doNotApplyStyle) {}
}
}
}
/**
* 주어진 높이를 화면의 가운데 놓기위한
* Top 위치 값을 돌려 준다.
*/
function calcTopForCenter(height) {
return ( screen.height - height ) / 2;
}
/**
* 주어진 폭을 화면의 가운데 놓기 위한
* Left 위치 값을 돌려 준다.
*/
function calcLeftForCenter(width) {
return ( screen.width - width ) / 2;
}
/**
* 대화 창을 띄운다.
*/
function showDialog(name, url, width, height, option) {
option = "width=" + width
+ ",height=" + height
+ ",alwaysRaised=yes"
+ ",dependent=yes"
+ (option == undefined || option.length == 0 ? "" : "," + option);
return showWindow(name, url, width, height, option);
}
/**
* 윈도우를 주어진 좌표에 띄운다. 위치가 주어지지 않으면
* 윈도우가 화면 가운데 오도록 띄운다.
*/
function showWindow(name, url, width, height, option, topPx, leftPx) {
if ( ! topPx ) topPx = calcTopForCenter(height);
if ( ! leftPx ) leftPx = calcLeftForCenter(width);
var win = window.open(url, name, option);
win.moveTo(leftPx, topPx);
if ( win ) win.focus();
return win;
}
/**
* 메세지 창을 띄워 주어진 메세지를 보여 준다.
*/
function showMessage(msg) {
alert(msg);
}
/**
* System 메세지를 보여 준다.
*/
function showSysMessage(msg) {
alert("System 메세지: " + msg);
}
/**
* 주어진 Select 객체의 값을 Input 객체에 세팅하고
* 다음 입력 항목으로 넘어간다.
*/
function setSelectedValueAndMoveNext(moveOrderIdList, selectObj, inputObj) {
ref(inputObj).value = getSelectedValue(selectObj);
moveNext(moveOrderIdList, ref(inputObj).id);
}
/**
* 다음 항목으로 이동한다.
* 이동시 disable 상태이거나, 보이지 않는 상태(display: none)이면
* 이 항목은 건너 띈다.
*
* @param moveOrderIdList 이동할 항목의 ID 배열.
* @param currentPositionId 현재 위치 ID. 배열에서 이 ID 다음 ID로 이동한다.
*/
function moveNext(moveOrderIdList, currentPositionId) {
var index = indexInArray(moveOrderIdList, currentPositionId);
if ( index == -1 ) alert("ID " + currentPositionId + "는 이동 목록(moveOrderIdList)에 없습니다.");
var nextIndex = -1;
var i = (index + 1) % moveOrderIdList.length;
for ( var count = 0; count < moveOrderIdList.length; count++, i = ((++i) % moveOrderIdList.length) ) {
var obj = ref(moveOrderIdList[i]);
if ( obj != undefined && obj != null && ! obj.disabled ) {
nextIndex = i;
break;
}
}
//alert(index + " -> " + nextIndex + " : " + moveOrderIdList[nextIndex]);
if ( nextIndex > -1 ) {
ref(moveOrderIdList[nextIndex]).focus();
ref(moveOrderIdList[nextIndex]).select();
}
}
/**
* 눌려진 Key가 Enter이면
* 다음 항목으로 이동한다.
*/
function moveNextIfEnter(moveOrderIdList, currentId) {
if ( event.keyCode == 13 ) {
moveNext(moveOrderIdList, currentId);
}
event.returnValue = ( event.keyCode != 13 );
}
function moveNextIfCtrlEnter(moveOrderIdList, currentId) {
if ( event.keyCode == 13 && event.ctrlKey ) {
moveNext(moveOrderIdList, currentId);
}
event.returnValue = ! ( event.keyCode == 13 && event.ctrlKey );
}
/**
* 주어진 Form의 요소 중에 valid.required의 값이 true인
* 항목을 표시한다.
*/
function markRequiredInput(form) {
for ( var i = 0; i < form.elements.length; i++ ) {
var elem = form.elements[i];
if ( ! elem.disabled && ! elem.readOnly ) {
if ( elem.getAttribute("valid.required") == "true" ) {
elem.style.backgroundColor = "#FFFFCC";
}
}
}
}
/**
* 주어진 Form에 정의된 Element를 뒤져서
* 편집 가능한 Text나 TextArea인 경우
* Focus를 주었을 때와 잃었을 때의 처리 핸들러를
* 설정한다. 기본 값으로 테두리를 빨간색으로 했다가
* 원래대로 돌리는 핸들러가 세팅된다.
*/
function setFocusAndBlurAction(form, focusAction, blurAction) {
/* 정의가 안 되어 있으면 기본 값을 넣는다. */
if ( focusAction == undefined ) focusAction = setBorderRed;
if ( blurAction == undefined ) blurAction = restoreBorderColor;
for ( var i = 0; i < form.elements.length; i++ ) {
var elem = form.elements[i];
//alert(elem.type);
if ( elem.type != undefined
&& ( elem.type == "text"
|| elem.type == "textarea"
|| elem.type == "password" )
&& ! elem.disabled
&& ! elem.readOnly ) {
elem.attachEvent("onfocus", baseOnFocusHandler);
elem.attachEvent("onfocus", focusAction);
elem.attachEvent("onblur" , blurAction );
}
}
}
/**
* Focus 이벤트 발생시 기본적으로 걸 함수
*/
function baseOnFocusHandler() {
var eventSrc = event.srcElement;
/* 이벤트 발생한 항목의 값이 선택된 상태가 되게 한다. */
eventSrc.select();
}
/**
* Event가 발생한 객체의 테두리를 빨간선으로 바꾼다.
*/
function setBorderRed() {
var eventSrc = event.srcElement;
oldBorderValue = eventSrc.style.border;
eventSrc.style.border = "1px solid #CCCCCC";
}
/**
* Blur 이벤트가 발생한 테두리의 색상을 원래대로
* 돌려놓는다.
*/
function restoreBorderColor() {
var eventSrc = event.srcElement;
eventSrc.style.borderColor = "";
}
// 1024x768 해상도에서 Main 영역에 필요한 최소 높이값
var MIN_MAIN_HEIGHT = 494;
/**
* 주어진 고정 높이를 고려했을 때 Main 화면 영역의
* 변할 수 있는 영역 높이 값을 돌려 준다.
*/
function getVarHeightOfMain(minVarHeight) {
var clientHeight = document.body.clientHeight;
var fixHeight = MIN_MAIN_HEIGHT - minVarHeight;
/* 변경될 높이 값을 구한다. */
var varHeight = Math.max(MIN_MAIN_HEIGHT, clientHeight) - fixHeight;
return varHeight;
}
/**
* 확인창을 띄운후 참이면, path로 이동한다.
*
*/
function confirmation(path, message) {
if (confirm(message)){
document.location.href = path;
}
}
function center_popup(page,name,w,h,scroll){
LeftPosition = (screen.width) ? (screen.width-w)/2 : 0;
TopPosition = (screen.height) ? (screen.height-h)/2 : 0;
settings ='height='+h+',width='+w+',top='+TopPosition+',left='+LeftPosition+',scrollbars='+scroll+',resizable';
var w = window.open(page,name,settings);
return w;
}