@pubinfo-pr/devtools 0.171.6 → 0.171.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/assets/{Navbar-L7rRcdIR.js → Navbar-D84j2-0V.js} +3 -2
- package/dist/client/assets/{PanelGrids-D1Mem7DG.js → PanelGrids-F8O_nB5x.js} +2 -2
- package/dist/client/assets/{SelectTabs-mJnHCcDh.js → SelectTabs-S1Y6g4Xn.js} +2 -2
- package/dist/client/assets/_plugin-vue_export-helper-D8E0syuh.js +6 -0
- package/dist/client/assets/{component-CxDL583T.js → component-zQaPK8ug.js} +4 -4
- package/dist/client/assets/{fetch-CC6_FGnT.js → fetch-fetJJUYt.js} +3 -7
- package/dist/client/assets/{import-CBxCEk9U.js → import-kaeBvG5r.js} +4 -4
- package/dist/client/assets/{index-BxhNhfma.js → index-BgqWVAMJ.js} +11 -6
- package/dist/client/assets/index-XXyHuz_l.css +443 -0
- package/dist/client/assets/issue-BHrGN1_d.css +10 -0
- package/dist/client/assets/issue-DgV1g0vO.js +130 -0
- package/dist/client/assets/{pages-BFUVSsAM.js → pages-RrD-Ux_k.js} +5 -12
- package/dist/client/assets/{server-router-DaxHNw-y.js → server-router-CoUFJpjd.js} +5 -4
- package/dist/client/index.html +2 -2
- package/dist/client/issue.svg +1 -0
- package/dist/index.mjs +155 -16
- package/dist/panel/index.d.mts +1 -0
- package/dist/panel/index.mjs +23 -0
- package/package.json +1 -1
- package/dist/client/assets/index-B9Onnz0R.css +0 -443
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { B as withCtx, G as isRef, V as withDirectives, Y as ref, b as defineComponent, c as vModelText, f as computed, g as createElementBlock, h as createCommentVNode, it as toDisplayString, k as openBlock, m as createBlock, nt as normalizeClass, p as createBaseVNode, r as Transition, tt as unref, v as createTextVNode, y as createVNode } from "./index-BgqWVAMJ.js";
|
|
2
|
+
import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-D8E0syuh.js";
|
|
3
|
+
import { t as PanelGrids_default } from "./PanelGrids-F8O_nB5x.js";
|
|
4
|
+
var _hoisted_1 = { class: "flex flex-col gap-4 m-auto h-full max-w-400 w-full p-5 px-5 md:px-20 of-auto" };
|
|
5
|
+
var _hoisted_2 = { class: "flex flex-col gap-4" };
|
|
6
|
+
var _hoisted_3 = { class: "flex flex-col gap-1" };
|
|
7
|
+
var _hoisted_4 = { class: "flex flex-col gap-1" };
|
|
8
|
+
var _hoisted_5 = { class: "flex flex-col gap-1" };
|
|
9
|
+
var _hoisted_6 = { class: "flex flex-col gap-1" };
|
|
10
|
+
var _hoisted_7 = { class: "flex flex-col gap-1" };
|
|
11
|
+
var _hoisted_8 = { class: "flex items-center justify-end gap-3 mt-2 mb-6" };
|
|
12
|
+
var _hoisted_9 = ["disabled"];
|
|
13
|
+
var _hoisted_10 = { class: "flex items-center gap-1.5" };
|
|
14
|
+
var API_ROOT = "/__pubinfo_devtools_api";
|
|
15
|
+
var issue_default = /* @__PURE__ */ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
16
|
+
name: "IssuePage",
|
|
17
|
+
__name: "issue",
|
|
18
|
+
setup(__props) {
|
|
19
|
+
const title = ref("");
|
|
20
|
+
const description = ref("");
|
|
21
|
+
const steps = ref("");
|
|
22
|
+
const expected = ref("");
|
|
23
|
+
const actual = ref("");
|
|
24
|
+
const submitting = ref(false);
|
|
25
|
+
const toastVisible = ref(false);
|
|
26
|
+
const toastMessage = ref("");
|
|
27
|
+
const toastType = ref("success");
|
|
28
|
+
let toastTimer = null;
|
|
29
|
+
function showToast(message, type = "success") {
|
|
30
|
+
if (toastTimer) clearTimeout(toastTimer);
|
|
31
|
+
toastMessage.value = message;
|
|
32
|
+
toastType.value = type;
|
|
33
|
+
toastVisible.value = true;
|
|
34
|
+
toastTimer = setTimeout(() => {
|
|
35
|
+
toastVisible.value = false;
|
|
36
|
+
}, 3e3);
|
|
37
|
+
}
|
|
38
|
+
async function submitIssue() {
|
|
39
|
+
submitting.value = true;
|
|
40
|
+
try {
|
|
41
|
+
const payload = {
|
|
42
|
+
title: title.value,
|
|
43
|
+
description: description.value,
|
|
44
|
+
steps: steps.value,
|
|
45
|
+
expected: expected.value,
|
|
46
|
+
actual: actual.value
|
|
47
|
+
};
|
|
48
|
+
const res = await fetch(`${API_ROOT}/issue`, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
headers: { "Content-Type": "application/json" },
|
|
51
|
+
body: JSON.stringify(payload)
|
|
52
|
+
});
|
|
53
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
54
|
+
if ((await res.json()).success) showToast(`提交成功!`, "success");
|
|
55
|
+
else showToast("提交成功!感谢你的反馈。", "success");
|
|
56
|
+
resetForm();
|
|
57
|
+
} catch {
|
|
58
|
+
showToast("提交失败,请稍后重试。", "error");
|
|
59
|
+
} finally {
|
|
60
|
+
submitting.value = false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function resetForm() {
|
|
64
|
+
title.value = "";
|
|
65
|
+
description.value = "";
|
|
66
|
+
steps.value = "";
|
|
67
|
+
expected.value = "";
|
|
68
|
+
actual.value = "";
|
|
69
|
+
}
|
|
70
|
+
const isFormValid = computed(() => title.value.trim().length > 0);
|
|
71
|
+
return (_ctx, _cache) => {
|
|
72
|
+
const _component_PanelGrids = PanelGrids_default;
|
|
73
|
+
return openBlock(), createBlock(_component_PanelGrids, { class: "h-screen w-full" }, {
|
|
74
|
+
default: withCtx(() => [createBaseVNode("div", _hoisted_1, [
|
|
75
|
+
_cache[10] || (_cache[10] = createBaseVNode("div", { class: "flex items-center gap-3 mt-6" }, [createBaseVNode("div", { class: "i-carbon-debug text-3xl text-orange" }), createBaseVNode("h1", { class: "text-2xl font-bold" }, " 提交 Bug Report ")], -1)),
|
|
76
|
+
_cache[11] || (_cache[11] = createBaseVNode("p", { class: "text-sm op50" }, " 在此填写 Bug 信息并提交。 ", -1)),
|
|
77
|
+
createVNode(Transition, { name: "toast" }, {
|
|
78
|
+
default: withCtx(() => [unref(toastVisible) ? (openBlock(), createElementBlock("div", {
|
|
79
|
+
key: 0,
|
|
80
|
+
class: normalizeClass(["fixed right-5 top-5 z-100 flex items-center gap-2 rounded-lg px-4 py-3 text-sm text-white shadow-lg", unref(toastType) === "success" ? "bg-green-6" : "bg-red-6"])
|
|
81
|
+
}, [createBaseVNode("div", { class: normalizeClass(unref(toastType) === "success" ? "i-carbon-checkmark-filled" : "i-carbon-warning-filled") }, null, 2), createTextVNode(" " + toDisplayString(unref(toastMessage)), 1)], 2)) : createCommentVNode("", true)]),
|
|
82
|
+
_: 1
|
|
83
|
+
}),
|
|
84
|
+
createBaseVNode("div", _hoisted_2, [
|
|
85
|
+
createBaseVNode("div", _hoisted_3, [_cache[5] || (_cache[5] = createBaseVNode("label", { class: "text-sm font-medium" }, [createTextVNode(" 标题 "), createBaseVNode("span", { class: "text-red" }, "*")], -1)), withDirectives(createBaseVNode("input", {
|
|
86
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isRef(title) ? title.value = $event : null),
|
|
87
|
+
type: "text",
|
|
88
|
+
placeholder: "简要描述你遇到的问题",
|
|
89
|
+
class: "w-full rounded-lg border n-border-base n-bg-base px-3 py-2 text-sm outline-none transition focus:border-primary"
|
|
90
|
+
}, null, 512), [[vModelText, unref(title)]])]),
|
|
91
|
+
createBaseVNode("div", _hoisted_4, [_cache[6] || (_cache[6] = createBaseVNode("label", { class: "text-sm font-medium" }, "问题描述", -1)), withDirectives(createBaseVNode("textarea", {
|
|
92
|
+
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => isRef(description) ? description.value = $event : null),
|
|
93
|
+
rows: "6",
|
|
94
|
+
placeholder: "详细描述你遇到的问题...",
|
|
95
|
+
class: "w-full rounded-lg border n-border-base n-bg-base px-3 py-2 text-sm outline-none transition resize-y focus:border-primary"
|
|
96
|
+
}, null, 512), [[vModelText, unref(description)]])]),
|
|
97
|
+
createBaseVNode("div", _hoisted_5, [_cache[7] || (_cache[7] = createBaseVNode("label", { class: "text-sm font-medium" }, "复现步骤", -1)), withDirectives(createBaseVNode("textarea", {
|
|
98
|
+
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => isRef(steps) ? steps.value = $event : null),
|
|
99
|
+
rows: "6",
|
|
100
|
+
placeholder: "1. 打开页面\n2. 点击按钮\n3. ...",
|
|
101
|
+
class: "w-full rounded-lg border n-border-base n-bg-base px-3 py-2 text-sm outline-none transition resize-y focus:border-primary"
|
|
102
|
+
}, null, 512), [[vModelText, unref(steps)]])]),
|
|
103
|
+
createBaseVNode("div", _hoisted_6, [_cache[8] || (_cache[8] = createBaseVNode("label", { class: "text-sm font-medium" }, "期望行为", -1)), withDirectives(createBaseVNode("textarea", {
|
|
104
|
+
"onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => isRef(expected) ? expected.value = $event : null),
|
|
105
|
+
rows: "4",
|
|
106
|
+
placeholder: "你期望发生什么...",
|
|
107
|
+
class: "w-full rounded-lg border n-border-base n-bg-base px-3 py-2 text-sm outline-none transition resize-y focus:border-primary"
|
|
108
|
+
}, null, 512), [[vModelText, unref(expected)]])]),
|
|
109
|
+
createBaseVNode("div", _hoisted_7, [_cache[9] || (_cache[9] = createBaseVNode("label", { class: "text-sm font-medium" }, "实际行为", -1)), withDirectives(createBaseVNode("textarea", {
|
|
110
|
+
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => isRef(actual) ? actual.value = $event : null),
|
|
111
|
+
rows: "4",
|
|
112
|
+
placeholder: "实际上发生了什么...",
|
|
113
|
+
class: "w-full rounded-lg border n-border-base n-bg-base px-3 py-2 text-sm outline-none transition resize-y focus:border-primary"
|
|
114
|
+
}, null, 512), [[vModelText, unref(actual)]])])
|
|
115
|
+
]),
|
|
116
|
+
createBaseVNode("div", _hoisted_8, [createBaseVNode("button", {
|
|
117
|
+
disabled: !unref(isFormValid) || unref(submitting),
|
|
118
|
+
class: "rounded-lg bg-orange px-4 py-2 text-sm text-white font-medium transition hover:bg-orange-6 disabled:cursor-not-allowed disabled:op50",
|
|
119
|
+
onClick: submitIssue
|
|
120
|
+
}, [createBaseVNode("span", _hoisted_10, [createBaseVNode("div", { class: normalizeClass(unref(submitting) ? "i-carbon-circle-dash animate-spin" : "i-carbon-send-alt") }, null, 2), createTextVNode(" " + toDisplayString(unref(submitting) ? "提交中..." : "提交"), 1)])], 8, _hoisted_9), createBaseVNode("button", {
|
|
121
|
+
class: "rounded-lg border n-border-base px-4 py-2 text-sm transition hover:bg-active",
|
|
122
|
+
onClick: resetForm
|
|
123
|
+
}, " 重置 ")])
|
|
124
|
+
])]),
|
|
125
|
+
_: 1
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}), [["__scopeId", "data-v-20b6063c"]]);
|
|
130
|
+
export { issue_default as default };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as usePackageVersion$1, i as overviewFetch,
|
|
3
|
-
import { t as
|
|
1
|
+
import { B as withCtx, J as readonly, M as renderSlot, R as watch, Y as ref, _ as createStaticVNode, b as defineComponent, f as computed, g as createElementBlock, h as createCommentVNode, it as toDisplayString, k as openBlock, m as createBlock, p as createBaseVNode, q as reactive, t as __vitePreload, tt as unref, u as Fragment, v as createTextVNode, y as createVNode } from "./index-BgqWVAMJ.js";
|
|
2
|
+
import { a as usePackageVersion$1, i as overviewFetch, o as Badge_default, p as createEventHook } from "./fetch-fetJJUYt.js";
|
|
3
|
+
import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-D8E0syuh.js";
|
|
4
|
+
import { t as PanelGrids_default } from "./PanelGrids-F8O_nB5x.js";
|
|
4
5
|
function usePackageVersion(packageName) {
|
|
5
6
|
const info = ref(null);
|
|
6
7
|
const isLoading = ref(false);
|
|
@@ -273,15 +274,7 @@ var pages_default = /* @__PURE__ */ defineComponent({
|
|
|
273
274
|
createBaseVNode("div", _hoisted_17, toDisplayString(unref(formatDuration$1)(unref(timings).hmr)), 1)
|
|
274
275
|
])])
|
|
275
276
|
]),
|
|
276
|
-
_cache[13] || (_cache[13] = createBaseVNode("div", { class: "flex flex-wrap gap-6 mt-5 items-center justify-center" },
|
|
277
|
-
href: "https://github.com/nuxt/devtools/issues",
|
|
278
|
-
target: "_blank",
|
|
279
|
-
flex: "~ gap1",
|
|
280
|
-
"items-center": "",
|
|
281
|
-
op50: "",
|
|
282
|
-
hover: "op100 text-rose",
|
|
283
|
-
transition: ""
|
|
284
|
-
}, [createBaseVNode("div", { "i-carbon-debug": "" }), createTextVNode(" Bug Reports ")])], -1)),
|
|
277
|
+
_cache[13] || (_cache[13] = createBaseVNode("div", { class: "flex flex-wrap gap-6 mt-5 items-center justify-center" }, null, -1)),
|
|
285
278
|
_cache[14] || (_cache[14] = createBaseVNode("div", { "flex-auto": "" }, null, -1))
|
|
286
279
|
])]),
|
|
287
280
|
_: 1
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./javascript-DIagQh28.js","./javascript-CZLwsMB1.js","./typescript-CzrZyZmM.js","./typescript-DkhbmgdN.js","./vue-Co3JBzx2.js","./css-DbgpCiOq.js","./html-mHHj5Mh3.js","./json-CzPoZe0r.js","./json-WgRhEAOB.js","./html-C5tHi8hG.js","./css-D-vtiAqw.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import { A as
|
|
3
|
-
import { a as Icon_default, i as SectionBlock_default, n as TextInput_default, r as Button_default, t as Navbar_default } from "./Navbar-
|
|
4
|
-
import { c as
|
|
5
|
-
import { t as
|
|
2
|
+
import { $ as toRef, A as provide, B as withCtx, C as inject, D as onBeforeUnmount, E as nextTick, F as resolveDynamicComponent, G as isRef, L as useSlots, M as renderSlot, N as resolveComponent, O as onMounted, P as resolveDirective, R as watch, S as h, T as mergeProps, V as withDirectives, Y as ref, Z as shallowRef, b as defineComponent, d as KeepAlive, f as computed, g as createElementBlock, h as createCommentVNode, i as vModelCheckbox, it as toDisplayString, j as renderList, k as openBlock, l as withKeys, m as createBlock, nt as normalizeClass, p as createBaseVNode, q as reactive, r as Transition, rt as normalizeStyle, s as vModelSelect, t as __vitePreload, tt as unref, u as Fragment, v as createTextVNode, x as getCurrentInstance, y as createVNode, z as watchEffect } from "./index-BgqWVAMJ.js";
|
|
3
|
+
import { a as Icon_default, i as SectionBlock_default, n as TextInput_default, r as Button_default, t as Navbar_default } from "./Navbar-D84j2-0V.js";
|
|
4
|
+
import { c as onClickOutside, d as useLocalStorage, f as useVModel, m as createSharedComposable, o as Badge_default, s as createReusableTemplate, t as apiListFetch, u as useElementSize } from "./fetch-fetJJUYt.js";
|
|
5
|
+
import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-D8E0syuh.js";
|
|
6
|
+
import { t as PanelGrids_default } from "./PanelGrids-F8O_nB5x.js";
|
|
6
7
|
var _sfc_main = {};
|
|
7
8
|
var _hoisted_1$10 = { class: "n-card n-card-base" };
|
|
8
9
|
function _sfc_render(_ctx, _cache) {
|
package/dist/client/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
|
7
7
|
<title>Vite Plugins</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-BgqWVAMJ.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-XXyHuz_l.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body data-vite-inspect-mode="DEV" class="n-bg-base text-color-base font-sans">
|
|
12
12
|
<div id="app"></div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 14 14"><!-- Icon from Flex color icons by Streamline - https://creativecommons.org/licenses/by/4.0/ --><g fill="none"><path fill="#d7e0ff" d="M.797 6.75c0-3.697 1.55-5.282 2.068-5.81h8.27c.517.528 2.068 2.113 2.068 5.81c0 4.224-4.073 5.782-6.14 6.31C4.994 12.532.796 10.974.796 6.749"/><path stroke="#4147d5" stroke-linecap="round" stroke-linejoin="round" d="M.797 6.75c0-3.697 1.55-5.282 2.068-5.81h8.27c.517.528 2.068 2.113 2.068 5.81c0 4.224-4.073 5.782-6.14 6.31C4.994 12.532.796 10.974.796 6.749"/><path fill="#fff" d="M6.999 9.42c1.521 0 2.377-.856 2.377-2.377c0-1.522-.856-2.377-2.377-2.377s-2.377.855-2.377 2.377c0 1.52.856 2.376 2.377 2.376"/><path stroke="#4147d5" stroke-linecap="round" stroke-linejoin="round" d="M6.999 9.42c1.521 0 2.377-.856 2.377-2.377c0-1.522-.856-2.377-2.377-2.377s-2.377.855-2.377 2.377c0 1.52.856 2.376 2.377 2.376"/><path stroke="#4147d5" stroke-linecap="round" stroke-linejoin="round" d="M9.095 5.74a1.83 1.83 0 0 1 1.39-.634M9.376 6.873h1.108m-6.968 0h1.108m.281-1.133a1.83 1.83 0 0 0-1.39-.634m5.58 3.234a1.83 1.83 0 0 0 1.39.633m-5.58-.633a1.83 1.83 0 0 1-1.39.633m4.27-4.217c.202-.151.37-.37.487-.633s.178-.562.178-.866M6.206 4.756a1.6 1.6 0 0 1-.487-.633a2.15 2.15 0 0 1-.178-.866"/></g></svg>
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { t as DIR_CLIENT } from "./dirs2.mjs";
|
|
2
|
+
import { Buffer } from "node:buffer";
|
|
2
3
|
import sirv from "sirv";
|
|
3
4
|
import { basename, dirname, extname, join, relative } from "node:path";
|
|
4
5
|
import { pathToFileURL } from "node:url";
|
|
5
6
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
6
7
|
import { readFile, readdir, stat } from "node:fs/promises";
|
|
8
|
+
import { execSync } from "node:child_process";
|
|
9
|
+
import { arch, platform, release } from "node:os";
|
|
10
|
+
import process from "node:process";
|
|
7
11
|
import { Lang, parse } from "@ast-grep/napi";
|
|
8
12
|
|
|
9
13
|
//#region src/server/controller/api.ts
|
|
@@ -486,6 +490,132 @@ async function getRequestList(root) {
|
|
|
486
490
|
};
|
|
487
491
|
}
|
|
488
492
|
|
|
493
|
+
//#endregion
|
|
494
|
+
//#region src/server/controller/issue.ts
|
|
495
|
+
/**
|
|
496
|
+
* 安全执行 git 命令,失败时返回 null
|
|
497
|
+
*/
|
|
498
|
+
function execGit(command, cwd) {
|
|
499
|
+
try {
|
|
500
|
+
return execSync(command, {
|
|
501
|
+
cwd,
|
|
502
|
+
encoding: "utf-8",
|
|
503
|
+
timeout: 5e3
|
|
504
|
+
}).trim() || null;
|
|
505
|
+
} catch {
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* 采集 Git 信息
|
|
511
|
+
*/
|
|
512
|
+
function collectGitInfo(root) {
|
|
513
|
+
return {
|
|
514
|
+
userName: execGit("git config user.name", root),
|
|
515
|
+
userEmail: execGit("git config user.email", root),
|
|
516
|
+
branch: execGit("git rev-parse --abbrev-ref HEAD", root),
|
|
517
|
+
commitHash: execGit("git rev-parse --short HEAD", root),
|
|
518
|
+
remoteUrl: execGit("git remote get-url origin", root)
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* 读取项目 package.json
|
|
523
|
+
*/
|
|
524
|
+
function collectPackageJson(root) {
|
|
525
|
+
try {
|
|
526
|
+
const pkgPath = join(root, "package.json");
|
|
527
|
+
if (!existsSync(pkgPath)) return {};
|
|
528
|
+
return JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
529
|
+
} catch {
|
|
530
|
+
return {};
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* 采集完整的环境信息
|
|
535
|
+
*/
|
|
536
|
+
function getEnvironmentInfo(root) {
|
|
537
|
+
return {
|
|
538
|
+
nodeVersion: process.version,
|
|
539
|
+
platform: platform(),
|
|
540
|
+
arch: arch(),
|
|
541
|
+
osVersion: release(),
|
|
542
|
+
packageJson: collectPackageJson(root),
|
|
543
|
+
git: collectGitInfo(root)
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* 将环境信息格式化为 Markdown 文本,用于 Issue body
|
|
548
|
+
*/
|
|
549
|
+
function formatEnvironmentMarkdown(env) {
|
|
550
|
+
const envObj = {
|
|
551
|
+
node: env.nodeVersion,
|
|
552
|
+
os: `${env.platform} ${env.arch} (${env.osVersion})`,
|
|
553
|
+
git: {
|
|
554
|
+
branch: env.git.branch,
|
|
555
|
+
commit: env.git.commitHash,
|
|
556
|
+
user: env.git.userName ? `${env.git.userName}${env.git.userEmail ? ` <${env.git.userEmail}>` : ""}` : null,
|
|
557
|
+
remote: env.git.remoteUrl
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
const lines = [];
|
|
561
|
+
lines.push(`### 环境信息`);
|
|
562
|
+
lines.push("");
|
|
563
|
+
lines.push("```json");
|
|
564
|
+
lines.push(JSON.stringify(envObj, null, 2));
|
|
565
|
+
lines.push("```");
|
|
566
|
+
lines.push("");
|
|
567
|
+
lines.push(`### package.json`);
|
|
568
|
+
lines.push("");
|
|
569
|
+
lines.push("```json");
|
|
570
|
+
lines.push(JSON.stringify(env.packageJson, null, 2));
|
|
571
|
+
lines.push("```");
|
|
572
|
+
return lines.join("\n");
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* 将表单数据格式化为 Issue body(Markdown)
|
|
576
|
+
*/
|
|
577
|
+
function formatIssueBody(body, environment) {
|
|
578
|
+
const sections = [];
|
|
579
|
+
sections.push(`## 问题描述`);
|
|
580
|
+
sections.push(body.description || "_未填写_");
|
|
581
|
+
sections.push("");
|
|
582
|
+
if (body.steps) {
|
|
583
|
+
sections.push(`## 复现步骤`);
|
|
584
|
+
sections.push(body.steps);
|
|
585
|
+
sections.push("");
|
|
586
|
+
}
|
|
587
|
+
if (body.expected) {
|
|
588
|
+
sections.push(`## 期望行为`);
|
|
589
|
+
sections.push(body.expected);
|
|
590
|
+
sections.push("");
|
|
591
|
+
}
|
|
592
|
+
if (body.actual) {
|
|
593
|
+
sections.push(`## 实际行为`);
|
|
594
|
+
sections.push(body.actual);
|
|
595
|
+
sections.push("");
|
|
596
|
+
}
|
|
597
|
+
sections.push(formatEnvironmentMarkdown(environment));
|
|
598
|
+
return sections.join("\n");
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* 处理 Issue 提交,采集环境信息后转发到 issue.elonehoo.cn
|
|
602
|
+
*/
|
|
603
|
+
async function submitIssue(root, body) {
|
|
604
|
+
const issueBody = formatIssueBody(body, getEnvironmentInfo(root));
|
|
605
|
+
const response = await fetch("https://issue.elonehoo.cn/issue", {
|
|
606
|
+
method: "POST",
|
|
607
|
+
headers: { "Content-Type": "application/json" },
|
|
608
|
+
body: JSON.stringify({
|
|
609
|
+
title: `[Bug] ${body.title}`,
|
|
610
|
+
body: issueBody
|
|
611
|
+
})
|
|
612
|
+
});
|
|
613
|
+
if (!response.ok) throw new Error(`Issue API responded with ${response.status}: ${response.statusText}`);
|
|
614
|
+
const result = await response.json();
|
|
615
|
+
if (!result.success) throw new Error("Issue API returned success: false");
|
|
616
|
+
return result;
|
|
617
|
+
}
|
|
618
|
+
|
|
489
619
|
//#endregion
|
|
490
620
|
//#region src/@data/pubinfo.ts
|
|
491
621
|
const pubinfoImport = [
|
|
@@ -1613,22 +1743,6 @@ function analyzeFile(content, filePath, functionNames, componentNames) {
|
|
|
1613
1743
|
result.functions.get(calleeName).push(loc);
|
|
1614
1744
|
}
|
|
1615
1745
|
}
|
|
1616
|
-
const importMatches = rootNode.findAll({ rule: { kind: "import_specifier" } });
|
|
1617
|
-
for (const match of importMatches) {
|
|
1618
|
-
const text = match.text();
|
|
1619
|
-
const specName = text.split(/\s/)[0];
|
|
1620
|
-
if (specName && hitFunctions.has(specName)) {
|
|
1621
|
-
const range = match.range();
|
|
1622
|
-
const loc = {
|
|
1623
|
-
file: filePath,
|
|
1624
|
-
line: range.start.line + 1,
|
|
1625
|
-
column: range.start.column + 1,
|
|
1626
|
-
code: text
|
|
1627
|
-
};
|
|
1628
|
-
if (!result.functions.has(specName)) result.functions.set(specName, []);
|
|
1629
|
-
result.functions.get(specName).push(loc);
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
1746
|
}
|
|
1633
1747
|
if (hitComponents.size > 0) {
|
|
1634
1748
|
const jsxMatches = rootNode.findAll({ rule: { kind: "jsx_opening_element" } });
|
|
@@ -2343,6 +2457,31 @@ function pubinfoDevtools() {
|
|
|
2343
2457
|
}
|
|
2344
2458
|
return;
|
|
2345
2459
|
}
|
|
2460
|
+
if (req.url === "/environment-info") {
|
|
2461
|
+
try {
|
|
2462
|
+
sendJSON(res, getEnvironmentInfo(server.config.root));
|
|
2463
|
+
} catch (error) {
|
|
2464
|
+
sendError(res, "Failed to get environment info", error);
|
|
2465
|
+
}
|
|
2466
|
+
return;
|
|
2467
|
+
}
|
|
2468
|
+
if (req.url === "/issue" && req.method === "POST") {
|
|
2469
|
+
try {
|
|
2470
|
+
const chunks = [];
|
|
2471
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
2472
|
+
req.on("end", async () => {
|
|
2473
|
+
try {
|
|
2474
|
+
const body = JSON.parse(Buffer.concat(chunks).toString());
|
|
2475
|
+
sendJSON(res, await submitIssue(server.config.root, body));
|
|
2476
|
+
} catch (error) {
|
|
2477
|
+
sendError(res, "Failed to submit issue", error);
|
|
2478
|
+
}
|
|
2479
|
+
});
|
|
2480
|
+
} catch (error) {
|
|
2481
|
+
sendError(res, "Failed to submit issue", error);
|
|
2482
|
+
}
|
|
2483
|
+
return;
|
|
2484
|
+
}
|
|
2346
2485
|
next();
|
|
2347
2486
|
});
|
|
2348
2487
|
}
|
package/dist/panel/index.d.mts
CHANGED
package/dist/panel/index.mjs
CHANGED
|
@@ -3845,6 +3845,27 @@ function setupImportPanel() {
|
|
|
3845
3845
|
});
|
|
3846
3846
|
}
|
|
3847
3847
|
|
|
3848
|
+
//#endregion
|
|
3849
|
+
//#region src/panel/issue.ts
|
|
3850
|
+
/**
|
|
3851
|
+
* 注册 Issue 提交面板。
|
|
3852
|
+
*
|
|
3853
|
+
* 在 DevTools 中提供一个快速提交 Bug Report 的入口,
|
|
3854
|
+
* 用户可以填写信息后跳转到 GitHub 创建 Issue。
|
|
3855
|
+
*/
|
|
3856
|
+
function setupIssuePanel() {
|
|
3857
|
+
addCustomTab({
|
|
3858
|
+
name: "pubinfo-issue",
|
|
3859
|
+
title: "提交 Bug",
|
|
3860
|
+
icon: "/__pubinfo_devtools/issue.svg",
|
|
3861
|
+
view: {
|
|
3862
|
+
type: "iframe",
|
|
3863
|
+
src: "/__pubinfo_devtools/#/issue"
|
|
3864
|
+
},
|
|
3865
|
+
category: "advanced"
|
|
3866
|
+
});
|
|
3867
|
+
}
|
|
3868
|
+
|
|
3848
3869
|
//#endregion
|
|
3849
3870
|
//#region src/panel/overview.ts
|
|
3850
3871
|
/**
|
|
@@ -3911,6 +3932,7 @@ function setupUnoCSSPanel() {
|
|
|
3911
3932
|
*
|
|
3912
3933
|
* - UnoCSS:直接复用 Uno 的内置面板(iframe 方式)。
|
|
3913
3934
|
* - Server Router:本项目提供的服务路由调试面板。
|
|
3935
|
+
* - Issue:快速提交 Bug Report 到 GitHub。
|
|
3914
3936
|
*/
|
|
3915
3937
|
function setupDevtoolsPanel() {
|
|
3916
3938
|
setupOverviewPanel();
|
|
@@ -3919,6 +3941,7 @@ function setupDevtoolsPanel() {
|
|
|
3919
3941
|
setupComponentPanel();
|
|
3920
3942
|
setupImportPanel();
|
|
3921
3943
|
setupIconesPanel();
|
|
3944
|
+
setupIssuePanel();
|
|
3922
3945
|
}
|
|
3923
3946
|
|
|
3924
3947
|
//#endregion
|