@chromepilot/recording-ui 0.0.0-stage → 0.1.1
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/api.d.ts +47 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +101 -0
- package/dist/api.js.map +1 -0
- package/dist/api.test.d.ts +2 -0
- package/dist/api.test.d.ts.map +1 -0
- package/dist/api.test.js +89 -0
- package/dist/api.test.js.map +1 -0
- package/dist/components/BatchDeleteBar.d.ts +13 -0
- package/dist/components/BatchDeleteBar.d.ts.map +1 -0
- package/dist/components/BatchDeleteBar.js +13 -0
- package/dist/components/BatchDeleteBar.js.map +1 -0
- package/dist/components/EventStreamPanel.d.ts +16 -0
- package/dist/components/EventStreamPanel.d.ts.map +1 -0
- package/dist/components/EventStreamPanel.js +106 -0
- package/dist/components/EventStreamPanel.js.map +1 -0
- package/dist/components/OtherRecordingTabs.d.ts +19 -0
- package/dist/components/OtherRecordingTabs.d.ts.map +1 -0
- package/dist/components/OtherRecordingTabs.js +82 -0
- package/dist/components/OtherRecordingTabs.js.map +1 -0
- package/dist/components/RecordingControls.d.ts +15 -0
- package/dist/components/RecordingControls.d.ts.map +1 -0
- package/dist/components/RecordingControls.js +100 -0
- package/dist/components/RecordingControls.js.map +1 -0
- package/dist/components/RecordingDetailBody.d.ts +27 -0
- package/dist/components/RecordingDetailBody.d.ts.map +1 -0
- package/dist/components/RecordingDetailBody.js +84 -0
- package/dist/components/RecordingDetailBody.js.map +1 -0
- package/dist/components/RecordingHistoryList.d.ts +28 -0
- package/dist/components/RecordingHistoryList.d.ts.map +1 -0
- package/dist/components/RecordingHistoryList.js +45 -0
- package/dist/components/RecordingHistoryList.js.map +1 -0
- package/dist/components/SyncPlayer.d.ts +20 -0
- package/dist/components/SyncPlayer.d.ts.map +1 -0
- package/dist/components/SyncPlayer.js +84 -0
- package/dist/components/SyncPlayer.js.map +1 -0
- package/dist/components/TimelineRuler.d.ts +18 -0
- package/dist/components/TimelineRuler.d.ts.map +1 -0
- package/dist/components/TimelineRuler.js +217 -0
- package/dist/components/TimelineRuler.js.map +1 -0
- package/dist/format.d.ts +13 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +37 -0
- package/dist/format.js.map +1 -0
- package/dist/format.test.d.ts +2 -0
- package/dist/format.test.d.ts.map +1 -0
- package/dist/format.test.js +42 -0
- package/dist/format.test.js.map +1 -0
- package/dist/hooks.d.ts +25 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +76 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/logic.d.ts +5 -0
- package/dist/logic.d.ts.map +1 -0
- package/dist/logic.js +6 -0
- package/dist/logic.js.map +1 -0
- package/dist/player.d.ts +3 -0
- package/dist/player.d.ts.map +1 -0
- package/dist/player.js +4 -0
- package/dist/player.js.map +1 -0
- package/dist/stack.d.ts +58 -0
- package/dist/stack.d.ts.map +1 -0
- package/dist/stack.js +86 -0
- package/dist/stack.js.map +1 -0
- package/dist/stack.test.d.ts +2 -0
- package/dist/stack.test.d.ts.map +1 -0
- package/dist/stack.test.js +93 -0
- package/dist/stack.test.js.map +1 -0
- package/dist/types.d.ts +81 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +58 -3
- package/README.md +0 -3
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FID-133:chromepilot server 录制 API 客户端。
|
|
3
|
+
* baseUrl 可配:sidepanel 传 `http://localhost:<port>/api`,server web 传 `/api`。
|
|
4
|
+
* 非 2xx 一律抛 RecordingApiError(carry server error code),由调用方映射用户文案。
|
|
5
|
+
*/
|
|
6
|
+
import type { ActiveRecordingInfo, BatchDeleteResponse, CpuProfile, RecordingEvents, RecordingListResponse, RecordingMeta } from "./types.js";
|
|
7
|
+
export declare class RecordingApiError extends Error {
|
|
8
|
+
code: string;
|
|
9
|
+
status: number;
|
|
10
|
+
constructor(status: number, code: string, message?: string);
|
|
11
|
+
}
|
|
12
|
+
export interface StartRecordingResult {
|
|
13
|
+
sessionId: string;
|
|
14
|
+
tabId: number | null;
|
|
15
|
+
}
|
|
16
|
+
export declare class RecordingApi {
|
|
17
|
+
private readonly baseUrl;
|
|
18
|
+
constructor(baseUrl: string);
|
|
19
|
+
private request;
|
|
20
|
+
/** 历史录制;urlKey 过滤 + cursor 滚动分页(不传 = 全量,兼容旧调用) */
|
|
21
|
+
list(opts?: {
|
|
22
|
+
urlKey?: string;
|
|
23
|
+
cursor?: string;
|
|
24
|
+
limit?: number;
|
|
25
|
+
}): Promise<RecordingListResponse>;
|
|
26
|
+
/** 活跃录制清单(sidepanel"正在录制"区块数据源) */
|
|
27
|
+
active(): Promise<ActiveRecordingInfo[]>;
|
|
28
|
+
/** 开始录制当前 tab(tabId+url 必传;同 tab 重复 → 409 tab_already_recording) */
|
|
29
|
+
start(input: {
|
|
30
|
+
tabId: number;
|
|
31
|
+
url: string;
|
|
32
|
+
title?: string;
|
|
33
|
+
}): Promise<StartRecordingResult>;
|
|
34
|
+
/** 停止录制;零事件 → 422 recording_no_events(服务端标记 failed) */
|
|
35
|
+
stop(sessionId: string): Promise<{
|
|
36
|
+
sessionId: string;
|
|
37
|
+
}>;
|
|
38
|
+
/** 批量删除;active 项被拒删,由响应分流 */
|
|
39
|
+
batchDelete(ids: string[]): Promise<BatchDeleteResponse>;
|
|
40
|
+
/** 录制事件(rrweb + 网络 + 控制台 + 异常) */
|
|
41
|
+
events(sessionId: string): Promise<RecordingEvents>;
|
|
42
|
+
/** 单条元数据 */
|
|
43
|
+
meta(sessionId: string): Promise<RecordingMeta>;
|
|
44
|
+
/** FID-133 iter6 P3:CPU profile sidecar 懒加载;无 sidecar 返回 null(不抛) */
|
|
45
|
+
cpuProfile(sessionId: string): Promise<CpuProfile | null>;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,UAAU,EACV,eAAe,EACf,qBAAqB,EACrB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAM3D;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,MAAM;YAE9B,OAAO;IAuBrB,kDAAkD;IAClD,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC;IASjG,mCAAmC;IAC7B,MAAM,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAK9C,oEAAoE;IACpE,KAAK,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAO3F,uDAAuD;IACvD,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAOvD,6BAA6B;IAC7B,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAOxD,kCAAkC;IAClC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAInD,YAAY;IACZ,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAI/C,qEAAqE;IAC/D,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;CAahE"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export class RecordingApiError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
status;
|
|
4
|
+
constructor(status, code, message) {
|
|
5
|
+
super(message || code);
|
|
6
|
+
this.name = "RecordingApiError";
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.code = code;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class RecordingApi {
|
|
12
|
+
baseUrl;
|
|
13
|
+
constructor(baseUrl) {
|
|
14
|
+
this.baseUrl = baseUrl;
|
|
15
|
+
}
|
|
16
|
+
async request(path, init) {
|
|
17
|
+
let res;
|
|
18
|
+
try {
|
|
19
|
+
res = await fetch(`${this.baseUrl}${path}`, {
|
|
20
|
+
headers: { "Content-Type": "application/json" },
|
|
21
|
+
...init,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
throw new RecordingApiError(0, "network_error", "network_error");
|
|
26
|
+
}
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
let code = `http_${res.status}`;
|
|
29
|
+
try {
|
|
30
|
+
const body = (await res.json());
|
|
31
|
+
if (typeof body.error === "string")
|
|
32
|
+
code = body.error;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// 保留 http_<status> 兜底
|
|
36
|
+
}
|
|
37
|
+
throw new RecordingApiError(res.status, code);
|
|
38
|
+
}
|
|
39
|
+
return (await res.json());
|
|
40
|
+
}
|
|
41
|
+
/** 历史录制;urlKey 过滤 + cursor 滚动分页(不传 = 全量,兼容旧调用) */
|
|
42
|
+
list(opts) {
|
|
43
|
+
const params = new URLSearchParams();
|
|
44
|
+
if (opts?.urlKey)
|
|
45
|
+
params.set("urlKey", opts.urlKey);
|
|
46
|
+
if (opts?.cursor)
|
|
47
|
+
params.set("cursor", opts.cursor);
|
|
48
|
+
if (opts?.limit)
|
|
49
|
+
params.set("limit", String(opts.limit));
|
|
50
|
+
const qs = params.toString();
|
|
51
|
+
return this.request(`/recordings${qs ? `?${qs}` : ""}`);
|
|
52
|
+
}
|
|
53
|
+
/** 活跃录制清单(sidepanel"正在录制"区块数据源) */
|
|
54
|
+
async active() {
|
|
55
|
+
const data = await this.request("/recordings/active");
|
|
56
|
+
return data.recordings ?? [];
|
|
57
|
+
}
|
|
58
|
+
/** 开始录制当前 tab(tabId+url 必传;同 tab 重复 → 409 tab_already_recording) */
|
|
59
|
+
start(input) {
|
|
60
|
+
return this.request("/recordings/start", {
|
|
61
|
+
method: "POST",
|
|
62
|
+
body: JSON.stringify({ tabId: input.tabId, url: input.url, title: input.title ?? "" }),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/** 停止录制;零事件 → 422 recording_no_events(服务端标记 failed) */
|
|
66
|
+
stop(sessionId) {
|
|
67
|
+
return this.request("/recordings/stop", {
|
|
68
|
+
method: "POST",
|
|
69
|
+
body: JSON.stringify({ sessionId }),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/** 批量删除;active 项被拒删,由响应分流 */
|
|
73
|
+
batchDelete(ids) {
|
|
74
|
+
return this.request("/recordings/batch-delete", {
|
|
75
|
+
method: "POST",
|
|
76
|
+
body: JSON.stringify({ ids }),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/** 录制事件(rrweb + 网络 + 控制台 + 异常) */
|
|
80
|
+
events(sessionId) {
|
|
81
|
+
return this.request(`/recordings/${encodeURIComponent(sessionId)}/events`);
|
|
82
|
+
}
|
|
83
|
+
/** 单条元数据 */
|
|
84
|
+
meta(sessionId) {
|
|
85
|
+
return this.request(`/recordings/${encodeURIComponent(sessionId)}`);
|
|
86
|
+
}
|
|
87
|
+
/** FID-133 iter6 P3:CPU profile sidecar 懒加载;无 sidecar 返回 null(不抛) */
|
|
88
|
+
async cpuProfile(sessionId) {
|
|
89
|
+
try {
|
|
90
|
+
const data = await this.request(`/recordings/${encodeURIComponent(sessionId)}/cpu-profile`);
|
|
91
|
+
return data.profile ?? null;
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
if (e instanceof RecordingApiError && (e.code === "no_cpu_profile" || e.status === 404)) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
throw e;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.test.d.ts","sourceRoot":"","sources":["../src/api.test.ts"],"names":[],"mappings":""}
|
package/dist/api.test.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { RecordingApi, RecordingApiError } from "./api.js";
|
|
3
|
+
function mockFetchOnce(status, body) {
|
|
4
|
+
vi.stubGlobal("fetch", vi.fn().mockResolvedValueOnce({
|
|
5
|
+
ok: status >= 200 && status < 300,
|
|
6
|
+
status,
|
|
7
|
+
json: async () => body,
|
|
8
|
+
}));
|
|
9
|
+
}
|
|
10
|
+
describe("RecordingApi(FID-133)", () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
vi.unstubAllGlobals();
|
|
13
|
+
});
|
|
14
|
+
it("list 拼装 urlKey/cursor/limit 查询串", async () => {
|
|
15
|
+
const fetchMock = vi.fn().mockResolvedValue({
|
|
16
|
+
ok: true,
|
|
17
|
+
status: 200,
|
|
18
|
+
json: async () => ({ recordings: [], nextCursor: null }),
|
|
19
|
+
});
|
|
20
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
21
|
+
const api = new RecordingApi("http://localhost:34568/api");
|
|
22
|
+
await api.list({ urlKey: "https://a.com/x", cursor: "abc_1", limit: 20 });
|
|
23
|
+
const url = fetchMock.mock.calls[0][0];
|
|
24
|
+
expect(url).toContain("/recordings?");
|
|
25
|
+
expect(url).toContain("urlKey=https%3A%2F%2Fa.com%2Fx");
|
|
26
|
+
expect(url).toContain("cursor=abc_1");
|
|
27
|
+
expect(url).toContain("limit=20");
|
|
28
|
+
});
|
|
29
|
+
it("active 解包 recordings 数组", async () => {
|
|
30
|
+
mockFetchOnce(200, { recordings: [{ sessionId: "rec-1", tabId: 7 }] });
|
|
31
|
+
const api = new RecordingApi("/api");
|
|
32
|
+
const list = await api.active();
|
|
33
|
+
expect(list).toHaveLength(1);
|
|
34
|
+
expect(list[0]).toMatchObject({ sessionId: "rec-1", tabId: 7 });
|
|
35
|
+
});
|
|
36
|
+
it("start 透传 tabId/url/title", async () => {
|
|
37
|
+
const fetchMock = vi.fn().mockResolvedValue({
|
|
38
|
+
ok: true,
|
|
39
|
+
status: 200,
|
|
40
|
+
json: async () => ({ sessionId: "rec-new", tabId: 7 }),
|
|
41
|
+
});
|
|
42
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
43
|
+
const api = new RecordingApi("/api");
|
|
44
|
+
const res = await api.start({ tabId: 7, url: "https://a.com/x", title: "页面A" });
|
|
45
|
+
expect(res.sessionId).toBe("rec-new");
|
|
46
|
+
const init = fetchMock.mock.calls[0][1];
|
|
47
|
+
expect(JSON.parse(init.body)).toMatchObject({ tabId: 7, url: "https://a.com/x", title: "页面A" });
|
|
48
|
+
});
|
|
49
|
+
it("非 2xx 抛 RecordingApiError 并携带 server error code", async () => {
|
|
50
|
+
mockFetchOnce(409, { error: "tab_already_recording", sessionId: "rec-x" });
|
|
51
|
+
const api = new RecordingApi("/api");
|
|
52
|
+
await expect(api.start({ tabId: 7, url: "https://a.com" })).rejects.toMatchObject({
|
|
53
|
+
name: "RecordingApiError",
|
|
54
|
+
status: 409,
|
|
55
|
+
code: "tab_already_recording",
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
it("网络失败抛 network_error", async () => {
|
|
59
|
+
vi.stubGlobal("fetch", vi.fn().mockRejectedValue(new Error("conn refused")));
|
|
60
|
+
const api = new RecordingApi("/api");
|
|
61
|
+
await expect(api.active()).rejects.toMatchObject({ code: "network_error" });
|
|
62
|
+
});
|
|
63
|
+
it("非 JSON 错误体回退 http_<status>", async () => {
|
|
64
|
+
vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
|
|
65
|
+
ok: false,
|
|
66
|
+
status: 503,
|
|
67
|
+
json: async () => { throw new Error("not json"); },
|
|
68
|
+
}));
|
|
69
|
+
const api = new RecordingApi("/api");
|
|
70
|
+
try {
|
|
71
|
+
await api.active();
|
|
72
|
+
expect.unreachable();
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
expect(e).toBeInstanceOf(RecordingApiError);
|
|
76
|
+
expect(e.code).toBe("http_503");
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
it("batchDelete 透传 ids", async () => {
|
|
80
|
+
mockFetchOnce(200, { ok: true, deleted: ["a"], missing: [], active: [], deletedCount: 1 });
|
|
81
|
+
const fetchMock = vi.mocked(fetch);
|
|
82
|
+
const api = new RecordingApi("/api");
|
|
83
|
+
const res = await api.batchDelete(["a", "b"]);
|
|
84
|
+
expect(res.deleted).toEqual(["a"]);
|
|
85
|
+
const init = fetchMock.mock.calls[0][1];
|
|
86
|
+
expect(JSON.parse(init.body)).toEqual({ ids: ["a", "b"] });
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=api.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.test.js","sourceRoot":"","sources":["../src/api.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FID-133:批量删除内联确认条(方案检裁决:窄面板不用弹窗,内联常驻可取消)。
|
|
3
|
+
*/
|
|
4
|
+
export interface BatchDeleteBarProps {
|
|
5
|
+
count: number;
|
|
6
|
+
busy?: boolean;
|
|
7
|
+
/** 额外不可删数(选中项里含录制中,已由服务端拒绝) */
|
|
8
|
+
skippedActive?: number;
|
|
9
|
+
onCancel: () => void;
|
|
10
|
+
onConfirm: () => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function BatchDeleteBar({ count, busy, skippedActive, onCancel, onConfirm }: BatchDeleteBarProps): import("react").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=BatchDeleteBar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BatchDeleteBar.d.ts","sourceRoot":"","sources":["../../src/components/BatchDeleteBar.tsx"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,+BAA+B;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,IAAY,EAAE,aAAiB,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,mBAAmB,+BAiClH"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export function BatchDeleteBar({ count, busy = false, skippedActive = 0, onCancel, onConfirm }) {
|
|
3
|
+
return (_jsxs("div", { style: {
|
|
4
|
+
display: "flex",
|
|
5
|
+
alignItems: "center",
|
|
6
|
+
gap: 8,
|
|
7
|
+
padding: "6px 8px",
|
|
8
|
+
borderRadius: 6,
|
|
9
|
+
background: "#fff7ed",
|
|
10
|
+
border: "1px solid #fed7aa",
|
|
11
|
+
}, children: [_jsxs("span", { style: { flex: 1, fontSize: 11, color: "#9a3412", minWidth: 0 }, children: ["\u5DF2\u9009 ", count, " \u6761\u5F55\u5236\uFF0C\u5220\u9664\u540E\u65E0\u6CD5\u6062\u590D", skippedActive > 0 ? `(其中 ${skippedActive} 条录制中,将被跳过)` : ""] }), _jsx("button", { onClick: onCancel, disabled: busy, style: { flexShrink: 0, fontSize: 11, padding: "3px 8px", borderRadius: 4, border: "1px solid #d1d5db", background: "#fff", color: "#374151", cursor: "pointer" }, children: "\u53D6\u6D88" }), _jsx("button", { onClick: onConfirm, disabled: busy, style: { flexShrink: 0, fontSize: 11, padding: "3px 8px", borderRadius: 4, border: "none", background: busy ? "#fca5a5" : "#ea580c", color: "#fff", cursor: busy ? "wait" : "pointer" }, children: busy ? "删除中…" : "确认删除" })] }));
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=BatchDeleteBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BatchDeleteBar.js","sourceRoot":"","sources":["../../src/components/BatchDeleteBar.tsx"],"names":[],"mappings":";AAYA,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,GAAG,KAAK,EAAE,aAAa,GAAG,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAuB;IACjH,OAAO,CACL,eACE,KAAK,EAAE;YACL,OAAO,EAAE,MAAM;YACf,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,CAAC;YACN,OAAO,EAAE,SAAS;YAClB,YAAY,EAAE,CAAC;YACf,UAAU,EAAE,SAAS;YACrB,MAAM,EAAE,mBAAmB;SAC5B,aAED,gBAAM,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAAE,8BAC/D,KAAK,yEACR,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,aAAa,aAAa,CAAC,CAAC,CAAC,EAAE,IACtD,EACP,iBACE,OAAO,EAAE,QAAQ,EACjB,QAAQ,EAAE,IAAI,EACd,KAAK,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,6BAG1J,EACT,iBACE,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,IAAI,EACd,KAAK,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,YAEtL,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,GAChB,IACL,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TimelineEventItem } from "../types.js";
|
|
2
|
+
export type EventStreamTab = "network" | "console" | "exceptions";
|
|
3
|
+
export interface EventStreamPanelProps {
|
|
4
|
+
network: TimelineEventItem[];
|
|
5
|
+
console: TimelineEventItem[];
|
|
6
|
+
exceptions: TimelineEventItem[];
|
|
7
|
+
/** 首个 rrweb 事件 timestamp(偏移基准);null 时联动禁用 */
|
|
8
|
+
baseTimestamp: number | null;
|
|
9
|
+
/** 播放器当前偏移 ms(调用方轮询 getCurrentTime 传入) */
|
|
10
|
+
currentOffsetMs: number | null;
|
|
11
|
+
/** 点击事件行 → seek 播放器 */
|
|
12
|
+
onSeek: (offsetMs: number) => void;
|
|
13
|
+
height?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function EventStreamPanel({ network, console: consoleEvents, exceptions, baseTimestamp, currentOffsetMs, onSeek, height, }: EventStreamPanelProps): import("react").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=EventStreamPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventStreamPanel.d.ts","sourceRoot":"","sources":["../../src/components/EventStreamPanel.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,6CAA6C;IAC7C,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,0CAA0C;IAC1C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,uBAAuB;IACvB,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAoCD,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,OAAO,EAAE,aAAa,EACtB,UAAU,EACV,aAAa,EACb,eAAe,EACf,MAAM,EACN,MAAY,GACb,EAAE,qBAAqB,+BAiHvB"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* FID-133:事件流面板——网络请求 / 控制台 / 异常(JS 栈)三页签,
|
|
4
|
+
* 与回放播放器时间轴联动:播放进度高亮"当前事件"(最后一个已越过的),
|
|
5
|
+
* 点击事件行 seek 播放器到对应时间点。
|
|
6
|
+
*
|
|
7
|
+
* 时间口径:事件 timestamp 是 epoch ms;播放器 getCurrentTime 是回放偏移 ms。
|
|
8
|
+
* 换算基准 = 首个 rrweb 事件 timestamp(调用方传入 baseTimestamp)。
|
|
9
|
+
*/
|
|
10
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
11
|
+
function formatClock(ts) {
|
|
12
|
+
const d = new Date(ts);
|
|
13
|
+
const pad = (n, l = 2) => n.toString().padStart(l, "0");
|
|
14
|
+
return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${pad(d.getMilliseconds(), 3)}`;
|
|
15
|
+
}
|
|
16
|
+
function rowText(kind, ev) {
|
|
17
|
+
const p = ev.payload;
|
|
18
|
+
if (kind === "network") {
|
|
19
|
+
const status = p.status;
|
|
20
|
+
return {
|
|
21
|
+
main: `${p.method || "GET"} ${p.url || ""}`,
|
|
22
|
+
sub: p.phase === "request" ? "请求发出" : p.phase === "response" ? "响应返回" : undefined,
|
|
23
|
+
badge: status != null ? String(status) : p.phase,
|
|
24
|
+
badgeColor: status != null ? (status >= 400 ? "#ef4444" : status >= 300 ? "#f59e0b" : "#22c55e") : "#9ca3af",
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (kind === "console") {
|
|
28
|
+
const level = p.level || "log";
|
|
29
|
+
return {
|
|
30
|
+
main: p.message || (p.args ?? []).map((a) => (typeof a === "string" ? a : JSON.stringify(a))).join(" "),
|
|
31
|
+
sub: p.stack ? p.stack.split("\n").slice(0, 2).join(" ") : undefined,
|
|
32
|
+
badge: level,
|
|
33
|
+
badgeColor: level === "error" ? "#ef4444" : level === "warn" ? "#f59e0b" : "#3b82f6",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
main: p.message || "(未知异常)",
|
|
38
|
+
sub: p.stack ? p.stack.split("\n").slice(0, 2).join(" ") : undefined,
|
|
39
|
+
badge: "异常",
|
|
40
|
+
badgeColor: "#ef4444",
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function EventStreamPanel({ network, console: consoleEvents, exceptions, baseTimestamp, currentOffsetMs, onSeek, height = 260, }) {
|
|
44
|
+
const [tab, setTab] = useState("network");
|
|
45
|
+
const listRef = useRef(null);
|
|
46
|
+
const tabs = [
|
|
47
|
+
{ key: "network", label: "网络请求", items: network },
|
|
48
|
+
{ key: "console", label: "控制台", items: consoleEvents },
|
|
49
|
+
{ key: "exceptions", label: "异常", items: exceptions },
|
|
50
|
+
];
|
|
51
|
+
const active = tabs.find((t) => t.key === tab);
|
|
52
|
+
// 当前高亮:偏移 <= 当前播放偏移的最后一个事件
|
|
53
|
+
const highlightedIdx = useMemo(() => {
|
|
54
|
+
if (baseTimestamp == null || currentOffsetMs == null)
|
|
55
|
+
return -1;
|
|
56
|
+
const nowTs = baseTimestamp + currentOffsetMs;
|
|
57
|
+
let best = -1;
|
|
58
|
+
for (let i = 0; i < active.items.length; i++) {
|
|
59
|
+
if (active.items[i].timestamp <= nowTs)
|
|
60
|
+
best = i;
|
|
61
|
+
else
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
return best;
|
|
65
|
+
}, [active.items, baseTimestamp, currentOffsetMs]);
|
|
66
|
+
// 高亮行自动滚入可视区
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (highlightedIdx < 0 || !listRef.current)
|
|
69
|
+
return;
|
|
70
|
+
const el = listRef.current.children[highlightedIdx];
|
|
71
|
+
el?.scrollIntoView?.({ block: "nearest" });
|
|
72
|
+
}, [highlightedIdx]);
|
|
73
|
+
return (_jsxs("div", { style: { border: "1px solid #e5e7eb", borderRadius: 6, background: "#fff" }, children: [_jsx("div", { style: { display: "flex", gap: 4, padding: "6px 8px 0", borderBottom: "1px solid #f3f4f6" }, children: tabs.map((t) => (_jsxs("button", { onClick: () => setTab(t.key), style: {
|
|
74
|
+
fontSize: 12,
|
|
75
|
+
padding: "4px 8px",
|
|
76
|
+
border: "none",
|
|
77
|
+
borderBottom: tab === t.key ? "2px solid #2563eb" : "2px solid transparent",
|
|
78
|
+
background: "transparent",
|
|
79
|
+
color: tab === t.key ? "#2563eb" : "#6b7280",
|
|
80
|
+
cursor: "pointer",
|
|
81
|
+
fontWeight: tab === t.key ? 600 : 400,
|
|
82
|
+
}, children: [t.label, " (", t.items.length, ")"] }, t.key))) }), _jsx("div", { ref: listRef, style: { height, overflowY: "auto", padding: "4px 0" }, children: active.items.length === 0 ? (_jsxs("div", { style: { padding: "20px 0", textAlign: "center", fontSize: 12, color: "#9ca3af" }, children: ["\u672C\u6B21\u5F55\u5236\u6CA1\u6709\u6355\u6349\u5230", active.label] })) : (active.items.map((ev, idx) => {
|
|
83
|
+
const { main, sub, badge, badgeColor } = rowText(tab, ev);
|
|
84
|
+
const highlighted = idx === highlightedIdx;
|
|
85
|
+
const offsetMs = baseTimestamp != null ? ev.timestamp - baseTimestamp : null;
|
|
86
|
+
return (_jsxs("div", { onClick: () => offsetMs != null && offsetMs >= 0 && onSeek(offsetMs), title: offsetMs != null ? "点击跳转到此时间点" : undefined, style: {
|
|
87
|
+
display: "flex",
|
|
88
|
+
alignItems: "flex-start",
|
|
89
|
+
gap: 8,
|
|
90
|
+
padding: "4px 10px",
|
|
91
|
+
fontSize: 12,
|
|
92
|
+
background: highlighted ? "#dbeafe" : idx % 2 === 0 ? "#fafafa" : "#fff",
|
|
93
|
+
cursor: offsetMs != null ? "pointer" : "default",
|
|
94
|
+
borderLeft: highlighted ? "3px solid #2563eb" : "3px solid transparent",
|
|
95
|
+
}, children: [_jsx("span", { style: { fontFamily: "monospace", fontSize: 11, color: "#9ca3af", flexShrink: 0 }, children: formatClock(ev.timestamp) }), _jsx("span", { style: {
|
|
96
|
+
fontSize: 10,
|
|
97
|
+
padding: "1px 5px",
|
|
98
|
+
borderRadius: 4,
|
|
99
|
+
color: "#fff",
|
|
100
|
+
background: badgeColor ?? "#9ca3af",
|
|
101
|
+
flexShrink: 0,
|
|
102
|
+
marginTop: 1,
|
|
103
|
+
}, children: badge ?? "-" }), _jsxs("span", { style: { flex: 1, minWidth: 0 }, children: [_jsx("span", { style: { display: "block", color: "#111827", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontFamily: tab === "console" || tab === "exceptions" ? "monospace" : undefined }, children: main }), sub && (_jsx("span", { style: { display: "block", color: "#9ca3af", fontSize: 10, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontFamily: "monospace" }, children: sub }))] })] }, `${ev.timestamp}-${idx}`));
|
|
104
|
+
})) })] }));
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=EventStreamPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventStreamPanel.js","sourceRoot":"","sources":["../../src/components/EventStreamPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ActiveRecordingInfo } from "../types.js";
|
|
2
|
+
export interface RecordingTabInfo {
|
|
3
|
+
title?: string;
|
|
4
|
+
url?: string;
|
|
5
|
+
groupColor?: string;
|
|
6
|
+
groupTitle?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface OtherRecordingTabsProps {
|
|
9
|
+
recordings: ActiveRecordingInfo[];
|
|
10
|
+
currentTabId: number;
|
|
11
|
+
/** tabId → 面板 Tabs 列表里的展示信息(标题/组色),缺省退化 URL 显示 */
|
|
12
|
+
tabInfo?: Map<number, RecordingTabInfo>;
|
|
13
|
+
/** 点击「跳转」→ 激活对应 tab(chrome.tabs 由消费方实现) */
|
|
14
|
+
onJump?: (tabId: number) => void;
|
|
15
|
+
/** 两步确认后的真正停止;不传则不渲染停止按钮 */
|
|
16
|
+
onStop?: (sessionId: string) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare function OtherRecordingTabs({ recordings, currentTabId, tabInfo, onJump, onStop }: OtherRecordingTabsProps): import("react").JSX.Element | null;
|
|
19
|
+
//# sourceMappingURL=OtherRecordingTabs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OtherRecordingTabs.d.ts","sourceRoot":"","sources":["../../src/components/OtherRecordingTabs.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAIvD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAyBD,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACxC,2CAA2C;IAC3C,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,4BAA4B;IAC5B,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAiCD,wBAAgB,kBAAkB,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,uBAAuB,sCA2DhH"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* FID-133 iter6:"其他标签页也在录制"区块可辨识化改造(用户裁定 P1)。
|
|
4
|
+
* 同标题 tab 无法区分 → 每条必须显示 tabId 徽标 + 完整 title;
|
|
5
|
+
* 提供「跳转」聚焦对应 tab、「停止」两步内联确认(3s 自动复位)。
|
|
6
|
+
* onJump/onStop 为可选回调:不传则对应按钮不渲染(只读消费方如 hmh 向后兼容)。
|
|
7
|
+
*/
|
|
8
|
+
import { useEffect, useState } from "react";
|
|
9
|
+
import { useNow } from "../hooks.js";
|
|
10
|
+
import { formatDuration } from "../format.js";
|
|
11
|
+
const COLOR_MAP = {
|
|
12
|
+
grey: "#9ca3af",
|
|
13
|
+
blue: "#60a5fa",
|
|
14
|
+
red: "#f87171",
|
|
15
|
+
yellow: "#facc15",
|
|
16
|
+
green: "#4ade80",
|
|
17
|
+
pink: "#f472b6",
|
|
18
|
+
purple: "#c084fc",
|
|
19
|
+
cyan: "#22d3ee",
|
|
20
|
+
orange: "#fb923c",
|
|
21
|
+
};
|
|
22
|
+
const BTN_STYLE = {
|
|
23
|
+
fontSize: 10,
|
|
24
|
+
padding: "1px 6px",
|
|
25
|
+
borderRadius: 4,
|
|
26
|
+
border: "1px solid #d1d5db",
|
|
27
|
+
background: "#fff",
|
|
28
|
+
color: "#374151",
|
|
29
|
+
cursor: "pointer",
|
|
30
|
+
flexShrink: 0,
|
|
31
|
+
};
|
|
32
|
+
/** 两步确认按钮:首次点击变「确认?」,3s 内再点才真正执行,超时自动复位 */
|
|
33
|
+
function ConfirmStopButton({ onConfirm }) {
|
|
34
|
+
const [arming, setArming] = useState(false);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!arming)
|
|
37
|
+
return undefined;
|
|
38
|
+
const t = setTimeout(() => setArming(false), 3000);
|
|
39
|
+
return () => clearTimeout(t);
|
|
40
|
+
}, [arming]);
|
|
41
|
+
return (_jsx("button", { onClick: (e) => {
|
|
42
|
+
e.stopPropagation();
|
|
43
|
+
if (arming) {
|
|
44
|
+
setArming(false);
|
|
45
|
+
onConfirm();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
setArming(true);
|
|
49
|
+
}
|
|
50
|
+
}, style: {
|
|
51
|
+
...BTN_STYLE,
|
|
52
|
+
...(arming
|
|
53
|
+
? { background: "#fef2f2", borderColor: "#ef4444", color: "#b91c1c", fontWeight: 600 }
|
|
54
|
+
: {}),
|
|
55
|
+
}, children: arming ? "确认停止?" : "停止" }));
|
|
56
|
+
}
|
|
57
|
+
export function OtherRecordingTabs({ recordings, currentTabId, tabInfo, onJump, onStop }) {
|
|
58
|
+
const now = useNow(1000);
|
|
59
|
+
const others = recordings.filter((r) => r.tabId !== currentTabId);
|
|
60
|
+
if (others.length === 0)
|
|
61
|
+
return null;
|
|
62
|
+
return (_jsxs("div", { style: { borderRadius: 6, border: "1px solid #fde68a", background: "#fffbeb", padding: "6px 8px" }, children: [_jsxs("div", { style: { fontSize: 11, fontWeight: 600, color: "#92400e", marginBottom: 4 }, children: ["\u5176\u4ED6\u6807\u7B7E\u9875\u4E5F\u5728\u5F55\u5236 (", others.length, ")"] }), _jsx("ul", { style: { margin: 0, padding: 0, listStyle: "none" }, children: others.map((r) => {
|
|
63
|
+
const info = r.tabId != null ? tabInfo?.get(r.tabId) : undefined;
|
|
64
|
+
const label = info?.title || r.title || r.url || "未知页面";
|
|
65
|
+
const color = COLOR_MAP[info?.groupColor ?? ""] ?? "#9ca3af";
|
|
66
|
+
const elapsed = formatDuration(Math.max(0, now - r.startTime));
|
|
67
|
+
const jumpable = r.tabId != null && onJump;
|
|
68
|
+
return (_jsxs("li", { style: { display: "flex", alignItems: "center", gap: 6, padding: "3px 0", minWidth: 0 }, children: [_jsx("span", { style: { width: 7, height: 7, borderRadius: "50%", background: color, flexShrink: 0 } }), _jsxs("span", { style: {
|
|
69
|
+
fontSize: 10,
|
|
70
|
+
fontFamily: "monospace",
|
|
71
|
+
padding: "0 4px",
|
|
72
|
+
borderRadius: 3,
|
|
73
|
+
background: "#fef3c7",
|
|
74
|
+
color: "#92400e",
|
|
75
|
+
flexShrink: 0,
|
|
76
|
+
}, title: "\u6807\u7B7E\u9875 ID", children: ["tab ", r.tabId ?? "?"] }), _jsx("span", { style: { fontSize: 11, color: "#374151", flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, title: label, children: label }), _jsxs("span", { style: { fontSize: 10, color: "#b45309", flexShrink: 0 }, children: ["\u5DF2\u5F55 ", elapsed] }), jumpable && (_jsx("button", { onClick: (e) => {
|
|
77
|
+
e.stopPropagation();
|
|
78
|
+
onJump(r.tabId);
|
|
79
|
+
}, style: BTN_STYLE, children: "\u8DF3\u8F6C" })), onStop && _jsx(ConfirmStopButton, { onConfirm: () => onStop(r.sessionId) })] }, r.sessionId));
|
|
80
|
+
}) })] }));
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=OtherRecordingTabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OtherRecordingTabs.js","sourceRoot":"","sources":["../../src/components/OtherRecordingTabs.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RecordingApi } from "../api.js";
|
|
2
|
+
import type { ActiveRecordingInfo } from "../types.js";
|
|
3
|
+
/** server 错误码 → 用户文案(方案检文案终稿) */
|
|
4
|
+
export declare function recordingErrorText(e: unknown): string;
|
|
5
|
+
export interface RecordingControlsProps {
|
|
6
|
+
api: RecordingApi;
|
|
7
|
+
tabId: number;
|
|
8
|
+
tabUrl: string;
|
|
9
|
+
tabTitle: string;
|
|
10
|
+
/** server 活跃录制清单(含其他 agent 的);本 tab 那条即"正在录制"状态 */
|
|
11
|
+
activeRecordings: ActiveRecordingInfo[];
|
|
12
|
+
onChanged?: () => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function RecordingControls({ api, tabId, tabUrl, tabTitle, activeRecordings, onChanged, }: RecordingControlsProps): import("react").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=RecordingControls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RecordingControls.d.ts","sourceRoot":"","sources":["../../src/components/RecordingControls.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAIvD,iCAAiC;AACjC,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAiBrD;AAED,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,YAAY,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,gBAAgB,EAAE,mBAAmB,EAAE,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,KAAK,EACL,MAAM,EACN,QAAQ,EACR,gBAAgB,EAChB,SAAS,GACV,EAAE,sBAAsB,+BAsGxB"}
|