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>
375 lines
8.4 KiB
JavaScript
375 lines
8.4 KiB
JavaScript
function wsTreeCtrl()
|
|
|
|
{
|
|
|
|
// Methods
|
|
|
|
this.initializeDocument = initializeDocument;
|
|
|
|
this.InsItem = InsItem;
|
|
|
|
this.GenerateCode = GenerateCode;
|
|
|
|
this.ToggleTree = ToggleTree;
|
|
|
|
this.ResetItem = ResetItem;
|
|
|
|
this.ExpandAllTree = ExpandAllTree;
|
|
|
|
this.RecudeAllTree = RecudeAllTree;
|
|
|
|
|
|
|
|
// constant
|
|
|
|
var nCount = 0;
|
|
|
|
var LastRootItem = 0;
|
|
|
|
var ImgDir = "../images/Analysis/";
|
|
|
|
var ItemImg = "../images/Analysis/html.gif";
|
|
|
|
|
|
|
|
// variable
|
|
|
|
var Doc;
|
|
|
|
var browserVersion;
|
|
|
|
var id = "";
|
|
|
|
var Item = new Array();
|
|
|
|
|
|
|
|
|
|
|
|
function initializeDocument()
|
|
|
|
{
|
|
|
|
if (document.all) { //IE4
|
|
|
|
Doc = document.all;
|
|
|
|
browserVersion = 1;
|
|
|
|
|
|
|
|
}else if (document.layers) { //NS4
|
|
|
|
Doc = document.layers;
|
|
|
|
browserVersion = 2;
|
|
|
|
|
|
|
|
}else if(document.getElementById) { //NS6
|
|
|
|
Doc = document;
|
|
|
|
browserVersion = 3;
|
|
|
|
|
|
|
|
}else { //other
|
|
|
|
Doc = document.all;
|
|
|
|
browserVersion = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function InsItem(parentItem, description, hreference, target)
|
|
|
|
{
|
|
|
|
var iDepth = 0;
|
|
|
|
var iLength = Item.length;
|
|
|
|
|
|
|
|
if(parentItem == null) {
|
|
|
|
parentItem = iLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Item[parentItem] != null) {
|
|
|
|
iDepth = Item[parentItem][4];
|
|
|
|
iDepth++;
|
|
|
|
}
|
|
|
|
|
|
|
|
Item[iLength] = new Array();
|
|
|
|
Item[iLength][0] = parentItem;
|
|
|
|
Item[iLength][1] = description;
|
|
|
|
Item[iLength][2] = hreference;
|
|
|
|
Item[iLength][3] = target;
|
|
|
|
Item[iLength][4] = iDepth;
|
|
|
|
Item[iLength][5] = true;
|
|
|
|
|
|
|
|
nCount++;
|
|
|
|
|
|
|
|
return iLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
function GenerateCode()
|
|
|
|
{
|
|
|
|
var NextItemDepth = 0;
|
|
|
|
var CurItemDepth = 0;
|
|
|
|
|
|
|
|
DocWrite("<table border='0' cellpadding='0' cellspacing='0' width=600>");
|
|
|
|
|
|
|
|
for(var i=0; i<nCount; i++) {
|
|
|
|
|
|
|
|
DocWrite("<tr id=wsTree_" + i + "><td>");
|
|
|
|
|
|
|
|
DocWrite("<table border='0' cellpadding='0' cellspacing='0'><tr><td>");
|
|
|
|
DocWrite(GetSpace(i, Item[i][4], false));
|
|
|
|
DocWrite("</td><td>");
|
|
|
|
|
|
|
|
DocWrite("<a href=\"javascript:ToggleTree('" + i + "','" + GetChildItems(i) + "')\" onfocus='this.blur()' >");
|
|
|
|
|
|
|
|
var TempNodeImg;
|
|
|
|
if(GetItemCount(i, Item[i][4]) == 1) {
|
|
|
|
if(Item.length == 1) { TempNodeImg = "r.gif"; }
|
|
|
|
else { TempNodeImg = "L.gif"; }
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if(i == 0) { TempNodeImg = "f.gif"; }
|
|
|
|
else { TempNodeImg = "T.gif"; }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DocWrite("<img id=wsTreeNodeImg_" + i + " src='" + ImgDir + TempNodeImg + "' border='0'>");
|
|
|
|
DocWrite("</a>");
|
|
|
|
|
|
|
|
DocWrite("</td><td>");
|
|
|
|
DocWrite("<img id=wsTreeItemImg_" + i + " src='" + ImgDir + "html.gif" + "' border='0'>");
|
|
|
|
DocWrite("</td><td>");
|
|
|
|
DocWrite(" ");
|
|
|
|
|
|
|
|
if(Item[i][2] != "" && Item[i][2] != null) {
|
|
|
|
DocWrite("<a href='" + Item[i][2] + "'");
|
|
|
|
|
|
|
|
if(Item[i][3] != "undefined" && Item[i][3] != null && Item[i][3] != "") {
|
|
|
|
DocWrite(" target='" + Item[i][3] + "'");
|
|
|
|
}
|
|
|
|
DocWrite(">");
|
|
|
|
}
|
|
|
|
|
|
|
|
DocWrite(Item[i][1]);
|
|
|
|
|
|
|
|
if(Item[i][2] != "" && Item[i][2] != null) {
|
|
|
|
DocWrite("</a>");
|
|
|
|
}
|
|
|
|
|
|
|
|
DocWrite("</td></tr></table>");
|
|
|
|
DocWrite("</td></tr>");
|
|
|
|
}
|
|
|
|
DocWrite("</table>");
|
|
|
|
|
|
|
|
LastRootItem = GetRootItem(nCount-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
function GetSpace(CurItem, Depth, bBlank)
|
|
|
|
{
|
|
|
|
var Space = "";
|
|
|
|
|
|
|
|
for(var i=0; i<Depth; i++) {
|
|
|
|
if(bBlank == false) {
|
|
|
|
//alert("CurItem==["+CurItem+"], Depth==["+i+"]");
|
|
|
|
if(bHaveSameDepthChildItem(CurItem, i)) {
|
|
|
|
Space += "<img src=" + ImgDir + "i.gif>";
|
|
|
|
}else {
|
|
|
|
Space += "<img src=" + ImgDir + "white.gif>";
|
|
|
|
}
|
|
|
|
|
|
|
|
}else {
|
|
|
|
Space += "<img src=" + ImgDir + "white.gif>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//alert("Space===["+Space+"]");
|
|
|
|
return Space;
|
|
|
|
}
|
|
|
|
|
|
|
|
function bHaveSameDepthChildItem(CurItem, Depth)
|
|
|
|
{
|
|
|
|
if(CurItem < 0 || CurItem > Item.length) { return false; }
|
|
|
|
|
|
|
|
var PItem = Item[CurItem][0];
|
|
|
|
var RootItem = GetRootItemEx(PItem, Depth);
|
|
|
|
|
|
|
|
if(GetItemCount(RootItem, Depth) >= 2) {
|
|
|
|
//alert("true");
|
|
|
|
return true;
|
|
|
|
}else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function GetChildItems(iNode)
|
|
|
|
{
|
|
|
|
var ChildItems = "";
|
|
|
|
var CurDepth = Item[iNode][4];
|
|
|
|
|
|
|
|
for(var i=iNode+1; i<Item.length; i++) {
|
|
|
|
|
|
|
|
if(CurDepth >= Item[i][4]) { return ChildItems; }
|
|
|
|
|
|
|
|
if(Item[i][4] > Item[iNode][4]) {
|
|
|
|
ChildItems += i + ";"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ChildItems;
|
|
|
|
}
|
|
|
|
|
|
|
|
function ToggleTree(CurNode, NodeItem)
|
|
|
|
{
|
|
|
|
if(NodeItem == "") { return; }
|
|
|
|
|
|
|
|
var NodeStatus;
|
|
|
|
var arr = new Array();
|
|
|
|
|
|
|
|
arr = NodeItem.split(";");
|
|
|
|
|
|
|
|
if(Item[CurNode][5] == true) {
|
|
|
|
ToggleDisplayLayer(arr, CurNode, "none");
|
|
|
|
Item[CurNode][5] = false;
|
|
|
|
}else {
|
|
|
|
ToggleDisplayLayer(arr, CurNode, "");
|
|
|
|
Item[CurNode][5] = true;
|
|
|
|
ResetItem(CurNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function ToggleDisplayLayer(ItemArray, CurNode, Display)
|
|
|
|
{
|
|
|
|
var NodeImg;
|
|
|
|
var ItemImg;
|
|
|
|
var bShow;
|
|
|
|
|
|
|
|
if(Display == "none") { bShow = false; }
|
|
|
|
else{ bShow = true; }
|
|
|
|
|
|
|
|
if(!bShow) {
|
|
|
|
ItemImg = ImgDir + "folder.gif";
|
|
|
|
|
|
|
|
if(GetItemCount(CurNode,Item[CurNode][4]) == 1) {
|
|
|
|
if(GetItemCount(GetRootItemEx(CurNode, 0),0) == 1 && CurNode == 0) {
|
|
|
|
NodeImg = ImgDir + "Rplus.gif";
|
|
|
|
}else {
|
|
|
|
NodeImg = ImgDir + "Lplus.gif";
|
|
|
|
}
|
|
|
|
|
|
|
|
}else {
|
|
|
|
if(CurNode == 0) {
|
|
|
|
NodeImg = ImgDir + "fplus.gif";
|
|
|
|
}else {
|
|
|
|
NodeImg = ImgDir + "Tplus.gif";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ItemImg = ImgDir + "folderopen.gif";
|
|
|
|
|
|
|
|
if(GetItemCount(CurNode,Item[CurNode][4]) == 1) {
|
|
|
|
if(GetItemCount(GetRootItemEx(CurNode, 0),0) == 1 && CurNode == 0) {
|
|
|
|
NodeImg = ImgDir + "Rminus.gif";
|
|
|
|
}else {
|
|
|
|
NodeImg = ImgDir + "Lminus.gif";
|
|
|
|
}
|
|
|
|
|
|
|
|
}else {
|
|
|
|
if(CurNode == 0) {
|
|
|
|
NodeImg = ImgDir + "fminus.gif";
|
|
|
|
}else {
|
|
|
|
NodeImg = ImgDir + "Tminus.gif";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(var i=0; i<ItemArray.length-1; i++) {
|
|
|
|
SetTreeVisible(ItemArray[i], bShow);
|
|
|
|
SetImgVisible(CurNode, NodeImg, 1);
|
|
|
|
SetImgVisible(CurNode, ItemImg, 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function ResetItem(iNode)
|
|
|
|
{
|
|
|
|
for(var i=iNode; i<Item.length; i++) {
|
|
|
|
|
|
|
|
if(!Item[i][5]) {
|
|
|
|
var arr = new Array();
|
|
|
|
arr = GetChildItems(i).split(";");
|
|
|
|
|
|
|
|
for(var j=0; j<arr.length-1; j++) {
|
|
|
|
SetTreeVisible(arr[j], false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function SetTreeVisible(iItem, bShow)
|
|
|
|
{
|
|
|
|
if(!bShow) {
|
|
|
|
if(browserVersion == 1) {
|
|
|
|
Doc["wsTree_" + iItem].style.display = "none";
|
|
|
|
|
|
|
|
}else if(browserVersion == 3) {
|
|
|
|
document.getElementById("wsTree_" + iItem).style.display = "none";
|
|
|
|
|
|
|
|
}else {
|
|
|
|
Doc["wsTree_" + iItem].visibility = "hiden";
|
|
|
|
}
|
|
|
|
|
|
|
|
}else {
|
|
|
|
if(browserVersion == 1) {
|
|
|
|
Doc["wsTree_" + iItem].style.display = "block";
|
|
|
|
|
|
|
|
}else if(browserVersion == 3) {
|
|
|
|
Doc.getElementById("wsTree_" + iItem).style.display = "";
|
|
|
|
|
|
|
|
}else {
|
|
|
|
Doc["wsTree_" + iItem].visibility = "show";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function SetImgVisible(iItem, ImgName, iType)
|
|
|
|
{
|
|
|
|
var ItemName;
|
|
|
|
switch(iType) {
|
|
|
|
case 1: ItemName = "wsTreeNodeImg_"; break;
|
|
|
|
case 2: ItemName = "wsTreeItemImg_"; break;
|
|
|
|
default: ItemName = "wsTreeItemImg_"; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(browserVersion == 3) {
|
|
|
|
Doc.getElementById(ItemName + iItem).src = ImgName;
|
|
|
|
|
|
|
|
}else {
|
|
|
|
Doc[ItemName + iItem].src = ImgName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function ExpandAllTree()
|
|
|
|
{
|
|
|
|
for(var i=Item.length-1; i>=0; i--) {
|
|
|
|
Item[i][5] = false;
|
|
|
|
ToggleTree(i, GetChildItems(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function RecudeAllTree()
|
|
|
|
{
|
|
|
|
for(var i=Item.length-1; i>=0; i--) {
|
|
|
|
Item[i][5] = true;
|
|
|
|
ToggleTree(i, GetChildItems(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function GetRootItem(ChildItem)
|
|
|
|
{
|
|
|
|
if(Item[ChildItem][4] == 0) {
|
|
|
|
return ChildItem;
|
|
|
|
}else {
|
|
|
|
return GetRootItem(Item[ChildItem][0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function GetRootItemEx(ChildItem, Depth)
|
|
|
|
{
|
|
|
|
if(Item[ChildItem][4] == Depth) {
|
|
|
|
return ChildItem;
|
|
|
|
}else {
|
|
|
|
return GetRootItemEx(Item[ChildItem][0], Depth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function GetItemCount(CurItem, Depth)
|
|
|
|
{
|
|
|
|
var nRet = 0;
|
|
|
|
for(var i=CurItem; i<Item.length; i++) {
|
|
|
|
if(Item[i][4] < Depth) break;
|
|
|
|
|
|
|
|
if(Item[i][4] == Depth) {
|
|
|
|
|
|
|
|
nRet++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
function DocWrite(strHtml)
|
|
|
|
{
|
|
|
|
document.write(strHtml);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function ToggleTree(CurNode, NodeItem)
|
|
|
|
{
|
|
|
|
m_wsTreeCtrl.ToggleTree(CurNode, NodeItem);
|
|
|
|
}
|