Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion plugins/jenkins-lite/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,64 @@

---

## v1.2.1 (最新)
## v1.4.0 (最新)

### 🆕 新增

- **日志高亮 + 自动滚到底**:BuildLogModal 打开后日志自动滚到底部;含 `ERROR / Exception / FATAL / BUILD FAILURE / failed / Error:` 的行红字 + 浅红底 + 红色左边框
- **复制错误日志**:弹窗底部新增「复制错误 (N)」按钮,仅复制含错误关键字的行,N 为错误行数
- **日志滚动快捷键**:弹窗打开时 `↑ / ↓` 滚一行、`PgUp / PgDn` 翻页、`Home / End` 顶/底
- **键盘操作提示**:Sidebar / JobsList / BuildHistory 各自下方加 `<kbd>` 风格的快捷键提示行
- **Sidebar 视图即时切换**:`↑↓` 直接切视图,不再需要 `Enter` 确认
- **JobsList 即时联动右侧**:`↑↓ / Shift+↑↓` 切换选中项时自动联动右侧构建历史
- **弹窗 Enter 确认 / Esc 取消**:构建确认和收藏确认弹窗都支持 Enter 直接确认、Esc 取消
- **Esc 后焦点还原**:弹窗关闭时焦点回到打开它的那条 Job / build,不再被强制弹到搜索框

### 🎨 优化

- **BuildLogModal 布局**:`.log-body` 去掉冲突的 `min/max-height` 限制,`.modal-footer` 加 `flex: 0 0 auto`,日志很长时 footer 始终可见
- **键盘提示分隔符**:Sidebar 提示行加 `·` 分隔,多个快捷键之间不挤

### 🐛 修复

- **空白页**:根因是 Vue 3 `provide / inject` 在同组件内不自洽(provide 存到 `instance.provides`,同组件 inject 走 `appContext.provides`),App.vue 改用直接 import 模块级 ref
- **JobItem 受控展开**:Folder 展开状态从组件内提升到 JobsList,便于键盘导航跨层操作

### 🔧 内部

- `useBuildPolling` 新增 `stopWatchingBuild(jobName?, buildNumber?)` 参数化清理
- `useKeyboardNav` 模块级 ref export 给 App.vue 直接使用(绕过 provide/inject 同组件限制)
- `tests/App.smoke.test.ts` 新增,捕获 App 根挂载类回归

---

## v1.3.0

### 🆕 新增

- **构建完成通知**:触发构建后自动监听该 build 直到结束,完成时弹出系统通知(成功 / 失败 / 不稳定 / 中止)
- **构建日志弹窗**:右侧历史面板点击构建记录不再跳转 Jenkins,而是打开弹窗直接查看 console log
- 弹窗内仍提供「在 Jenkins 中打开」按钮,需要详细页面时一键跳转
- 支持「复制日志」到剪贴板
- **键盘快捷键**:
- `←` / `→` 在 Sidebar / JobsList / BuildHistory 三个面板间循环切换(焦点默认在 Sidebar)
- `↑` / `↓` 在当前面板内上下移动选中项
- `Shift + ↑` / `Shift + ↓` 在 JobsList 中进入 Folder / 退出到父 Folder(同级导航走纯 ↑↓)
- `Enter` 触发当前选中项的主操作:Sidebar 切视图 / JobsList 触发构建(含二次确认)/ BuildHistory 打开构建日志
- `Cmd / Ctrl + Enter` 在 JobsList 收藏当前选中项(走二次确认,防误触)
- `Esc` 关闭弹窗
- 被聚焦的面板有蓝色描边,选中项左侧出现蓝色高亮条

### 🔧 内部

- `preload.js` 新增 `getBuildConsole` 接口(`/job/<segments>/<n>/consoleText`),沿用 Folder 嵌套路径分段规则
- `useBuildPolling` 新增 `watchBuild(jobName, buildNumber, onComplete)`:独立定时器监听单个 build 完成,不影响右侧历史面板的轮询
- 新增 `useKeyboardNav` composable:provide/inject 集中管面板焦点与选中索引
- `JobItem` 的 Folder 展开状态从组件内提升到 `JobsList`,以便键盘导航能跨层操作

---

## v1.2.1

### 🎨 优化

Expand Down
2 changes: 1 addition & 1 deletion plugins/jenkins-lite/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,4 @@ grep -rn 'X\.Y\.0' --include='*.ts' --include='*.vue' --include='*.json' --inclu

- `jenkins` / `Jenkins` / `j` / `jl` — 打开插件
- `构建` / `build` — 触发构建
- `jenkins收藏` / `jenkins-fav` — 收藏视图
- `jenkins收藏` / `jenkins-fav` — 收藏视图
2 changes: 1 addition & 1 deletion plugins/jenkins-lite/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jenkins-lite",
"version": "1.2.1",
"version": "1.4.0",
"description": "Jenkins Lite 一款轻量级的 Jenkins 辅助工具。告别繁琐的网页操作,插件提供实时查询与一键构建功能,帮助开发者快速检索任务状态、监控构建进度并秒级触发构建,显著提升 CI/CD 工作效率。",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion plugins/jenkins-lite/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "jenkins-lite",
"title": "Jenkins Lite",
"description": " 一款轻量级 Jenkins 辅助工具。告别繁琐的网页操作,可轻松实现实时查询任务状态、监控构建进度、一键触发构建,可显著提升 CI/CD 效率。",
"version": "1.2.1",
"version": "1.4.0",
"main": "index.html",
"logo": "logo.png",
"author": "康康学长",
Expand Down
49 changes: 49 additions & 0 deletions plugins/jenkins-lite/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,44 @@ function jenkinsRequest(jenkinsUrl, username, apiToken, apiPath) {
})
}

