@composy/log-viewer-core 0.0.1 → 0.0.2
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/CHANGELOG.md +52 -0
- package/README.md +175 -37
- package/dist/index.js +614 -299
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +548 -1
- package/dist/index.min.js.map +1 -0
- package/es/.dts-output-manifest.json +1 -0
- package/es/.dts.tsbuildinfo +1 -0
- package/es/core/EventEmitter.d.ts +0 -1
- package/es/core/EventEmitter.js +13 -9
- package/es/core/EventEmitter.js.map +1 -1
- package/es/core/LogViewer.d.ts +14 -11
- package/es/core/LogViewer.js +243 -64
- package/es/core/LogViewer.js.map +1 -1
- package/es/filters/FilterEngine.d.ts +0 -1
- package/es/filters/FilterEngine.js +31 -26
- package/es/filters/FilterEngine.js.map +1 -1
- package/es/index.d.ts +7 -7
- package/es/index.js +3 -3
- package/es/index.js.map +1 -1
- package/es/renderers/DiffRenderer.d.ts +0 -1
- package/es/renderers/DiffRenderer.js +13 -3
- package/es/renderers/DiffRenderer.js.map +1 -1
- package/es/renderers/TimelineRenderer.d.ts +7 -3
- package/es/renderers/TimelineRenderer.js +56 -22
- package/es/renderers/TimelineRenderer.js.map +1 -1
- package/es/styles/index.d.ts +1 -5
- package/es/styles/index.js +167 -131
- package/es/styles/index.js.map +1 -1
- package/es/types/index.d.ts +4 -1
- package/es/types/index.js +1 -1
- package/es/types/index.js.map +1 -1
- package/es/utils/index.d.ts +1 -2
- package/es/utils/index.js +54 -6
- package/es/utils/index.js.map +1 -1
- package/esm/core/EventEmitter.js +13 -9
- package/esm/core/EventEmitter.js.map +1 -1
- package/esm/core/LogViewer.js +243 -64
- package/esm/core/LogViewer.js.map +1 -1
- package/esm/filters/FilterEngine.js +31 -26
- package/esm/filters/FilterEngine.js.map +1 -1
- package/esm/index.js +2 -2
- package/esm/index.js.map +1 -1
- package/esm/renderers/DiffRenderer.js +13 -3
- package/esm/renderers/DiffRenderer.js.map +1 -1
- package/esm/renderers/TimelineRenderer.js +56 -22
- package/esm/renderers/TimelineRenderer.js.map +1 -1
- package/esm/styles/index.js +167 -131
- package/esm/styles/index.js.map +1 -1
- package/esm/types/index.js +1 -1
- package/esm/types/index.js.map +1 -1
- package/esm/utils/index.js +54 -6
- package/esm/utils/index.js.map +1 -1
- package/lib/core/EventEmitter.cjs +13 -9
- package/lib/core/EventEmitter.cjs.map +1 -1
- package/{esm/core/EventEmitter.d.ts → lib/core/EventEmitter.d.cts} +0 -1
- package/lib/core/LogViewer.cjs +247 -68
- package/lib/core/LogViewer.cjs.map +1 -1
- package/{esm/core/LogViewer.d.ts → lib/core/LogViewer.d.cts} +14 -11
- package/lib/filters/FilterEngine.cjs +31 -26
- package/lib/filters/FilterEngine.cjs.map +1 -1
- package/lib/filters/{FilterEngine.d.ts → FilterEngine.d.cts} +0 -1
- package/lib/index.cjs +3 -3
- package/lib/index.cjs.map +1 -1
- package/{esm/index.d.ts → lib/index.d.cts} +7 -7
- package/lib/renderers/DiffRenderer.cjs +13 -3
- package/lib/renderers/DiffRenderer.cjs.map +1 -1
- package/lib/renderers/{DiffRenderer.d.ts → DiffRenderer.d.cts} +0 -1
- package/lib/renderers/TimelineRenderer.cjs +55 -21
- package/lib/renderers/TimelineRenderer.cjs.map +1 -1
- package/lib/renderers/{TimelineRenderer.d.ts → TimelineRenderer.d.cts} +7 -3
- package/lib/styles/index.cjs +167 -131
- package/lib/styles/index.cjs.map +1 -1
- package/{esm/styles/index.d.ts → lib/styles/index.d.cts} +1 -5
- package/lib/types/index.cjs +1 -1
- package/lib/types/index.cjs.map +1 -1
- package/{esm/types/index.d.ts → lib/types/index.d.cts} +4 -1
- package/lib/utils/index.cjs +54 -6
- package/lib/utils/index.cjs.map +1 -1
- package/{esm/utils/index.d.ts → lib/utils/index.d.cts} +1 -2
- package/package.json +15 -9
- package/es/core/EventEmitter.d.ts.map +0 -1
- package/es/core/LogViewer.d.ts.map +0 -1
- package/es/filters/FilterEngine.d.ts.map +0 -1
- package/es/index.d.ts.map +0 -1
- package/es/renderers/DiffRenderer.d.ts.map +0 -1
- package/es/renderers/TimelineRenderer.d.ts.map +0 -1
- package/es/styles/index.d.ts.map +0 -1
- package/es/types/index.d.ts.map +0 -1
- package/es/utils/index.d.ts.map +0 -1
- package/esm/core/EventEmitter.d.ts.map +0 -1
- package/esm/core/LogViewer.d.ts.map +0 -1
- package/esm/filters/FilterEngine.d.ts +0 -26
- package/esm/filters/FilterEngine.d.ts.map +0 -1
- package/esm/index.d.ts.map +0 -1
- package/esm/renderers/DiffRenderer.d.ts +0 -18
- package/esm/renderers/DiffRenderer.d.ts.map +0 -1
- package/esm/renderers/TimelineRenderer.d.ts +0 -22
- package/esm/renderers/TimelineRenderer.d.ts.map +0 -1
- package/esm/styles/index.d.ts.map +0 -1
- package/esm/types/index.d.ts.map +0 -1
- package/esm/utils/index.d.ts.map +0 -1
- package/lib/core/EventEmitter.d.ts +0 -11
- package/lib/core/LogViewer.d.ts +0 -46
- package/lib/index.d.ts +0 -26
- package/lib/styles/index.d.ts +0 -9
- package/lib/types/index.d.ts +0 -113
- package/lib/utils/index.d.ts +0 -18
package/es/index.d.ts
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
* @composy/log-viewer-core
|
|
3
3
|
* 审计日志查看器 - 操作日志可视化与追溯
|
|
4
4
|
*/
|
|
5
|
+
/**
|
|
6
|
+
* 创建 LogViewer 实例 - 工厂函数
|
|
7
|
+
*/
|
|
8
|
+
import type { LogViewerConfig } from './types';
|
|
9
|
+
import { LogViewer } from './core/LogViewer';
|
|
5
10
|
export declare const VERSION = "0.1.0";
|
|
6
11
|
export type { ActionType, ThemeMode, AnomalyType, DiffEntry, LogEntry, FilterConfig, PaginationConfig, LogViewerConfig, LogViewerInstance, LogViewerEvents, } from './types';
|
|
7
12
|
export { ACTION_LABELS, ACTION_COLORS } from './types';
|
|
@@ -9,18 +14,13 @@ export { LogViewer } from './core/LogViewer';
|
|
|
9
14
|
export { EventEmitter } from './core/EventEmitter';
|
|
10
15
|
export { FilterEngine } from './filters/FilterEngine';
|
|
11
16
|
export { TimelineRenderer } from './renderers/TimelineRenderer';
|
|
17
|
+
export type { TimelineRendererOptions } from './renderers/TimelineRenderer';
|
|
12
18
|
export { DiffRenderer } from './renderers/DiffRenderer';
|
|
13
|
-
export { formatDate, formatRelativeTime, escapeHtml, debounce, uid, formatValue, deepClone } from './utils';
|
|
19
|
+
export { formatDate, formatRelativeTime, escapeHtml, debounce, uid, formatValue, deepClone, } from './utils';
|
|
14
20
|
export { injectStyles } from './styles';
|
|
15
|
-
/**
|
|
16
|
-
* 创建 LogViewer 实例 - 工厂函数
|
|
17
|
-
*/
|
|
18
|
-
import type { LogViewerConfig } from './types';
|
|
19
|
-
import { LogViewer } from './core/LogViewer';
|
|
20
21
|
/**
|
|
21
22
|
* createLogViewer - create Log Viewer function
|
|
22
23
|
* @param config - 参数说明
|
|
23
24
|
* @returns 返回值说明
|
|
24
25
|
*/
|
|
25
26
|
export declare function createLogViewer(config: LogViewerConfig): LogViewer;
|
|
26
|
-
//# sourceMappingURL=index.d.ts.map
|
package/es/index.js
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
* ***********************************
|
|
3
3
|
* @composy/log-viewer-core v0.0.1 *
|
|
4
4
|
* Built with rollup *
|
|
5
|
-
* Build time: 2024-
|
|
5
|
+
* Build time: 2024-10-12 17:29:20 *
|
|
6
6
|
* Build mode: production *
|
|
7
7
|
* Minified: No *
|
|
8
8
|
* ***********************************
|
|
9
9
|
*/
|
|
10
10
|
import { EventEmitter } from "./core/EventEmitter.js";
|
|
11
|
-
import { FilterEngine } from "./filters/FilterEngine.js";
|
|
12
11
|
import { ACTION_COLORS, ACTION_LABELS } from "./types/index.js";
|
|
12
|
+
import { FilterEngine } from "./filters/FilterEngine.js";
|
|
13
13
|
import { debounce, deepClone, escapeHtml, formatDate, formatRelativeTime, formatValue, uid } from "./utils/index.js";
|
|
14
|
-
import { TimelineRenderer } from "./renderers/TimelineRenderer.js";
|
|
15
14
|
import { DiffRenderer } from "./renderers/DiffRenderer.js";
|
|
15
|
+
import { TimelineRenderer } from "./renderers/TimelineRenderer.js";
|
|
16
16
|
import { injectStyles } from "./styles/index.js";
|
|
17
17
|
import { LogViewer } from "./core/LogViewer.js";
|
|
18
18
|
//#region src/index.ts
|
package/es/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * @composy/log-viewer-core\r\n * 审计日志查看器 - 操作日志可视化与追溯\r\n */\r\n\r\n/**\r\n * 创建 LogViewer 实例 - 工厂函数\r\n */\r\nimport type { LogViewerConfig } from './types'\r\nimport { LogViewer } from './core/LogViewer'\r\n\r\nexport const VERSION = '0.1.0'\r\n\r\n// 类型\r\nexport type {\r\n ActionType,\r\n ThemeMode,\r\n AnomalyType,\r\n DiffEntry,\r\n LogEntry,\r\n FilterConfig,\r\n PaginationConfig,\r\n LogViewerConfig,\r\n LogViewerInstance,\r\n LogViewerEvents,\r\n} from './types'\r\nexport { ACTION_LABELS, ACTION_COLORS } from './types'\r\n\r\n// 核心\r\nexport { LogViewer } from './core/LogViewer'\r\nexport { EventEmitter } from './core/EventEmitter'\r\n\r\n// 筛选\r\nexport { FilterEngine } from './filters/FilterEngine'\r\n\r\n// 渲染器\r\nexport { TimelineRenderer } from './renderers/TimelineRenderer'\r\nexport type { TimelineRendererOptions } from './renderers/TimelineRenderer'\r\nexport { DiffRenderer } from './renderers/DiffRenderer'\r\n\r\n// 工具\r\nexport {\r\n formatDate,\r\n formatRelativeTime,\r\n escapeHtml,\r\n debounce,\r\n uid,\r\n formatValue,\r\n deepClone,\r\n} from './utils'\r\n\r\n// 样式\r\nexport { injectStyles } from './styles'\r\n\r\n/**\r\n * createLogViewer - create Log Viewer function\r\n * @param config - 参数说明\r\n * @returns 返回值说明\r\n */\r\nexport function createLogViewer(config: LogViewerConfig): LogViewer {\r\n return new LogViewer(config)\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAWO,MAAM,UAAU;AAgDhB,SAAS,gBAAgB,QAAoC;CAClE,OAAO,IAAI,UAAU,MAAM;AAC7B"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ***********************************
|
|
3
3
|
* @composy/log-viewer-core v0.0.1 *
|
|
4
4
|
* Built with rollup *
|
|
5
|
-
* Build time: 2024-
|
|
5
|
+
* Build time: 2024-10-12 17:29:20 *
|
|
6
6
|
* Build mode: production *
|
|
7
7
|
* Minified: No *
|
|
8
8
|
* ***********************************
|
|
@@ -20,7 +20,7 @@ var DiffRenderer = class {
|
|
|
20
20
|
if (entry.metadata && Object.keys(entry.metadata).length > 0) {
|
|
21
21
|
const meta = document.createElement("div");
|
|
22
22
|
meta.className = "lv-metadata";
|
|
23
|
-
meta.textContent =
|
|
23
|
+
meta.textContent = formatValue(entry.metadata);
|
|
24
24
|
container.appendChild(meta);
|
|
25
25
|
}
|
|
26
26
|
return container;
|
|
@@ -32,7 +32,17 @@ var DiffRenderer = class {
|
|
|
32
32
|
const table = document.createElement("table");
|
|
33
33
|
table.className = "lv-diff-table";
|
|
34
34
|
const thead = document.createElement("thead");
|
|
35
|
-
|
|
35
|
+
const headerRow = document.createElement("tr");
|
|
36
|
+
for (const label of [
|
|
37
|
+
"字段",
|
|
38
|
+
"变更前",
|
|
39
|
+
"变更后"
|
|
40
|
+
]) {
|
|
41
|
+
const th = document.createElement("th");
|
|
42
|
+
th.textContent = label;
|
|
43
|
+
headerRow.appendChild(th);
|
|
44
|
+
}
|
|
45
|
+
thead.appendChild(headerRow);
|
|
36
46
|
table.appendChild(thead);
|
|
37
47
|
const tbody = document.createElement("tbody");
|
|
38
48
|
for (const change of changes) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiffRenderer.js","names":[],"sources":["../../src/renderers/DiffRenderer.ts"],"sourcesContent":["/**\n * 变更对比渲染器 - 渲染字段变更前后的 Diff 表格\n */\n\nimport type { DiffEntry, LogEntry } from '../types'\nimport {
|
|
1
|
+
{"version":3,"file":"DiffRenderer.js","names":[],"sources":["../../src/renderers/DiffRenderer.ts"],"sourcesContent":["/**\r\n * 变更对比渲染器 - 渲染字段变更前后的 Diff 表格\r\n */\r\n\r\nimport type { DiffEntry, LogEntry } from '../types'\r\nimport { formatValue } from '../utils'\r\n\r\n/**\r\n * DiffRenderer - Diff Renderer class\r\n */\r\nexport class DiffRenderer {\r\n /**\r\n * 渲染详情面板(包含 diff 表格和 metadata)\r\n */\r\n renderDetail(entry: LogEntry): HTMLElement {\r\n const container = document.createElement('div')\r\n container.className = 'lv-detail'\r\n\r\n if (entry.changes && entry.changes.length > 0) {\r\n container.appendChild(this.renderDiffTable(entry.changes))\r\n }\r\n\r\n if (entry.metadata && Object.keys(entry.metadata).length > 0) {\r\n const meta = document.createElement('div')\r\n meta.className = 'lv-metadata'\r\n meta.textContent = formatValue(entry.metadata)\r\n container.appendChild(meta)\r\n }\r\n\r\n return container\r\n }\r\n\r\n /**\r\n * 渲染 Diff 表格\r\n */\r\n renderDiffTable(changes: DiffEntry[]): HTMLElement {\r\n const table = document.createElement('table')\r\n table.className = 'lv-diff-table'\r\n\r\n // Header\r\n const thead = document.createElement('thead')\r\n const headerRow = document.createElement('tr')\r\n for (const label of ['字段', '变更前', '变更后']) {\r\n const th = document.createElement('th')\r\n th.textContent = label\r\n headerRow.appendChild(th)\r\n }\r\n thead.appendChild(headerRow)\r\n table.appendChild(thead)\r\n\r\n // Body\r\n const tbody = document.createElement('tbody')\r\n for (const change of changes) {\r\n const tr = document.createElement('tr')\r\n\r\n const tdField = document.createElement('td')\r\n tdField.textContent = change.label || change.field\r\n tr.appendChild(tdField)\r\n\r\n const tdOld = document.createElement('td')\r\n tdOld.className = 'lv-diff-old'\r\n tdOld.textContent = formatValue(change.oldValue)\r\n tr.appendChild(tdOld)\r\n\r\n const tdNew = document.createElement('td')\r\n tdNew.className = 'lv-diff-new'\r\n tdNew.textContent = formatValue(change.newValue)\r\n tr.appendChild(tdNew)\r\n\r\n tbody.appendChild(tr)\r\n }\r\n table.appendChild(tbody)\r\n\r\n return table\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;AAUO,IAAM,eAAN,MAAmB;;;;CAIxB,aAAa,OAA8B;EACzC,MAAM,YAAY,SAAS,cAAc,KAAK;EAC9C,UAAU,YAAY;EAEtB,IAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAC1C,UAAU,YAAY,KAAK,gBAAgB,MAAM,OAAO,CAAC;EAG3D,IAAI,MAAM,YAAY,OAAO,KAAK,MAAM,QAAQ,CAAA,CAAE,SAAS,GAAG;GAC5D,MAAM,OAAO,SAAS,cAAc,KAAK;GACzC,KAAK,YAAY;GACjB,KAAK,cAAc,YAAY,MAAM,QAAQ;GAC7C,UAAU,YAAY,IAAI;EAC5B;EAEA,OAAO;CACT;;;;CAKA,gBAAgB,SAAmC;EACjD,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,MAAM,YAAY;EAGlB,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,MAAM,YAAY,SAAS,cAAc,IAAI;EAC7C,KAAA,MAAW,SAAS;GAAC;GAAM;GAAO;EAAK,GAAG;GACxC,MAAM,KAAK,SAAS,cAAc,IAAI;GACtC,GAAG,cAAc;GACjB,UAAU,YAAY,EAAE;EAC1B;EACA,MAAM,YAAY,SAAS;EAC3B,MAAM,YAAY,KAAK;EAGvB,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,KAAA,MAAW,UAAU,SAAS;GAC5B,MAAM,KAAK,SAAS,cAAc,IAAI;GAEtC,MAAM,UAAU,SAAS,cAAc,IAAI;GAC3C,QAAQ,cAAc,OAAO,SAAS,OAAO;GAC7C,GAAG,YAAY,OAAO;GAEtB,MAAM,QAAQ,SAAS,cAAc,IAAI;GACzC,MAAM,YAAY;GAClB,MAAM,cAAc,YAAY,OAAO,QAAQ;GAC/C,GAAG,YAAY,KAAK;GAEpB,MAAM,QAAQ,SAAS,cAAc,IAAI;GACzC,MAAM,YAAY;GAClB,MAAM,cAAc,YAAY,OAAO,QAAQ;GAC/C,GAAG,YAAY,KAAK;GAEpB,MAAM,YAAY,EAAE;EACtB;EACA,MAAM,YAAY,KAAK;EAEvB,OAAO;CACT;AACF"}
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
* 时间线渲染器 - 将日志条目渲染为时间线 DOM
|
|
3
3
|
*/
|
|
4
4
|
import type { LogEntry } from '../types';
|
|
5
|
+
export interface TimelineRendererOptions {
|
|
6
|
+
showDiff?: boolean;
|
|
7
|
+
showAnomalyBadge?: boolean;
|
|
8
|
+
locale?: 'zh-CN' | 'en-US';
|
|
9
|
+
}
|
|
5
10
|
/**
|
|
6
11
|
* TimelineRenderer - Timeline Renderer class
|
|
7
12
|
*/
|
|
@@ -9,14 +14,13 @@ export declare class TimelineRenderer {
|
|
|
9
14
|
/**
|
|
10
15
|
* 渲染时间线
|
|
11
16
|
*/
|
|
12
|
-
render(entries: LogEntry[], expandedIds: Set<string
|
|
17
|
+
render(entries: LogEntry[], expandedIds: Set<string>, options?: TimelineRendererOptions): HTMLElement;
|
|
13
18
|
/**
|
|
14
19
|
* 渲染单条时间线条目
|
|
15
20
|
*/
|
|
16
|
-
renderItem(entry: LogEntry, expanded: boolean): HTMLElement;
|
|
21
|
+
renderItem(entry: LogEntry, expanded: boolean, options?: TimelineRendererOptions): HTMLElement;
|
|
17
22
|
/**
|
|
18
23
|
* 渲染分页
|
|
19
24
|
*/
|
|
20
25
|
renderPagination(page: number, pageSize: number, total: number): HTMLElement;
|
|
21
26
|
}
|
|
22
|
-
//# sourceMappingURL=TimelineRenderer.d.ts.map
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* ***********************************
|
|
3
3
|
* @composy/log-viewer-core v0.0.1 *
|
|
4
4
|
* Built with rollup *
|
|
5
|
-
* Build time: 2024-
|
|
5
|
+
* Build time: 2024-10-12 17:29:20 *
|
|
6
6
|
* Build mode: production *
|
|
7
7
|
* Minified: No *
|
|
8
8
|
* ***********************************
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { ACTION_LABELS } from "../types/index.js";
|
|
11
11
|
import { formatDate } from "../utils/index.js";
|
|
12
12
|
//#region src/renderers/TimelineRenderer.ts
|
|
13
13
|
const ANOMALY_LABELS = {
|
|
@@ -16,29 +16,53 @@ const ANOMALY_LABELS = {
|
|
|
16
16
|
"high-frequency": "高频操作",
|
|
17
17
|
none: ""
|
|
18
18
|
};
|
|
19
|
+
const ANOMALY_LABELS_EN = {
|
|
20
|
+
"off-hours": "Off hours",
|
|
21
|
+
sensitive: "Sensitive",
|
|
22
|
+
"high-frequency": "High frequency",
|
|
23
|
+
none: ""
|
|
24
|
+
};
|
|
25
|
+
const ACTION_LABELS_EN = {
|
|
26
|
+
create: "Create",
|
|
27
|
+
update: "Update",
|
|
28
|
+
delete: "Delete",
|
|
29
|
+
query: "Query",
|
|
30
|
+
login: "Login",
|
|
31
|
+
logout: "Logout",
|
|
32
|
+
export: "Export",
|
|
33
|
+
import: "Import",
|
|
34
|
+
approve: "Approve",
|
|
35
|
+
reject: "Reject",
|
|
36
|
+
other: "Other"
|
|
37
|
+
};
|
|
19
38
|
var TimelineRenderer = class {
|
|
20
39
|
/**
|
|
21
40
|
* 渲染时间线
|
|
22
41
|
*/
|
|
23
|
-
render(entries, expandedIds) {
|
|
42
|
+
render(entries, expandedIds, options = {}) {
|
|
24
43
|
const container = document.createElement("div");
|
|
25
44
|
container.className = "lv-timeline";
|
|
26
45
|
if (entries.length === 0) {
|
|
27
|
-
|
|
46
|
+
const emptyIcon = document.createElement("div");
|
|
47
|
+
emptyIcon.className = "lv-empty-icon";
|
|
48
|
+
emptyIcon.textContent = "--";
|
|
49
|
+
const emptyText = document.createElement("div");
|
|
50
|
+
emptyText.textContent = options.locale === "en-US" ? "No log entries" : "暂无日志记录";
|
|
51
|
+
container.append(emptyIcon, emptyText);
|
|
28
52
|
container.className = "";
|
|
29
53
|
return container;
|
|
30
54
|
}
|
|
31
|
-
for (const entry of entries) container.appendChild(this.renderItem(entry, expandedIds.has(entry.id)));
|
|
55
|
+
for (const entry of entries) container.appendChild(this.renderItem(entry, expandedIds.has(entry.id), options));
|
|
32
56
|
return container;
|
|
33
57
|
}
|
|
34
58
|
/**
|
|
35
59
|
* 渲染单条时间线条目
|
|
36
60
|
*/
|
|
37
|
-
renderItem(entry, expanded) {
|
|
61
|
+
renderItem(entry, expanded, options = {}) {
|
|
38
62
|
const item = document.createElement("div");
|
|
39
63
|
item.className = "lv-timeline-item";
|
|
40
64
|
item.setAttribute("data-id", entry.id);
|
|
41
|
-
const isAnomaly = entry.anomaly && entry.anomaly !== "none";
|
|
65
|
+
const isAnomaly = options.showAnomalyBadge !== false && entry.anomaly && entry.anomaly !== "none";
|
|
42
66
|
const dot = document.createElement("div");
|
|
43
67
|
dot.className = `lv-timeline-dot${isAnomaly ? " lv-timeline-dot--anomaly" : ""}`;
|
|
44
68
|
item.appendChild(dot);
|
|
@@ -55,9 +79,8 @@ var TimelineRenderer = class {
|
|
|
55
79
|
user.textContent = entry.user;
|
|
56
80
|
header.appendChild(user);
|
|
57
81
|
const actionTag = document.createElement("span");
|
|
58
|
-
actionTag.className =
|
|
59
|
-
actionTag.textContent = ACTION_LABELS[entry.action] || entry.action;
|
|
60
|
-
actionTag.style.backgroundColor = ACTION_COLORS[entry.action] || "#8c8c8c";
|
|
82
|
+
actionTag.className = `lv-action-tag lv-action-tag--${Object.keys(ACTION_LABELS).includes(entry.action) ? entry.action : "other"}`;
|
|
83
|
+
actionTag.textContent = (options.locale === "en-US" ? ACTION_LABELS_EN[entry.action] : ACTION_LABELS[entry.action]) || entry.action;
|
|
61
84
|
header.appendChild(actionTag);
|
|
62
85
|
const moduleBadge = document.createElement("span");
|
|
63
86
|
moduleBadge.className = "lv-timeline-module";
|
|
@@ -69,10 +92,10 @@ var TimelineRenderer = class {
|
|
|
69
92
|
ip.textContent = entry.ip;
|
|
70
93
|
header.appendChild(ip);
|
|
71
94
|
}
|
|
72
|
-
if (isAnomaly) {
|
|
95
|
+
if (options.showAnomalyBadge !== false && isAnomaly) {
|
|
73
96
|
const badge = document.createElement("span");
|
|
74
97
|
badge.className = "lv-anomaly-badge";
|
|
75
|
-
badge.textContent = ANOMALY_LABELS[entry.anomaly];
|
|
98
|
+
badge.textContent = (options.locale === "en-US" ? ANOMALY_LABELS_EN[entry.anomaly] : ANOMALY_LABELS)[entry.anomaly] || entry.anomaly;
|
|
76
99
|
header.appendChild(badge);
|
|
77
100
|
}
|
|
78
101
|
card.appendChild(header);
|
|
@@ -82,9 +105,11 @@ var TimelineRenderer = class {
|
|
|
82
105
|
detail.textContent = entry.detail;
|
|
83
106
|
card.appendChild(detail);
|
|
84
107
|
}
|
|
85
|
-
if (entry.changes && entry.changes.length > 0) {
|
|
86
|
-
const hint = document.createElement("
|
|
108
|
+
if (options.showDiff !== false && entry.changes && entry.changes.length > 0) {
|
|
109
|
+
const hint = document.createElement("button");
|
|
110
|
+
hint.type = "button";
|
|
87
111
|
hint.className = "lv-timeline-expand-hint";
|
|
112
|
+
hint.setAttribute("aria-expanded", String(expanded));
|
|
88
113
|
hint.textContent = expanded ? "[ 收起变更详情 ]" : `[ \u67E5\u770B\u53D8\u66F4\u8BE6\u60C5 (${entry.changes.length} \u4E2A\u5B57\u6BB5) ]`;
|
|
89
114
|
card.appendChild(hint);
|
|
90
115
|
}
|
|
@@ -97,34 +122,43 @@ var TimelineRenderer = class {
|
|
|
97
122
|
renderPagination(page, pageSize, total) {
|
|
98
123
|
const container = document.createElement("div");
|
|
99
124
|
container.className = "lv-pagination";
|
|
100
|
-
const
|
|
125
|
+
const safePageSize = Number.isFinite(pageSize) && pageSize > 0 ? Math.floor(pageSize) : 1;
|
|
126
|
+
const safeTotal = Number.isFinite(total) && total > 0 ? Math.floor(total) : 0;
|
|
127
|
+
const safePage = Number.isFinite(page) && page > 0 ? Math.floor(page) : 1;
|
|
128
|
+
const totalPages = Math.ceil(safeTotal / safePageSize);
|
|
101
129
|
if (totalPages <= 1) return container;
|
|
102
130
|
const prev = document.createElement("button");
|
|
131
|
+
prev.type = "button";
|
|
103
132
|
prev.className = "lv-pagination-btn";
|
|
104
133
|
prev.textContent = "<";
|
|
105
|
-
prev.disabled =
|
|
106
|
-
prev.setAttribute("
|
|
134
|
+
prev.disabled = safePage <= 1;
|
|
135
|
+
prev.setAttribute("aria-label", "Previous page");
|
|
136
|
+
prev.setAttribute("data-page", String(safePage - 1));
|
|
107
137
|
container.appendChild(prev);
|
|
108
138
|
const maxVisible = 7;
|
|
109
|
-
let startPage = Math.max(1,
|
|
139
|
+
let startPage = Math.max(1, safePage - Math.floor(maxVisible / 2));
|
|
110
140
|
const endPage = Math.min(totalPages, startPage + maxVisible - 1);
|
|
111
141
|
if (endPage - startPage < maxVisible - 1) startPage = Math.max(1, endPage - maxVisible + 1);
|
|
112
142
|
for (let i = startPage; i <= endPage; i++) {
|
|
113
143
|
const btn = document.createElement("button");
|
|
114
|
-
btn.
|
|
144
|
+
btn.type = "button";
|
|
145
|
+
btn.className = `lv-pagination-btn${i === safePage ? " lv-pagination-btn--active" : ""}`;
|
|
115
146
|
btn.textContent = String(i);
|
|
116
147
|
btn.setAttribute("data-page", String(i));
|
|
148
|
+
if (i === safePage) btn.setAttribute("aria-current", "page");
|
|
117
149
|
container.appendChild(btn);
|
|
118
150
|
}
|
|
119
151
|
const next = document.createElement("button");
|
|
152
|
+
next.type = "button";
|
|
120
153
|
next.className = "lv-pagination-btn";
|
|
121
154
|
next.textContent = ">";
|
|
122
|
-
next.disabled =
|
|
123
|
-
next.setAttribute("
|
|
155
|
+
next.disabled = safePage >= totalPages;
|
|
156
|
+
next.setAttribute("aria-label", "Next page");
|
|
157
|
+
next.setAttribute("data-page", String(safePage + 1));
|
|
124
158
|
container.appendChild(next);
|
|
125
159
|
const info = document.createElement("span");
|
|
126
160
|
info.className = "lv-pagination-info";
|
|
127
|
-
info.textContent = `\u5171 ${
|
|
161
|
+
info.textContent = `\u5171 ${safeTotal} \u6761`;
|
|
128
162
|
container.appendChild(info);
|
|
129
163
|
return container;
|
|
130
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimelineRenderer.js","names":[],"sources":["../../src/renderers/TimelineRenderer.ts"],"sourcesContent":["/**\n * 时间线渲染器 - 将日志条目渲染为时间线 DOM\n */\n\nimport type { LogEntry, AnomalyType } from '../types'\nimport { ACTION_LABELS, ACTION_COLORS } from '../types'\nimport { formatDate, escapeHtml } from '../utils'\n\nconst ANOMALY_LABELS: Record<AnomalyType, string> = {\n 'off-hours': '非工作时间',\n sensitive: '敏感操作',\n 'high-frequency': '高频操作',\n none: '',\n}\n\n/**\n * TimelineRenderer - Timeline Renderer class\n */\nexport class TimelineRenderer {\n /**\n * 渲染时间线\n */\n render(entries: LogEntry[], expandedIds: Set<string>): HTMLElement {\n const container = document.createElement('div')\n container.className = 'lv-timeline'\n\n if (entries.length === 0) {\n container.innerHTML = `<div class=\"lv-empty\"><div class=\"lv-empty-icon\">--</div><div>暂无日志记录</div></div>`\n container.className = ''\n return container\n }\n\n for (const entry of entries) {\n container.appendChild(this.renderItem(entry, expandedIds.has(entry.id)))\n }\n\n return container\n }\n\n /**\n * 渲染单条时间线条目\n */\n renderItem(entry: LogEntry, expanded: boolean): HTMLElement {\n const item = document.createElement('div')\n item.className = 'lv-timeline-item'\n item.setAttribute('data-id', entry.id)\n\n const isAnomaly = entry.anomaly && entry.anomaly !== 'none'\n\n // Dot\n const dot = document.createElement('div')\n dot.className = `lv-timeline-dot${isAnomaly ? ' lv-timeline-dot--anomaly' : ''}`\n item.appendChild(dot)\n\n // Card\n const card = document.createElement('div')\n card.className = `lv-timeline-card${isAnomaly ? ' lv-timeline-card--anomaly' : ''}`\n\n // Header\n const header = document.createElement('div')\n header.className = 'lv-timeline-header'\n\n const time = document.createElement('span')\n time.className = 'lv-timeline-time'\n time.textContent = formatDate(entry.timestamp)\n header.appendChild(time)\n\n const user = document.createElement('span')\n user.className = 'lv-timeline-user'\n user.textContent = entry.user\n header.appendChild(user)\n\n const actionTag = document.createElement('span')\n actionTag.className = 'lv-action-tag'\n actionTag.textContent = ACTION_LABELS[entry.action] || entry.action\n actionTag.style.backgroundColor = ACTION_COLORS[entry.action] || '#8c8c8c'\n header.appendChild(actionTag)\n\n const moduleBadge = document.createElement('span')\n moduleBadge.className = 'lv-timeline-module'\n moduleBadge.textContent = entry.module\n header.appendChild(moduleBadge)\n\n if (entry.ip) {\n const ip = document.createElement('span')\n ip.className = 'lv-timeline-ip'\n ip.textContent = entry.ip\n header.appendChild(ip)\n }\n\n if (isAnomaly) {\n const badge = document.createElement('span')\n badge.className = 'lv-anomaly-badge'\n badge.textContent = ANOMALY_LABELS[entry.anomaly!]\n header.appendChild(badge)\n }\n\n card.appendChild(header)\n\n // Detail text\n if (entry.detail) {\n const detail = document.createElement('div')\n detail.className = 'lv-timeline-detail'\n detail.textContent = entry.detail\n card.appendChild(detail)\n }\n\n // Expand hint\n if (entry.changes && entry.changes.length > 0) {\n const hint = document.createElement('div')\n hint.className = 'lv-timeline-expand-hint'\n hint.textContent = expanded ? '[ 收起变更详情 ]' : `[ 查看变更详情 (${entry.changes.length} 个字段) ]`\n card.appendChild(hint)\n }\n\n item.appendChild(card)\n\n return item\n }\n\n /**\n * 渲染分页\n */\n renderPagination(page: number, pageSize: number, total: number): HTMLElement {\n const container = document.createElement('div')\n container.className = 'lv-pagination'\n\n const totalPages = Math.ceil(total / pageSize)\n if (totalPages <= 1) return container\n\n // Prev\n const prev = document.createElement('button')\n prev.className = 'lv-pagination-btn'\n prev.textContent = '<'\n prev.disabled = page <= 1\n prev.setAttribute('data-page', String(page - 1))\n container.appendChild(prev)\n\n // Page buttons\n const maxVisible = 7\n let startPage = Math.max(1, page - Math.floor(maxVisible / 2))\n const endPage = Math.min(totalPages, startPage + maxVisible - 1)\n if (endPage - startPage < maxVisible - 1) {\n startPage = Math.max(1, endPage - maxVisible + 1)\n }\n\n for (let i = startPage; i <= endPage; i++) {\n const btn = document.createElement('button')\n btn.className = `lv-pagination-btn${i === page ? ' lv-pagination-btn--active' : ''}`\n btn.textContent = String(i)\n btn.setAttribute('data-page', String(i))\n container.appendChild(btn)\n }\n\n // Next\n const next = document.createElement('button')\n next.className = 'lv-pagination-btn'\n next.textContent = '>'\n next.disabled = page >= totalPages\n next.setAttribute('data-page', String(page + 1))\n container.appendChild(next)\n\n // Info\n const info = document.createElement('span')\n info.className = 'lv-pagination-info'\n info.textContent = `共 ${total} 条`\n container.appendChild(info)\n\n return container\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TimelineRenderer.js","names":[],"sources":["../../src/renderers/TimelineRenderer.ts"],"sourcesContent":["/**\r\n * 时间线渲染器 - 将日志条目渲染为时间线 DOM\r\n */\r\n\r\nimport type { LogEntry, AnomalyType } from '../types'\r\nimport { ACTION_LABELS } from '../types'\r\nimport { formatDate } from '../utils'\r\n\r\nexport interface TimelineRendererOptions {\r\n showDiff?: boolean\r\n showAnomalyBadge?: boolean\r\n locale?: 'zh-CN' | 'en-US'\r\n}\r\n\r\nconst ANOMALY_LABELS: Record<AnomalyType, string> = {\r\n 'off-hours': '非工作时间',\r\n sensitive: '敏感操作',\r\n 'high-frequency': '高频操作',\r\n none: '',\r\n}\r\n\r\nconst ANOMALY_LABELS_EN: Record<AnomalyType, string> = {\r\n 'off-hours': 'Off hours',\r\n sensitive: 'Sensitive',\r\n 'high-frequency': 'High frequency',\r\n none: '',\r\n}\r\n\r\nconst ACTION_LABELS_EN: Record<string, string> = {\r\n create: 'Create',\r\n update: 'Update',\r\n delete: 'Delete',\r\n query: 'Query',\r\n login: 'Login',\r\n logout: 'Logout',\r\n export: 'Export',\r\n import: 'Import',\r\n approve: 'Approve',\r\n reject: 'Reject',\r\n other: 'Other',\r\n}\r\n\r\n/**\r\n * TimelineRenderer - Timeline Renderer class\r\n */\r\nexport class TimelineRenderer {\r\n /**\r\n * 渲染时间线\r\n */\r\n render(\r\n entries: LogEntry[],\r\n expandedIds: Set<string>,\r\n options: TimelineRendererOptions = {}\r\n ): HTMLElement {\r\n const container = document.createElement('div')\r\n container.className = 'lv-timeline'\r\n\r\n if (entries.length === 0) {\r\n const emptyIcon = document.createElement('div')\r\n emptyIcon.className = 'lv-empty-icon'\r\n emptyIcon.textContent = '--'\r\n const emptyText = document.createElement('div')\r\n emptyText.textContent =\r\n options.locale === 'en-US' ? 'No log entries' : '暂无日志记录'\r\n container.append(emptyIcon, emptyText)\r\n container.className = ''\r\n return container\r\n }\r\n\r\n for (const entry of entries) {\r\n container.appendChild(\r\n this.renderItem(entry, expandedIds.has(entry.id), options)\r\n )\r\n }\r\n\r\n return container\r\n }\r\n\r\n /**\r\n * 渲染单条时间线条目\r\n */\r\n renderItem(\r\n entry: LogEntry,\r\n expanded: boolean,\r\n options: TimelineRendererOptions = {}\r\n ): HTMLElement {\r\n const item = document.createElement('div')\r\n item.className = 'lv-timeline-item'\r\n item.setAttribute('data-id', entry.id)\r\n\r\n const isAnomaly =\r\n options.showAnomalyBadge !== false &&\r\n entry.anomaly &&\r\n entry.anomaly !== 'none'\r\n\r\n // Dot\r\n const dot = document.createElement('div')\r\n dot.className = `lv-timeline-dot${isAnomaly ? ' lv-timeline-dot--anomaly' : ''}`\r\n item.appendChild(dot)\r\n\r\n // Card\r\n const card = document.createElement('div')\r\n card.className = `lv-timeline-card${isAnomaly ? ' lv-timeline-card--anomaly' : ''}`\r\n\r\n // Header\r\n const header = document.createElement('div')\r\n header.className = 'lv-timeline-header'\r\n\r\n const time = document.createElement('span')\r\n time.className = 'lv-timeline-time'\r\n time.textContent = formatDate(entry.timestamp)\r\n header.appendChild(time)\r\n\r\n const user = document.createElement('span')\r\n user.className = 'lv-timeline-user'\r\n user.textContent = entry.user\r\n header.appendChild(user)\r\n\r\n const actionTag = document.createElement('span')\r\n const actionKey = Object.keys(ACTION_LABELS).includes(entry.action)\r\n ? entry.action\r\n : 'other'\r\n actionTag.className = `lv-action-tag lv-action-tag--${actionKey}`\r\n actionTag.textContent =\r\n (options.locale === 'en-US'\r\n ? ACTION_LABELS_EN[entry.action]\r\n : ACTION_LABELS[entry.action]) || entry.action\r\n header.appendChild(actionTag)\r\n\r\n const moduleBadge = document.createElement('span')\r\n moduleBadge.className = 'lv-timeline-module'\r\n moduleBadge.textContent = entry.module\r\n header.appendChild(moduleBadge)\r\n\r\n if (entry.ip) {\r\n const ip = document.createElement('span')\r\n ip.className = 'lv-timeline-ip'\r\n ip.textContent = entry.ip\r\n header.appendChild(ip)\r\n }\r\n\r\n if (options.showAnomalyBadge !== false && isAnomaly) {\r\n const badge = document.createElement('span')\r\n badge.className = 'lv-anomaly-badge'\r\n badge.textContent =\r\n (options.locale === 'en-US'\r\n ? ANOMALY_LABELS_EN[entry.anomaly!]\r\n : ANOMALY_LABELS)[entry.anomaly!] || entry.anomaly\r\n header.appendChild(badge)\r\n }\r\n\r\n card.appendChild(header)\r\n\r\n // Detail text\r\n if (entry.detail) {\r\n const detail = document.createElement('div')\r\n detail.className = 'lv-timeline-detail'\r\n detail.textContent = entry.detail\r\n card.appendChild(detail)\r\n }\r\n\r\n // Expand hint\r\n if (\r\n options.showDiff !== false &&\r\n entry.changes &&\r\n entry.changes.length > 0\r\n ) {\r\n const hint = document.createElement('button')\r\n hint.type = 'button'\r\n hint.className = 'lv-timeline-expand-hint'\r\n hint.setAttribute('aria-expanded', String(expanded))\r\n hint.textContent = expanded\r\n ? '[ 收起变更详情 ]'\r\n : `[ 查看变更详情 (${entry.changes.length} 个字段) ]`\r\n card.appendChild(hint)\r\n }\r\n\r\n item.appendChild(card)\r\n\r\n return item\r\n }\r\n\r\n /**\r\n * 渲染分页\r\n */\r\n renderPagination(page: number, pageSize: number, total: number): HTMLElement {\r\n const container = document.createElement('div')\r\n container.className = 'lv-pagination'\r\n\r\n const safePageSize =\r\n Number.isFinite(pageSize) && pageSize > 0 ? Math.floor(pageSize) : 1\r\n const safeTotal =\r\n Number.isFinite(total) && total > 0 ? Math.floor(total) : 0\r\n const safePage = Number.isFinite(page) && page > 0 ? Math.floor(page) : 1\r\n const totalPages = Math.ceil(safeTotal / safePageSize)\r\n if (totalPages <= 1) return container\r\n\r\n // Prev\r\n const prev = document.createElement('button')\r\n prev.type = 'button'\r\n prev.className = 'lv-pagination-btn'\r\n prev.textContent = '<'\r\n prev.disabled = safePage <= 1\r\n prev.setAttribute('aria-label', 'Previous page')\r\n prev.setAttribute('data-page', String(safePage - 1))\r\n container.appendChild(prev)\r\n\r\n // Page buttons\r\n const maxVisible = 7\r\n let startPage = Math.max(1, safePage - Math.floor(maxVisible / 2))\r\n const endPage = Math.min(totalPages, startPage + maxVisible - 1)\r\n if (endPage - startPage < maxVisible - 1) {\r\n startPage = Math.max(1, endPage - maxVisible + 1)\r\n }\r\n\r\n for (let i = startPage; i <= endPage; i++) {\r\n const btn = document.createElement('button')\r\n btn.type = 'button'\r\n btn.className = `lv-pagination-btn${i === safePage ? ' lv-pagination-btn--active' : ''}`\r\n btn.textContent = String(i)\r\n btn.setAttribute('data-page', String(i))\r\n if (i === safePage) btn.setAttribute('aria-current', 'page')\r\n container.appendChild(btn)\r\n }\r\n\r\n // Next\r\n const next = document.createElement('button')\r\n next.type = 'button'\r\n next.className = 'lv-pagination-btn'\r\n next.textContent = '>'\r\n next.disabled = safePage >= totalPages\r\n next.setAttribute('aria-label', 'Next page')\r\n next.setAttribute('data-page', String(safePage + 1))\r\n container.appendChild(next)\r\n\r\n // Info\r\n const info = document.createElement('span')\r\n info.className = 'lv-pagination-info'\r\n info.textContent = `共 ${safeTotal} 条`\r\n container.appendChild(info)\r\n\r\n return container\r\n }\r\n}\r\n"],"mappings":"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"}
|
package/es/styles/index.d.ts
CHANGED