feat(ui): Phase 8 UI/UX optimization and system documentation update
## Sidebar Enhancement - Change tabs to icon + small label layout for better space utilization - Add Teams tab with team collaboration entry point ## Settings Page Improvements - Connect theme toggle to gatewayStore.saveQuickConfig for persistence - Remove OpenFang backend download section, simplify UI - Add time range filter to UsageStats (7d/30d/all) - Add stat cards with icons (sessions, messages, input/output tokens) - Add token usage overview bar chart - Add 8 ZCLAW system skill definitions with categories ## Bug Fixes - Fix ChannelList duplicate content with deduplication logic - Integrate CreateTriggerModal in TriggersPanel - Add independent SecurityStatusPanel with 12 default enabled layers - Change workflow view to use SchedulerPanel as unified entry ## New Components - CreateTriggerModal: Event trigger creation modal - HandApprovalModal: Hand approval workflow dialog - HandParamsForm: Enhanced Hand parameter form - SecurityLayersPanel: 16-layer security status display ## Architecture - Add TOML config parsing support (toml-utils.ts, config-parser.ts) - Add request timeout and retry mechanism (request-helper.ts) - Add secure token storage (secure-storage.ts, secure_storage.rs) ## Tests - Add unit tests for config-parser, toml-utils, request-helper - Add team-client and teamStore tests ## Documentation - Update SYSTEM_ANALYSIS.md with Phase 8 completion - UI completion: 100% (30/30 components) - API coverage: 93% (63/68 endpoints) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
169
desktop/tests/toml-utils.test.ts
Normal file
169
desktop/tests/toml-utils.test.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* TOML Utility Tests
|
||||
*
|
||||
* Tests for TOML parsing and configuration handling.
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { tomlUtils, TomlParseError, TomlStringifyError } from '../src/lib/toml-utils';
|
||||
|
||||
describe('tomlUtils', () => {
|
||||
describe('parse', () => {
|
||||
it('should parse basic TOML correctly', () => {
|
||||
const toml = `
|
||||
[server]
|
||||
host = "127.0.0.1"
|
||||
port = 4200
|
||||
`;
|
||||
const result = tomlUtils.parse(toml);
|
||||
expect(result).toEqual({
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
port: 4200,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse nested tables correctly', () => {
|
||||
const toml = `
|
||||
[server]
|
||||
host = "127.0.0.1"
|
||||
|
||||
[server.websocket]
|
||||
port = 8080
|
||||
path = "/ws"
|
||||
`;
|
||||
const result = tomlUtils.parse(toml);
|
||||
expect(result).toEqual({
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
websocket: {
|
||||
port: 8080,
|
||||
path: '/ws',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse arrays correctly', () => {
|
||||
const toml = `
|
||||
[[servers]]
|
||||
name = "primary"
|
||||
port = 4200
|
||||
|
||||
[[servers]]
|
||||
name = "secondary"
|
||||
port = 4201
|
||||
`;
|
||||
const result = tomlUtils.parse(toml);
|
||||
expect(result).toEqual({
|
||||
servers: [
|
||||
{ name: 'primary', port: 4200 },
|
||||
{ name: 'secondary', port: 4201 },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw TomlParseError on invalid TOML', () => {
|
||||
const invalidToml = `
|
||||
[invalid
|
||||
key = value
|
||||
`;
|
||||
expect(() => tomlUtils.parse(invalidToml)).toThrow(TomlParseError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stringify', () => {
|
||||
it('should stringify basic objects correctly', () => {
|
||||
const data = {
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
port: 4200,
|
||||
},
|
||||
};
|
||||
const result = tomlUtils.stringify(data);
|
||||
expect(result).toContain('host = "127.0.0.1"');
|
||||
expect(result).toContain('port = 4200');
|
||||
});
|
||||
|
||||
it('should throw TomlStringifyError on invalid data', () => {
|
||||
const circularData: Record<string, unknown> = { self: {} };
|
||||
circularData.self = circularData;
|
||||
|
||||
expect(() => tomlUtils.stringify(circularData)).toThrow(TomlStringifyError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveEnvVars', () => {
|
||||
it('should resolve environment variables', () => {
|
||||
const content = 'api_key = "${API_KEY}"';
|
||||
const envVars = { API_KEY: 'secret-key-123' };
|
||||
const result = tomlUtils.resolveEnvVars(content, envVars);
|
||||
expect(result).toBe('api_key = "secret-key-123"');
|
||||
});
|
||||
|
||||
it('should return empty string for missing env vars', () => {
|
||||
const content = 'api_key = "${MISSING_VAR}"';
|
||||
const result = tomlUtils.resolveEnvVars(content);
|
||||
expect(result).toBe('api_key = ""');
|
||||
});
|
||||
|
||||
it('should handle multiple env vars', () => {
|
||||
const content = `
|
||||
key1 = "${VAR1}"
|
||||
key2 = "${VAR2}"
|
||||
`;
|
||||
const envVars = { VAR1: 'value1', VAR2: 'value2' };
|
||||
const result = tomlUtils.resolveEnvVars(content, envVars);
|
||||
expect(result).toContain('key1 = "value1"');
|
||||
expect(result).toContain('key2 = "value2"');
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseWithEnvVars', () => {
|
||||
it('should parse TOML with env var resolution', () => {
|
||||
const content = `
|
||||
[config]
|
||||
api_key = "${API_KEY}"
|
||||
model = "gpt-4"
|
||||
`;
|
||||
const envVars = { API_KEY: 'test-key-456' };
|
||||
const result = tomlUtils.parseWithEnvVars(content, envVars);
|
||||
expect(result).toEqual({
|
||||
config: {
|
||||
api_key: 'test-key-456',
|
||||
model: 'gpt-4',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasUnresolvedEnvVars', () => {
|
||||
it('should return true when env vars are present', () => {
|
||||
const content = 'api_key = "${API_KEY}"';
|
||||
expect(tomlUtils.hasUnresolvedEnvVars(content)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when no env vars', () => {
|
||||
const content = 'api_key = "hardcoded-key"';
|
||||
expect(tomlUtils.hasUnresolvedEnvVars(content)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('extractEnvVarNames', () => {
|
||||
it('should extract all env var names', () => {
|
||||
const content = `
|
||||
key1 = "${VAR1}"
|
||||
key2 = "${VAR2}"
|
||||
key1 = "${VAR1}"
|
||||
`;
|
||||
const result = tomlUtils.extractEnvVarNames(content);
|
||||
expect(result).toEqual(['VAR1', 'VAR2']);
|
||||
});
|
||||
|
||||
it('should return empty array for no env vars', () => {
|
||||
const content = 'key = "value"';
|
||||
expect(tomlUtils.extractEnvVarNames(content)).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user