// ==UserScript== // @name Bugzilla Script // @namespace xiwenge // @version 0.67.0 // @description 美化增强 Bugzilla 页面 // @author xiwenge // @icon https://www.bugzilla.org/assets/img/logo-header.svg // @match *://192.168.1.31/bugzilla* // @match *://192.168.1.31/bugzilla/show_bug.cgi* // @match *://192.168.1.31/bugzilla/buglist.cgi* // @match *://192.168.1.31/bugzilla/query.cgi* // @match *://192.168.1.31/bugzilla/summarize_time.cgi* // @match *://192.168.1.31/bugzilla/attachment.cgi* // @match *://192.168.1.31/bugzilla/enter_bug.cgi* // @match *://192.168.1.31/bugzilla/describecomponents.cgi* // @match *://192.168.1.31/bugzilla/show_activity.cgi* // @match *://192.168.1.31/bugzilla/process_bug.cgi* // @grant GM_xmlhttpRequest // @grant GM_setClipboard // @run-at document-end // ==/UserScript== var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value, }) : (obj[key] = value); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); (function () { "use strict"; const style = ` /** * 全局样式 * 在这里书写的样式会被编译为 style/index.ts,成为一个 js 模块 */ body { margin: 0 !important; padding: 13px !important; --primaryColor: #18A058; --primaryColorHover: #15904e; --textGrayColor: #b1b1b1; } /* 滚动条整体样式 */ ::-webkit-scrollbar { width: 12px; /* 滚动条宽度 */ } /* 滚动条轨道样式 */ ::-webkit-scrollbar-track { background: #f1f1f1; /* 轨道背景色 */ border-radius: 12px; /* 轨道圆角 */ } /* 滚动条滑块样式 */ ::-webkit-scrollbar-thumb { background: #b9bbbd; /* 滑块背景色 */ border-radius: 12px; /* 滑块圆角 */ } /* 滑块在悬停时的样式 */ ::-webkit-scrollbar-thumb:hover { cursor: pointer; background: #a6a9ac; /* 悬停时的背景色 */ transform: scale(1.2); /* 悬停时放大 */ } /* 横向滚动条整体样式 */ ::-webkit-scrollbar:horizontal { height: 12px; /* 横向滚动条高度 */ } /* 横向滚动条轨道样式 */ ::-webkit-scrollbar-track:horizontal { background: #f1f1f1; /* 轨道背景色 */ border-radius: 12px; /* 轨道圆角 */ } /* 横向滚动条滑块样式 */ ::-webkit-scrollbar-thumb:horizontal { background: #b9bbbd; /* 滑块背景色 */ border-radius: 12px; /* 滑块圆角 */ } /* 横向滑块在悬停时的样式 */ ::-webkit-scrollbar-thumb:hover:horizontal { cursor: pointer; background: #a6a9ac; /* 悬停时的背景色 */ transform: scale(1.2); /* 悬停时放大 */ } #header .links .form form, #footer .links .form form { display: inline-flex !important; align-items: center; } #header { position: sticky; top: 0px; z-index: 100; } #header #title { display: block; width: 270px; } .monaco-editor { width: 100% !important; height: 100% !important; } .navigation { padding: 2px; display: flex; align-items: center; } .bz_query_buttons[valign='middle'] { display: flex; } .bz_query_buttons[valign='middle'] form:not(:last-child) { margin-right: 10px; } .custom-button { display: inline-flex; align-items: center !important; width: fit-content !important; height: 28px; background-color: var(--primaryColor); border-radius: 4px !important; color: #fff; inset: 0; opacity: 1; transition-duration: 0.3s; transition-property: box-shadow, opacity, color, border; padding: 4px 12px !important; font-weight: 400; font-size: 12px; margin: 0 5px; box-sizing: border-box; text-decoration: none; line-height: 18px; border: 1px solid transparent; user-select: none; } .custom-button:hover { height: 28px; cursor: pointer; color: #fff !important; background-color: var(--primaryColorHover); } .custom-button:visited { color: #fff; } .plain-button { background: #ffffff !important; color: #757575 !important; border: 1px solid #cccccc !important; text-decoration: none !important; } .plain-button:hover { height: 28px; color: var(--primaryColor) !important; border: 1px solid var(--primaryColor) !important; } .text-button { background: transparent !important; color: #4a4a4a !important; border: none !important; text-decoration: none !important; } .text-button:hover { cursor: pointer; color: #4a4a4a !important; box-shadow: none !important; } .disabled-button { cursor: not-allowed !important; border-color: #d9d9d9 !important; color: rgba(0, 0, 0, 0.25) !important; background: rgba(0, 0, 0, 0.04) !important; box-shadow: none !important; pointer-events: none !important; } .disabled-button:hover { cursor: not-allowed !important; border-color: #d9d9d9 !important; color: rgba(0, 0, 0, 0.25) !important; box-shadow: none !important; } .field_label { vertical-align: middle !important; } select { height: 28px; border-radius: 4px; padding: 4px; border-color: #d9d9d9; box-sizing: border-box; } select:hover { cursor: pointer; } select:focus-visible { outline: #d9d9d9; } #available_columns, #selected_columns { height: 300px; display: block; margin-right: 4px; } #assigned_to_list_vue_app { height: 28px; } #assigned_to_list_vue_app .n-base-selection-label { height: 28px; } input:not([class="n-input__input-el"])[type='checkbox']:hover { cursor: pointer; } input:not([class="n-input__input-el"])[type='radio']:hover { cursor: pointer; } input:not([class="n-input__input-el"]):not([type='radio']):not([type='checkbox']):not([type='range']):not([type='color']):not([type='hidden']):not([type='reset']):not([type='file']) { height: 28px !important; border-radius: 4px; padding: 0 6px; outline: 0px solid transparent; border: 1px solid #d9d9d9; box-sizing: border-box; } textarea { border-radius: 4px; padding: 4px; outline: 0px solid transparent; border: 1px solid #d9d9d9; } #status { margin-bottom: unset; align-items: center; display: flex; margin-top: 3px; } .knob-buttons:has(input[id='commit']) { margin-top: 4px; } #bug_status { margin: 0 6px; } .bz_section_spacer { display: none; } #bz_assignee_input { width: 543px; } #set_default_assignee_label { display: none; } #set_default_assignee { display: none; } .bz_assignee_td { display: flex; align-items: center; width: 598px; } #bz_show_bug_column_1 tr th { min-height: 34px !important; } #bz_show_bug_column_1 tr:has(th[id='field_label_tag']) { transform: translateY(2px); } #bz_show_bug_column_1 tr:has(th[id='field_label_dependson']) { transform: translateY(4px); } #bz_show_bug_column_1 tr:has(th[id='field_label_blocked']) { transform: translateY(6px); } #bz_show_bug_column_1 tr:has(td[id='show_dependency_tree_or_graph']) { display: none; } #bz_show_bug_column_1 tr td { min-height: 34px !important; } #bz_show_bug_column_2 .field_label { vertical-align: middle !important; max-width: 200px; } #bz_show_bug_column_2 table tr td { max-width: 100%; } #cf_newfeatureid { width: 100%; } .global-message { width: fit-content; height: fit-content; padding: 8px 24px; box-sizing: border-box; display: inline-flex; align-items: center; position: fixed; left: 50%; transform: translate(-50%, -50%); z-index: 99999999; background-color: #ffffff; border-radius: 4px; transition: opacity 0.5s ease-in-out, top 0.5s ease-in-out; animation: message-fadein 0.5s ease-in-out forwards; box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.2); } .global-message_text { margin-left: 8px; font-size: 14px; } @keyframes message-fadein { 0% { opacity: 0.5; top: 10px; } 100% { opacity: 1; top: 30px; } } @keyframes loading { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .global-dialog { height: fit-content; max-width: 100vw; max-height: 100vh; z-index: 9999; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); background-color: #ffffff; border-radius: 4px; } .global-dialog .control-btn:hover { cursor: pointer; } .global-dialog .control-btn:not(:last-child) { margin-right: 8px; } .global-dialog .close-btn:hover { filter: drop-shadow(0px 0px 2px #ff5953); } .global-dialog .exit-full-screen-btn:hover { filter: drop-shadow(0px 0px 2px #fabe33); } .global-dialog .full-screen-btn:hover { filter: drop-shadow(0px 0px 2px #53c32b); } .global-dialog-header { padding: 6px 12px; background-color: #f5f5f5; border-radius: 4px 4px 0 0; } .global-dialog-footer { padding: 6px 12px; background-color: #f5f5f5; border-radius: 0 0 4px 4px; display: flex; justify-content: flex-end; box-sizing: border-box; } .global-dialog-body { max-width: 100%; max-height: calc(100% - 68px); height: 100%; padding: 12px 24px; overflow-y: auto; overflow-x: auto; box-sizing: border-box; } .global-dialog-mask { width: 100vw; height: 100vh; position: fixed; top: 0; left: 0; background-color: rgba(0, 0, 0, 0.5); } .global-dialog-mask-transparent { background-color: transparent; } .global-loading { width: 100%; height: 100%; position: relative; } .global-loading::after { content: ""; width: 20px; height: 20px; border: 2px solid var(--primaryColor); border-left: 2px solid transparent; border-radius: 50%; position: absolute; top: calc(50% - 10px); left: calc(50% - 10px); transform: translate(-50%, -50%); animation: loading 1.5s infinite linear; background-color: transparent; } .self-rotate { animation: loading 1.5s infinite linear; } .attachment-container { width: 100%; height: 100%; overflow-y: auto; overflow-x: auto; } .flex { display: flex; } .flex-wrap { flex-wrap: wrap; } .flex-center { display: flex; justify-content: center; align-items: center; } .flex-align-center { display: flex; align-items: center; } .flex-justify-center { display: flex; justify-content: center; } .flex-justify-space-between { display: flex; justify-content: space-between; } .flex-justify-end { display: flex; justify-content: flex-end; } .show { display: block; } .show-inline-block { display: inline-block; } .hide { display: none; } .cursor-pointer:hover { cursor: pointer; } .text-underline { text-decoration: underline; } .font-size-16px { font-size: 16px; } .font-bold { font-weight: bold; } .margin-right-8px { margin-right: 8px; } .margin-left-8px { margin-left: 8px; } .margin-bottom-8px { margin-bottom: 8px; } .margin-top-8px { margin-top: 8px; } .link-title { font-weight: bold; transition: all 0.3s ease-in-out; } .link-title:hover { color: var(--primaryColor) !important; text-decoration: unset !important; } .separator { margin: 0 6px 0 4px; color: #cccccc; } .links .form a[title="Quicksearch Help"] { margin-left: 6px; } #attachment_table { border: 1px solid #d9d9d9; } #attachment_table td { border: 1px solid #d9d9d9; } #attachment_table tr td[valign="top"]:nth-child(2):has(a) { display: flex; justify-content: center; align-items: center; } #summary_field.search_field_row input { padding-bottom: unset !important; vertical-align: middle; } #short_desc { padding-bottom: unset !important; } #summary_field.search_field_row select { padding-bottom: 4px; vertical-align: middle; } .bz_quip { display: block; color: var(--textGrayColor); font-weight: bold; font-size: 12px; font-style: italic; margin-top: 8px; font-family: '黑体'; } .bz_query_timestamp { color: var(--textGrayColor); font-style: normal; font-size: 14px; display: inline-block; font-family: '黑体'; } .n-base-selection__border, .n-base-selection__state-border { display: none; } .n-checkbox .n-checkbox-box .n-checkbox-icon { transform: rotate(-12deg) translate(0.5px, 1px); } #setting-city { display: inline-block; color: var(--primaryColor); } #setting-city:hover { cursor: pointer; } #setting-city svg { transition: all 0.3s; transform: translateY(3px); font-size: 16px; } #component_list_vue_app { height: 28px; width: 400px; } #component_list_vue_app .n-base-selection-label { height: 28px; } #version_list_vue_app { height: 28px; width: 400px; } #version_list_vue_app .n-base-selection-label { height: 28px; } #cc_list_vue_app { height: 28px; width: 400px; } #cc_list_vue_app .n-base-selection-label { height: 28px; } #newcc_list_vue_app { height: 28px; width: 400px; } #newcc_list_vue_app .n-base-selection-label { height: 28px; } #feature_list_vue_app { height: 28px; min-width: 200px; max-width: 800px; width: 100%; } #feature_list_vue_app .n-base-selection-label { height: 28px; } #search_history_list_vue_app_top, #search_history_list_vue_app_bottom { height: 28px; width: 120px; max-width: 200px; } #search_history_list_vue_app_top .n-base-selection-label, #search_history_list_vue_app_bottom .n-base-selection-label { height: 28px; border-radius: 4px; } #comp_desc_container { display: none; } #comp_desc { height: fit-content; } .validation_error_text { font-size: 12px; color: #e80505; font-weight: 400; } .bug-new_filename { color: grey; font-weight: 600; margin-left: 6px; } .collection-list-title:hover { cursor: pointer; color: var(--primaryColor); } #titles #subtitle { font-weight: 600; } .bz_alias_short_desc_container.edit_form { padding: 10px; } .margin-0 { margin: 0; } .mt-5 { margin-top: 5px; } .ml-5 { margin-left: 5px; } .mr-5 { margin-right: 5px; } .mb-5 { margin-bottom: 5px; } .n-base-selection-placeholder { font-size: 12px; } .bz_comment.bz_first_comment .bz_comment_text p { margin-block-start: 0; margin-block-end: 0; } .clear-br-label { user-select: none; } .clear-br-label:hover { cursor: pointer; color: var(--primaryColorHover); } `; const applyCallBack = (fun, ...args) => { if (fun && typeof fun === "function") { return fun(...args); } }; const showMessage = (type, message, duration = 2e3) => { const existMessageNode = document.querySelector(".global-message"); if (existMessageNode) { document.body.removeChild(existMessageNode); } const svgSuccess = ``; const svgError = ``; const svgMap = /* @__PURE__ */ new Map([ ["success", svgSuccess], ["error", svgError], ]); const innerHTML = ` ${svgMap.get(type)} `; const messageNode = document.createElement("div"); let timer = null; messageNode.classList.add("global-message"); messageNode.innerHTML = innerHTML; document.body.appendChild(messageNode); timer = setTimeout(() => { const animation = messageNode.animate( [ { opacity: 1, top: "30px" }, { opacity: 0, top: "10px" }, ], { duration: 500, easing: "ease-in-out", fill: "forwards", }, ); animation.onfinish = () => { var _a; animation.cancel(); messageNode && ((_a = document.body) == null ? void 0 : _a.removeChild(messageNode)); clearTimeout(timer); }; }, duration); return () => { var _a; messageNode && ((_a = document.body) == null ? void 0 : _a.removeChild(messageNode)); clearTimeout(timer); }; }; const showSuccessMessage = (message, duration = 2e3) => { return showMessage("success", message, duration); }; const showErrorMessage = (message, duration = 2e3) => { return showMessage("error", message, duration); }; const PERSONS_MAP = { anbin: "安斌", anna: "柏红梅", annabai: "柏红梅", BrukcalLi: "李林浩", lilinhao: "李林浩", cehn: "王笑晨", cehnwang: "王笑晨", cesar: "陈述", cesarchen: "陈述", cherry: "兰春花", Cherrylan: "兰春花", chuwanting: "储婉婷", chenxiaoxia: "陈晓霞", dizizhao: "狄子钊", dingjiaju: "丁佳驹", fiona: "牟卫灵", fionam: "牟卫灵", frank: "席小丁", frankxi: "席小丁", xiwenge: "郗文革", fuge: "付戈", harehe: "何小波", huanglin: "黄林", huangqing: "黄青", huangxudong: "黄旭东", huangyifei: "黄一非", huangyueqi: "黄月琪", huangyou: "黄友", humming: "马云", hummingma: "马云", huqing: "胡青", jenny: "王亮", jennywang: "王亮", jiangqianqian: "姜倩倩", jiangjiacheng: "蒋佳成", jizeyu: "纪泽宇", joe: "周强", zhouqiang: "周强", jose: "赖振海", joselai: "赖振海", kevin: "张亚峰", lidehua: "李德华", lifuyi: "李福一", lihaichuan: "李海川", liju: "李桔", lilei: "李雷", linchao: "林超", lisa: "姚艳丽", lisayao: "姚艳丽", liubowen: "刘博文", liuxu: "刘旭", liuyicheng: "刘伊铖", lixianxiang: "李先祥", lixiaoyi: "李小益", liyandong: "李彦东", lucy: "赵亚兰", lucyzhao: "赵亚兰", luoshengming: "罗圣明", magina: "刘松平", maginaliu: "刘松平", Majun: "马军", majun: "马军", mandyyang: "杨曼", maqingbin: "马庆宾", mijie: "米杰", sandywang: "王硕", shenbei: "申倍", demanshen: "申倍", shenfangshuai: "申方帅", shenxiang: "沈祥", shikun: "石坤", larryshi: "石坤", liutianrui: "刘添瑞", sunfeng: "孙丰", stevensun: "孙丰", shizhipeng: "石志鹏", songjie: "宋杰", steven: "刘洋", stevenliu: "刘洋", talk: "陈涛", talkchen: "陈涛", tangshuangxiao: "唐霜晓", tianmaosheng: "田茂生", una: "高秋涵", Unagao: "高秋涵", vern: "张超", Vernzhang: "张超", wangdandan: "王丹丹", wangfeiyan: "王飞燕", wanghairong: "王海容", wuguangmin: "吴光敏", wangshijie: "王世杰", wangyi: "王屹", weiliangpeng: "韦良鹏", wendy: "吴红省", wuhaidong: "吴海东", wuhongsheng: "吴红省", wendywu: "吴红省", xuhang: "徐航", yanghuanhuan: "杨欢欢", yangmingxuan: "杨明轩", yanieye: "叶伟", yafengzhang: "张亚峰", yihuan: "王义欢", yihuanwang: "王义欢", zengchenglong: "曾成龙", zhangrunsheng: "张润生", gausszhang: "张润生", zhangyingqi: "张莹琦", zhangzheyi: "张喆懿", zhaozuwen: "赵祖雯", zhengsong: "郑松", "zhengsong.ext": "郑松", zhoulin: "周林", zhuhewei: "朱赫伟", test: "永洪测试", yonghong: "永洪测试", yonghongcode: "永洪测试", yonghongdoc: "永洪测试", }; const FORM_ITEM_1 = [ { show: true, disabled: false, value: "#bz_show_bug_column_1 tr:has(td[id='bz_field_status'])", label: "Status", }, { show: true, disabled: false, value: "#bz_show_bug_column_1 tr:has(td[id='field_container_product'])", label: "Product", }, { show: true, disabled: false, value: "#bz_show_bug_column_1 tr:has(td[id='field_container_component'])", label: "Component", }, { show: true, disabled: true, value: "#bz_show_bug_column_1 tr:has(th[id='field_label_version'])", label: "Version", }, { show: true, disabled: false, value: "#bz_show_bug_column_1 tr:has(th[id='field_label_rep_platform'])", label: "Hardware", }, { show: true, disabled: false, value: "#bz_show_bug_column_1 tr:has(label[for='priority'])", label: "Importance", }, { show: true, disabled: true, value: "#bz_show_bug_column_1 tr:has(td[class='bz_assignee_td'])", label: "Assigned To", }, { show: true, disabled: false, value: "#bz_show_bug_column_1 tr:has(th[id='field_label_bug_file_loc'])", label: "URL", }, { show: true, disabled: false, value: "#bz_show_bug_column_1 tr:has(th[id='field_label_tag'])", label: "Tags", }, { show: true, disabled: false, value: "#bz_show_bug_column_1 tr:has(th[id='field_label_dependson'])", label: "Depends on", }, { show: true, disabled: false, value: "#bz_show_bug_column_1 tr:has(th[id='field_label_blocked'])", label: "Blocks", }, ]; const FORM_ITEM_2 = [ { show: true, disabled: true, value: "#bz_show_bug_column_2 table tr:first-child", label: "Reported", }, { show: true, disabled: true, value: "#bz_show_bug_column_2 table tr:nth-child(2)", label: "Modified", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(3)", label: "CC List", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(5)", label: "See Also", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(6)", label: "Bug类型1", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(7)", label: "Bug类型2", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(8)", label: "请选择Feature号", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(9)", label: "是否有Matrix/Case覆盖", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(10)", label: "TestCase类型", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(11)", label: "客户是否也发现了这个问题", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(12)", label: "公司名称", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(13)", label: "问题复杂度", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(14)", label: "Bug提报时的版本状态", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(15)", label: "Bug产生原因(开发人员填写)", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(16)", label: "Bug产生细节原因(开发人员填写)", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(17)", label: "如果是改出来的Bug,填入是谁改出来的(开发人员填写)", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(18)", label: "如果是改出来的Bug,填入Bug号或Feature号(开发人员填写)", }, { show: true, disabled: true, value: "#bz_show_bug_column_2 table tr:nth-child(19)", label: "影响范围和测试建议(开发人员填写)", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(20)", label: "Bug被Reopen原因", }, { show: true, disabled: false, value: "#bz_show_bug_column_2 table tr:nth-child(21)", label: "对应testlink用例编号", }, ]; const COMMENT_DEFAULT_TEMPLATE_1 = ` 📌【复现条件】 ───────────────────────────── 🔍【复现步骤】 ───────────────────────────── 1. 2. ✅【预期结果】 ───────────────────────────── ❌【实际结果】 ───────────────────────────── 💡【备注信息】 ───────────────────────────── `; const COMMENT_DEFAULT_TEMPLATE_2 = ` 📌【复现条件】 ───────────────────────────── 🔍【复现步骤】 ───────────────────────────── 1. 2. ✅【预期结果】 ───────────────────────────── ❌【实际结果】 ───────────────────────────── 💡【备注信息】 ───────────────────────────── `; const BUG_STATUS = { NEW: "NEW", ASSIGNED: "ASSIGNED", REOPENED: "REOPENED", VERIFIED: "VERIFIED", RESOLVED: "RESOLVED", CLOSED: "CLOSED", }; const RESOLUTION = { FIXED: "FIXED", INVALID: "INVALID", WONTFIX: "WONTFIX", DUPLICATE: "DUPLICATE", WORKSFORME: "WORKSFORME", MOVED: "MOVED", FIX_NEXT_VER: "FIX_NEXT_VER", }; const STORAGE_KEY_MAP = { COLLECTED_BUGS: "collectedBugs", PERSONS_MAP: "personsMap", QUIP_TYPE: "quipType", COMPLETED_BUGS: "completedBugs", CITY: "city", FORM_ITEM_CONTROL: "formItemControl", CUSTOM_BRANCHES: "customBranches", NEW_BUG_COMMENT_TEMPLATE: "newBugCommentTemplate", LIST_PAGE_ACTION_BTNS: "listPageActionBtns", HASCLEAR_COMPLETED_BUGS: "hasClearCompletedBugs", SEARCH_HISTORY: "searchHistory", QUICK_SUMMARY: "quickSummary", GITLAB_CONFIG: "gitlabConfig", HAS_AUTO_SYNC_PERSON_MAP: "hasAutoSyncPersonMap", AUTO_CLEAR_FIRST_COMMENT_BR: "autoClearFirstCommentBr", PAGE_DETAIL_CONTROL: "pageDetailControl", }; const GITLAB_ORIGIN = "http://192.168.1.180:8888"; const FIRE_BASE_SCRIPT_URL = { APP: "https://www.gstatic.com/firebasejs/10.7.1/firebase-app-compat.js", AUTH: "https://www.gstatic.com/firebasejs/10.7.1/firebase-auth-compat.js", DATABASE: "https://www.gstatic.com/firebasejs/10.7.1/firebase-database-compat.js", }; const FIRE_BASE_CONFIG = { apiKey: "AIzaSyCuNIxlkvH6zV-V_Ashi0y7-l1ihAaHEu8", authDomain: "bugzilla-6ecaf.firebaseapp.com", databaseURL: "https://bugzilla-6ecaf-default-rtdb.asia-southeast1.firebasedatabase.app", projectId: "bugzilla-6ecaf", storageBucket: "bugzilla-6ecaf.firebasestorage.app", messagingSenderId: "81688421567", appId: "1:81688421567:web:c94cb82be4131a8540920a", }; const getCollectedBugs = () => { var _a; return ( ((_a = JSON.parse( localStorage.getItem(STORAGE_KEY_MAP.COLLECTED_BUGS) ?? "{}", )) == null ? void 0 : _a.list) ?? [] ); }; const getCollectInfo = (id) => { const collectedBugs = getCollectedBugs(); const hasCollected = collectedBugs.length && collectedBugs.some((bug) => bug.id.includes(id)); return { collectedBugs, hasCollected }; }; const deleteCollectedBug = (id) => { const collectedBugs = getCollectedBugs(); const newCollectedBugs = collectedBugs.filter( (bug) => !bug.id.includes(id), ); localStorage.setItem( STORAGE_KEY_MAP.COLLECTED_BUGS, JSON.stringify({ list: newCollectedBugs }), ); }; const setCollectionBug = (id, title, url) => { const { collectedBugs = [], hasCollected } = getCollectInfo(id); if (hasCollected) { showErrorMessage("此bug已收藏"); return; } collectedBugs.push({ id, title, url }); localStorage.setItem( STORAGE_KEY_MAP.COLLECTED_BUGS, JSON.stringify({ list: collectedBugs }), ); showSuccessMessage("收藏成功"); }; const setCollectionIcon = (collectionNode, id) => { if (!collectionNode) { return; } collectionNode.innerHTML = getCollectInfo(id).hasCollected ? ` ` : ` `; }; const createDialog = ({ title = "", body, footer, maskTransparent = false, okText = "确定", cancelText = "取消", onOk, onCancel, hideOk = false, hideCancel = false, className = "", bodyClassName = "", style: style2 = "", bodyStyle = "", autoFullScreen = false, onMount = () => {}, onDestroy = () => {}, }) => { let storeDialogWidth = 0; let storeDialogHeight = 0; let isDialogFullScreen = void 0; let isDragging = false; let startX = 0; let startY = 0; let dialogStartX = 0; let dialogStartY = 0; const titleTransformWidthMap = /* @__PURE__ */ new Map([ [1, 8], [2, 20], [3, 32], ]); const existDialogNodes = document.querySelectorAll(".global-dialog"); const length = existDialogNodes.length; const zIndex = 900 + length; const maskNode = document.createElement("div"); maskTransparent && maskNode.classList.add("global-dialog-mask-transparent"); const dialogNode = document.createElement("div"); const header = document.createElement("div"); header.style.display = "flex"; header.style.alignItems = "center"; const dialogBody = document.createElement("div"); const headerBtn = document.createElement("div"); headerBtn.style.display = "inline-block"; const headerTitle = document.createElement("div"); const titleNode = document.createElement("div"); headerTitle.classList.add("flex-center"); headerTitle.style.flex = "1"; if (!autoFullScreen && !isDialogFullScreen) { headerTitle.style.cursor = "move"; } headerTitle.appendChild(titleNode); titleNode.style.userSelect = "none"; titleNode.innerText = title; const closeBtn = document.createElement("span"); closeBtn.title = "关闭弹窗(Esc)"; const exitFullScreenBtn = document.createElement("span"); exitFullScreenBtn.title = "退出全屏"; const fullScreenBtn = document.createElement("span"); fullScreenBtn.title = "全屏显示"; const closeIcon = ``; const exitFullScreenIcon = ``; const fullScreenIcon = ``; closeBtn.innerHTML = closeIcon; closeBtn.classList.add("control-btn"); closeBtn.classList.add("close-btn"); exitFullScreenBtn.innerHTML = exitFullScreenIcon; exitFullScreenBtn.classList.add("control-btn"); exitFullScreenBtn.classList.add("exit-full-screen-btn"); fullScreenBtn.innerHTML = fullScreenIcon; fullScreenBtn.classList.add("control-btn"); fullScreenBtn.classList.add("full-screen-btn"); const resizeObserver = new ResizeObserver((entries) => { for (const entry of entries) { if (!isDialogFullScreen) { storeDialogWidth = entry.contentRect.width; storeDialogHeight = entry.contentRect.height; } else { dialogBody.style.width = "100%"; if (dialogBody == null ? void 0 : dialogBody.firstChild) { const firstChild = dialogBody.firstChild; firstChild.style = firstChild.style ?? ""; firstChild.style.width = "100%"; firstChild.style.height = "100%"; } } } }); resizeObserver.observe(dialogNode); const closeDialog = () => { document.removeEventListener("keydown", enterEvent); document.removeEventListener("keydown", escEvent); document.removeEventListener("mousemove", dragMove); document.removeEventListener("mouseup", dragEnd); const animation2 = dialogNode.animate( [ { opacity: 1, transition: "transition: opacity 0.5s ease-in-out, top 0.5s ease-in-out;", }, { opacity: 0, transition: "transition: opacity 0.5s ease-in-out, top 0.5s ease-in-out;", }, ], { duration: 500, easing: "ease-in-out", fill: "forwards", }, ); animation2.onfinish = () => { animation2.cancel(); document.body.removeChild(maskNode); const dialogs = document.querySelectorAll(".global-dialog"); if (dialogs.length === 0) { document.body.style.overflow = "auto"; } isDialogFullScreen = false; resizeObserver.disconnect(); onDestroy(); }; }; closeBtn.addEventListener("click", () => { closeDialog(); }); exitFullScreenBtn.addEventListener("click", () => { if (isDialogFullScreen) { headerTitle.style.cursor = "move"; isDialogFullScreen = false; dialogNode.style.width = `${Math.ceil(storeDialogWidth)}px`; dialogNode.style.height = `${Math.ceil(storeDialogHeight)}px`; dialogNode.style.transform = "translate(-50%, -50%)"; dialogNode.style.left = "50%"; dialogNode.style.top = "50%"; dialogNode.style.margin = "0"; } }); fullScreenBtn.addEventListener("click", () => { if (!isDialogFullScreen) { headerTitle.style.cursor = "auto"; isDialogFullScreen = true; dialogNode.style.width = "100%"; dialogNode.style.height = "99.6%"; dialogNode.style.transform = "translate(-50%, -50.4%)"; dialogNode.style.left = ""; dialogNode.style.top = ""; dialogNode.style.margin = "0"; dialogBody.style.width = "100%"; dialogBody.style.height = "100%"; } }); if (autoFullScreen) { fullScreenBtn.click(); } headerBtn.appendChild(closeBtn); if (!autoFullScreen) { headerBtn.appendChild(exitFullScreenBtn); headerBtn.appendChild(fullScreenBtn); } header.appendChild(headerBtn); titleNode.style.transform = `translateX(-${titleTransformWidthMap.get(headerBtn.children.length)}px)`; header.appendChild(headerTitle); header.classList.add("global-dialog-header"); dialogBody.classList.add("global-dialog-body"); const footerInner = document.createElement("div"); maskNode.classList.add("global-dialog-mask"); dialogNode.classList.add("global-dialog"); if (className) { dialogNode.classList.add(className); } if (style2) { dialogNode.style = style2; } if (bodyClassName) { dialogBody.classList.add(bodyClassName); } if (bodyStyle) { dialogBody.style = bodyStyle; } if (typeof footer === "string") { footerInner.innerHTML = footer; } else if (footer) { footerInner.appendChild(footer); } else if (footer !== false && footer !== null) { footerInner.classList.add("global-dialog-footer"); if (!hideOk) { const footerSaveBtn = document.createElement("div"); footerSaveBtn.classList.add("custom-button"); footerSaveBtn.innerText = okText + " (Enter)"; footerSaveBtn.addEventListener("click", () => { applyCallBack(onOk, closeDialog); }); footerInner.appendChild(footerSaveBtn); } if (!hideCancel) { const footerCancelBtn = document.createElement("div"); footerCancelBtn.classList.add("custom-button"); footerCancelBtn.classList.add("plain-button"); footerCancelBtn.innerText = cancelText + " (Esc)"; footerCancelBtn.addEventListener("click", async () => { const res = (await applyCallBack(onCancel)) ?? true; if (res) { closeDialog(); } }); footerInner.appendChild(footerCancelBtn); } } if (typeof body === "string") { dialogBody.innerHTML = body; } else { dialogBody.appendChild(body); } dialogNode.appendChild(header); dialogNode.appendChild(dialogBody); dialogNode.appendChild(footerInner); maskNode.style.zIndex = `${zIndex}`; maskNode.appendChild(dialogNode); document.body.appendChild(maskNode); document.body.style.overflow = "hidden"; const animation = dialogNode.animate( [ { opacity: 0, top: "46%", transition: "transition: opacity 0.5s ease-in-out, top 0.5s ease-in-out;", }, { opacity: 1, top: "50%", transition: "transition: opacity 0.5s ease-in-out, top 0.5s ease-in-out;", }, ], { duration: 500, easing: "ease-in-out", fill: "forwards", }, ); animation.onfinish = () => { animation.cancel(); }; const escEvent = (e) => { if (e.key === "Escape") { closeDialog(); } }; const enterEvent = (e) => { if (e.key === "Enter") { applyCallBack(onOk, closeDialog); } }; const dragStart = (e) => { if (isDialogFullScreen) return; isDragging = true; startX = e.clientX; startY = e.clientY; document.body.style.userSelect = "none"; const rect = dialogNode.getBoundingClientRect(); dialogStartX = rect.left; dialogStartY = rect.top; }; const dragEnd = () => { isDragging = false; document.body.style.userSelect = "auto"; }; const dragMove = (e) => { if (!isDragging || isDialogFullScreen) return; const dx = e.clientX - startX; const dy = e.clientY - startY; const newLeft = dialogStartX + dx; const newTop = dialogStartY + dy; const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; const dialogWidth = dialogNode.offsetWidth; const dialogHeight = dialogNode.offsetHeight; const clampedLeft = Math.max( 0, Math.min(newLeft, windowWidth - dialogWidth), ); const clampedTop = Math.max( 0, Math.min(newTop, windowHeight - dialogHeight), ); dialogNode.style.left = `${clampedLeft}px`; dialogNode.style.top = `${clampedTop}px`; dialogNode.style.transform = "none"; dialogNode.style.margin = "0"; }; document.addEventListener("keydown", enterEvent); document.addEventListener("keydown", escEvent); headerTitle.addEventListener("mousedown", dragStart); document.addEventListener("mousemove", dragMove); document.addEventListener("mouseup", dragEnd); onMount(); return closeDialog; }; const copyText = (text, showDetail = false) => { if (!text) { showErrorMessage("没有可复制的内容"); return; } if (typeof GM_setClipboard !== "function") { showErrorMessage("当前环境不支持复制功能"); return; } if (!showDetail) { GM_setClipboard(text, "text", () => { showSuccessMessage("复制成功"); }); return; } showTextDetail(text, (body) => { createDialog({ title: "内容详情", body, okText: "确定复制", onOk: (closeDialog) => { GM_setClipboard(text, "text", () => { showSuccessMessage("复制成功"); closeDialog(); }); }, }); }); }; const showTextDetail = (text, cb) => { const body = document.createElement("div"); const textareaNode = document.createElement("div"); const texts = text.split("\n"); texts.forEach((item) => { const span = document.createElement("span"); span.textContent = item; textareaNode.appendChild(span); textareaNode.appendChild(document.createElement("br")); }); textareaNode.style.setProperty("width", "98%"); textareaNode.style.setProperty("height", "96%"); textareaNode.style.setProperty("border", "1px solid #d9d9d9"); textareaNode.style.setProperty("outline", "0px solid transparent"); textareaNode.style.setProperty("padding", "6px"); textareaNode.style.setProperty("border-radius", "4px"); textareaNode.style.setProperty("overflow-y", "scroll"); body.appendChild(textareaNode); body.style.setProperty("width", "30vw"); body.style.setProperty("height", "30vh"); applyCallBack(cb, body); }; const PATHNAME = window.location.pathname; const ZHOU_OF_WEEK_MAP = { SUNDAY: "周日", MONDAY: "周一", TUESDAY: "周二", WEDNESDAY: "周三", THURSDAY: "周四", FRIDAY: "周五", SATURDAY: "周六", }; const XINGQI_OF_WEEK_MAP = { SUNDAY: "星期日", MONDAY: "星期一", TUESDAY: "星期二", WEDNESDAY: "星期三", THURSDAY: "星期四", FRIDAY: "星期五", SATURDAY: "星期六", }; const getTodayDate = () => { const today = /* @__PURE__ */ new Date(); return today.toISOString().split("T")[0]; }; const getSpecialDayBaseToday = (day) => { const today = /* @__PURE__ */ new Date(); today.setDate(today.getDate() + day); return today.toISOString().split("T")[0]; }; const getSpecialDayBeforeDate = (target, days) => { const date = new Date(target); date.setDate(date.getDate() - days); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; }; const getDatesInRange = (targetDate, range) => { const dates = []; const target = new Date(targetDate); for (let i = 0; i < range; i++) { dates.push(getSpecialDayBeforeDate(target, i + 1)); } return dates; }; const getDayOfWeek = (textType, dateTime) => { const days = { zhou: Object.values(ZHOU_OF_WEEK_MAP), xingqi: Object.values(XINGQI_OF_WEEK_MAP), }; const date = new Date(dateTime || getTodayDate()); const dayIndex = date.getDay(); return days[textType][dayIndex]; }; const DEFAULT_PAGE_DETAIL_CONTROL = { showSaveConfirmDialog: true, showHintWhenAutoAddReport: true, showAttechmentDialog: true, directOpenGitlabWhenHashRecognized: true, }; const setPageDetailControl = (key, value) => { const controlLocal = getPageDetailControl(); localStorage.setItem( STORAGE_KEY_MAP.PAGE_DETAIL_CONTROL, JSON.stringify({ ...controlLocal, [key]: value, }), ); }; const getPageDetailControl = (key) => { const controlLocal = JSON.parse( localStorage.getItem(STORAGE_KEY_MAP.PAGE_DETAIL_CONTROL) || "{}", ); const control = { ...DEFAULT_PAGE_DETAIL_CONTROL, ...controlLocal }; if (key) { return control[key]; } return control; }; function getReportBugsByDate(date = getTodayDate()) { const todayReportLocal = JSON.parse(localStorage.getItem(date) ?? "[]"); return todayReportLocal; } function isBugInReport(bugId, date = getTodayDate()) { const todayReportLocal = getReportBugsByDate(date); return todayReportLocal.some((it) => it.id === bugId); } const addBugWithRepeatCheck = ( bug, date = getTodayDate(), isSaveForm = false, ) => { if (isBugInReport(bug.id, date)) { if (!isSaveForm || getPageDetailControl("showHintWhenAutoAddReport")) { showErrorMessage("该BUG已在日报中"); } return false; } const todayReportLocal = getReportBugsByDate(date); todayReportLocal.push(bug); localStorage.setItem(date, JSON.stringify(todayReportLocal)); if (!isSaveForm || getPageDetailControl("showHintWhenAutoAddReport")) { showSuccessMessage("添加日报成功"); } return true; }; const removeBugFromReport = (bugId, date = getTodayDate()) => { const todayReportLocal = getReportBugsByDate(date); const index = todayReportLocal.findIndex((it) => it.id === bugId); if (index === -1) { showErrorMessage("该BUG不存在"); return false; } todayReportLocal.splice(index, 1); localStorage.setItem(date, JSON.stringify(todayReportLocal)); showSuccessMessage("移除成功"); return true; }; const bugHistoryDialog = () => { let appIns = null; const appId = "bug_history_vue_app"; createDialog({ title: "历史记录", hideOk: true, cancelText: "关闭", bodyStyle: "width: 60vw; height: 60vh;", body: `
`, onMount: () => { const days = getDatesInRange(getSpecialDayBaseToday(1), 14); const bugHistory = []; for (let i = 0; i < days.length; i++) { const date = days[i]; const reportLocal = getReportBugsByDate(date); if (reportLocal.length > 0) { const ids = []; const bugItems = reportLocal; for (let i2 = 0; i2 < bugItems.length; i2++) { const bugItem = bugItems[i2]; if (ids.includes(bugItem.id)) { continue; } ids.push(bugItem.id); bugHistory.push({ date, bugId: bugItem.id, bugName: bugItem.name, bugUrl: bugItem.url, }); } } } const { createApp, ref, reactive, h } = Vue; const app = createApp({ template: `]*>)([\s\S]*?)(<\/pre>)/g,
(_match, preOpen, preContent, preClose) => {
const replacedContent = replaceHashInPreContent(preContent);
return `${preOpen}${replacedContent}${preClose}`;
},
);
}
if (target instanceof HTMLElement) {
let domElements = [];
if (["PRE", "DIV"].includes(target.tagName)) {
domElements = [target];
} else {
domElements = Array.from(target.querySelectorAll("pre"));
if (domElements.length === 0) {
domElements = Array.from(target.querySelectorAll("div"));
}
}
domElements.forEach((domElement) => {
const originalHtml = domElement.innerHTML;
const newHtml = replaceHashInPreContent(originalHtml);
domElement.innerHTML = newHtml;
const hashLinks = domElement.querySelectorAll(".commit-hash-link");
hashLinks.forEach((link) => {
link.addEventListener("click", (e) => {
e.preventDefault();
const hash = link.dataset.hash || "";
const projectName = link.dataset.project || "";
customClickHandler(e, hash, projectName);
});
});
});
return;
}
throw new Error("target 必须是 HTML 字符串或 HTMLElement 类型");
};
const openGitlabByHash = (hash, projectName) => {
window.open(
`${GITLAB_ORIGIN}/project/${projectName}/-/commit/${hash}`,
"_blank",
);
};
function clearBrAndBlank(rootNode) {
if (!rootNode || !(rootNode instanceof Node)) {
console.warn("传入的根节点无效,请传入有效的 DOM 节点");
return false;
}
if (rootNode.nodeType !== Node.ELEMENT_NODE) {
return true;
}
const rootElement = rootNode;
const pElements = rootElement.querySelectorAll("p");
if (pElements.length === 0) {
return true;
}
pElements.forEach((pElement) => {
const brElements = Array.from(pElement.querySelectorAll("br"));
brElements.forEach((br) => {
if (br.parentElement === pElement) {
br.remove();
}
});
});
const childNodes = Array.from(rootElement.childNodes);
const pNodeList = Array.from(pElements);
childNodes.forEach((node) => {
var _a;
if (node.nodeType !== Node.TEXT_NODE) return;
const textContent =
((_a = node.textContent) == null ? void 0 : _a.trim()) || "";
if (textContent !== "") return;
const prevSibling = node.previousSibling;
const nextSibling = node.nextSibling;
const prevIsP = prevSibling && pNodeList.includes(prevSibling);
const nextIsP = nextSibling && pNodeList.includes(nextSibling);
if (prevIsP && nextIsP) {
node.remove();
}
});
return true;
}
const viewImageFullScreen = (parentElement) => {
if (!parentElement) {
return;
}
const imgs = parentElement.querySelectorAll("img");
imgs.forEach((img) => {
img.style.cursor = "zoom-in";
img.title = "点击图片全屏查看";
const imgCloned = img.cloneNode(true);
imgCloned.title = "点击图片关闭弹窗";
img.addEventListener("click", () => {
const closeDialog = createDialog({
title: "查看图片(点击图片关闭弹窗)",
body: imgCloned,
autoFullScreen: true,
hideOk: true,
cancelText: "关闭",
});
imgCloned.addEventListener("click", () => {
closeDialog();
});
});
});
};
const renderBugDetail = () => {
var _a, _b, _c, _d;
const persons = getPersonMap();
const table1 = document.querySelector("#bz_show_bug_column_1");
const table2 = document.querySelector("#bz_show_bug_column_2");
const reporterNode = document.querySelector(
"#bz_show_bug_column_2 .vcard .email",
);
const table2AllRows = Array.from(
document.querySelectorAll("#bz_show_bug_column_2 tr"),
);
const reporterEmail = getPersonEmail(
(reporterNode == null ? void 0 : reporterNode.href) ?? "",
);
const reportNodes = Array.from(
document.querySelectorAll(".vcard .email .fn"),
);
const historyBtn = document.querySelector(
"#bz_show_bug_column_2 tr:nth-child(2) a",
);
const editTitleBtn = document.querySelector("#editme_action");
const assigneeEditBtn = document.querySelector("#bz_assignee_edit_action");
const assigneeTakeBtn = document.querySelector("#bz_assignee_take_action");
const markDuplicateBtn = document.querySelector(
"#dup_id_discoverable_action",
);
const markDuplicateBox = document.querySelector("#dup_id_discoverable");
const duplicateSettings = document.querySelector("#duplicate_settings");
const replaceTitleInput = document.querySelector("#summary_alias_input");
const commentTextArea = document.querySelector("#comment");
const commentBox = document.querySelector("#add_comment");
const commentBoxLabel = document.querySelector("#add_comment label");
const attachmentDetails = Array.from(
document.querySelectorAll(
"#attachment_table td[valign='top']:nth-child(2) a",
),
);
const saveFormBtn1 = document.querySelector(
".bz_alias_short_desc_container .knob-buttons input",
);
const saveFormBtn2 = document.querySelector(
"#add_comment .knob-buttons input",
);
const bugStatus = document.querySelector("#bug_status");
const resolution = document.querySelector("#resolution");
const resolutionSettings = document.querySelector("#resolution_settings");
const assigneeInputNode = document.querySelector("#bz_assignee_input");
const assigneeEditNode = document.querySelector(
"#bz_assignee_edit_container",
);
const assignToSelect = document.querySelector("#assigned_to");
const bugTitleBox = document.querySelector("#summary_alias_container");
const bugTitleNode = document.querySelector("#short_desc_nonedit_display");
const bugIDNode = document.querySelector(
".bz_alias_short_desc_container a b",
);
const bugId =
(_a = bugIDNode.innerText.match(/(\d+)$/)) == null ? void 0 : _a[1];
const effectNode = document.querySelector("#cf_effect");
const bzSpacerNodes = Array.from(
document.querySelectorAll(
"#bz_show_bug_column_1 tr:has(td[class='bz_section_spacer'])",
),
);
const navigationNode = document.querySelector(".navigation");
const attachmentNode = document.querySelector(
"#attachment_table .bz_attach_footer a:not(a[id='view_all'])",
);
const attachmentViewAll = document.querySelector(
"#attachment_table .bz_attach_footer a[id='view_all']",
);
const navigationABtns = Array.from(
document.querySelectorAll("#bugzilla-body .navigation a"),
);
const navigationFontBtns = Array.from(
document.querySelectorAll("#bugzilla-body .navigation i font"),
);
const commentNodes = Array.from(
document.querySelectorAll(
"#comments .bz_comment_table .bz_comment:not(.bz_first_comment) .bz_comment_text",
),
);
const firstComment = document.querySelector(
".bz_comment.bz_first_comment .bz_comment_text",
);
const firstCommentHead = document.querySelector(
".bz_comment.bz_first_comment .bz_first_comment_head",
);
let completeBtn = null;
if (table1 && table2) {
const table1Width = table1.clientWidth;
table2.style.setProperty(
"width",
Math.round(document.body.clientWidth - table1Width) + "px",
);
}
if (historyBtn) {
historyBtn.innerText = "流转历史";
historyBtn.classList.add("custom-button");
historyBtn.classList.add("plain-button");
historyBtn.style.margin = "0 6px";
historyBtn.addEventListener("click", (e) => {
e.preventDefault();
createDialog({
title: "流转历史",
hideOk: true,
cancelText: "关闭",
bodyStyle: "width: 60vw; height: 60vh;",
body: `
`,
onMount: () => {
iframeCallback("history-iframe", (contentDocument) => {
const header = contentDocument.querySelector("#header");
const footer = contentDocument.querySelector("#footer");
if (header) {
header.remove();
}
if (footer) {
footer.remove();
}
});
},
});
});
}
reportNodes.forEach((node) => {
if (Object.keys(persons).includes(node.innerText)) {
node.innerText = persons[node.innerText];
} else if (node.innerText.includes("-")) {
const splits = node.innerText.split("-");
const left = splits[0];
const right = splits[1];
if (/^[a-zA-Z0-9]+$/.test(left)) {
node.innerText = persons[left];
}
if (/^[a-zA-Z0-9]+$/.test(right)) {
node.innerText = persons[right];
}
}
});
createButton(
"复制报告人姓名",
(button) => {
var _a2;
button.classList.add("plain-button");
(_a2 = reporterNode == null ? void 0 : reporterNode.parentNode) == null
? void 0
: _a2.insertBefore(button, reporterNode.nextSibling);
},
() => {
copyText(reporterNode.innerText);
},
);
if (bzSpacerNodes.length) {
bzSpacerNodes.forEach((node) => {
node.style.display = "none";
});
}
if (effectNode && !effectNode.value) {
effectNode.value = "本 case";
}
if (bugTitleBox && bugTitleNode && bugIDNode) {
const reportBtn = createButton(
"日报/移除",
(button) => {
button.classList.add("custom-button");
if (!isBugInReport(bugId)) {
button.innerText = "添加日报";
button.style.setProperty("border", "1px solid rgb(200, 200, 200)");
} else {
button.classList.add("plain-button");
button.innerText = "移除日报";
button.style.setProperty("border", "1px solid #cccccc");
}
bugTitleBox.parentNode.insertBefore(button, bugTitleBox.nextSibling);
},
() => {
if (!isBugInReport(bugId)) {
addBugWithRepeatCheck({
id: bugId,
name: bugTitleNode.innerText,
url: window.location.href,
});
reportBtn.classList.add("plain-button");
reportBtn.innerText = "移除日报";
} else {
removeBugFromReport(bugId);
reportBtn.classList.remove("plain-button");
reportBtn.innerText = "添加日报";
}
},
);
createButton(
"复制 COMMIT",
(button) => {
button.classList.add("plain-button");
bugTitleBox.parentNode.insertBefore(button, bugTitleBox.nextSibling);
},
() => {
copyText(
`git commit -m "bug: ${bugId} 修复:${bugTitleNode.innerText}"`,
);
},
);
createButton(
"复制 ID",
(button) => {
button.classList.add("plain-button");
bugTitleBox.parentNode.insertBefore(button, bugTitleBox.nextSibling);
},
() => {
copyText(bugId);
},
);
}
if (assigneeInputNode) {
assigneeInputNode.parentNode.classList.add("bz_assignee_td");
const backButton = createButton(
"取消",
(button) => {
button.classList.add("plain-button");
button.style.display = "none";
button.style.marginRight = "0";
assigneeInputNode.parentNode.appendChild(button);
},
(_, button) => {
assigneeInputNode.classList.add("bz_default_hidden");
assigneeEditNode.classList.remove("bz_default_hidden");
if (button.style.display === "block") {
button.style.display = "none";
const aLink = document.querySelector(
"#bz_assignee_edit_container .email",
);
if (aLink) {
const email = getPersonEmail(aLink.href);
if (email) {
assignToSelect.value = email;
const assignToAppNode = document.querySelector(
"#assigned_to_list_vue_app",
);
if (assignToAppNode) {
assignToAppNode.remove();
assignToList();
}
}
}
}
},
);
if (editTitleBtn) {
bugTitleBox.classList.remove("bz_default_hidden");
replaceTitleInput.classList.add("bz_default_hidden");
editTitleBtn.innerText = "编辑标题";
editTitleBtn.classList.add("custom-button");
editTitleBtn.classList.add("plain-button");
editTitleBtn.addEventListener("click", (e) => {
e.preventDefault();
bugTitleBox.classList.remove("bz_default_hidden");
replaceTitleInput.classList.add("bz_default_hidden");
const alias = replaceTitleInput.querySelector("#alias");
const shortDesc = replaceTitleInput.querySelector("#short_desc");
const replaceClone = replaceTitleInput.cloneNode(true);
replaceClone.classList.remove("bz_default_hidden");
const aliasInput = replaceClone.querySelector("#alias");
const shortDescInput = replaceClone.querySelector("#short_desc");
if (aliasInput) {
aliasInput.addEventListener("input", (e2) => {
alias.value = e2.target.value;
});
}
if (shortDescInput) {
shortDescInput.addEventListener("input", (e2) => {
shortDesc.value = e2.target.value;
});
}
createDialog({
title: "更改标题",
body: replaceClone,
okText: "保存",
onOk: (closeDialog) => {
onFormSubmit(saveFormBtn1.form, false);
closeDialog();
},
});
});
}
if (assigneeEditBtn) {
assigneeEditBtn.innerText = "加载资源中...";
assigneeEditBtn.classList.add("custom-button");
assigneeEditBtn.classList.add("plain-button");
assigneeEditBtn.classList.add("disabled-button");
assigneeEditBtn.addEventListener("click", () => {
var _a2;
assigneeInputNode.classList.remove("bz_default_hidden");
assigneeEditNode.classList.add("bz_default_hidden");
if (assignToSelect.nextElementSibling.tagName === "BR") {
(_a2 = assignToSelect.nextElementSibling) == null
? void 0
: _a2.remove();
}
if (backButton.style.display === "none") {
backButton.style.display = "block";
}
});
}
if (assigneeTakeBtn) {
assigneeTakeBtn.classList.add("bz_default_hidden");
const takeNode = document.createElement("span");
takeNode.innerText = "转给自己";
takeNode.classList.add("custom-button");
takeNode.classList.add("plain-button");
const assignToPerson = assignToSelect.value;
(_b = assigneeTakeBtn.parentNode) == null
? void 0
: _b.insertBefore(takeNode, assigneeTakeBtn.nextSibling);
takeNode.addEventListener("click", () => {
createDialog({
body: "确定将此任务转给自己?",
bodyStyle: "width: 400px; height: 50px;",
okText: "确定",
onOk: (closeDialog) => {
var _a2;
assigneeTakeBtn.click();
closeDialog();
(_a2 = assigneeInputNode.querySelector("br")) == null
? void 0
: _a2.remove();
onFormSubmit(saveFormBtn1.form, false);
},
onDestroy: () => {
assigneeInputNode.classList.add("bz_default_hidden");
assigneeEditNode.classList.remove("bz_default_hidden");
assignToSelect.value = assignToPerson;
},
});
});
}
}
if (bugStatus && resolution && markDuplicateBox) {
const status1 = bugStatus.value;
const status2 = resolution.value;
completeBtn = createButton(
"标记完成",
(btn) => {
var _a2;
btn.classList.add("custom-button");
btn.classList.add("plain-button");
(_a2 = duplicateSettings.parentNode) == null
? void 0
: _a2.insertBefore(btn, markDuplicateBox);
},
async () => {
resolutionSettings.classList.remove("bz_default_hidden");
resolution.value = RESOLUTION.FIXED;
bugStatus.value = BUG_STATUS.RESOLVED;
cancelBtn.classList.remove("hide");
completeBtn && completeBtn.classList.add("hide");
markDuplicateBox.classList.add("hide");
},
);
const cancelBtn = createButton(
"取消",
(btn) => {
var _a2;
btn.classList.add("plain-button");
btn.classList.add("hide");
(_a2 = duplicateSettings.parentNode) == null
? void 0
: _a2.appendChild(btn);
},
() => {
duplicateSettings.classList.add("bz_default_hidden");
markDuplicateBox.classList.remove("bz_default_hidden");
cancelBtn.classList.add("hide");
completeBtn && completeBtn.classList.remove("hide");
markDuplicateBox.classList.remove("hide");
bugStatus.value = status1;
if (status2) {
resolution.value = RESOLUTION.FIXED;
} else {
resolutionSettings.classList.add("bz_default_hidden");
}
},
);
if (markDuplicateBtn) {
markDuplicateBtn.classList.add("custom-button");
markDuplicateBtn.classList.add("plain-button");
markDuplicateBtn.innerText = "标记重复";
markDuplicateBtn.addEventListener("click", (e) => {
e.preventDefault();
duplicateSettings.classList.remove("bz_default_hidden");
markDuplicateBox.classList.add("bz_default_hidden");
cancelBtn.classList.remove("hide");
completeBtn && completeBtn.classList.add("hide");
});
}
}
if (commentBox) {
clearTextNode(commentBox);
const branchBox = document.createElement("div");
branchBox.style.setProperty("max-width", "610px");
branchBox.style.setProperty("display", "flex");
branchBox.style.setProperty("flex-wrap", "wrap");
if (getCustomBranches().length === 0) {
replaceCustomBranches([
{ title: ": " },
{ title: "develop" },
{ title: "v10.x" },
{ title: "v11.x" },
{ title: "custom_v11.0.1_huaweiDIS" },
{ title: "_R4" },
]);
}
getCustomBranches().forEach((item) => {
createButton(
item.title,
(btn) => {
btn.classList.add("custom-button");
btn.classList.add("plain-button");
btn.classList.add("mb-5");
branchBox.appendChild(btn);
},
() => {
commentTextArea.value = commentTextArea.value + item.title;
},
);
});
(_c = commentBox == null ? void 0 : commentBox.parentElement) == null
? void 0
: _c.insertBefore(branchBox, commentBox);
if (commentBoxLabel) {
commentBoxLabel.classList.add("hide");
}
if (commentTextArea) {
commentTextArea.style.setProperty("min-width", "760px");
commentTextArea.addEventListener("focus", () => {
commentTextArea.rows = 10;
});
}
}
if (attachmentDetails.length) {
const fileNames = Array.from(
document.querySelectorAll(
"#attachment_table td[valign='top']:nth-child(0) b",
),
);
const fileTypeNodes = Array.from(
document.querySelectorAll(
"#attachment_table td[valign='top']:nth-child(1) .bz_attach_extra_info",
),
);
attachmentDetails.forEach((attachment, index) => {
var _a2, _b2, _c2, _d2, _e;
attachment.classList.add("custom-button");
attachment.classList.add("plain-button");
attachment.style.margin = "6px 16px";
const url =
(_a2 = attachment.href.split("&")) == null ? void 0 : _a2[0];
const fileType =
((_e =
(_d2 =
(_c2 =
(_b2 = fileTypeNodes[index]) == null
? void 0
: _b2.innerText) == null
? void 0
: _c2.trim().match(/\(([^)]+)\)/)) == null
? void 0
: _d2[1].split(", ")) == null
? void 0
: _e[1]) ?? "";
const isViewType =
fileType.includes("image") ||
(fileType.includes("video") && !fileType.includes("wmv"));
if (isViewType) {
attachment.innerText = "查看";
} else {
attachment.innerText = "下载";
}
attachment.addEventListener("click", (e) => {
var _a3;
e.preventDefault();
if (fileType.includes("image")) {
const loadingNode = createLoading();
const imageBodyNode = document.createElement("div");
imageBodyNode.classList.add("attachment-container");
imageBodyNode.classList.add("hide");
const imageNode = document.createElement("img");
imageNode.src = url;
imageNode.style = "width: 100%; height: auto;";
imageNode.addEventListener("load", () => {
imageBodyNode.classList.remove("hide");
imageBodyNode.classList.add("show");
loadingNode.classList.add("hide");
});
imageBodyNode.appendChild(imageNode);
const bodyNode = document.createElement("div");
bodyNode.appendChild(loadingNode);
bodyNode.appendChild(imageBodyNode);
createDialog({
title: "图片详情",
hideOk: true,
cancelText: "关闭",
body: bodyNode,
});
} else if (fileType.includes("video") && !fileType.includes("wmv")) {
const loadingNode = createLoading();
const videoBodyNode = document.createElement("div");
videoBodyNode.classList.add("attachment-container");
videoBodyNode.classList.add("hide");
const videoNode = document.createElement("video");
videoNode.controls = true;
videoNode.autoplay = true;
videoNode.loop = true;
videoNode.style = "width: 100%; height: auto;";
const sourceNode = document.createElement("source");
sourceNode.src = url;
sourceNode.type = fileType;
sourceNode.style = "width: 100%; height: auto;";
videoNode.addEventListener("canplaythrough", () => {
videoBodyNode.classList.remove("hide");
videoBodyNode.classList.add("show");
loadingNode.classList.add("hide");
});
videoNode.appendChild(sourceNode);
videoBodyNode.appendChild(videoNode);
const bodyNode = document.createElement("div");
bodyNode.appendChild(loadingNode);
bodyNode.appendChild(videoBodyNode);
createDialog({
title: "视频详情",
hideOk: true,
cancelText: "关闭",
body: bodyNode,
});
} else if (!isViewType) {
downloadResource(
url,
(_a3 = fileNames[index]) == null ? void 0 : _a3.innerText,
);
} else {
showErrorMessage(
"文件不存在,或者不支持从此处" + attachment.innerText,
);
}
});
});
}
const saveForm = (e, saveFormBtn) => {
e.preventDefault();
if (!getPageDetailControl("showSaveConfirmDialog")) {
onFormSubmit(saveFormBtn.form, true, bugId, bugTitleNode.innerText);
return;
}
const tips = [];
if (assignToSelect.value !== reporterEmail) {
tips.push("bug 没有指给报告人");
}
if (!commentTextArea.value) {
tips.push("bug 没有填写备注");
}
if (
![BUG_STATUS.RESOLVED, BUG_STATUS.VERIFIED, BUG_STATUS.CLOSED].includes(
bugStatus.value,
)
) {
tips.push("bug 状态不是 RESOLVED, VERIFIED, CLOSED 其中一个");
}
if (tips.length) {
createDialog({
title: "请确认",
body: `
确定提交表单?
${tips.map((tip, index) => `${index + 1}. ${tip}`).join("")}
`,
style: "transform: translate(-50%, -70%)",
bodyStyle: "width: 500px;",
okText: "确定提交",
onOk: () => {
onFormSubmit(saveFormBtn.form, true, bugId, bugTitleNode.innerText);
},
});
return;
}
onFormSubmit(saveFormBtn.form, true, bugId, bugTitleNode.innerText);
};
if (saveFormBtn1) {
saveFormBtn1.classList.add("custom-button");
saveFormBtn1.value = "保存表单";
saveFormBtn1.title = "此功能可以通过页面顶部页面设置进行配置";
saveFormBtn1.addEventListener("click", (e) => saveForm(e, saveFormBtn1));
}
if (saveFormBtn2) {
saveFormBtn2.classList.add("custom-button");
saveFormBtn2.value = "保存表单";
saveFormBtn2.title = "此功能可以通过页面顶部页面设置进行配置";
saveFormBtn2.addEventListener("click", (e) => saveForm(e, saveFormBtn2));
saveFormBtn2.parentElement.style.setProperty("width", "170px");
saveFormBtn2.parentElement.style.setProperty("display", "flex");
saveFormBtn2.parentElement.style.setProperty("align-items", "center");
const quickSaveBtn = document.createElement("span");
quickSaveBtn.classList.add("custom-button");
quickSaveBtn.innerText = "一键填写";
quickSaveBtn.title = "自动获取 commit 信息,仅限开发人员使用";
quickSaveBtn.addEventListener("click", async (e) => {
const assignToTesterBtn = document.querySelector(
"#assign_to_tester_btn",
);
assignToTesterBtn && assignToTesterBtn.click();
completeBtn && completeBtn.click();
const gitlabConfig = getGitlabConfig();
if (!gitlabConfig) {
showErrorMessage("请先配置 GitLab 信息");
gitlabConfigDialog();
return;
}
const closeMessage = showSuccessMessage(
"正在查询相关的 commit 记录...",
1e3 * 60 * 60,
);
const commits = await getBugCommitsFromProjects(bugId);
closeMessage();
if (!commits.length) {
showErrorMessage(
"没有找到相关的 commit 记录,请检查 Personal Access Token 是否正确,或者修改查询范围",
5e3,
);
return;
}
commentTextArea.value = "";
commits.forEach((commit) => {
commentTextArea.value +=
getProjectName(commit.projectId) +
": " +
commit.targetBranch +
": " +
commit.commitHash +
" " +
commit.commitMessage +
"\n";
});
if (gitlabConfig.autoSaveForm) {
saveForm(e, saveFormBtn2);
}
});
saveFormBtn2.parentElement &&
((_d = saveFormBtn2.parentElement) == null
? void 0
: _d.insertBefore(quickSaveBtn, saveFormBtn2));
}
if (navigationNode) {
const div = document.createElement("div");
div.classList.add("flex-justify-space-between");
const parentNode = navigationNode.parentNode;
parentNode.insertBefore(div, navigationNode.nextSibling);
div.appendChild(navigationNode);
const quickBottomBtn = document.createElement("a");
quickBottomBtn.href = "#footer";
quickBottomBtn.innerText = "快速沉底";
quickBottomBtn.classList.add("custom-button");
quickBottomBtn.classList.add("plain-button");
navigationNode.appendChild(quickBottomBtn);
const collectionNode = document.createElement("div");
collectionNode.classList.add("flex-center");
setCollectionIcon(collectionNode, bugIDNode.innerText);
div.appendChild(collectionNode);
const collectBugNode1 = document.getElementById("collect-bug");
if (collectBugNode1) {
const callback = (_, collectBugNode) => {
const { collectedBugs, hasCollected } = getCollectInfo(
bugIDNode.innerText,
);
let newBugs = {
list: collectedBugs,
};
if (!hasCollected) {
newBugs = {
list: [
...collectedBugs,
{
id: bugIDNode.innerText,
title: bugTitleNode.innerText,
url: window.location.href,
},
],
};
if (collectBugNode.dataset.type !== "no-collected") {
showErrorMessage("数据与页面状态不一致,页面刷新后重试");
setTimeout(() => {
window.location.reload();
}, 1e3);
return;
}
showSuccessMessage("收藏成功");
} else {
newBugs = {
list:
collectedBugs.length > 0 &&
collectedBugs.filter((bug) => bug.id !== bugIDNode.innerText),
};
if (collectBugNode.dataset.type !== "collected") {
showErrorMessage("数据与页面状态不一致,页面刷新后重试");
setTimeout(() => {
window.location.reload();
}, 1e3);
return;
}
showSuccessMessage("已取消收藏");
}
localStorage.setItem(
STORAGE_KEY_MAP.COLLECTED_BUGS,
JSON.stringify(newBugs),
);
setCollectionIcon(collectionNode, bugIDNode.innerText);
const collectBugNode2 = document.getElementById("collect-bug");
if (collectBugNode2) {
collectBugNode2.addEventListener("click", (e) =>
callback(e, collectBugNode2),
);
}
};
collectBugNode1.addEventListener("click", (e) =>
callback(e, collectBugNode1),
);
}
}
if (attachmentNode) {
attachmentNode.classList.add("custom-button");
attachmentNode.innerText = "添加附件";
attachmentNode.title = "此功能可以通过页面顶部页面设置进行配置";
if (getPageDetailControl("showAttechmentDialog")) {
attachmentNode.addEventListener("click", (e) => {
e.preventDefault();
createDialog({
title: "上传附件",
okText: "关闭弹窗 & 刷新页面",
cancelText: "关闭",
bodyStyle: "width: 60vw; height: 70vh;",
body: `
备注:点击 Submit 按钮上传,上传后点击右下角关闭并刷新按钮刷新整个页面,查看上传结果
`,
onMount: () => {
iframeCallback("attachment-iframe", (contentDocument) => {
const header = contentDocument.querySelector("#header");
const footer = contentDocument.querySelector("#footer");
if (header) {
header.remove();
}
if (footer) {
footer.remove();
}
});
},
onOk: () => {
window.location.reload();
},
});
});
}
}
if (attachmentViewAll) {
attachmentViewAll.remove();
}
if (table2AllRows == null ? void 0 : table2AllRows.length) {
table2AllRows.forEach((row) => {
var _a2;
if (
row.firstElementChild &&
row.firstElementChild.classList.contains("bz_hidden_field")
) {
row.firstElementChild.classList.remove("bz_hidden_field");
}
if (
((_a2 = row.firstElementChild) == null
? void 0
: _a2.nextElementSibling) &&
row.firstElementChild.nextElementSibling.classList.contains(
"bz_hidden_field",
)
) {
row.firstElementChild.nextElementSibling.classList.remove(
"bz_hidden_field",
);
}
});
}
if (navigationABtns.length) {
navigationABtns.forEach((node) => {
navBtnAddStyle(node);
});
}
if (navigationFontBtns.length) {
navigationFontBtns.forEach((node) => {
navBtnAddStyle(node, true);
});
}
showHideFormItemsByData();
if (commentNodes.length) {
commentNodes.forEach((node) => {
switchCommitHash2ALink(node, (e, hash, projectName) => {
if (
getPageDetailControl("directOpenGitlabWhenHashRecognized") &&
projectName
) {
openGitlabByHash(hash, projectName);
return;
}
const opts = [
{
label: "复制 hash",
key: "copy",
},
{
label: "从 bi 打开",
key: "bi",
},
{
label: "从 core 打开",
key: "core",
},
{
label: "从 pptr 打开",
key: "PPTR",
},
{
label: "从 workbook 打开",
key: "yh-plugin-workbook",
},
];
const appIns = moreAction(opts, (key) => {
if (key === "copy") {
copyText(hash);
return;
}
openGitlabByHash(hash, key);
});
if (appIns && appIns._) {
applyCallBack(appIns._.setupState.showDropdown, {
posX: e.clientX,
posY: e.clientY,
});
}
});
});
}
if (
localStorage.getItem(STORAGE_KEY_MAP.AUTO_CLEAR_FIRST_COMMENT_BR) ===
"true" &&
firstComment
) {
clearBrAndBlank(firstComment);
}
if (firstCommentHead) {
const span = document.createElement("span");
span.style.setProperty("display", "inline-flex");
span.style.setProperty("align-items", "center");
span.style.setProperty("transform", "translateY(2px)");
firstCommentHead.appendChild(span);
const checkBox = document.createElement("input");
const checkBoxLabel = document.createElement("label");
checkBoxLabel.classList.add("ml-5");
checkBoxLabel.classList.add("clear-br-label");
checkBoxLabel.innerText = "自动调整本评论文本的上下间距";
checkBoxLabel.title = "仅处理富文本评论。设置后下次自动生效";
checkBox.type = "checkbox";
checkBox.classList.add("ml-5");
span.appendChild(checkBox);
span.appendChild(checkBoxLabel);
checkBox.checked =
localStorage.getItem(STORAGE_KEY_MAP.AUTO_CLEAR_FIRST_COMMENT_BR) ===
"true";
const setCheck = (checked) => {
if (checked) {
clearBrAndBlank(firstComment);
}
checkBox.checked = checked;
localStorage.setItem(
STORAGE_KEY_MAP.AUTO_CLEAR_FIRST_COMMENT_BR,
checked ? "true" : "false",
);
};
checkBoxLabel.addEventListener("click", () => {
setCheck(!checkBox.checked);
});
checkBox.addEventListener("change", (e) => {
setCheck(e.target.checked);
});
firstCommentHead.appendChild(span);
}
viewImageFullScreen(firstComment);
};
const newCCList = () => {
const persons = getPersonMap();
const ccSelect = document.querySelector("#newcc");
const ccSelectOptions = Array.from(
document.querySelectorAll("#newcc > option"),
);
const div = document.createElement("div");
div.id = "cc_list_vue_app";
ccSelect.parentNode.insertBefore(div, ccSelect);
ccSelect.classList.add("bz_default_hidden");
ccSelectOptions.forEach((node) => {
const strMatch = node.innerText.match(
/<([^]+)@(yonghongtech|test|sina).(com|cn)>/,
);
const englishName = strMatch ? strMatch[1] : "";
node.innerText =
englishName && persons[englishName]
? persons[englishName] +
" - " +
node.innerText.replace("-", "").replace(persons[englishName], "")
: node.innerText;
});
const { createApp, ref, reactive } = Vue;
const app = createApp({
template: `
`,
setup() {
const selectedValue = ref(ccSelect.value);
const options = reactive(
ccSelectOptions.map((option) => {
return {
label: option.innerText,
value: option.value,
};
}),
);
return {
selectedValue,
options,
handleUpdateValue(value) {
ccSelect.value = value;
},
};
},
});
app.use(naive);
return app.mount("#cc_list_vue_app");
};
const componentList = () => {
const component = document.querySelector("#component");
if (!component) {
return;
}
const componentOptions = Array.from(
document.querySelectorAll("#component > option"),
);
const div = document.createElement("div");
div.id = "component_list_vue_app";
component.parentNode.insertBefore(div, component);
component.classList.add("bz_default_hidden");
const { createApp, ref, reactive } = Vue;
const app = createApp({
template: `
`,
setup() {
const selectedValue = ref(component.value);
const options = reactive(
componentOptions.map((option) => {
return {
label: option.innerText,
value: option.value,
};
}),
);
return {
selectedValue,
options,
handleUpdateValue(value) {
component.value = value;
const errorComponents = Array.from(
document.querySelectorAll(".validation_error_text"),
);
errorComponents.forEach((error) => {
if (
error.innerText === "You must select a Component for this bug."
) {
error.classList.add("bz_default_hidden");
}
});
},
};
},
});
app.use(naive);
return app.mount("#component_list_vue_app");
};
const featureList = () => {
const feature = document.querySelector("#cf_newfeatureid");
const featureOptions = Array.from(
document.querySelectorAll("#cf_newfeatureid > option"),
);
const div = document.createElement("div");
div.id = "feature_list_vue_app";
feature.parentNode.insertBefore(div, feature);
feature.classList.add("bz_default_hidden");
const { createApp, ref, reactive } = Vue;
const app = createApp({
template: `
`,
setup() {
const selectedValue = ref(feature.value);
const options = reactive(
featureOptions.map((option) => {
return {
label: option.innerText,
value: option.value,
};
}),
);
return {
selectedValue,
options,
handleUpdateValue(value) {
feature.value = value;
},
};
},
});
app.use(naive);
return app.mount("#feature_list_vue_app");
};
const versionList = () => {
const version = document.querySelector("#version");
if (!version) {
return;
}
const versionOptions = Array.from(
document.querySelectorAll("#version > option"),
);
const div = document.createElement("div");
div.id = "version_list_vue_app";
version.parentNode.insertBefore(div, version);
version.classList.add("bz_default_hidden");
const { createApp, ref, reactive } = Vue;
const app = createApp({
template: `
`,
setup() {
const selectedValue = ref(version.value);
const options = reactive(
versionOptions.map((option) => {
return {
label: option.innerText,
value: option.value,
};
}),
);
return {
selectedValue,
options,
handleUpdateValue(value) {
version.value = value;
},
};
},
});
app.use(naive);
return app.mount("#version_list_vue_app");
};
const renderBugDetailPage = () => {
if (PATHNAME === PathNameEnum.BUG_DETAIL) {
renderBugDetail();
assignToList();
newCCList();
featureList();
componentList();
versionList();
}
};
const renderBugReportEntry = () => {
const products = Array.from(
document.querySelectorAll("table th[valign='top'] a"),
);
const productDescs = Array.from(
document.querySelectorAll("table td[valign='top']"),
);
if (products.length) {
products.forEach((p) => {
p.classList.add("custom-button");
p.addEventListener("click", (e) => {
e.preventDefault();
window.open(p.href, "_blank");
});
});
}
if (productDescs.length) {
productDescs.forEach((pd) => {
pd.vAlign = "center";
});
}
};
const updateQuickSummary = (text, isAdd, isShowMessage = true) => {
let quickSummary = getQuickSummary();
if (isAdd) {
if (quickSummary.some((item) => item.title === text)) {
if (isShowMessage) {
showErrorMessage("快捷短语已存在");
}
return;
}
quickSummary.push({ title: text });
if (isShowMessage) {
showSuccessMessage("添加成功");
}
} else {
quickSummary = quickSummary.filter((item) => item.title !== text);
if (isShowMessage) {
showSuccessMessage("删除成功");
}
}
localStorage.setItem(
STORAGE_KEY_MAP.QUICK_SUMMARY,
JSON.stringify(quickSummary),
);
};
const getQuickSummary = () => {
return JSON.parse(
localStorage.getItem(STORAGE_KEY_MAP.QUICK_SUMMARY) ?? "[]",
);
};
const replaceQuickSummary = (quickSummary) => {
localStorage.setItem(
STORAGE_KEY_MAP.QUICK_SUMMARY,
JSON.stringify(quickSummary),
);
};
const quickSummaryDialog = () => {
let appIns = null;
const appId = "quick_summary_vue_app";
createDialog({
title: "自定义快捷短语",
cancelText: "关闭",
okText: "刷新页面",
bodyStyle: "width: 60vw; height: 60vh;",
body: `
`,
onOk: () => {
window.location.reload();
},
onMount: () => {
const quickSummary = getQuickSummary();
const { createApp, ref, h } = Vue;
const app = createApp({
template: `
搜索:
新增
`,
setup() {
const searchValue = ref("");
const quickSummaryText = ref("");
const data = ref(quickSummary);
const columns = ref([
{
title: "名称",
dataIndex: "title",
key: "title",
width: "calc(60vw - 380px)",
ellipsis: {
tooltip: true,
},
},
{
title: "排序",
dataIndex: "sort",
key: "sort",
width: 200,
render: (_, index) => {
return h(
naive.NSpace,
{
horizontal: true,
},
{
default: () => [
h(naive.NButton, {
strong: true,
tertiary: true,
size: "small",
textContent: "↑",
disabled: index === 0,
onClick: () => {
data.value = moveUp(data.value, index);
replaceQuickSummary(data.value);
},
}),
h(naive.NButton, {
strong: true,
tertiary: true,
size: "small",
textContent: "↓",
disabled: index === data.value.length - 1,
onClick: () => {
data.value = moveDown(data.value, index);
replaceQuickSummary(data.value);
},
}),
],
},
);
},
},
{
title: "操作",
key: "actions",
width: 180,
render: (row) => {
return h(
naive.NSpace,
{
horizontal: true,
},
{
default: () => [
h(naive.NButton, {
strong: true,
tertiary: true,
size: "small",
textContent: "删除",
onClick: () => {
data.value = data.value.filter(
(item) => item.title !== row.title,
);
updateQuickSummary(row.title, false);
},
}),
],
},
);
},
},
]);
const onSearch = debounce((value) => {
if (value) {
data.value = data.value.filter((item) =>
item.title.includes(value),
);
} else {
data.value = getQuickSummary();
}
}, 500);
const addQuickSummary = debounce(() => {
if (quickSummaryText.value) {
data.value = [...data.value, { title: quickSummaryText.value }];
updateQuickSummary(quickSummaryText.value, true);
quickSummaryText.value = "";
}
}, 500);
return {
searchValue,
quickSummaryText,
data,
columns,
onSearch,
addQuickSummary,
};
},
});
app.use(naive);
appIns = app.mount("#" + appId);
},
});
return appIns;
};
const countLineBreaks = (str) => {
if (!str) {
return 0;
}
return (str.match(/[\n\r]/g) || []).length;
};
const validateSummary = (value) => {
const errorComponents = Array.from(
document.querySelectorAll(".validation_error_text"),
);
if (value) {
errorComponents.forEach((error) => {
if (error.innerText === "You must enter a Summary for this bug.") {
error.classList.add("bz_default_hidden");
}
});
} else {
errorComponents.forEach((error) => {
if (error.innerText === "You must enter a Summary for this bug.") {
error.classList.remove("bz_default_hidden");
}
});
}
};
const renderBugReport = () => {
var _a, _b, _c, _d, _e, _f;
const newBugForm = document.querySelector("#Create");
const allTableCells = newBugForm
? Array.from(newBugForm.querySelectorAll("table tr td"))
: null;
const descriptionTextArea = document.querySelector("#comment");
const versionLabel = document.querySelector("#field_label_version");
const guessNote = document.querySelector("#os_guess_note");
const commit = document.querySelector("#commit");
const shortDesc = document.querySelector("#short_desc");
const attachFalseInput = document.querySelector("#attachment_false input");
const attachTrueInput = document.querySelector("#attachment_true input");
const attatchData = document.querySelector(
"#attachment_true .attachment_entry input",
);
const priority = document.querySelector("#field_label_priority");
const topTip = document.querySelector("form table tr");
const possibleDuplicatesContainer = document.querySelector(
"#possible_duplicates_container",
);
const assignedToHelpLink = document.querySelector(
"#field_label_assigned_to .field_help_link",
);
if (descriptionTextArea) {
descriptionTextArea.onfocus = null;
descriptionTextArea.addEventListener("focus", (e) => {
e.preventDefault();
e.stopPropagation();
});
const col = descriptionTextArea.parentElement;
for (let i = 0; i < col.children.length; i++) {
const child = col.children[i];
if (child.tagName === "BR") {
child.remove();
}
}
}
if (Array.isArray(allTableCells)) {
allTableCells.forEach((cell) => {
var _a2;
const textContent =
((_a2 = cell == null ? void 0 : cell.textContent) == null
? void 0
: _a2.trim().replace(/\s+/g, "")) || "";
if (
(cell.colSpan === 4 || cell.colSpan === 3) &&
cell.childElementCount === 0 &&
textContent === ""
) {
cell.remove();
}
});
}
if (versionLabel) {
versionLabel.rowSpan = 1;
versionLabel.nextElementSibling.rowSpan = 1;
}
if (guessNote) {
((_a = guessNote.parentNode) == null
? void 0
: _a.firstElementChild
).colSpan = 1;
guessNote.firstElementChild.innerText =
"已经预填部分字段,请自行检查正确与否";
}
if (commit) {
commit.classList.add("custom-button");
commit.classList.add("margin-0");
commit.value = "提交 bug";
commit.addEventListener("mouseup", () => {
const timer = setTimeout(() => {
const errorComponents = Array.from(
document.querySelectorAll(".validation_error_text"),
);
errorComponents.forEach((error) => {
if (error.innerText === "You must enter a Summary for this bug.") {
error.style.setProperty("position", "absolute");
error.style.setProperty("top", "8px");
error.style.setProperty("right", "160px");
}
});
clearTimeout(timer);
}, 50);
});
}
if (shortDesc) {
const quickSummaryBox = document.createElement("tr");
const quickSummaryBoxTitle = document.createElement("th");
const quickSummaryBoxCell = document.createElement("td");
quickSummaryBoxCell.colSpan = 3;
quickSummaryBox.appendChild(quickSummaryBoxTitle);
quickSummaryBox.appendChild(quickSummaryBoxCell);
quickSummaryBoxCell.style.setProperty("width", "650px");
quickSummaryBoxCell.style.setProperty("display", "flex");
quickSummaryBoxCell.style.setProperty("flex-wrap", "wrap");
if (getQuickSummary().length === 0) {
replaceQuickSummary([{ title: "" }]);
}
getQuickSummary().forEach((item) => {
createButton(
item.title,
(btn) => {
btn.classList.add("custom-button");
btn.classList.add("plain-button");
btn.classList.add("margin-0");
btn.classList.add("mr-5");
btn.classList.add("mb-5");
quickSummaryBoxCell.appendChild(btn);
},
() => {
const descText = shortDesc.value + item.title;
shortDesc.value = descText;
validateSummary(descText);
},
);
});
(_b =
possibleDuplicatesContainer == null
? void 0
: possibleDuplicatesContainer.parentElement) == null
? void 0
: _b.insertBefore(quickSummaryBox, possibleDuplicatesContainer);
shortDesc.parentElement.style.setProperty("display", "flex");
shortDesc.parentElement.style.setProperty("align-items", "center");
shortDesc.parentElement.style.setProperty("width", "800px");
shortDesc.parentElement.style.setProperty("position", "relative");
shortDesc.addEventListener("input", (e) => {
var _a2;
return validateSummary(
(_a2 = e == null ? void 0 : e.target) == null ? void 0 : _a2.value,
);
});
const div = document.createElement("div");
div.classList.add("custom-button");
div.innerText = "自定义快捷短语";
div.addEventListener("click", () => {
quickSummaryDialog();
});
shortDesc.parentElement.insertBefore(div, shortDesc.nextElementSibling);
}
const btnGroup = document.createElement("div");
btnGroup.classList.add("mt-5");
btnGroup.style.setProperty("display", "flex");
btnGroup.style.setProperty("justify-content", "flex-start");
btnGroup.style.setProperty("align-items", "center");
(descriptionTextArea == null
? void 0
: descriptionTextArea.parentElement) &&
descriptionTextArea.parentElement.appendChild(btnGroup);
const switchBtn = createButton(
"切换为普通输入框",
(btn) => {
btn.classList.add("custom-button");
btn.classList.add("margin-0");
btn.classList.add("mr-5");
btn.title = "切换为普通输入框后,不支持切回富文本";
if (
descriptionTextArea == null
? void 0
: descriptionTextArea.parentElement
) {
btnGroup.appendChild(btn);
}
},
() => {
switchBtn.remove();
const descriptionCKEEditor = document.querySelector("#cke_comment");
if (descriptionCKEEditor) {
descriptionCKEEditor.style.setProperty("display", "none");
}
descriptionTextArea.style.setProperty("display", "block");
descriptionTextArea.style.setProperty("visibility", "visible");
descriptionTextArea.value =
localStorage.getItem(STORAGE_KEY_MAP.NEW_BUG_COMMENT_TEMPLATE) ||
COMMENT_DEFAULT_TEMPLATE_1;
descriptionTextArea.rows =
countLineBreaks(descriptionTextArea.value) + 2;
createButton(
"将当前描述内容设置为默认模板",
(btn) => {
btn.classList.add("custom-button");
btn.classList.add("margin-0");
btn.classList.add("mr-5");
btn.classList.add("plain-button");
if (
descriptionTextArea == null
? void 0
: descriptionTextArea.parentElement
) {
btnGroup.appendChild(btn);
}
},
() => {
if (
!(descriptionTextArea == null
? void 0
: descriptionTextArea.value)
) {
showErrorMessage("请输入模板内容");
return;
}
localStorage.setItem(
STORAGE_KEY_MAP.NEW_BUG_COMMENT_TEMPLATE,
(descriptionTextArea == null
? void 0
: descriptionTextArea.value) || "",
);
showSuccessMessage("模板已更新");
},
);
createButton(
"使用模板1",
(btn) => {
btn.classList.add("custom-button");
btn.classList.add("plain-button");
btn.title = COMMENT_DEFAULT_TEMPLATE_1;
if (
descriptionTextArea == null
? void 0
: descriptionTextArea.parentElement
) {
btnGroup.appendChild(btn);
}
},
() => {
descriptionTextArea.rows = 24;
descriptionTextArea.value = COMMENT_DEFAULT_TEMPLATE_1;
},
);
createButton(
"使用模板2",
(btn) => {
btn.classList.add("custom-button");
btn.classList.add("plain-button");
btn.title = COMMENT_DEFAULT_TEMPLATE_2;
if (
descriptionTextArea == null
? void 0
: descriptionTextArea.parentElement
) {
btnGroup.appendChild(btn);
}
},
() => {
descriptionTextArea.rows = 19;
descriptionTextArea.value = COMMENT_DEFAULT_TEMPLATE_2;
},
);
},
);
if (attachFalseInput && attachTrueInput && attatchData) {
attachFalseInput.value = "上传附件";
attachTrueInput.value = "取消上传";
attachFalseInput.classList.add("custom-button");
attachFalseInput.classList.add("margin-0");
attachFalseInput.classList.add("plain-button");
attachTrueInput.classList.add("custom-button");
attachTrueInput.classList.add("margin-0");
attachTrueInput.classList.add("plain-button");
const uploadFileBtn = document.createElement("span");
const fileName = document.createElement("span");
uploadFileBtn.classList.add("custom-button");
uploadFileBtn.classList.add("margin-0");
uploadFileBtn.classList.add("plain-button");
uploadFileBtn.innerText = "重新上传";
fileName.classList.add("bug-new_filename");
attatchData.classList.add("bz_default_hidden");
(_c = attatchData.parentNode) == null
? void 0
: _c.insertBefore(fileName, attatchData.nextElementSibling);
(_d = attatchData.parentNode) == null
? void 0
: _d.insertBefore(uploadFileBtn, attatchData.nextElementSibling);
attachFalseInput.addEventListener("click", () => {
attatchData.click();
});
uploadFileBtn.addEventListener("click", () => {
attatchData.click();
});
attatchData.addEventListener("change", (e) => {
const pathArr = e.target.value.split("\\");
const sizeM = e.target.files[0].size / 1024;
fileName.innerText =
"文件名:" +
pathArr[pathArr.length - 1] +
" 大小:" +
sizeM.toFixed(2) +
"kb";
});
}
if (topTip) {
topTip.remove();
}
if (priority) {
(_f =
(_e = priority.parentElement) == null
? void 0
: _e.firstElementChild) == null
? void 0
: _f.remove();
}
if (assignedToHelpLink) {
assignedToHelpLink.style.setProperty("color", "var(--primaryColor)");
}
};
const ccList = () => {
const persons = getPersonMap();
const ccSelect = document.querySelector("#cc");
if (!ccSelect) {
return;
}
const ccSelectOptions = Array.from(
document.querySelectorAll("#cc > option"),
);
const div = document.createElement("div");
div.id = "cc_list_vue_app";
ccSelect.parentNode.insertBefore(div, ccSelect);
ccSelect.classList.add("bz_default_hidden");
ccSelectOptions.forEach((node) => {
const strMatch = node.innerText.match(
/<([^]+)@(yonghongtech|test|sina).(com|cn)>/,
);
const englishName = strMatch ? strMatch[1] : "";
node.innerText =
englishName && persons[englishName]
? persons[englishName] +
" - " +
node.innerText.replace("-", "").replace(persons[englishName], "")
: node.innerText;
});
const { createApp, ref, reactive } = Vue;
const app = createApp({
template: `
`,
setup() {
const selectedValue = ref(ccSelect.value);
const options = reactive(
ccSelectOptions.map((option) => {
return {
label: option.innerText,
value: option.value,
};
}),
);
return {
selectedValue,
options,
handleUpdateValue(value) {
ccSelect.value = value;
},
};
},
});
app.use(naive);
return app.mount("#cc_list_vue_app");
};
const renderBugReportPage = () => {
if (PATHNAME === PathNameEnum.BUG_NEW) {
if (isBugReportPage()) {
renderBugReport();
componentList();
assignToList();
versionList();
featureList();
ccList();
}
if (isBugReportEntryPage()) {
renderBugReportEntry();
}
}
};
const renderBugReportEntryPage = () => {
if (PATHNAME === PathNameEnum.BUG_NEW_ENTRY) {
renderBugReportEntry();
}
};
const renderBugAttachment = () => {
const attachmentSubmit = document.querySelector(
".attachment_entry input[value='Submit']",
);
if (attachmentSubmit) {
attachmentSubmit.classList.add("custom-button");
}
};
const renderBugAttachmentPage = () => {
if (PATHNAME === PathNameEnum.BUG_ATTACHMENT) {
renderBugAttachment();
}
};
const renderBugHistory = () => {
const table = document.querySelector("#bugzilla-body table");
const tds = Array.from(
document.querySelectorAll("#bugzilla-body table td"),
);
const bugLinks = Array.from(
document.querySelectorAll("#bugzilla-body .bz_bug_link"),
);
if (table) {
table.style = "border-collapse: collapse";
const persons = getPersonMap();
if (Array.isArray(tds)) {
tds.forEach((td) => {
td.innerText = getChineseName(persons, td.innerText);
});
}
}
if (bugLinks.length > 0) {
bugLinks.forEach((link) => {
link.classList.add("hide");
});
}
};
const renderBugHistoryPage = () => {
if (PATHNAME === PathNameEnum.BUG_HISTORY) {
renderBugHistory();
}
};
const addStyle = (css) => {
const style2 = document.createElement("style");
style2.type = "text/css";
style2.innerHTML = css;
document.getElementsByTagName("head")[0].appendChild(style2);
};
const renderBugProcess = () => {
const bugLink = document.querySelector("#bugzilla-body .bz_bug_link");
if (bugLink) {
bugLink.innerText = "返回 " + bugLink.innerText;
bugLink.classList.add("custom-button");
}
};
const renderBugProcessPage = () => {
if (PATHNAME === PathNameEnum.BUG_PROCESS) {
renderBugProcess();
}
};
try {
async function setup() {
addStyle(style);
await loadScriptByGM(CDNScriptURLEnum.VUE);
await loadScriptByGM(CDNScriptURLEnum.NAIVE_UI);
renderBugCommon();
renderBugListPage();
renderBugDetailPage();
renderBugReportPage();
renderBugReportEntryPage();
renderBugAttachmentPage();
renderBugHistoryPage();
renderBugProcessPage();
}
setup();
} catch (error) {
console.error(error);
}
})();