// Jenkins 文本端点调用(不解析 JSON,直接返回原始字符串)
function jenkinsRequestText(jenkinsUrl, username, apiToken, apiPath) {
return new Promise((resolve, reject) => {
const parsedUrl = new URL(jenkinsUrl)
const isHttps = parsedUrl.protocol === 'https:'
const httpModule = isHttps ? https : http

const auth = Buffer.from(username + ':' + apiToken).toString('base64')
const cleanPath = apiPath.startsWith('/') ? apiPath : '/' + apiPath

const options = {
hostname: parsedUrl.hostname,
port: parsedUrl.port || (isHttps ? 443 : 80),
path: cleanPath,
method: 'GET',
headers: {
'Authorization': 'Basic ' + auth,
'Accept': 'text/plain'
}
}

const req = httpModule.request(options, (res) => {
let data = ''
res.on('data', (chunk) => { data += chunk })
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(data)
} else {
reject(new Error('HTTP ' + res.statusCode))
}
})
})

req.on('error', reject)
req.end()
})
}

// Jenkins 构建触发
function jenkinsBuild(jenkinsUrl, username, apiToken, jobName) {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -163,6 +201,17 @@ window.services = {
return jenkinsRequest(jenkinsUrl, username, apiToken, '/api/json')
.then(function() { return { success: true, error: null } })
.catch(function(err) { return { success: false, error: err.message } })
},
// 获取构建的 console log(纯文本)
getBuildConsole: function(jenkinsUrl, username, apiToken, jobName, buildNumber) {
return jenkinsRequestText(
jenkinsUrl,
username,
apiToken,
getJobPath(jobName) + '/' + encodeURIComponent(String(buildNumber)) + '/consoleText'
)
.then(function(data) { return { data: data || '', error: null } })
.catch(function(err) { return { data: '', error: err.message } })
}
},
// 读文件
Expand Down
2 changes: 1 addition & 1 deletion plugins/jenkins-lite/public/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"title": "Jenkins Lite",
"description": "Jenkins Lite 一款轻量级的 Jenkins 辅助工具。告别繁琐的网页操作,插件提供实时查询与一键构建功能,帮助开发者快速检索任务状态、监控构建进度并秒级触发构建,显著提升 CI/CD 工作效率。",
"author": "康康学长",
"version": "1.2.1",
"version": "1.4.0",
"main": "index.html",
"preload": "preload/services.js",
"logo": "logo.png",
Expand Down
49 changes: 49 additions & 0 deletions plugins/jenkins-lite/public/preload/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,44 @@ function jenkinsRequest(jenkinsUrl, username, apiToken, apiPath) {
})
}

// Jenkins 文本端点调用(不解析 JSON,直接返回原始字符串)
function jenkinsRequestText(jenkinsUrl, username, apiToken, apiPath) {
return new Promise((resolve, reject) => {
const parsedUrl = new URL(jenkinsUrl)
const isHttps = parsedUrl.protocol === 'https:'
const httpModule = isHttps ? https : http

const auth = Buffer.from(username + ':' + apiToken).toString('base64')
const cleanPath = apiPath.startsWith('/') ? apiPath : '/' + apiPath

const options = {
hostname: parsedUrl.hostname,
port: parsedUrl.port || (isHttps ? 443 : 80),
path: cleanPath,
method: 'GET',
headers: {
'Authorization': 'Basic ' + auth,
'Accept': 'text/plain'
}
}

const req = httpModule.request(options, (res) => {
let data = ''
res.on('data', (chunk) => { data += chunk })
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(data)
} else {
reject(new Error('HTTP ' + res.statusCode))
}
})
})

req.on('error', reject)
req.end()
})
}

// Jenkins 构建触发
function jenkinsBuild(jenkinsUrl, username, apiToken, jobName) {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -120,6 +158,17 @@ window.services = {
return jenkinsRequest(jenkinsUrl, username, apiToken, '/api/json')
.then(function() { return { success: true, error: null } })
.catch(function(err) { return { success: false, error: err.message } })
},
// 获取构建的 console log(纯文本)
getBuildConsole: function(jenkinsUrl, username, apiToken, jobName, buildNumber) {
return jenkinsRequestText(
jenkinsUrl,
username,
apiToken,
'/job/' + encodeURIComponent(jobName) + '/' + encodeURIComponent(String(buildNumber)) + '/consoleText'
)
.then(function(data) { return { data: data || '', error: null } })
.catch(function(err) { return { data: '', error: err.message } })
}
},
// 读文件
Expand Down
Loading
Loading