Tabby 插件 server-stats 一直展示loading...的问题
修复内容: 我修改了 src/components/bottom-bar.component.ts 文件,增加了一个强制重置逻辑:无论数据获取成功还是失败,都会强制结束加载状态。原因分析: 这个问题是由于程序在获取服务器数据失败时(例如超时、网络问题或不支持的系统),没有正确地把界面的状态从“加载中”切换回来。今天在使用Tabby的时候发现了一个比较好玩的插件server-stats,安装后发现一
Tabby 插件 server-stats 一直展示loading...的问题
今天在使用Tabby的时候发现了一个比较好玩的插件server-stats,安装后发现一直是loading…的状态。以下是我解决问题的步骤。
一、问题展现
- 使用的工具:Tabby V1.0.229
- 安装的插件是server-stats。具体安装步骤是 配置 ➡️插件 ➡️server-stats ➡️ 获取 即可安装。安装之后状态栏就一直是loading…的状态。

纳闷了,咋回事儿呢。下载源码下来看看。
二、问题解决
下载源码:
git clone https://github.com/kasuganosoras/tabby-server-stats.git
1. 处理问题1,loading… 的问题
文件位置:src/components/bottom-bar.component.ts
原因分析: 这个问题是由于程序在获取服务器数据失败时(例如超时、网络问题或不支持的系统),没有正确地把界面的状态从“加载中”切换回来。这就导致了一旦第一次获取失败,界面就会永久卡在 Loading… 。
修复内容: 我修改了 src/components/bottom-bar.component.ts 文件,增加了一个强制重置逻辑:无论数据获取成功还是失败,都会强制结束加载状态。如果获取失败,界面将显示默认值(0%),而不是一直转圈。
同时,我还顺手修复了一个小问题,让 “Loading…” 这个词现在可以正确支持多语言翻译了。
源码如下:
import { Component, OnInit, OnDestroy, ChangeDetectorRef, NgZone } from '@angular/core'
import { Subscription } from 'rxjs'
import { AppService, ConfigService } from 'tabby-core'
import { StatsService } from '../services/stats.service'
import { CustomMetric } from '../config'
@Component({
selector: 'server-stats-bottom-bar',
template: `
<div class="stats-container"
*ngIf="visible"
[style.background]="styleConfig.background">
<div class="stat-section" *ngIf="loading">
<div class="loading-text">Loading...</div>
</div>
需要调整的位置如下:
import { Component, OnInit, OnDestroy, ChangeDetectorRef, NgZone } from '@angular/core'
import { Subscription } from 'rxjs'
import { AppService, ConfigService } from 'tabby-core'
import { StatsService } from '../services/stats.service'
import { CustomMetric } from '../config'
@Component({
selector: 'server-stats-bottom-bar',
template: `
<div class="stats-container"
*ngIf="visible"
[style.background]="styleConfig.background">
<div class="stat-section" *ngIf="loading">
<div class="loading-text">{{ 'Loading...' | translate }}</div>
</div>
修改了之后,保存并进行编译。
npm run build
将生成的dist文件放到,Tabby的插件位置重启即可。
我电脑的位置是C:\Users\XXXX\AppData\Roaming\tabby\plugins\node_modules\tabby-server-stats 将dist替换即可。
这就解决了loading…的问题。
2. 状态栏展示cpu、内存、磁盘 都为 0%的问题
没有了loading...的问题后,发现展示的数据不正确。发现是展示的时候对于不同系统兼容性的问题,没有处理。
问题文件1位置:src/components/bottom-bar.component.ts
问题文件2位置:src/services/stats.service.ts
具体的问题分析如下:
1. 出现这个问题大概率是没有识别到显示指标的命令,所以需要找到形成语句的位置,并进行调整。具体找的环节我就不多说了。
2. 找到语句位置调整指标命令,大概率是可以解决问题的。
2.1 src/components/bottom-bar.component.ts
具体的代码调调整是针对src/components/bottom-bar.component.ts 的checkAndFetch()这个方法,位置如下:

async checkAndFetch() {
const isEnabled = this.config.store.plugin?.serverStats?.enabled;
const displayMode = this.config.store.plugin?.serverStats?.displayMode || 'bottomBar';
if (displayMode !== 'bottomBar') {
if (this.visible) {
this.visible = false;
this.loading = true;
this.cdr.detectChanges();
}
return;
}
let activeTab: any = this.app.activeTab
if (!isEnabled || !activeTab) {
if (this.visible) {
this.visible = false;
this.loading = true;
this.cdr.detectChanges();
}
return;
}
if (activeTab['focusedTab']) {
activeTab = activeTab['focusedTab'];
}
const session = activeTab['session'];
if (session) {
if (!this.visible) {
this.visible = true;
this.loading = true;
this.cdr.detectChanges();
}
try {
const data = await this.statsService.fetchStats(session)
this.loading = false;
if (data) {
this.updateStats(data);
this.currentStats = data;
}
this.cdr.detectChanges();
return;
} catch (e) {
this.loading = false;
this.cdr.detectChanges();
}
} else {
if (this.visible) {
this.visible = false;
this.loading = true;
this.cdr.detectChanges();
}
}
}
调整位置如下:
2.2 src/services/stats.service.ts :
- 调整src/services/stats.service.ts的 StatsService 类中的private baseStatsCommand 变量

将原有的代码
// 以后可以在这里扩展更多命令
private baseStatsCommand = `
stats=$( (grep 'cpu ' /proc/stat; awk 'NR>2 {r+=$2; t+=$10} END{print r, t}' /proc/net/dev; sleep 1; grep 'cpu ' /proc/stat; awk 'NR>2 {r+=$2; t+=$10} END{print r, t}' /proc/net/dev) | awk 'NR==1 {t1=$2+$3+$4+$5+$6+$7+$8; i1=$5} NR==2 {rx1=$1; tx1=$2} NR==3 {t2=$2+$3+$4+$5+$6+$7+$8; i2=$5} NR==4 {rx2=$1; tx2=$2} END { dt=t2-t1; di=i2-i1; cpu=(dt<=0)?0:(dt-di)/dt*100; rx=rx2-rx1; tx=tx2-tx1; printf "%.1f %.0f %.0f", cpu, rx, tx }' );
mem=$(free | awk 'NR==2{printf "%.2f", $3*100/$2 }');
disk=$(df -h / | awk 'NR==2{print $5}' | sed 's/%//');
echo "TABBY-STATS-START $stats $mem $disk"
改为
private baseStatsCommand = `export LC_ALL=C; PATH=$PATH:/usr/bin:/bin:/usr/sbin:/sbin; OS=$(uname -s 2>/dev/null || echo "Linux"); if [ "$OS" = "Darwin" ]; then cpu=$(ps -A -o %cpu | awk '{s+=$1} END {print s}' 2>/dev/null || echo "0"); mem=$(ps -A -o %mem | awk '{s+=$1} END {print s}' 2>/dev/null || echo "0"); disk=$(df -h / 2>/dev/null | awk 'NR==2{print $5}' | sed 's/%//' || echo "0"); echo "TABBY-STATS-START $cpu 0 0 $mem $disk"; else stats=$( (grep 'cpu ' /proc/stat; awk 'NR>2 {r+=$2; t+=$10} END{print r, t}' /proc/net/dev; sleep 1; grep 'cpu ' /proc/stat; awk 'NR>2 {r+=$2; t+=$10} END{print r, t}' /proc/net/dev) 2>/dev/null | awk 'NR==1 {t1=$2+$3+$4+$5+$6+$7+$8; i1=$5} NR==2 {rx1=$1; tx1=$2} NR==3 {t2=$2+$3+$4+$5+$6+$7+$8; i2=$5} NR==4 {rx2=$1; tx2=$2} END { dt=t2-t1; di=i2-i1; cpu=(dt<=0)?0:(dt-di)/dt*100; rx=rx2-rx1; tx=tx2-tx1; printf "%.1f %.0f %.0f", cpu, rx, tx }' ); mem=$(free 2>/dev/null | awk 'NR==2{printf "%.2f", $3*100/$2 }'); disk=$(df -h / 2>/dev/null | awk 'NR==2{print $5}' | sed 's/%//'); if [ -z "$stats" ]; then stats="0 0 0"; fi; if [ -z "$mem" ]; then mem="0"; fi; if [ -z "$disk" ]; then disk="0"; fi; echo "TABBY-STATS-START $stats $mem $disk"; fi`
注意:这个地方不要换行
并且在src/services/stats.service.ts的第40行 调整

// Flatten command to single line to prevent SSH exec issues
finalCommand = finalCommand.replace(/\n/g, ' ');
// Wrap in /bin/sh -c to ensure POSIX compatibility (fixes issues with fish shell, etc.)
finalCommand = `/bin/sh -c '${finalCommand.replace(/'/g, "'\\''")}'`;
调整完成,编译&放入插件。重启Tabby,问题解决。
![![[Pasted image 20251218173951.png]]](https://i-blog.csdnimg.cn/direct/57c3c535df6741c2a87669a903866c8e.png)
终于可以开心的使用Tabby啦!!!
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)