@ww-ai-lab/openclaw-office 2026.3.8 → 2026.3.18
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/README.md +14 -30
- package/README.zh.md +14 -30
- package/bin/openclaw-office.js +342 -16
- package/dist/assets/{ActivityHeatmap-CnKWcUWF.js → ActivityHeatmap-gbPJ6H5y.js} +1 -1
- package/dist/assets/{CostPieChart-DmUzkXKt.js → CostPieChart-CSQLUrFF.js} +1 -1
- package/dist/assets/{NetworkGraph-C0F11y9I.js → NetworkGraph-CwZMRSkm.js} +1 -1
- package/dist/assets/{Scene3D-q5P1N1qu.js → Scene3D-CJZ10gBQ.js} +1 -1
- package/dist/assets/{TokenLineChart-odcmdCAg.js → TokenLineChart-Dy4j2Dp9.js} +1 -1
- package/dist/assets/{generateCategoricalChart-Onj3oDrM.js → generateCategoricalChart-DnxAF2gL.js} +1 -1
- package/dist/assets/index-B3Rh7oeP.css +1 -0
- package/dist/assets/index-WMjJihFL.js +462 -0
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/bin/openclaw-office-config.d.ts +0 -44
- package/bin/openclaw-office-config.js +0 -219
- package/bin/openclaw-office-server.d.ts +0 -34
- package/bin/openclaw-office-server.js +0 -342
- package/dist/assets/index-DweWoR1-.css +0 -1
- package/dist/assets/index-QZYyP0qG.js +0 -462
package/README.md
CHANGED
|
@@ -33,19 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
#### Demo Video
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
<a href="https://www.youtube.com/watch?v=ACXSFTSlVLY">
|
|
38
|
-
<img src="https://img.youtube.com/vi/ACXSFTSlVLY/maxresdefault.jpg" alt="OpenClaw Office Demo Video" width="100%" />
|
|
39
|
-
</a>
|
|
40
|
-
</p>
|
|
41
|
-
|
|
42
|
-
<p align="center">
|
|
43
|
-
▶ Click the preview image above to play on YouTube
|
|
44
|
-
</p>
|
|
45
|
-
|
|
46
|
-
> GitHub sanitizes repository README content and does not allow embedded YouTube/iframe players, so the most reliable “preview + click-to-play” pattern is a linked video thumbnail.
|
|
47
|
-
|
|
48
|
-
[Watch on YouTube](https://www.youtube.com/watch?v=ACXSFTSlVLY)
|
|
36
|
+
https://github.com/WW-AI-Lab/openclaw-office/raw/main/assets/iShot_2026-03-02_21.33.38.mp4
|
|
49
37
|
|
|
50
38
|
### Console
|
|
51
39
|
|
|
@@ -136,15 +124,6 @@ OPENCLAW_GATEWAY_TOKEN=<token> openclaw-office
|
|
|
136
124
|
| `--host <host>` | Bind address | `0.0.0.0` |
|
|
137
125
|
| `-h, --help` | Show help | — |
|
|
138
126
|
|
|
139
|
-
The production server exposes Office publicly and proxies browser WebSocket traffic through the same origin path `/gateway-ws`. Its upstream Gateway address is resolved in this order:
|
|
140
|
-
|
|
141
|
-
1. `--gateway`
|
|
142
|
-
2. `OPENCLAW_GATEWAY_URL`
|
|
143
|
-
3. persisted Office config at `~/.openclaw/openclaw-office.json`
|
|
144
|
-
4. default `ws://localhost:18789`
|
|
145
|
-
|
|
146
|
-
When `--gateway` or `OPENCLAW_GATEWAY_URL` is provided, Office automatically persists the value to `~/.openclaw/openclaw-office.json` for future restarts.
|
|
147
|
-
|
|
148
127
|
> **Note:** This serves the pre-built production bundle. For development with hot reload, see [Development](#development) below.
|
|
149
128
|
|
|
150
129
|
---
|
|
@@ -159,10 +138,11 @@ pnpm install
|
|
|
159
138
|
|
|
160
139
|
### 2. Configure Gateway Connection
|
|
161
140
|
|
|
162
|
-
Create a `.env.local` file (gitignored) with your Gateway
|
|
141
|
+
Create a `.env.local` file (gitignored) with your Gateway connection details:
|
|
163
142
|
|
|
164
143
|
```bash
|
|
165
144
|
cat > .env.local << 'EOF'
|
|
145
|
+
VITE_GATEWAY_URL=ws://localhost:18789
|
|
166
146
|
VITE_GATEWAY_TOKEN=<your-gateway-token>
|
|
167
147
|
EOF
|
|
168
148
|
```
|
|
@@ -173,17 +153,20 @@ Get your Gateway token:
|
|
|
173
153
|
openclaw config get gateway.auth.token
|
|
174
154
|
```
|
|
175
155
|
|
|
176
|
-
### 3.
|
|
156
|
+
### 3. Browser Device Identity
|
|
157
|
+
|
|
158
|
+
OpenClaw Office now performs the same browser-side device identity signing flow as the built-in OpenClaw Control UI. In the common cases below, you should not need `gateway.controlUi.dangerouslyDisableDeviceAuth`:
|
|
177
159
|
|
|
178
|
-
OpenClaw Office
|
|
160
|
+
- OpenClaw Office opened on `http://localhost:*` or `http://127.0.0.1:*`
|
|
161
|
+
- OpenClaw Office served over HTTPS
|
|
162
|
+
|
|
163
|
+
If you open OpenClaw Office from a remote machine over plain HTTP, the browser may not expose `crypto.subtle`, so Gateway can still reject the connection. In that case, prefer HTTPS first. Only use the dangerous bypass as a temporary last resort:
|
|
179
164
|
|
|
180
165
|
```bash
|
|
181
166
|
openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth true
|
|
182
167
|
```
|
|
183
168
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
> **Security Note:** This bypass is intended for local development. In production, use a reverse proxy or other secure authentication mechanism.
|
|
169
|
+
If you change Gateway auth policy, restart Gateway afterward.
|
|
187
170
|
|
|
188
171
|
### 4. Start the Gateway
|
|
189
172
|
|
|
@@ -199,13 +182,14 @@ Ensure the OpenClaw Gateway is running on the configured address (default `local
|
|
|
199
182
|
pnpm dev
|
|
200
183
|
```
|
|
201
184
|
|
|
202
|
-
Open `http://localhost:5180` in your browser.
|
|
185
|
+
Open `http://localhost:5180` in your browser.
|
|
203
186
|
|
|
204
187
|
### Environment Variables
|
|
205
188
|
|
|
206
189
|
| Variable | Required | Default | Description |
|
|
207
190
|
| -------------------- | ------------------------------------- | ---------------------- | ------------------------------------ |
|
|
208
|
-
| `VITE_GATEWAY_URL` | No | `ws://localhost:18789` |
|
|
191
|
+
| `VITE_GATEWAY_URL` | No | `ws://localhost:18789` | Gateway WebSocket address |
|
|
192
|
+
| `VITE_GATEWAY_WS_PATH` | No | `/gateway-ws` | Browser-side reverse proxy WS path |
|
|
209
193
|
| `VITE_GATEWAY_TOKEN` | Yes (when connecting to real Gateway) | — | Gateway auth token |
|
|
210
194
|
| `VITE_MOCK` | No | `false` | Enable mock mode (no Gateway needed) |
|
|
211
195
|
|
package/README.zh.md
CHANGED
|
@@ -33,19 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
#### 演示视频
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
<a href="https://www.youtube.com/watch?v=ACXSFTSlVLY">
|
|
38
|
-
<img src="https://img.youtube.com/vi/ACXSFTSlVLY/maxresdefault.jpg" alt="OpenClaw Office 演示视频" width="100%" />
|
|
39
|
-
</a>
|
|
40
|
-
</p>
|
|
41
|
-
|
|
42
|
-
<p align="center">
|
|
43
|
-
▶ 点击上方预览图即可跳转播放
|
|
44
|
-
</p>
|
|
45
|
-
|
|
46
|
-
> GitHub 会清洗仓库 README 内容,不允许真正内嵌 YouTube / iframe 播放器,所以最稳妥的实现方式就是“预览图 + 点击播放跳转”。
|
|
47
|
-
|
|
48
|
-
[在 YouTube 观看](https://www.youtube.com/watch?v=ACXSFTSlVLY)
|
|
36
|
+
https://github.com/WW-AI-Lab/openclaw-office/raw/main/assets/iShot_2026-03-02_21.33.38.mp4
|
|
49
37
|
|
|
50
38
|
### 控制台
|
|
51
39
|
|
|
@@ -136,15 +124,6 @@ OPENCLAW_GATEWAY_TOKEN=<token> openclaw-office
|
|
|
136
124
|
| `--host <host>` | 绑定地址 | `0.0.0.0` |
|
|
137
125
|
| `-h, --help` | 显示帮助 | — |
|
|
138
126
|
|
|
139
|
-
生产服务端会对外暴露 Office,并通过同源路径 `/gateway-ws` 代理浏览器的 WebSocket 流量。其上游 Gateway 地址按以下优先级解析:
|
|
140
|
-
|
|
141
|
-
1. `--gateway`
|
|
142
|
-
2. `OPENCLAW_GATEWAY_URL`
|
|
143
|
-
3. Office 持久化配置 `~/.openclaw/openclaw-office.json`
|
|
144
|
-
4. 默认值 `ws://localhost:18789`
|
|
145
|
-
|
|
146
|
-
当提供 `--gateway` 或 `OPENCLAW_GATEWAY_URL` 时,Office 会自动将该值持久化到 `~/.openclaw/openclaw-office.json`,供后续重启复用。
|
|
147
|
-
|
|
148
127
|
> **说明:** 此方式运行的是预构建的生产版本。如需热重载开发,请参见下方 [开发](#开发) 部分。
|
|
149
128
|
|
|
150
129
|
---
|
|
@@ -159,10 +138,11 @@ pnpm install
|
|
|
159
138
|
|
|
160
139
|
### 2. 配置 Gateway 连接
|
|
161
140
|
|
|
162
|
-
创建 `.env.local` 文件(已在 `.gitignore` 中,不会被提交),填入 Gateway
|
|
141
|
+
创建 `.env.local` 文件(已在 `.gitignore` 中,不会被提交),填入 Gateway 连接信息:
|
|
163
142
|
|
|
164
143
|
```bash
|
|
165
144
|
cat > .env.local << 'EOF'
|
|
145
|
+
VITE_GATEWAY_URL=ws://localhost:18789
|
|
166
146
|
VITE_GATEWAY_TOKEN=<你的 gateway token>
|
|
167
147
|
EOF
|
|
168
148
|
```
|
|
@@ -173,17 +153,20 @@ EOF
|
|
|
173
153
|
openclaw config get gateway.auth.token
|
|
174
154
|
```
|
|
175
155
|
|
|
176
|
-
### 3.
|
|
156
|
+
### 3. 浏览器 Device Identity
|
|
157
|
+
|
|
158
|
+
OpenClaw Office 现在会像 OpenClaw 内置 Control UI 一样,在浏览器侧完成 device identity 签名。以下常见场景通常**不再需要** `gateway.controlUi.dangerouslyDisableDeviceAuth`:
|
|
177
159
|
|
|
178
|
-
|
|
160
|
+
- 在 `http://localhost:*` 或 `http://127.0.0.1:*` 打开 OpenClaw Office
|
|
161
|
+
- 通过 HTTPS 访问 OpenClaw Office
|
|
162
|
+
|
|
163
|
+
如果你是从远程机器通过纯 HTTP 访问,浏览器可能拿不到 `crypto.subtle`,Gateway 仍可能拒绝连接。此时应优先改用 HTTPS;只有在临时调试且确认风险的情况下,才建议使用危险 bypass:
|
|
179
164
|
|
|
180
165
|
```bash
|
|
181
166
|
openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth true
|
|
182
167
|
```
|
|
183
168
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
> **安全提示:** 此 bypass 配置仅建议在本地开发环境使用。生产环境应通过反向代理或其他安全机制处理认证。
|
|
169
|
+
如果修改了 Gateway 认证策略,之后需要**重启 Gateway**。
|
|
187
170
|
|
|
188
171
|
### 4. 启动 Gateway
|
|
189
172
|
|
|
@@ -199,13 +182,14 @@ openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth true
|
|
|
199
182
|
pnpm dev
|
|
200
183
|
```
|
|
201
184
|
|
|
202
|
-
在浏览器中打开 `http://localhost:5180
|
|
185
|
+
在浏览器中打开 `http://localhost:5180`。
|
|
203
186
|
|
|
204
187
|
### 环境变量
|
|
205
188
|
|
|
206
189
|
| 变量 | 必须 | 默认值 | 说明 |
|
|
207
190
|
| -------------------- | ------------------------- | ---------------------- | -------------------------------- |
|
|
208
|
-
| `VITE_GATEWAY_URL` | 否 | `ws://localhost:18789` |
|
|
191
|
+
| `VITE_GATEWAY_URL` | 否 | `ws://localhost:18789` | Gateway WebSocket 地址 |
|
|
192
|
+
| `VITE_GATEWAY_WS_PATH` | 否 | `/gateway-ws` | 浏览器侧反向代理 WS 路径 |
|
|
209
193
|
| `VITE_GATEWAY_TOKEN` | 是(连接真实 Gateway 时) | — | Gateway 认证 token |
|
|
210
194
|
| `VITE_MOCK` | 否 | `false` | 启用 Mock 模式(不需要 Gateway) |
|
|
211
195
|
|
package/bin/openclaw-office.js
CHANGED
|
@@ -1,31 +1,357 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import { createServer, request as httpRequest } from "node:http";
|
|
4
|
+
import { request as httpsRequest } from "node:https";
|
|
5
|
+
import { readFileSync } from "node:fs";
|
|
6
|
+
import { readFile, access } from "node:fs/promises";
|
|
7
|
+
import { resolve, join, extname } from "node:path";
|
|
3
8
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
printHelp,
|
|
7
|
-
resolveConfig,
|
|
8
|
-
parseArgs,
|
|
9
|
-
writePersistedOfficeConfig,
|
|
10
|
-
} from "./openclaw-office-config.js";
|
|
11
|
-
import { createOfficeServer, formatStartupSummary } from "./openclaw-office-server.js";
|
|
9
|
+
import { networkInterfaces, homedir } from "node:os";
|
|
12
10
|
|
|
13
11
|
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
14
12
|
const distDir = resolve(__dirname, "..", "dist");
|
|
15
13
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
const MIME_TYPES = {
|
|
15
|
+
".html": "text/html; charset=utf-8",
|
|
16
|
+
".js": "application/javascript; charset=utf-8",
|
|
17
|
+
".css": "text/css; charset=utf-8",
|
|
18
|
+
".json": "application/json; charset=utf-8",
|
|
19
|
+
".svg": "image/svg+xml",
|
|
20
|
+
".png": "image/png",
|
|
21
|
+
".jpg": "image/jpeg",
|
|
22
|
+
".jpeg": "image/jpeg",
|
|
23
|
+
".gif": "image/gif",
|
|
24
|
+
".ico": "image/x-icon",
|
|
25
|
+
".woff": "font/woff",
|
|
26
|
+
".woff2": "font/woff2",
|
|
27
|
+
".ttf": "font/ttf",
|
|
28
|
+
".webp": "image/webp",
|
|
29
|
+
".glb": "model/gltf-binary",
|
|
30
|
+
".gltf": "model/gltf+json",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// --- Argument parsing ---
|
|
34
|
+
|
|
35
|
+
function parseArgs() {
|
|
36
|
+
const args = process.argv.slice(2);
|
|
37
|
+
const result = { token: "", gatewayUrl: "", port: 0, host: "" };
|
|
38
|
+
for (let i = 0; i < args.length; i++) {
|
|
39
|
+
const arg = args[i];
|
|
40
|
+
const next = args[i + 1];
|
|
41
|
+
if ((arg === "--token" || arg === "-t") && next) {
|
|
42
|
+
result.token = next; i++;
|
|
43
|
+
} else if ((arg === "--gateway" || arg === "-g") && next) {
|
|
44
|
+
result.gatewayUrl = next; i++;
|
|
45
|
+
} else if ((arg === "--port" || arg === "-p") && next) {
|
|
46
|
+
result.port = parseInt(next, 10); i++;
|
|
47
|
+
} else if (arg === "--host" && next) {
|
|
48
|
+
result.host = next; i++;
|
|
49
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
50
|
+
printHelp();
|
|
51
|
+
process.exit(0);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function printHelp() {
|
|
58
|
+
console.log(`
|
|
59
|
+
\x1b[36mOpenClaw Office\x1b[0m — Visual monitoring frontend for OpenClaw
|
|
60
|
+
|
|
61
|
+
\x1b[1mUsage:\x1b[0m
|
|
62
|
+
openclaw-office [options]
|
|
63
|
+
|
|
64
|
+
\x1b[1mOptions:\x1b[0m
|
|
65
|
+
-t, --token <token> Gateway auth token
|
|
66
|
+
-g, --gateway <url> Gateway WebSocket URL (default: ws://localhost:18789)
|
|
67
|
+
-p, --port <port> Server port (default: 5180, or PORT env)
|
|
68
|
+
--host <host> Bind address (default: 0.0.0.0)
|
|
69
|
+
-h, --help Show this help
|
|
70
|
+
|
|
71
|
+
\x1b[1mToken auto-detection:\x1b[0m
|
|
72
|
+
The token is resolved in this order:
|
|
73
|
+
1. --token flag
|
|
74
|
+
2. OPENCLAW_GATEWAY_TOKEN environment variable
|
|
75
|
+
3. Auto-read from ~/.openclaw/openclaw.json
|
|
76
|
+
|
|
77
|
+
\x1b[1mExamples:\x1b[0m
|
|
78
|
+
openclaw-office
|
|
79
|
+
openclaw-office --token my-secret-token
|
|
80
|
+
openclaw-office --gateway ws://192.168.1.100:18789
|
|
81
|
+
PORT=3000 openclaw-office
|
|
82
|
+
`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// --- Token auto-detection from openclaw config file ---
|
|
86
|
+
|
|
87
|
+
function readTokenFromConfig() {
|
|
88
|
+
const candidates = [
|
|
89
|
+
join(homedir(), ".openclaw", "openclaw.json"),
|
|
90
|
+
join(homedir(), ".clawdbot", "clawdbot.json"),
|
|
91
|
+
];
|
|
92
|
+
for (const filePath of candidates) {
|
|
93
|
+
try {
|
|
94
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
95
|
+
const config = JSON.parse(raw);
|
|
96
|
+
const token = config?.gateway?.auth?.token;
|
|
97
|
+
if (token && typeof token === "string" && token.length > 0) {
|
|
98
|
+
return { token, source: filePath };
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
// file not found or parse error
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// --- Config resolution ---
|
|
108
|
+
|
|
109
|
+
function resolveConfig() {
|
|
110
|
+
const args = parseArgs();
|
|
111
|
+
|
|
112
|
+
let token = "";
|
|
113
|
+
let tokenSource = "";
|
|
114
|
+
|
|
115
|
+
if (args.token) {
|
|
116
|
+
token = args.token;
|
|
117
|
+
tokenSource = "command line --token";
|
|
118
|
+
} else if (process.env.OPENCLAW_GATEWAY_TOKEN) {
|
|
119
|
+
token = process.env.OPENCLAW_GATEWAY_TOKEN;
|
|
120
|
+
tokenSource = "OPENCLAW_GATEWAY_TOKEN env";
|
|
121
|
+
} else {
|
|
122
|
+
const fromFile = readTokenFromConfig();
|
|
123
|
+
if (fromFile) {
|
|
124
|
+
token = fromFile.token;
|
|
125
|
+
tokenSource = fromFile.source;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const gatewayUrl = args.gatewayUrl || process.env.OPENCLAW_GATEWAY_URL || "ws://localhost:18789";
|
|
130
|
+
const port = args.port || parseInt(process.env.PORT || "5180", 10);
|
|
131
|
+
const host = args.host || process.env.HOST || "0.0.0.0";
|
|
132
|
+
|
|
133
|
+
return { token, tokenSource, gatewayUrl, port, host };
|
|
20
134
|
}
|
|
21
135
|
|
|
136
|
+
// --- HTTP Server ---
|
|
137
|
+
|
|
22
138
|
const config = resolveConfig();
|
|
23
|
-
|
|
24
|
-
|
|
139
|
+
|
|
140
|
+
const runtimeConfig = JSON.stringify({
|
|
141
|
+
gatewayUrl: config.gatewayUrl,
|
|
142
|
+
gatewayToken: config.token,
|
|
143
|
+
gatewayWsPath: "/gateway-ws",
|
|
144
|
+
});
|
|
145
|
+
const configScript = `<script>window.__OPENCLAW_CONFIG__=${runtimeConfig};</script>`;
|
|
146
|
+
const gatewayWsPrefixes = new Set(["/gateway-ws", "/api/gateway/ws"]);
|
|
147
|
+
|
|
148
|
+
async function tryReadFile(filePath) {
|
|
149
|
+
try {
|
|
150
|
+
await access(filePath);
|
|
151
|
+
return await readFile(filePath);
|
|
152
|
+
} catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let indexHtmlCache = null;
|
|
158
|
+
|
|
159
|
+
async function getIndexHtml() {
|
|
160
|
+
if (indexHtmlCache) return indexHtmlCache;
|
|
161
|
+
const raw = await readFile(join(distDir, "index.html"), "utf-8");
|
|
162
|
+
indexHtmlCache = raw.replace("</head>", `${configScript}\n</head>`);
|
|
163
|
+
return indexHtmlCache;
|
|
25
164
|
}
|
|
26
165
|
|
|
27
|
-
|
|
166
|
+
function toHttpUrl(rawUrl) {
|
|
167
|
+
const url = new URL(rawUrl);
|
|
168
|
+
if (url.protocol === "ws:") {
|
|
169
|
+
url.protocol = "http:";
|
|
170
|
+
} else if (url.protocol === "wss:") {
|
|
171
|
+
url.protocol = "https:";
|
|
172
|
+
}
|
|
173
|
+
return url;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function serializeUpgradeResponse(res) {
|
|
177
|
+
const lines = [`HTTP/1.1 ${res.statusCode} ${res.statusMessage}`];
|
|
178
|
+
for (const [key, value] of Object.entries(res.headers)) {
|
|
179
|
+
if (Array.isArray(value)) {
|
|
180
|
+
for (const item of value) {
|
|
181
|
+
lines.push(`${key}: ${item}`);
|
|
182
|
+
}
|
|
183
|
+
} else if (typeof value !== "undefined") {
|
|
184
|
+
lines.push(`${key}: ${value}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
lines.push("\r\n");
|
|
188
|
+
return lines.join("\r\n");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function writeSocketError(socket, statusCode, message) {
|
|
192
|
+
if (socket.destroyed) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
socket.write(
|
|
196
|
+
`HTTP/1.1 ${statusCode} ${message}\r\nConnection: close\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: ${Buffer.byteLength(message)}\r\n\r\n${message}`,
|
|
197
|
+
);
|
|
198
|
+
socket.destroy();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function proxyWsUpgrade(req, downstreamSocket, downstreamHead) {
|
|
202
|
+
const upstreamUrl = toHttpUrl(config.gatewayUrl);
|
|
203
|
+
const headers = {
|
|
204
|
+
host: upstreamUrl.host,
|
|
205
|
+
connection: "Upgrade",
|
|
206
|
+
upgrade: "websocket",
|
|
207
|
+
origin: upstreamUrl.origin,
|
|
208
|
+
"sec-websocket-version": req.headers["sec-websocket-version"] || "13",
|
|
209
|
+
"sec-websocket-key": req.headers["sec-websocket-key"],
|
|
210
|
+
};
|
|
211
|
+
if (req.headers["sec-websocket-protocol"]) {
|
|
212
|
+
headers["sec-websocket-protocol"] = req.headers["sec-websocket-protocol"];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const doRequest = upstreamUrl.protocol === "https:" ? httpsRequest : httpRequest;
|
|
216
|
+
const upstreamReq = doRequest(upstreamUrl, { method: "GET", headers });
|
|
217
|
+
let settled = false;
|
|
218
|
+
let upgraded = false;
|
|
219
|
+
|
|
220
|
+
const fail = (statusCode, message) => {
|
|
221
|
+
if (settled) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
settled = true;
|
|
225
|
+
writeSocketError(downstreamSocket, statusCode, message);
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
upstreamReq.on("upgrade", (upstreamRes, upstreamSocket, upstreamHead) => {
|
|
229
|
+
if (settled) {
|
|
230
|
+
upstreamSocket.destroy();
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
settled = true;
|
|
234
|
+
upgraded = true;
|
|
235
|
+
|
|
236
|
+
if (downstreamSocket.destroyed) {
|
|
237
|
+
upstreamSocket.destroy();
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
downstreamSocket.write(serializeUpgradeResponse(upstreamRes));
|
|
242
|
+
|
|
243
|
+
if (downstreamHead.length > 0) {
|
|
244
|
+
upstreamSocket.write(downstreamHead);
|
|
245
|
+
}
|
|
246
|
+
if (upstreamHead.length > 0) {
|
|
247
|
+
downstreamSocket.write(upstreamHead);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
downstreamSocket.pipe(upstreamSocket, { end: false });
|
|
251
|
+
upstreamSocket.pipe(downstreamSocket, { end: false });
|
|
252
|
+
|
|
253
|
+
const closeBoth = () => {
|
|
254
|
+
if (!downstreamSocket.destroyed) {
|
|
255
|
+
downstreamSocket.destroy();
|
|
256
|
+
}
|
|
257
|
+
if (!upstreamSocket.destroyed) {
|
|
258
|
+
upstreamSocket.destroy();
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
downstreamSocket.on("error", closeBoth);
|
|
263
|
+
upstreamSocket.on("error", closeBoth);
|
|
264
|
+
downstreamSocket.on("close", closeBoth);
|
|
265
|
+
upstreamSocket.on("close", closeBoth);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
upstreamReq.on("response", (upstreamRes) => {
|
|
269
|
+
upstreamRes.resume();
|
|
270
|
+
fail(upstreamRes.statusCode || 502, upstreamRes.statusMessage || "Bad Gateway");
|
|
271
|
+
});
|
|
272
|
+
upstreamReq.on("error", () => {
|
|
273
|
+
fail(502, "Bad Gateway");
|
|
274
|
+
});
|
|
275
|
+
downstreamSocket.on("error", () => {
|
|
276
|
+
if (!upgraded) {
|
|
277
|
+
upstreamReq.destroy();
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
downstreamSocket.on("close", () => {
|
|
281
|
+
if (!upgraded) {
|
|
282
|
+
upstreamReq.destroy();
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
upstreamReq.end();
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const server = createServer(async (req, res) => {
|
|
290
|
+
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
291
|
+
const pathname = decodeURIComponent(url.pathname);
|
|
292
|
+
|
|
293
|
+
// Serve injected index.html for root and SPA routes
|
|
294
|
+
if (pathname === "/" || pathname === "/index.html") {
|
|
295
|
+
const html = await getIndexHtml();
|
|
296
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
297
|
+
res.end(html);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Try serving static file
|
|
302
|
+
const filePath = join(distDir, pathname);
|
|
303
|
+
const content = await tryReadFile(filePath);
|
|
304
|
+
|
|
305
|
+
if (content) {
|
|
306
|
+
const ext = extname(filePath).toLowerCase();
|
|
307
|
+
const mime = MIME_TYPES[ext] || "application/octet-stream";
|
|
308
|
+
res.writeHead(200, { "Content-Type": mime });
|
|
309
|
+
res.end(content);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// SPA fallback for client-side routes
|
|
314
|
+
const html = await getIndexHtml();
|
|
315
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
316
|
+
res.end(html);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
server.on("upgrade", (req, socket, head) => {
|
|
320
|
+
const pathname = new URL(req.url || "/", "http://localhost").pathname;
|
|
321
|
+
if (!gatewayWsPrefixes.has(pathname)) {
|
|
322
|
+
writeSocketError(socket, 404, "Not Found");
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
proxyWsUpgrade(req, socket, head);
|
|
326
|
+
});
|
|
28
327
|
|
|
29
328
|
server.listen(config.port, config.host, () => {
|
|
30
|
-
console.log(
|
|
329
|
+
console.log();
|
|
330
|
+
console.log(" \x1b[36m\u{1F3E2} OpenClaw Office\x1b[0m");
|
|
331
|
+
console.log();
|
|
332
|
+
console.log(` \x1b[32m\u{27A1}\x1b[0m Local: \x1b[36mhttp://localhost:${config.port}\x1b[0m`);
|
|
333
|
+
if (config.host === "0.0.0.0") {
|
|
334
|
+
const nets = networkInterfaces();
|
|
335
|
+
for (const name of Object.keys(nets)) {
|
|
336
|
+
for (const net of nets[name] || []) {
|
|
337
|
+
if (net.family === "IPv4" && !net.internal) {
|
|
338
|
+
console.log(` \x1b[32m\u{27A1}\x1b[0m Network: \x1b[36mhttp://${net.address}:${config.port}\x1b[0m`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
console.log();
|
|
344
|
+
console.log(` \x1b[32m\u{27A1}\x1b[0m Gateway: \x1b[33m${config.gatewayUrl}\x1b[0m`);
|
|
345
|
+
if (config.token) {
|
|
346
|
+
console.log(` \x1b[32m\u{2713}\x1b[0m Token: \x1b[32mloaded\x1b[0m \x1b[90m(from ${config.tokenSource})\x1b[0m`);
|
|
347
|
+
} else {
|
|
348
|
+
console.log(` \x1b[33m\u{26A0}\x1b[0m Token: \x1b[33mnot found\x1b[0m`);
|
|
349
|
+
console.log();
|
|
350
|
+
console.log(" \x1b[90mTo connect to Gateway, provide a token:\x1b[0m");
|
|
351
|
+
console.log(" \x1b[90m openclaw-office --token <your-token>\x1b[0m");
|
|
352
|
+
console.log(" \x1b[90m or install openclaw CLI and the token will be auto-detected\x1b[0m");
|
|
353
|
+
}
|
|
354
|
+
console.log();
|
|
355
|
+
console.log(" Press \x1b[1mCtrl+C\x1b[0m to stop");
|
|
356
|
+
console.log();
|
|
31
357
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as H,h as v,d as b,j as r}from"./index-
|
|
1
|
+
import{u as H,h as v,d as b,j as r}from"./index-WMjJihFL.js";const N=10,d=24,x=10,u=14,w=[{max:0,color:"#f3f4f6"},{max:5,color:"#bbf7d0"},{max:10,color:"#4ade80"},{max:1/0,color:"#16a34a"}],D=[{max:0,color:"#1e293b"},{max:5,color:"#14532d"},{max:10,color:"#166534"},{max:1/0,color:"#22c55e"}];function E(c,i){const l=i?D:w;for(const s of l)if(c<=s.max)return s.color;return l[l.length-1].color}function M(c){const i=Date.now(),l=3600*1e3,s=new Map;for(const t of c){const a=t.timestamp,n=(i-a)/l;if(n<0||n>=d)continue;const m=23-Math.min(23,Math.floor(n));let o=s.get(t.agentId);o||(o={name:t.agentName,counts:Array.from({length:d},()=>0)},s.set(t.agentId,o)),m>=0&&m<d&&o.counts[m]++}return Array.from(s.entries()).map(([t,{name:a,counts:n}])=>({agentId:t,agentName:a,counts:n})).toSorted((t,a)=>{const n=t.counts.reduce((o,e)=>o+e,0);return a.counts.reduce((o,e)=>o+e,0)-n}).slice(0,N)}function O(){const{t:c}=H("panels"),i=v(e=>e.eventHistory),s=v(e=>e.theme)==="dark",[t,a]=b.useState(null),n=b.useMemo(()=>M(i),[i]);if(n.length===0)return r.jsx("div",{className:"flex h-48 items-center justify-center text-sm text-gray-500 dark:text-gray-400",children:c("common:empty.noActivityData")});const m=Date.now(),o=3600*1e3;return r.jsxs("div",{className:"relative",children:[r.jsx("svg",{width:d*x+60,height:N*u+24,className:"overflow-visible",children:n.map((e,f)=>r.jsxs("g",{children:[r.jsx("text",{x:0,y:f*u+u/2+4,fontSize:9,fill:s?"#e2e8f0":"#374151",children:e.agentName.length>10?`${e.agentName.slice(0,8)}…`:e.agentName}),e.counts.map((h,g)=>{const L=55+g*x,j=f*u+4,y=m-(d-g)*o,S=y+o,A=`${new Date(y).getHours()}:00-${new Date(S).getHours()}:00`;return r.jsx("rect",{x:L,y:j,width:x-1,height:u-1,fill:E(h,s),onMouseEnter:C=>{const p=C.target.getBoundingClientRect();a({agentName:e.agentName,hour:A,count:h,x:p.left,y:p.top})},onMouseLeave:()=>a(null)},g)})]},e.agentId))}),t&&r.jsxs("div",{className:"fixed z-10 rounded border border-gray-200 bg-white px-2 py-1 text-xs shadow dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200",style:{left:t.x,top:t.y-32},children:[t.agentName," | ",t.hour," | ",t.count," ",c("activityHeatmap.eventsUnit")]})]})}export{O as ActivityHeatmap};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{e as f,g as Ce,d as me,u as Qe,h as xe,j as S,i as Xe}from"./index-
|
|
1
|
+
import{e as f,g as Ce,d as me,u as Qe,h as xe,j as S,i as Xe}from"./index-WMjJihFL.js";import{c as I,f as A,H as Be,I as Ye,J as Fe,K as et,b as D,T as he,M as T,L as _,N as Ke,e as ye,h as Me,D as tt,C as rt,n as z,q as K,S as nt,A as it,d as at,k as Oe,l as ot,i as M,p as st,u as ct,G as lt,m as ee,j as ut,O as Ve,P as ft,Q as Y,U as Pe,z as pt,V as dt,R as vt,F as mt}from"./generateCategoricalChart-DnxAF2gL.js";var ht=["points","className","baseLinePoints","connectNulls"];function V(){return V=Object.assign?Object.assign.bind():function(r){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var t in n)Object.prototype.hasOwnProperty.call(n,t)&&(r[t]=n[t])}return r},V.apply(this,arguments)}function yt(r,e){if(r==null)return{};var n=gt(r,e),t,i;if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(r);for(i=0;i<o.length;i++)t=o[i],!(e.indexOf(t)>=0)&&Object.prototype.propertyIsEnumerable.call(r,t)&&(n[t]=r[t])}return n}function gt(r,e){if(r==null)return{};var n={};for(var t in r)if(Object.prototype.hasOwnProperty.call(r,t)){if(e.indexOf(t)>=0)continue;n[t]=r[t]}return n}function ke(r){return Ot(r)||xt(r)||At(r)||bt()}function bt(){throw new TypeError(`Invalid attempt to spread non-iterable instance.
|
|
2
2
|
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function At(r,e){if(r){if(typeof r=="string")return fe(r,e);var n=Object.prototype.toString.call(r).slice(8,-1);if(n==="Object"&&r.constructor&&(n=r.constructor.name),n==="Map"||n==="Set")return Array.from(r);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return fe(r,e)}}function xt(r){if(typeof Symbol<"u"&&r[Symbol.iterator]!=null||r["@@iterator"]!=null)return Array.from(r)}function Ot(r){if(Array.isArray(r))return fe(r)}function fe(r,e){(e==null||e>r.length)&&(e=r.length);for(var n=0,t=new Array(e);n<e;n++)t[n]=r[n];return t}var _e=function(e){return e&&e.x===+e.x&&e.y===+e.y},Pt=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[],n=[[]];return e.forEach(function(t){_e(t)?n[n.length-1].push(t):n[n.length-1].length>0&&n.push([])}),_e(e[0])&&n[n.length-1].push(e[0]),n[n.length-1].length<=0&&(n=n.slice(0,-1)),n},U=function(e,n){var t=Pt(e);n&&(t=[t.reduce(function(o,a){return[].concat(ke(o),ke(a))},[])]);var i=t.map(function(o){return o.reduce(function(a,s,l){return"".concat(a).concat(l===0?"M":"L").concat(s.x,",").concat(s.y)},"")}).join("");return t.length===1?"".concat(i,"Z"):i},kt=function(e,n,t){var i=U(e,t);return"".concat(i.slice(-1)==="Z"?i.slice(0,-1):i,"L").concat(U(n.reverse(),t).slice(1))},_t=function(e){var n=e.points,t=e.className,i=e.baseLinePoints,o=e.connectNulls,a=yt(e,ht);if(!n||!n.length)return null;var s=I("recharts-polygon",t);if(i&&i.length){var l=a.stroke&&a.stroke!=="none",c=kt(n,i,o);return f.createElement("g",{className:s},f.createElement("path",V({},A(a,!0),{fill:c.slice(-1)==="Z"?a.fill:"none",stroke:"none",d:c})),l?f.createElement("path",V({},A(a,!0),{fill:"none",d:U(n,o)})):null,l?f.createElement("path",V({},A(a,!0),{fill:"none",d:U(i,o)})):null)}var p=U(n,o);return f.createElement("path",V({},A(a,!0),{fill:p.slice(-1)==="Z"?a.fill:"none",className:s,d:p}))},le,je;function jt(){if(je)return le;je=1;var r=Be(),e=Ye(),n=Fe();function t(i,o){return i&&i.length?r(i,n(o,2),e):void 0}return le=t,le}var wt=jt();const St=Ce(wt);var ue,we;function Tt(){if(we)return ue;we=1;var r=Be(),e=Fe(),n=et();function t(i,o){return i&&i.length?r(i,e(o,2),n):void 0}return ue=t,ue}var Et=Tt();const Rt=Ce(Et);var It=["cx","cy","angle","ticks","axisLine"],Lt=["ticks","tick","angle","tickFormatter","stroke"];function W(r){"@babel/helpers - typeof";return W=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(e){return typeof e}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},W(r)}function J(){return J=Object.assign?Object.assign.bind():function(r){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var t in n)Object.prototype.hasOwnProperty.call(n,t)&&(r[t]=n[t])}return r},J.apply(this,arguments)}function Se(r,e){var n=Object.keys(r);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(r);e&&(t=t.filter(function(i){return Object.getOwnPropertyDescriptor(r,i).enumerable})),n.push.apply(n,t)}return n}function $(r){for(var e=1;e<arguments.length;e++){var n=arguments[e]!=null?arguments[e]:{};e%2?Se(Object(n),!0).forEach(function(t){ae(r,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(n)):Se(Object(n)).forEach(function(t){Object.defineProperty(r,t,Object.getOwnPropertyDescriptor(n,t))})}return r}function Te(r,e){if(r==null)return{};var n=$t(r,e),t,i;if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(r);for(i=0;i<o.length;i++)t=o[i],!(e.indexOf(t)>=0)&&Object.prototype.propertyIsEnumerable.call(r,t)&&(n[t]=r[t])}return n}function $t(r,e){if(r==null)return{};var n={};for(var t in r)if(Object.prototype.hasOwnProperty.call(r,t)){if(e.indexOf(t)>=0)continue;n[t]=r[t]}return n}function Nt(r,e){if(!(r instanceof e))throw new TypeError("Cannot call a class as a function")}function Ee(r,e){for(var n=0;n<e.length;n++){var t=e[n];t.enumerable=t.enumerable||!1,t.configurable=!0,"value"in t&&(t.writable=!0),Object.defineProperty(r,ze(t.key),t)}}function Dt(r,e,n){return e&&Ee(r.prototype,e),n&&Ee(r,n),Object.defineProperty(r,"prototype",{writable:!1}),r}function Ct(r,e,n){return e=re(e),Bt(r,qe()?Reflect.construct(e,n||[],re(r).constructor):e.apply(r,n))}function Bt(r,e){if(e&&(W(e)==="object"||typeof e=="function"))return e;if(e!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return Ft(r)}function Ft(r){if(r===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r}function qe(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(qe=function(){return!!r})()}function re(r){return re=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(n){return n.__proto__||Object.getPrototypeOf(n)},re(r)}function Kt(r,e){if(typeof e!="function"&&e!==null)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(e&&e.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),e&&pe(r,e)}function pe(r,e){return pe=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,i){return t.__proto__=i,t},pe(r,e)}function ae(r,e,n){return e=ze(e),e in r?Object.defineProperty(r,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):r[e]=n,r}function ze(r){var e=Mt(r,"string");return W(e)=="symbol"?e:e+""}function Mt(r,e){if(W(r)!="object"||!r)return r;var n=r[Symbol.toPrimitive];if(n!==void 0){var t=n.call(r,e);if(W(t)!="object")return t;throw new TypeError("@@toPrimitive must return a primitive value.")}return(e==="string"?String:Number)(r)}var oe=(function(r){function e(){return Nt(this,e),Ct(this,e,arguments)}return Kt(e,r),Dt(e,[{key:"getTickValueCoord",value:function(t){var i=t.coordinate,o=this.props,a=o.angle,s=o.cx,l=o.cy;return T(s,l,i,a)}},{key:"getTickTextAnchor",value:function(){var t=this.props.orientation,i;switch(t){case"left":i="end";break;case"right":i="start";break;default:i="middle";break}return i}},{key:"getViewBox",value:function(){var t=this.props,i=t.cx,o=t.cy,a=t.angle,s=t.ticks,l=St(s,function(p){return p.coordinate||0}),c=Rt(s,function(p){return p.coordinate||0});return{cx:i,cy:o,startAngle:a,endAngle:a,innerRadius:c.coordinate||0,outerRadius:l.coordinate||0}}},{key:"renderAxisLine",value:function(){var t=this.props,i=t.cx,o=t.cy,a=t.angle,s=t.ticks,l=t.axisLine,c=Te(t,It),p=s.reduce(function(d,u){return[Math.min(d[0],u.coordinate),Math.max(d[1],u.coordinate)]},[1/0,-1/0]),v=T(i,o,p[0],a),y=T(i,o,p[1],a),x=$($($({},A(c,!1)),{},{fill:"none"},A(l,!1)),{},{x1:v.x,y1:v.y,x2:y.x,y2:y.y});return f.createElement("line",J({className:"recharts-polar-radius-axis-line"},x))}},{key:"renderTicks",value:function(){var t=this,i=this.props,o=i.ticks,a=i.tick,s=i.angle,l=i.tickFormatter,c=i.stroke,p=Te(i,Lt),v=this.getTickTextAnchor(),y=A(p,!1),x=A(a,!1),d=o.map(function(u,h){var g=t.getTickValueCoord(u),b=$($($($({textAnchor:v,transform:"rotate(".concat(90-s,", ").concat(g.x,", ").concat(g.y,")")},y),{},{stroke:"none",fill:c},x),{},{index:h},g),{},{payload:u});return f.createElement(_,J({className:I("recharts-polar-radius-axis-tick",Ke(a)),key:"tick-".concat(u.coordinate)},ye(t.props,u,h)),e.renderTickItem(a,b,l?l(u.value,h):u.value))});return f.createElement(_,{className:"recharts-polar-radius-axis-ticks"},d)}},{key:"render",value:function(){var t=this.props,i=t.ticks,o=t.axisLine,a=t.tick;return!i||!i.length?null:f.createElement(_,{className:I("recharts-polar-radius-axis",this.props.className)},o&&this.renderAxisLine(),a&&this.renderTicks(),Me.renderCallByParent(this.props,this.getViewBox()))}}],[{key:"renderTickItem",value:function(t,i,o){var a;return f.isValidElement(t)?a=f.cloneElement(t,i):D(t)?a=t(i):a=f.createElement(he,J({},i,{className:"recharts-polar-radius-axis-tick-value"}),o),a}}])})(me.PureComponent);ae(oe,"displayName","PolarRadiusAxis");ae(oe,"axisType","radiusAxis");ae(oe,"defaultProps",{type:"number",radiusAxisId:0,cx:0,cy:0,angle:0,orientation:"right",stroke:"#ccc",axisLine:!0,tick:!0,tickCount:5,allowDataOverflow:!1,scale:"auto",allowDuplicatedCategory:!0});function G(r){"@babel/helpers - typeof";return G=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(e){return typeof e}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},G(r)}function C(){return C=Object.assign?Object.assign.bind():function(r){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var t in n)Object.prototype.hasOwnProperty.call(n,t)&&(r[t]=n[t])}return r},C.apply(this,arguments)}function Re(r,e){var n=Object.keys(r);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(r);e&&(t=t.filter(function(i){return Object.getOwnPropertyDescriptor(r,i).enumerable})),n.push.apply(n,t)}return n}function N(r){for(var e=1;e<arguments.length;e++){var n=arguments[e]!=null?arguments[e]:{};e%2?Re(Object(n),!0).forEach(function(t){se(r,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(n)):Re(Object(n)).forEach(function(t){Object.defineProperty(r,t,Object.getOwnPropertyDescriptor(n,t))})}return r}function Vt(r,e){if(!(r instanceof e))throw new TypeError("Cannot call a class as a function")}function Ie(r,e){for(var n=0;n<e.length;n++){var t=e[n];t.enumerable=t.enumerable||!1,t.configurable=!0,"value"in t&&(t.writable=!0),Object.defineProperty(r,Ge(t.key),t)}}function qt(r,e,n){return e&&Ie(r.prototype,e),n&&Ie(r,n),Object.defineProperty(r,"prototype",{writable:!1}),r}function zt(r,e,n){return e=ne(e),Wt(r,We()?Reflect.construct(e,n||[],ne(r).constructor):e.apply(r,n))}function Wt(r,e){if(e&&(G(e)==="object"||typeof e=="function"))return e;if(e!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return Gt(r)}function Gt(r){if(r===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r}function We(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(We=function(){return!!r})()}function ne(r){return ne=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(n){return n.__proto__||Object.getPrototypeOf(n)},ne(r)}function Ht(r,e){if(typeof e!="function"&&e!==null)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(e&&e.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),e&&de(r,e)}function de(r,e){return de=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,i){return t.__proto__=i,t},de(r,e)}function se(r,e,n){return e=Ge(e),e in r?Object.defineProperty(r,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):r[e]=n,r}function Ge(r){var e=Zt(r,"string");return G(e)=="symbol"?e:e+""}function Zt(r,e){if(G(r)!="object"||!r)return r;var n=r[Symbol.toPrimitive];if(n!==void 0){var t=n.call(r,e);if(G(t)!="object")return t;throw new TypeError("@@toPrimitive must return a primitive value.")}return(e==="string"?String:Number)(r)}var Ut=Math.PI/180,Le=1e-5,ce=(function(r){function e(){return Vt(this,e),zt(this,e,arguments)}return Ht(e,r),qt(e,[{key:"getTickLineCoord",value:function(t){var i=this.props,o=i.cx,a=i.cy,s=i.radius,l=i.orientation,c=i.tickSize,p=c||8,v=T(o,a,s,t.coordinate),y=T(o,a,s+(l==="inner"?-1:1)*p,t.coordinate);return{x1:v.x,y1:v.y,x2:y.x,y2:y.y}}},{key:"getTickTextAnchor",value:function(t){var i=this.props.orientation,o=Math.cos(-t.coordinate*Ut),a;return o>Le?a=i==="outer"?"start":"end":o<-Le?a=i==="outer"?"end":"start":a="middle",a}},{key:"renderAxisLine",value:function(){var t=this.props,i=t.cx,o=t.cy,a=t.radius,s=t.axisLine,l=t.axisLineType,c=N(N({},A(this.props,!1)),{},{fill:"none"},A(s,!1));if(l==="circle")return f.createElement(tt,C({className:"recharts-polar-angle-axis-line"},c,{cx:i,cy:o,r:a}));var p=this.props.ticks,v=p.map(function(y){return T(i,o,a,y.coordinate)});return f.createElement(_t,C({className:"recharts-polar-angle-axis-line"},c,{points:v}))}},{key:"renderTicks",value:function(){var t=this,i=this.props,o=i.ticks,a=i.tick,s=i.tickLine,l=i.tickFormatter,c=i.stroke,p=A(this.props,!1),v=A(a,!1),y=N(N({},p),{},{fill:"none"},A(s,!1)),x=o.map(function(d,u){var h=t.getTickLineCoord(d),g=t.getTickTextAnchor(d),b=N(N(N({textAnchor:g},p),{},{stroke:"none",fill:c},v),{},{index:u,payload:d,x:h.x2,y:h.y2});return f.createElement(_,C({className:I("recharts-polar-angle-axis-tick",Ke(a)),key:"tick-".concat(d.coordinate)},ye(t.props,d,u)),s&&f.createElement("line",C({className:"recharts-polar-angle-axis-tick-line"},y,h)),a&&e.renderTickItem(a,b,l?l(d.value,u):d.value))});return f.createElement(_,{className:"recharts-polar-angle-axis-ticks"},x)}},{key:"render",value:function(){var t=this.props,i=t.ticks,o=t.radius,a=t.axisLine;return o<=0||!i||!i.length?null:f.createElement(_,{className:I("recharts-polar-angle-axis",this.props.className)},a&&this.renderAxisLine(),this.renderTicks())}}],[{key:"renderTickItem",value:function(t,i,o){var a;return f.isValidElement(t)?a=f.cloneElement(t,i):D(t)?a=t(i):a=f.createElement(he,C({},i,{className:"recharts-polar-angle-axis-tick-value"}),o),a}}])})(me.PureComponent);se(ce,"displayName","PolarAngleAxis");se(ce,"axisType","angleAxis");se(ce,"defaultProps",{type:"category",angleAxisId:0,scale:"auto",cx:0,cy:0,orientation:"outer",axisLine:!0,tickLine:!0,tickSize:8,tick:!0,hide:!1,allowDuplicatedCategory:!0});var te;function H(r){"@babel/helpers - typeof";return H=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(e){return typeof e}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},H(r)}function q(){return q=Object.assign?Object.assign.bind():function(r){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var t in n)Object.prototype.hasOwnProperty.call(n,t)&&(r[t]=n[t])}return r},q.apply(this,arguments)}function $e(r,e){var n=Object.keys(r);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(r);e&&(t=t.filter(function(i){return Object.getOwnPropertyDescriptor(r,i).enumerable})),n.push.apply(n,t)}return n}function m(r){for(var e=1;e<arguments.length;e++){var n=arguments[e]!=null?arguments[e]:{};e%2?$e(Object(n),!0).forEach(function(t){P(r,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(n)):$e(Object(n)).forEach(function(t){Object.defineProperty(r,t,Object.getOwnPropertyDescriptor(n,t))})}return r}function Jt(r,e){if(!(r instanceof e))throw new TypeError("Cannot call a class as a function")}function Ne(r,e){for(var n=0;n<e.length;n++){var t=e[n];t.enumerable=t.enumerable||!1,t.configurable=!0,"value"in t&&(t.writable=!0),Object.defineProperty(r,Ze(t.key),t)}}function Qt(r,e,n){return e&&Ne(r.prototype,e),n&&Ne(r,n),Object.defineProperty(r,"prototype",{writable:!1}),r}function Xt(r,e,n){return e=ie(e),Yt(r,He()?Reflect.construct(e,n||[],ie(r).constructor):e.apply(r,n))}function Yt(r,e){if(e&&(H(e)==="object"||typeof e=="function"))return e;if(e!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return er(r)}function er(r){if(r===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r}function He(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(He=function(){return!!r})()}function ie(r){return ie=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(n){return n.__proto__||Object.getPrototypeOf(n)},ie(r)}function tr(r,e){if(typeof e!="function"&&e!==null)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(e&&e.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),e&&ve(r,e)}function ve(r,e){return ve=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,i){return t.__proto__=i,t},ve(r,e)}function P(r,e,n){return e=Ze(e),e in r?Object.defineProperty(r,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):r[e]=n,r}function Ze(r){var e=rr(r,"string");return H(e)=="symbol"?e:e+""}function rr(r,e){if(H(r)!="object"||!r)return r;var n=r[Symbol.toPrimitive];if(n!==void 0){var t=n.call(r,e);if(H(t)!="object")return t;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(r)}var E=(function(r){function e(n){var t;return Jt(this,e),t=Xt(this,e,[n]),P(t,"pieRef",null),P(t,"sectorRefs",[]),P(t,"id",ct("recharts-pie-")),P(t,"handleAnimationEnd",function(){var i=t.props.onAnimationEnd;t.setState({isAnimationFinished:!0}),D(i)&&i()}),P(t,"handleAnimationStart",function(){var i=t.props.onAnimationStart;t.setState({isAnimationFinished:!1}),D(i)&&i()}),t.state={isAnimationFinished:!n.isAnimationActive,prevIsAnimationActive:n.isAnimationActive,prevAnimationId:n.animationId,sectorToFocus:0},t}return tr(e,r),Qt(e,[{key:"isActiveIndex",value:function(t){var i=this.props.activeIndex;return Array.isArray(i)?i.indexOf(t)!==-1:t===i}},{key:"hasActiveIndex",value:function(){var t=this.props.activeIndex;return Array.isArray(t)?t.length!==0:t||t===0}},{key:"renderLabels",value:function(t){var i=this.props.isAnimationActive;if(i&&!this.state.isAnimationFinished)return null;var o=this.props,a=o.label,s=o.labelLine,l=o.dataKey,c=o.valueKey,p=A(this.props,!1),v=A(a,!1),y=A(s,!1),x=a&&a.offsetRadius||20,d=t.map(function(u,h){var g=(u.startAngle+u.endAngle)/2,b=T(u.cx,u.cy,u.outerRadius+x,g),k=m(m(m(m({},p),u),{},{stroke:"none"},v),{},{index:h,textAnchor:e.getTextAnchor(b.x,u.cx)},b),B=m(m(m(m({},p),u),{},{fill:"none",stroke:u.fill},y),{},{index:h,points:[T(u.cx,u.cy,u.outerRadius,g),b]}),j=l;return z(l)&&z(c)?j="value":z(l)&&(j=c),f.createElement(_,{key:"label-".concat(u.startAngle,"-").concat(u.endAngle,"-").concat(u.midAngle,"-").concat(h)},s&&e.renderLabelLineItem(s,B,"line"),e.renderLabelItem(a,k,K(u,j)))});return f.createElement(_,{className:"recharts-pie-labels"},d)}},{key:"renderSectorsStatically",value:function(t){var i=this,o=this.props,a=o.activeShape,s=o.blendStroke,l=o.inactiveShape;return t.map(function(c,p){if((c==null?void 0:c.startAngle)===0&&(c==null?void 0:c.endAngle)===0&&t.length!==1)return null;var v=i.isActiveIndex(p),y=l&&i.hasActiveIndex()?l:null,x=v?a:y,d=m(m({},c),{},{stroke:s?c.fill:c.stroke,tabIndex:-1});return f.createElement(_,q({ref:function(h){h&&!i.sectorRefs.includes(h)&&i.sectorRefs.push(h)},tabIndex:-1,className:"recharts-pie-sector"},ye(i.props,c,p),{key:"sector-".concat(c==null?void 0:c.startAngle,"-").concat(c==null?void 0:c.endAngle,"-").concat(c.midAngle,"-").concat(p)}),f.createElement(nt,q({option:x,isActive:v,shapeType:"sector"},d)))})}},{key:"renderSectorsWithAnimation",value:function(){var t=this,i=this.props,o=i.sectors,a=i.isAnimationActive,s=i.animationBegin,l=i.animationDuration,c=i.animationEasing,p=i.animationId,v=this.state,y=v.prevSectors,x=v.prevIsAnimationActive;return f.createElement(it,{begin:s,duration:l,isActive:a,easing:c,from:{t:0},to:{t:1},key:"pie-".concat(p,"-").concat(x),onAnimationStart:this.handleAnimationStart,onAnimationEnd:this.handleAnimationEnd},function(d){var u=d.t,h=[],g=o&&o[0],b=g.startAngle;return o.forEach(function(k,B){var j=y&&y[B],L=B>0?at(k,"paddingAngle",0):0;if(j){var Z=Oe(j.endAngle-j.startAngle,k.endAngle-k.startAngle),O=m(m({},k),{},{startAngle:b+L,endAngle:b+Z(u)+L});h.push(O),b=O.endAngle}else{var F=k.endAngle,w=k.startAngle,Q=Oe(0,F-w),X=Q(u),R=m(m({},k),{},{startAngle:b+L,endAngle:b+X+L});h.push(R),b=R.endAngle}}),f.createElement(_,null,t.renderSectorsStatically(h))})}},{key:"attachKeyboardHandlers",value:function(t){var i=this;t.onkeydown=function(o){if(!o.altKey)switch(o.key){case"ArrowLeft":{var a=++i.state.sectorToFocus%i.sectorRefs.length;i.sectorRefs[a].focus(),i.setState({sectorToFocus:a});break}case"ArrowRight":{var s=--i.state.sectorToFocus<0?i.sectorRefs.length-1:i.state.sectorToFocus%i.sectorRefs.length;i.sectorRefs[s].focus(),i.setState({sectorToFocus:s});break}case"Escape":{i.sectorRefs[i.state.sectorToFocus].blur(),i.setState({sectorToFocus:0});break}}}}},{key:"renderSectors",value:function(){var t=this.props,i=t.sectors,o=t.isAnimationActive,a=this.state.prevSectors;return o&&i&&i.length&&(!a||!ot(a,i))?this.renderSectorsWithAnimation():this.renderSectorsStatically(i)}},{key:"componentDidMount",value:function(){this.pieRef&&this.attachKeyboardHandlers(this.pieRef)}},{key:"render",value:function(){var t=this,i=this.props,o=i.hide,a=i.sectors,s=i.className,l=i.label,c=i.cx,p=i.cy,v=i.innerRadius,y=i.outerRadius,x=i.isAnimationActive,d=this.state.isAnimationFinished;if(o||!a||!a.length||!M(c)||!M(p)||!M(v)||!M(y))return null;var u=I("recharts-pie",s);return f.createElement(_,{tabIndex:this.props.rootTabIndex,className:u,ref:function(g){t.pieRef=g}},this.renderSectors(),l&&this.renderLabels(a),Me.renderCallByParent(this.props,null,!1),(!x||d)&&st.renderCallByParent(this.props,a,!1))}}],[{key:"getDerivedStateFromProps",value:function(t,i){return i.prevIsAnimationActive!==t.isAnimationActive?{prevIsAnimationActive:t.isAnimationActive,prevAnimationId:t.animationId,curSectors:t.sectors,prevSectors:[],isAnimationFinished:!0}:t.isAnimationActive&&t.animationId!==i.prevAnimationId?{prevAnimationId:t.animationId,curSectors:t.sectors,prevSectors:i.curSectors,isAnimationFinished:!0}:t.sectors!==i.curSectors?{curSectors:t.sectors,isAnimationFinished:!0}:null}},{key:"getTextAnchor",value:function(t,i){return t>i?"start":t<i?"end":"middle"}},{key:"renderLabelLineItem",value:function(t,i,o){if(f.isValidElement(t))return f.cloneElement(t,i);if(D(t))return t(i);var a=I("recharts-pie-label-line",typeof t!="boolean"?t.className:"");return f.createElement(rt,q({},i,{key:o,type:"linear",className:a}))}},{key:"renderLabelItem",value:function(t,i,o){if(f.isValidElement(t))return f.cloneElement(t,i);var a=o;if(D(t)&&(a=t(i),f.isValidElement(a)))return a;var s=I("recharts-pie-label-text",typeof t!="boolean"&&!D(t)?t.className:"");return f.createElement(he,q({},i,{alignmentBaseline:"middle",className:s}),a)}}])})(me.PureComponent);te=E;P(E,"displayName","Pie");P(E,"defaultProps",{stroke:"#fff",fill:"#808080",legendType:"rect",cx:"50%",cy:"50%",startAngle:0,endAngle:360,innerRadius:0,outerRadius:"80%",paddingAngle:0,labelLine:!0,hide:!1,minAngle:0,isAnimationActive:!lt.isSsr,animationBegin:400,animationDuration:1500,animationEasing:"ease",nameKey:"name",blendStroke:!1,rootTabIndex:0});P(E,"parseDeltaAngle",function(r,e){var n=ee(e-r),t=Math.min(Math.abs(e-r),360);return n*t});P(E,"getRealPieData",function(r){var e=r.data,n=r.children,t=A(r,!1),i=ut(n,Ve);return e&&e.length?e.map(function(o,a){return m(m(m({payload:o},t),o),i&&i[a]&&i[a].props)}):i&&i.length?i.map(function(o){return m(m({},t),o.props)}):[]});P(E,"parseCoordinateOfPie",function(r,e){var n=e.top,t=e.left,i=e.width,o=e.height,a=ft(i,o),s=t+Y(r.cx,i,i/2),l=n+Y(r.cy,o,o/2),c=Y(r.innerRadius,a,0),p=Y(r.outerRadius,a,a*.8),v=r.maxRadius||Math.sqrt(i*i+o*o)/2;return{cx:s,cy:l,innerRadius:c,outerRadius:p,maxRadius:v}});P(E,"getComposedData",function(r){var e=r.item,n=r.offset,t=e.type.defaultProps!==void 0?m(m({},e.type.defaultProps),e.props):e.props,i=te.getRealPieData(t);if(!i||!i.length)return null;var o=t.cornerRadius,a=t.startAngle,s=t.endAngle,l=t.paddingAngle,c=t.dataKey,p=t.nameKey,v=t.valueKey,y=t.tooltipType,x=Math.abs(t.minAngle),d=te.parseCoordinateOfPie(t,n),u=te.parseDeltaAngle(a,s),h=Math.abs(u),g=c;z(c)&&z(v)?(Pe(!1,`Use "dataKey" to specify the value of pie,
|
|
3
3
|
the props "valueKey" will be deprecated in 1.1.0`),g="value"):z(c)&&(Pe(!1,`Use "dataKey" to specify the value of pie,
|
|
4
4
|
the props "valueKey" will be deprecated in 1.1.0`),g=v);var b=i.filter(function(O){return K(O,g,0)!==0}).length,k=(h>=360?b:b-1)*l,B=h-b*x-k,j=i.reduce(function(O,F){var w=K(F,g,0);return O+(M(w)?w:0)},0),L;if(j>0){var Z;L=i.map(function(O,F){var w=K(O,g,0),Q=K(O,p,F),X=(M(w)?w:0)/j,R;F?R=Z.endAngle+ee(u)*l*(w!==0?1:0):R=a;var ge=R+ee(u)*((w!==0?x:0)+X*B),be=(R+ge)/2,Ae=(d.innerRadius+d.outerRadius)/2,Ue=[{name:Q,value:w,payload:O,dataKey:g,type:y}],Je=T(d.cx,d.cy,Ae,be);return Z=m(m(m({percent:X,cornerRadius:o,name:Q,tooltipPayload:Ue,midAngle:be,middleRadius:Ae,tooltipPosition:Je},O),d),{},{value:K(O,g),startAngle:R,endAngle:ge,payload:O,paddingAngle:ee(u)*l}),Z})}return m(m({},d),{},{sectors:L,data:i})});var nr=pt({chartName:"PieChart",GraphicalChild:E,validateTooltipEventTypes:["item"],defaultTooltipEventType:"item",legendContent:"children",axisComponents:[{axisType:"angleAxis",AxisComp:ce},{axisType:"radiusAxis",AxisComp:oe}],formatAxisMap:dt,defaultProps:{layout:"centric",startAngle:0,endAngle:360,cx:"50%",cy:"50%",innerRadius:0,outerRadius:"80%"}});function De(r){return r>=1e6?`${(r/1e6).toFixed(1)}M`:r>=1e3?`${(r/1e3).toFixed(1)}k`:String(r)}function or(){const{t:r}=Qe(),e=xe(a=>a.agentCosts),n=xe(a=>a.agents),t=Object.entries(e).filter(([,a])=>a>0),i=t.reduce((a,[,s])=>a+s,0);if(t.length===0)return S.jsx("div",{className:"flex h-24 items-center justify-center text-sm text-gray-500 dark:text-gray-400",children:r("empty.noCostData")});const o=t.map(([a,s])=>{var l;return{name:((l=n.get(a))==null?void 0:l.name)??a,agentId:a,value:s,color:Xe(a)}});return S.jsxs("div",{className:"relative h-[200px] w-full",children:[S.jsx(vt,{width:"100%",height:"100%",children:S.jsxs(nr,{children:[S.jsx(E,{data:o,dataKey:"value",nameKey:"name",cx:"50%",cy:"50%",innerRadius:50,outerRadius:80,paddingAngle:2,children:o.map((a,s)=>S.jsx(Ve,{fill:a.color},s))}),S.jsx(mt,{formatter:(a,s)=>{const l=typeof a=="number"?a:0,c=i>0?(l/i*100).toFixed(0):"0";return`${s}: ${De(l)} (${c}%)`}})]})}),S.jsx("div",{className:"absolute inset-0 flex items-center justify-center pointer-events-none",children:S.jsx("span",{className:"text-sm font-bold text-gray-700 dark:text-gray-300",children:De(i)})})]})}export{or as CostPieChart};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as S,h as g,d as M,j as d,S as k}from"./index-
|
|
1
|
+
import{u as S,h as g,d as M,j as d,S as k}from"./index-WMjJihFL.js";const y=8,C=24,j=20,p=280;function T(l,n,s,f){const e=new Map,r=l.length;if(r===0)return e;for(let u=0;u<r;u++){const h=2*Math.PI*u/r-Math.PI/2;e.set(l[u].id,{x:n+f*Math.cos(h),y:s+f*Math.sin(h)})}return e}function w(l,n){if(n<=0)return y;const s=Math.min(l/n,1);return y+s*(C-y)}function E(){const{t:l}=S(),n=g(t=>t.agents),s=g(t=>t.links),f=g(t=>t.theme),[e,r]=M.useState(null),u=f==="dark",{topAgents:h,positions:x,maxToolCount:I}=M.useMemo(()=>{const t=Array.from(n.values()).toSorted((i,m)=>m.toolCallCount-i.toolCallCount).slice(0,j),o=Math.max(1,...t.map(i=>i.toolCallCount)),a=Math.min(80,Math.max(40,t.length*8)),c=T(t,p/2,p/2,a);return{topAgents:t,positions:c,maxToolCount:o}},[n]),v=M.useMemo(()=>{if(!e)return new Set;const t=new Set;for(const o of s)(o.sourceId===e||o.targetId===e)&&t.add(`${o.sourceId}-${o.targetId}`);return t},[s,e]);return h.length===0&&s.length===0?d.jsx("div",{className:"flex h-48 items-center justify-center text-sm text-gray-500 dark:text-gray-400",children:l("empty.noRelationData")}):d.jsxs("svg",{width:"100%",height:200,viewBox:`0 0 ${p} ${p}`,className:"overflow-visible",onMouseLeave:()=>r(null),children:[s.filter(t=>x.has(t.sourceId)&&x.has(t.targetId)).map(t=>{const o=x.get(t.sourceId),a=x.get(t.targetId),c=`${t.sourceId}-${t.targetId}`,i=v.has(c),m=Math.max(1,t.strength*3);return d.jsx("line",{x1:o.x,y1:o.y,x2:a.x,y2:a.y,stroke:i?"#3b82f6":"rgba(107,114,128,0.4)",strokeWidth:m},c)}),h.map(t=>{const o=x.get(t.id);if(!o)return null;const a=w(t.toolCallCount,I),c=e===t.id,i=c?1.2:1,m=k[t.status];return d.jsxs("g",{onMouseEnter:()=>r(t.id),onMouseLeave:()=>r(null),children:[d.jsx("circle",{cx:o.x,cy:o.y,r:a*i,fill:m,stroke:c?"#1e40af":"transparent",strokeWidth:2}),d.jsx("text",{x:o.x,y:o.y+a+10,textAnchor:"middle",fontSize:9,fill:u?"#e2e8f0":"#374151",children:t.name.length>8?`${t.name.slice(0,6)}…`:t.name})]},t.id)})]})}export{E as NetworkGraph};
|