claude-code-templates 1.13.1 → 1.14.0
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 +44 -239
- package/package.json +1 -1
- package/src/analytics-web/components/AgentsPage.js +33 -16
- package/src/analytics-web/components/DashboardPage.js +35 -105
- package/src/analytics-web/components/HeaderComponent.js +307 -0
- package/src/analytics-web/index.html +10 -27
- package/src/analytics-web/services/DataService.js +13 -0
- package/src/health-check.js +48 -44
package/README.md
CHANGED
|
@@ -7,269 +7,74 @@
|
|
|
7
7
|
|
|
8
8
|
# Claude Code Templates
|
|
9
9
|
|
|
10
|
-
**CLI tool for configuring and monitoring Claude Code** - Quick setup for any project with framework-specific commands and real-time monitoring dashboard.
|
|
10
|
+
**CLI tool for configuring and monitoring Claude Code** - Quick setup for any project with framework-specific commands and real-time monitoring dashboard.
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## 🚀 Quick Start
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
#
|
|
15
|
+
# Interactive setup (recommended)
|
|
16
16
|
npx claude-code-templates@latest
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Core Features
|
|
20
|
-
|
|
21
|
-
### 📊 Real-time Analytics Dashboard
|
|
22
|
-
Monitor and optimize your Claude Code agents with our comprehensive analytics dashboard:
|
|
23
|
-
- **Live Session Tracking**: See active conversations and their status in real-time
|
|
24
|
-
- **Real-time State Detection**: "Claude Code working...", "User typing...", "Awaiting user input..."
|
|
25
|
-
- **Usage Statistics**: Total sessions, tokens, and project activity with interactive charts
|
|
26
|
-
- **Conversation History**: Complete session logs with export capabilities (CSV/JSON)
|
|
27
|
-
- **Browser Notifications**: Get notified when Claude is waiting for your input
|
|
28
|
-
- **Performance Monitoring**: Track Claude Code agent performance and optimization opportunities
|
|
29
|
-
- **Web Interface**: Clean, terminal-style dashboard at `http://localhost:3333`
|
|
30
|
-
|
|
31
|
-
### 🔍 Comprehensive Health Check
|
|
32
|
-
Complete system validation and configuration verification:
|
|
33
|
-
- **System Requirements**: Validate OS, Node.js, memory, and network connectivity
|
|
34
|
-
- **Claude Code Setup**: Verify installation, authentication, and permissions
|
|
35
|
-
- **Project Configuration**: Check project structure and configuration files
|
|
36
|
-
- **Custom Commands**: Validate slash commands and syntax
|
|
37
|
-
- **Hooks Configuration**: Verify automation hooks and command availability
|
|
38
|
-
- **Interactive Results**: Real-time progress with immediate feedback and recommendations
|
|
39
|
-
- **Health Score**: Overall system health percentage with actionable insights
|
|
40
|
-
|
|
41
|
-
### 📋 Smart Project Setup
|
|
42
|
-
Intelligent project configuration with framework-specific commands:
|
|
43
|
-
- **Auto-Detection**: Automatically detect your project type and suggest optimal configurations
|
|
44
|
-
- **Quick Setup**: Framework-specific commands for testing, linting, building, debugging, and deployment
|
|
45
|
-
- **Optimized Workflows**: Pre-configured commands tailored to your development stack
|
|
46
|
-
- **Best Practices**: Industry-standard configurations and development patterns
|
|
47
|
-
|
|
48
|
-
## What Gets Installed
|
|
49
|
-
|
|
50
|
-
### Core Files
|
|
51
|
-
- **`CLAUDE.md`** - Main configuration file with language-specific best practices
|
|
52
|
-
- **`.claude/settings.json`** - Automation hooks and Claude Code settings
|
|
53
|
-
- **`.claude/commands/`** - Custom commands for common development tasks
|
|
54
|
-
- **`.mcp.json`** - Model Context Protocol server configurations
|
|
55
|
-
|
|
56
|
-
## Supported Languages & Frameworks
|
|
57
|
-
|
|
58
|
-
| Language | Frameworks | Status | Commands | Hooks | MCP |
|
|
59
|
-
|----------|------------|---------|----------|--------|-----|
|
|
60
|
-
| **JavaScript/TypeScript** | React, Vue, Angular, Node.js | ✅ Ready | 7+ | 9+ | 4+ |
|
|
61
|
-
| **Python** | Django, Flask, FastAPI | ✅ Ready | 5+ | 8+ | 4+ |
|
|
62
|
-
| **Common** | Universal | ✅ Ready | 2+ | 1+ | 4+ |
|
|
63
|
-
| **Go** | Gin, Echo, Fiber | 🚧 Coming Soon | - | - | - |
|
|
64
|
-
| **Rust** | Axum, Warp, Actix | 🚧 Coming Soon | - | - | - |
|
|
65
|
-
|
|
66
|
-
## Usage Examples
|
|
67
|
-
|
|
68
|
-
### Interactive Setup (Recommended)
|
|
69
|
-
```bash
|
|
70
|
-
cd my-react-app
|
|
71
|
-
npx claude-code-templates
|
|
72
|
-
# Choose between Analytics Dashboard, Health Check, or Project Setup
|
|
73
|
-
```
|
|
74
17
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# Launch real-time analytics dashboard
|
|
78
|
-
npx claude-code-templates --analytics
|
|
18
|
+
# Real-time analytics dashboard
|
|
19
|
+
npx claude-code-templates@latest --analytics
|
|
79
20
|
|
|
80
|
-
#
|
|
81
|
-
npx claude-code-templates --
|
|
82
|
-
npx claude-code-templates --agents
|
|
21
|
+
# System health check
|
|
22
|
+
npx claude-code-templates@latest --health-check
|
|
83
23
|
```
|
|
84
24
|
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
# Run comprehensive system validation
|
|
88
|
-
npx claude-code-templates --health-check
|
|
89
|
-
npx claude-code-templates --health
|
|
90
|
-
npx claude-code-templates --check
|
|
91
|
-
npx claude-code-templates --verify
|
|
92
|
-
```
|
|
25
|
+
## ✨ Core Features
|
|
93
26
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
27
|
+
- **📋 Smart Project Setup** - Auto-detect and configure any project with framework-specific commands
|
|
28
|
+
- **📊 Real-time Analytics** - Monitor Claude Code sessions with live state detection and performance metrics
|
|
29
|
+
- **🔍 Health Check** - Comprehensive system validation with actionable recommendations
|
|
30
|
+
- **🧩 Individual Components** - Install specialized agents, commands, and MCPs individually
|
|
98
31
|
|
|
99
|
-
|
|
100
|
-
npx claude-code-templates --language python --framework django --yes
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Analysis Tools
|
|
104
|
-
```bash
|
|
105
|
-
# Analyze existing commands
|
|
106
|
-
npx claude-code-templates --commands-stats
|
|
32
|
+
## 🎯 What You Get
|
|
107
33
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
### Alternative Commands
|
|
116
|
-
All these commands work exactly the same way:
|
|
117
|
-
|
|
118
|
-
```bash
|
|
119
|
-
npx claude-code-templates # ✅ Recommended (package name)
|
|
120
|
-
npx cct # ⚡ Super short (3 letters)
|
|
121
|
-
npx claude-setup # Setup-style command
|
|
122
|
-
npx create-claude-config # Create-style command
|
|
123
|
-
```
|
|
34
|
+
| Component | Description | Example |
|
|
35
|
+
|-----------|-------------|---------|
|
|
36
|
+
| **CLAUDE.md** | Project-specific Claude Code configuration | Framework best practices, coding standards |
|
|
37
|
+
| **Commands** | Custom slash commands for development tasks | `/generate-tests`, `/check-file`, `/optimize-bundle` |
|
|
38
|
+
| **Agents** | AI specialists for specific domains | API security audit, React performance, database optimization |
|
|
39
|
+
| **MCPs** | External service integrations | GitHub, databases, development tools |
|
|
40
|
+
| **Analytics** | Real-time monitoring dashboard | Live session tracking, usage statistics, exports |
|
|
124
41
|
|
|
125
|
-
##
|
|
42
|
+
## 🛠️ Supported Technologies
|
|
126
43
|
|
|
127
|
-
|
|
|
128
|
-
|
|
129
|
-
|
|
|
130
|
-
|
|
|
131
|
-
|
|
|
132
|
-
|
|
|
133
|
-
|
|
|
134
|
-
| `--analytics` | Launch real-time analytics dashboard | `--analytics` |
|
|
135
|
-
| `--chats` | Launch chats/conversations dashboard | `--chats` |
|
|
136
|
-
| `--agents` | Launch agents dashboard (alias for chats) | `--agents` |
|
|
137
|
-
| `--health-check` | Run comprehensive system validation | `--health-check` |
|
|
138
|
-
| `--health` | Run system health check (alias) | `--health` |
|
|
139
|
-
| `--check` | Run system validation (alias) | `--check` |
|
|
140
|
-
| `--verify` | Verify system configuration (alias) | `--verify` |
|
|
141
|
-
| `--commands-stats` | Analyze existing commands | `--commands-stats` |
|
|
142
|
-
| `--hooks-stats` | Analyze automation hooks | `--hooks-stats` |
|
|
143
|
-
| `--mcps-stats` | Analyze MCP server configurations | `--mcps-stats` |
|
|
144
|
-
| `--help` | Show help information | `--help` |
|
|
44
|
+
| Language | Frameworks | Status |
|
|
45
|
+
|----------|------------|---------|
|
|
46
|
+
| **JavaScript/TypeScript** | React, Vue, Angular, Node.js | ✅ Ready |
|
|
47
|
+
| **Python** | Django, Flask, FastAPI | ✅ Ready |
|
|
48
|
+
| **Common** | Universal configurations | ✅ Ready |
|
|
49
|
+
| **Go** | Gin, Echo, Fiber | 🚧 Coming Soon |
|
|
50
|
+
| **Rust** | Axum, Warp, Actix | 🚧 Coming Soon |
|
|
145
51
|
|
|
146
|
-
##
|
|
52
|
+
## 📖 Documentation
|
|
147
53
|
|
|
148
|
-
|
|
54
|
+
**[📚 Complete Documentation](https://aitmpl.com/docu/)** - Comprehensive guides, examples, and API reference
|
|
149
55
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
-
|
|
154
|
-
-
|
|
155
|
-
-
|
|
156
|
-
- **`FileWatcher`** - Real-time file system monitoring with efficient change detection
|
|
157
|
-
- **`DataCache`** - Multi-level caching system with smart invalidation strategies
|
|
158
|
-
|
|
159
|
-
#### Data Layer
|
|
160
|
-
- **`DataCache`** - Intelligent caching with file content, parsed data, and computation result caching
|
|
161
|
-
- **Performance Monitoring** - Request tracking, memory monitoring, and system health metrics
|
|
162
|
-
|
|
163
|
-
#### Notification System
|
|
164
|
-
- **`WebSocketServer`** - Real-time WebSocket communication with client management
|
|
165
|
-
- **`NotificationManager`** - Event-driven notification system with subscription management
|
|
166
|
-
- **Real-time Updates** - Live conversation state changes and data refresh notifications
|
|
167
|
-
|
|
168
|
-
#### Performance & Monitoring
|
|
169
|
-
- **`PerformanceMonitor`** - Comprehensive performance tracking and system health monitoring
|
|
170
|
-
- **Express Middleware** - Request timing, error tracking, and API performance metrics
|
|
171
|
-
- **WebSocket Monitoring** - Connection tracking, message metrics, and client health monitoring
|
|
172
|
-
|
|
173
|
-
### Frontend Architecture
|
|
174
|
-
|
|
175
|
-
#### Modular Components
|
|
176
|
-
- **`Dashboard`** - Main orchestration component with state management integration
|
|
177
|
-
- **`ConversationTable`** - Interactive conversation display with real-time status updates
|
|
178
|
-
- **`Charts`** - Dynamic data visualization with Chart.js integration
|
|
179
|
-
- **`StateService`** - Reactive state management with subscriber patterns
|
|
180
|
-
- **`DataService`** - API communication with intelligent caching and real-time integration
|
|
181
|
-
- **`WebSocketService`** - Real-time communication with automatic reconnection
|
|
182
|
-
|
|
183
|
-
#### Real-time Features
|
|
184
|
-
- **Live State Detection** - Real-time conversation status: "Claude working...", "User typing...", "Awaiting input..."
|
|
185
|
-
- **Auto-refresh** - Smart polling with WebSocket fallback for seamless data updates
|
|
186
|
-
- **Browser Notifications** - Desktop notifications for important state changes
|
|
187
|
-
- **Responsive Design** - Mobile-friendly interface with real-time data synchronization
|
|
188
|
-
|
|
189
|
-
### Performance Optimizations
|
|
190
|
-
|
|
191
|
-
#### Caching Strategy
|
|
192
|
-
- **File Content Cache** - Reduces disk I/O with timestamp-based invalidation
|
|
193
|
-
- **Parsed Data Cache** - Stores analyzed conversation data with dependency tracking
|
|
194
|
-
- **API Response Cache** - Client-side caching with TTL and smart refresh
|
|
195
|
-
- **Computation Cache** - Caches expensive calculations with automatic invalidation
|
|
196
|
-
|
|
197
|
-
#### Real-time Efficiency
|
|
198
|
-
- **WebSocket Integration** - Eliminates polling overhead for live updates
|
|
199
|
-
- **Smart Refresh** - Only updates changed data with differential loading
|
|
200
|
-
- **Process Detection** - Efficient system process monitoring without performance impact
|
|
201
|
-
- **Memory Management** - Automatic cleanup of old metrics and cached data
|
|
202
|
-
|
|
203
|
-
### Testing Framework
|
|
204
|
-
|
|
205
|
-
#### Comprehensive Test Suite
|
|
206
|
-
- **Unit Tests** - Individual module testing with 80%+ coverage requirement
|
|
207
|
-
- **Integration Tests** - End-to-end system testing with real data scenarios
|
|
208
|
-
- **Performance Tests** - Load testing and performance regression detection
|
|
209
|
-
- **WebSocket Tests** - Real-time communication testing with mock clients
|
|
210
|
-
|
|
211
|
-
#### Test Coverage
|
|
212
|
-
- **Backend Modules**: StateCalculator, DataCache, WebSocketServer, PerformanceMonitor
|
|
213
|
-
- **Frontend Services**: DataService, StateService, WebSocketService
|
|
214
|
-
- **Integration Testing**: Complete analytics system with real conversation data
|
|
215
|
-
- **Performance Testing**: Concurrent operations, memory usage, and response times
|
|
216
|
-
|
|
217
|
-
### Development Benefits
|
|
218
|
-
|
|
219
|
-
#### Scalability
|
|
220
|
-
- **Modular Design** - Easy to extend with new features and integrations
|
|
221
|
-
- **Dependency Injection** - Loose coupling for flexible testing and development
|
|
222
|
-
- **Event-driven Architecture** - Scalable notification system for future enhancements
|
|
223
|
-
|
|
224
|
-
#### Maintainability
|
|
225
|
-
- **Separation of Concerns** - Clear boundaries between data, business logic, and presentation
|
|
226
|
-
- **Comprehensive Logging** - Detailed performance and error tracking for debugging
|
|
227
|
-
- **Type Safety** - Consistent error handling and data validation throughout
|
|
228
|
-
|
|
229
|
-
#### Performance
|
|
230
|
-
- **Multi-level Caching** - Optimized data access patterns with intelligent invalidation
|
|
231
|
-
- **Real-time Updates** - WebSocket-based communication eliminates polling overhead
|
|
232
|
-
- **Memory Optimization** - Automatic cleanup and configurable memory thresholds
|
|
233
|
-
- **Request Monitoring** - Complete visibility into system performance and bottlenecks
|
|
234
|
-
|
|
235
|
-
## Safety Features
|
|
236
|
-
|
|
237
|
-
- **Automatic Backups**: Existing files are backed up before changes
|
|
238
|
-
- **Confirmation Required**: Always asks before making changes (unless `--yes` flag)
|
|
239
|
-
- **Dry Run Mode**: Preview installation with `--dry-run`
|
|
240
|
-
- **Cancel Anytime**: Press Ctrl+C or answer 'No' to cancel
|
|
241
|
-
|
|
242
|
-
## What Makes This Special?
|
|
243
|
-
|
|
244
|
-
### Before (Manual Setup)
|
|
245
|
-
- Hours of configuration research
|
|
246
|
-
- Manual CLAUDE.md creation
|
|
247
|
-
- Framework-specific command setup
|
|
248
|
-
- Automation hook configuration
|
|
249
|
-
- MCP server integration
|
|
250
|
-
|
|
251
|
-
### After (With Templates)
|
|
252
|
-
```bash
|
|
253
|
-
npx claude-code-templates --language javascript-typescript --framework react --yes
|
|
254
|
-
# ✅ Done in 30 seconds!
|
|
255
|
-
```
|
|
56
|
+
Quick links:
|
|
57
|
+
- [Getting Started](https://aitmpl.com/docu/docs/intro) - Installation and first steps
|
|
58
|
+
- [Project Setup](https://aitmpl.com/docu/docs/project-setup/interactive-setup) - Configure your projects
|
|
59
|
+
- [Analytics Dashboard](https://aitmpl.com/docu/docs/analytics/overview) - Real-time monitoring
|
|
60
|
+
- [Individual Components](https://aitmpl.com/docu/docs/components/overview) - Agents, Commands, MCPs
|
|
61
|
+
- [CLI Options](https://aitmpl.com/docu/docs/cli-options) - All available commands
|
|
256
62
|
|
|
257
63
|
## 🤝 Contributing
|
|
258
64
|
|
|
259
|
-
We welcome contributions
|
|
260
|
-
|
|
261
|
-
**See our [GitHub repository](https://github.com/davila7/claude-code-templates) for detailed guidelines**
|
|
65
|
+
We welcome contributions! Browse available templates and components at **[aitmpl.com](https://aitmpl.com)**, then check our [contributing guidelines](https://github.com/davila7/claude-code-templates/blob/main/CONTRIBUTING.md).
|
|
262
66
|
|
|
263
67
|
## 📄 License
|
|
264
68
|
|
|
265
|
-
|
|
69
|
+
MIT License - see the [LICENSE](LICENSE) file for details.
|
|
266
70
|
|
|
267
|
-
##
|
|
71
|
+
## 🔗 Links
|
|
268
72
|
|
|
269
|
-
-
|
|
270
|
-
-
|
|
271
|
-
-
|
|
73
|
+
- **🌐 Browse Components**: [aitmpl.com](https://aitmpl.com)
|
|
74
|
+
- **📚 Documentation**: [aitmpl.com/docu](https://aitmpl.com/docu)
|
|
75
|
+
- **🐛 Issues**: [GitHub Issues](https://github.com/davila7/claude-code-templates/issues)
|
|
76
|
+
- **💬 Discussions**: [GitHub Discussions](https://github.com/davila7/claude-code-templates/discussions)
|
|
272
77
|
|
|
273
78
|
---
|
|
274
79
|
|
|
275
|
-
**⭐ Found this useful? Give us a star
|
|
80
|
+
**⭐ Found this useful? Give us a star to support the project!**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-templates",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,6 +16,9 @@ class AgentsPage {
|
|
|
16
16
|
};
|
|
17
17
|
this.isInitialized = false;
|
|
18
18
|
|
|
19
|
+
// Initialize header component
|
|
20
|
+
this.headerComponent = null;
|
|
21
|
+
|
|
19
22
|
// Pagination state for conversations
|
|
20
23
|
this.pagination = {
|
|
21
24
|
currentPage: 0,
|
|
@@ -586,22 +589,8 @@ class AgentsPage {
|
|
|
586
589
|
async render() {
|
|
587
590
|
this.container.innerHTML = `
|
|
588
591
|
<div class="agents-page">
|
|
589
|
-
<!-- Page Header -->
|
|
590
|
-
<div
|
|
591
|
-
<div class="header-content">
|
|
592
|
-
<div class="header-left">
|
|
593
|
-
<div class="status-header">
|
|
594
|
-
<span class="session-timer-status-dot active"></span>
|
|
595
|
-
<h1 class="page-title">
|
|
596
|
-
Claude Code web UI
|
|
597
|
-
</h1>
|
|
598
|
-
</div>
|
|
599
|
-
<div class="page-subtitle">
|
|
600
|
-
Monitor and analyze Claude Code agent interactions in real-time
|
|
601
|
-
</div>
|
|
602
|
-
</div>
|
|
603
|
-
</div>
|
|
604
|
-
</div>
|
|
592
|
+
<!-- Page Header (will be replaced by HeaderComponent) -->
|
|
593
|
+
<div id="agents-header-container"></div>
|
|
605
594
|
|
|
606
595
|
<!-- Filters Section -->
|
|
607
596
|
<div class="conversations-filters">
|
|
@@ -784,6 +773,28 @@ class AgentsPage {
|
|
|
784
773
|
|
|
785
774
|
this.bindEvents();
|
|
786
775
|
this.setupInfiniteScroll();
|
|
776
|
+
this.initializeHeaderComponent();
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Initialize the header component
|
|
781
|
+
*/
|
|
782
|
+
initializeHeaderComponent() {
|
|
783
|
+
const headerContainer = this.container.querySelector('#agents-header-container');
|
|
784
|
+
if (headerContainer && typeof HeaderComponent !== 'undefined') {
|
|
785
|
+
this.headerComponent = new HeaderComponent(headerContainer, {
|
|
786
|
+
title: 'Claude Code Chats',
|
|
787
|
+
subtitle: 'Monitor and analyze Claude Code agent interactions in real-time',
|
|
788
|
+
version: 'v1.13.2', // Fallback version
|
|
789
|
+
showVersionBadge: true,
|
|
790
|
+
showLastUpdate: true,
|
|
791
|
+
showThemeSwitch: true,
|
|
792
|
+
showGitHubLink: true,
|
|
793
|
+
dataService: this.dataService // Pass DataService for dynamic version loading
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
this.headerComponent.render();
|
|
797
|
+
}
|
|
787
798
|
}
|
|
788
799
|
|
|
789
800
|
/**
|
|
@@ -4716,6 +4727,12 @@ class AgentsPage {
|
|
|
4716
4727
|
* Destroy agents page
|
|
4717
4728
|
*/
|
|
4718
4729
|
destroy() {
|
|
4730
|
+
// Cleanup header component
|
|
4731
|
+
if (this.headerComponent) {
|
|
4732
|
+
this.headerComponent.destroy();
|
|
4733
|
+
this.headerComponent = null;
|
|
4734
|
+
}
|
|
4735
|
+
|
|
4719
4736
|
// Cleanup components
|
|
4720
4737
|
Object.values(this.components).forEach(component => {
|
|
4721
4738
|
if (component.destroy) {
|
|
@@ -13,6 +13,9 @@ class DashboardPage {
|
|
|
13
13
|
this.refreshInterval = null;
|
|
14
14
|
this.isInitialized = false;
|
|
15
15
|
|
|
16
|
+
// Initialize header component
|
|
17
|
+
this.headerComponent = null;
|
|
18
|
+
|
|
16
19
|
// Subscribe to state changes
|
|
17
20
|
this.unsubscribe = this.stateService.subscribe(this.handleStateChange.bind(this));
|
|
18
21
|
}
|
|
@@ -118,42 +121,8 @@ class DashboardPage {
|
|
|
118
121
|
async render() {
|
|
119
122
|
this.container.innerHTML = `
|
|
120
123
|
<div class="dashboard-page">
|
|
121
|
-
<!-- Page Header -->
|
|
122
|
-
<div
|
|
123
|
-
<div class="header-content">
|
|
124
|
-
<div class="header-left">
|
|
125
|
-
<div class="status-header">
|
|
126
|
-
<span class="session-timer-status-dot active" id="session-status-dot"></span>
|
|
127
|
-
<h1 class="page-title">
|
|
128
|
-
Claude Code Analytics Dashboard
|
|
129
|
-
<span class="version-badge">v1.10.1</span>
|
|
130
|
-
</h1>
|
|
131
|
-
</div>
|
|
132
|
-
<div class="page-subtitle">
|
|
133
|
-
Real-time monitoring and analytics for Claude Code sessions
|
|
134
|
-
</div>
|
|
135
|
-
<div class="last-update-header">
|
|
136
|
-
<span class="last-update-label">last update:</span>
|
|
137
|
-
<span id="last-update-header-text">Never</span>
|
|
138
|
-
</div>
|
|
139
|
-
</div>
|
|
140
|
-
<div class="header-right">
|
|
141
|
-
<div class="theme-switch-container" title="Toggle light/dark theme">
|
|
142
|
-
<div class="theme-switch" id="header-theme-switch">
|
|
143
|
-
<div class="theme-switch-track">
|
|
144
|
-
<div class="theme-switch-thumb" id="header-theme-switch-thumb">
|
|
145
|
-
<span class="theme-switch-icon">🌙</span>
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
|
-
<a href="https://github.com/anthropics/claude-code-templates" target="_blank" class="github-link" title="Star on GitHub">
|
|
151
|
-
<span class="github-icon">⭐</span>
|
|
152
|
-
Star on GitHub
|
|
153
|
-
</a>
|
|
154
|
-
</div>
|
|
155
|
-
</div>
|
|
156
|
-
</div>
|
|
124
|
+
<!-- Page Header (will be replaced by HeaderComponent) -->
|
|
125
|
+
<div id="dashboard-header-container"></div>
|
|
157
126
|
|
|
158
127
|
<!-- Action Buttons -->
|
|
159
128
|
<div class="action-buttons-container">
|
|
@@ -394,7 +363,28 @@ class DashboardPage {
|
|
|
394
363
|
`;
|
|
395
364
|
|
|
396
365
|
this.bindEvents();
|
|
397
|
-
this.
|
|
366
|
+
this.initializeHeaderComponent();
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Initialize the header component
|
|
371
|
+
*/
|
|
372
|
+
initializeHeaderComponent() {
|
|
373
|
+
const headerContainer = this.container.querySelector('#dashboard-header-container');
|
|
374
|
+
if (headerContainer && typeof HeaderComponent !== 'undefined') {
|
|
375
|
+
this.headerComponent = new HeaderComponent(headerContainer, {
|
|
376
|
+
title: 'Claude Code Analytics Dashboard',
|
|
377
|
+
subtitle: 'Real-time monitoring and analytics for Claude Code sessions',
|
|
378
|
+
version: 'v1.13.2', // Fallback version
|
|
379
|
+
showVersionBadge: true,
|
|
380
|
+
showLastUpdate: true,
|
|
381
|
+
showThemeSwitch: true,
|
|
382
|
+
showGitHubLink: true,
|
|
383
|
+
dataService: this.dataService // Pass DataService for dynamic version loading
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
this.headerComponent.render();
|
|
387
|
+
}
|
|
398
388
|
}
|
|
399
389
|
|
|
400
390
|
/**
|
|
@@ -884,11 +874,6 @@ class DashboardPage {
|
|
|
884
874
|
retryBtn.addEventListener('click', () => this.loadInitialData());
|
|
885
875
|
}
|
|
886
876
|
|
|
887
|
-
// Theme toggle (header)
|
|
888
|
-
const headerThemeSwitch = this.container.querySelector('#header-theme-switch');
|
|
889
|
-
if (headerThemeSwitch) {
|
|
890
|
-
headerThemeSwitch.addEventListener('click', () => this.toggleTheme());
|
|
891
|
-
}
|
|
892
877
|
}
|
|
893
878
|
|
|
894
879
|
/**
|
|
@@ -2105,74 +2090,13 @@ class DashboardPage {
|
|
|
2105
2090
|
}
|
|
2106
2091
|
}
|
|
2107
2092
|
|
|
2108
|
-
/**
|
|
2109
|
-
* Initialize theme from localStorage
|
|
2110
|
-
*/
|
|
2111
|
-
initializeTheme() {
|
|
2112
|
-
const savedTheme = localStorage.getItem('claude-analytics-theme') || 'dark';
|
|
2113
|
-
const body = document.body;
|
|
2114
|
-
const headerThumb = this.container.querySelector('#header-theme-switch-thumb');
|
|
2115
|
-
const headerIcon = headerThumb?.querySelector('.theme-switch-icon');
|
|
2116
|
-
|
|
2117
|
-
body.setAttribute('data-theme', savedTheme);
|
|
2118
|
-
if (headerThumb && headerIcon) {
|
|
2119
|
-
if (savedTheme === 'light') {
|
|
2120
|
-
headerThumb.classList.add('light');
|
|
2121
|
-
headerIcon.textContent = '☀️';
|
|
2122
|
-
} else {
|
|
2123
|
-
headerThumb.classList.remove('light');
|
|
2124
|
-
headerIcon.textContent = '🌙';
|
|
2125
|
-
}
|
|
2126
|
-
}
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
|
-
/**
|
|
2130
|
-
* Toggle theme between light and dark
|
|
2131
|
-
*/
|
|
2132
|
-
toggleTheme() {
|
|
2133
|
-
const body = document.body;
|
|
2134
|
-
const headerThumb = this.container.querySelector('#header-theme-switch-thumb');
|
|
2135
|
-
const headerIcon = headerThumb?.querySelector('.theme-switch-icon');
|
|
2136
|
-
|
|
2137
|
-
// Also sync with global theme switch
|
|
2138
|
-
const globalThumb = document.getElementById('themeSwitchThumb');
|
|
2139
|
-
const globalIcon = globalThumb?.querySelector('.theme-switch-icon');
|
|
2140
|
-
|
|
2141
|
-
const isLight = body.getAttribute('data-theme') === 'light';
|
|
2142
|
-
const newTheme = isLight ? 'dark' : 'light';
|
|
2143
|
-
|
|
2144
|
-
body.setAttribute('data-theme', newTheme);
|
|
2145
|
-
|
|
2146
|
-
// Update header theme switch
|
|
2147
|
-
if (headerThumb && headerIcon) {
|
|
2148
|
-
headerThumb.classList.toggle('light', newTheme === 'light');
|
|
2149
|
-
headerIcon.textContent = newTheme === 'light' ? '☀️' : '🌙';
|
|
2150
|
-
}
|
|
2151
|
-
|
|
2152
|
-
// Sync with global theme switch
|
|
2153
|
-
if (globalThumb && globalIcon) {
|
|
2154
|
-
globalThumb.classList.toggle('light', newTheme === 'light');
|
|
2155
|
-
globalIcon.textContent = newTheme === 'light' ? '☀️' : '🌙';
|
|
2156
|
-
}
|
|
2157
|
-
|
|
2158
|
-
localStorage.setItem('claude-analytics-theme', newTheme);
|
|
2159
|
-
}
|
|
2160
2093
|
|
|
2161
2094
|
/**
|
|
2162
2095
|
* Update last update time
|
|
2163
2096
|
*/
|
|
2164
2097
|
updateLastUpdateTime() {
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
// Update both locations
|
|
2168
|
-
const lastUpdateText = this.container.querySelector('#last-update-text');
|
|
2169
|
-
const lastUpdateHeaderText = this.container.querySelector('#last-update-header-text');
|
|
2170
|
-
|
|
2171
|
-
if (lastUpdateText) {
|
|
2172
|
-
lastUpdateText.textContent = currentTime;
|
|
2173
|
-
}
|
|
2174
|
-
if (lastUpdateHeaderText) {
|
|
2175
|
-
lastUpdateHeaderText.textContent = currentTime;
|
|
2098
|
+
if (this.headerComponent) {
|
|
2099
|
+
this.headerComponent.updateLastUpdateTime();
|
|
2176
2100
|
}
|
|
2177
2101
|
}
|
|
2178
2102
|
|
|
@@ -2252,6 +2176,12 @@ class DashboardPage {
|
|
|
2252
2176
|
destroy() {
|
|
2253
2177
|
this.stopPeriodicRefresh();
|
|
2254
2178
|
|
|
2179
|
+
// Cleanup header component
|
|
2180
|
+
if (this.headerComponent) {
|
|
2181
|
+
this.headerComponent.destroy();
|
|
2182
|
+
this.headerComponent = null;
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2255
2185
|
// Cleanup Chart.js instances specifically
|
|
2256
2186
|
if (this.components.tokenChart) {
|
|
2257
2187
|
this.components.tokenChart.destroy();
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HeaderComponent - Unified header for all analytics pages
|
|
3
|
+
* Provides consistent branding, navigation, and controls across the application
|
|
4
|
+
*/
|
|
5
|
+
class HeaderComponent {
|
|
6
|
+
constructor(container, options = {}) {
|
|
7
|
+
this.container = container;
|
|
8
|
+
this.options = {
|
|
9
|
+
title: options.title || 'Claude Code Analytics Dashboard',
|
|
10
|
+
subtitle: options.subtitle || 'Real-time monitoring and analytics for Claude Code sessions',
|
|
11
|
+
showVersionBadge: options.showVersionBadge !== false,
|
|
12
|
+
showLastUpdate: options.showLastUpdate !== false,
|
|
13
|
+
showThemeSwitch: options.showThemeSwitch !== false,
|
|
14
|
+
showGitHubLink: options.showGitHubLink !== false,
|
|
15
|
+
version: options.version || 'v1.13.2', // Default fallback
|
|
16
|
+
customActions: options.customActions || [],
|
|
17
|
+
dataService: options.dataService || null, // DataService for dynamic version loading
|
|
18
|
+
...options
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
this.lastUpdateTime = null;
|
|
22
|
+
this.updateInterval = null;
|
|
23
|
+
this.actualVersion = this.options.version; // Will be updated dynamically
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Render the header component
|
|
28
|
+
*/
|
|
29
|
+
render() {
|
|
30
|
+
const headerHTML = `
|
|
31
|
+
<div class="page-header">
|
|
32
|
+
<div class="header-content">
|
|
33
|
+
<div class="header-left">
|
|
34
|
+
<div class="status-header">
|
|
35
|
+
<span class="session-timer-status-dot active" id="session-status-dot"></span>
|
|
36
|
+
<h1 class="page-title">
|
|
37
|
+
${this.options.title}
|
|
38
|
+
${this.options.showVersionBadge ? `<span class="version-badge" id="version-badge">${this.actualVersion}</span>` : ''}
|
|
39
|
+
</h1>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="page-subtitle">
|
|
42
|
+
${this.options.subtitle}
|
|
43
|
+
</div>
|
|
44
|
+
${this.options.showLastUpdate ? `
|
|
45
|
+
<div class="last-update-header">
|
|
46
|
+
<span class="last-update-label">last update:</span>
|
|
47
|
+
<span id="last-update-header-text">Never</span>
|
|
48
|
+
</div>
|
|
49
|
+
` : ''}
|
|
50
|
+
</div>
|
|
51
|
+
<div class="header-right">
|
|
52
|
+
${this.options.showThemeSwitch ? `
|
|
53
|
+
<div class="theme-switch-container" title="Toggle light/dark theme">
|
|
54
|
+
<div class="theme-switch" id="header-theme-switch">
|
|
55
|
+
<div class="theme-switch-track">
|
|
56
|
+
<div class="theme-switch-thumb" id="header-theme-switch-thumb">
|
|
57
|
+
<span class="theme-switch-icon">🌙</span>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
` : ''}
|
|
63
|
+
${this.options.showGitHubLink ? `
|
|
64
|
+
<a href="https://github.com/davila7/claude-code-templates" target="_blank" class="github-link" title="Star on GitHub">
|
|
65
|
+
<span class="github-icon">⭐</span>
|
|
66
|
+
Star on GitHub
|
|
67
|
+
</a>
|
|
68
|
+
` : ''}
|
|
69
|
+
${this.renderCustomActions()}
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
this.container.innerHTML = headerHTML;
|
|
76
|
+
this.bindEvents();
|
|
77
|
+
this.initializeTheme();
|
|
78
|
+
|
|
79
|
+
if (this.options.showLastUpdate) {
|
|
80
|
+
this.updateLastUpdateTime();
|
|
81
|
+
this.startUpdateInterval();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Load version dynamically if DataService is available
|
|
85
|
+
if (this.options.dataService) {
|
|
86
|
+
this.loadVersion();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Render custom actions in header
|
|
92
|
+
*/
|
|
93
|
+
renderCustomActions() {
|
|
94
|
+
if (!this.options.customActions || this.options.customActions.length === 0) {
|
|
95
|
+
return '';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return this.options.customActions.map(action => `
|
|
99
|
+
<button class="header-action-btn" id="${action.id}" title="${action.title || action.label}">
|
|
100
|
+
${action.icon ? `<span class="btn-icon">${action.icon}</span>` : ''}
|
|
101
|
+
${action.label}
|
|
102
|
+
</button>
|
|
103
|
+
`).join('');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Bind event listeners
|
|
108
|
+
*/
|
|
109
|
+
bindEvents() {
|
|
110
|
+
// Theme toggle
|
|
111
|
+
if (this.options.showThemeSwitch) {
|
|
112
|
+
const themeSwitch = this.container.querySelector('#header-theme-switch');
|
|
113
|
+
if (themeSwitch) {
|
|
114
|
+
themeSwitch.addEventListener('click', () => this.toggleTheme());
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Custom action handlers
|
|
119
|
+
this.options.customActions.forEach(action => {
|
|
120
|
+
const btn = this.container.querySelector(`#${action.id}`);
|
|
121
|
+
if (btn && action.handler) {
|
|
122
|
+
btn.addEventListener('click', action.handler);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Initialize theme from localStorage
|
|
129
|
+
*/
|
|
130
|
+
initializeTheme() {
|
|
131
|
+
if (!this.options.showThemeSwitch) return;
|
|
132
|
+
|
|
133
|
+
const savedTheme = localStorage.getItem('claude-analytics-theme') || 'dark';
|
|
134
|
+
const body = document.body;
|
|
135
|
+
const headerThumb = this.container.querySelector('#header-theme-switch-thumb');
|
|
136
|
+
const headerIcon = headerThumb?.querySelector('.theme-switch-icon');
|
|
137
|
+
|
|
138
|
+
body.setAttribute('data-theme', savedTheme);
|
|
139
|
+
if (headerThumb && headerIcon) {
|
|
140
|
+
if (savedTheme === 'light') {
|
|
141
|
+
headerThumb.classList.add('light');
|
|
142
|
+
headerIcon.textContent = '☀️';
|
|
143
|
+
} else {
|
|
144
|
+
headerThumb.classList.remove('light');
|
|
145
|
+
headerIcon.textContent = '🌙';
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Toggle theme between light and dark
|
|
152
|
+
*/
|
|
153
|
+
toggleTheme() {
|
|
154
|
+
const body = document.body;
|
|
155
|
+
const headerThumb = this.container.querySelector('#header-theme-switch-thumb');
|
|
156
|
+
const headerIcon = headerThumb?.querySelector('.theme-switch-icon');
|
|
157
|
+
|
|
158
|
+
// Also sync with global theme switch if exists
|
|
159
|
+
const globalThumb = document.getElementById('themeSwitchThumb');
|
|
160
|
+
const globalIcon = globalThumb?.querySelector('.theme-switch-icon');
|
|
161
|
+
|
|
162
|
+
const isLight = body.getAttribute('data-theme') === 'light';
|
|
163
|
+
const newTheme = isLight ? 'dark' : 'light';
|
|
164
|
+
|
|
165
|
+
body.setAttribute('data-theme', newTheme);
|
|
166
|
+
|
|
167
|
+
// Update header theme switch
|
|
168
|
+
if (headerThumb && headerIcon) {
|
|
169
|
+
headerThumb.classList.toggle('light', newTheme === 'light');
|
|
170
|
+
headerIcon.textContent = newTheme === 'light' ? '☀️' : '🌙';
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Sync with global theme switch
|
|
174
|
+
if (globalThumb && globalIcon) {
|
|
175
|
+
globalThumb.classList.toggle('light', newTheme === 'light');
|
|
176
|
+
globalIcon.textContent = newTheme === 'light' ? '☀️' : '🌙';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
localStorage.setItem('claude-analytics-theme', newTheme);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Update last update time
|
|
184
|
+
*/
|
|
185
|
+
updateLastUpdateTime() {
|
|
186
|
+
if (!this.options.showLastUpdate) return;
|
|
187
|
+
|
|
188
|
+
const currentTime = new Date().toLocaleTimeString();
|
|
189
|
+
const lastUpdateText = this.container.querySelector('#last-update-header-text');
|
|
190
|
+
|
|
191
|
+
if (lastUpdateText) {
|
|
192
|
+
lastUpdateText.textContent = currentTime;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
this.lastUpdateTime = currentTime;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Start periodic update of timestamp
|
|
200
|
+
*/
|
|
201
|
+
startUpdateInterval() {
|
|
202
|
+
if (this.updateInterval) {
|
|
203
|
+
clearInterval(this.updateInterval);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Update every 30 seconds
|
|
207
|
+
this.updateInterval = setInterval(() => {
|
|
208
|
+
this.updateLastUpdateTime();
|
|
209
|
+
}, 30000);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Stop update interval
|
|
214
|
+
*/
|
|
215
|
+
stopUpdateInterval() {
|
|
216
|
+
if (this.updateInterval) {
|
|
217
|
+
clearInterval(this.updateInterval);
|
|
218
|
+
this.updateInterval = null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Load version dynamically from backend
|
|
224
|
+
*/
|
|
225
|
+
async loadVersion() {
|
|
226
|
+
if (!this.options.dataService) return;
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
const versionData = await this.options.dataService.getVersion();
|
|
230
|
+
if (versionData && versionData.version) {
|
|
231
|
+
this.actualVersion = `v${versionData.version}`;
|
|
232
|
+
this.updateVersionBadge();
|
|
233
|
+
}
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.error('Error loading version:', error);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Update version badge in the DOM
|
|
241
|
+
*/
|
|
242
|
+
updateVersionBadge() {
|
|
243
|
+
const versionBadge = this.container.querySelector('#version-badge');
|
|
244
|
+
if (versionBadge) {
|
|
245
|
+
versionBadge.textContent = this.actualVersion;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Update header title
|
|
251
|
+
* @param {string} title - New title
|
|
252
|
+
*/
|
|
253
|
+
updateTitle(title) {
|
|
254
|
+
this.options.title = title;
|
|
255
|
+
const titleElement = this.container.querySelector('.page-title');
|
|
256
|
+
if (titleElement) {
|
|
257
|
+
titleElement.innerHTML = `
|
|
258
|
+
${title}
|
|
259
|
+
${this.options.showVersionBadge ? `<span class="version-badge" id="version-badge">${this.actualVersion}</span>` : ''}
|
|
260
|
+
`;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Update header subtitle
|
|
266
|
+
* @param {string} subtitle - New subtitle
|
|
267
|
+
*/
|
|
268
|
+
updateSubtitle(subtitle) {
|
|
269
|
+
this.options.subtitle = subtitle;
|
|
270
|
+
const subtitleElement = this.container.querySelector('.page-subtitle');
|
|
271
|
+
if (subtitleElement) {
|
|
272
|
+
subtitleElement.textContent = subtitle;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Update status dot state
|
|
278
|
+
* @param {boolean} active - Whether status should be active
|
|
279
|
+
*/
|
|
280
|
+
updateStatusDot(active) {
|
|
281
|
+
const statusDot = this.container.querySelector('#session-status-dot');
|
|
282
|
+
if (statusDot) {
|
|
283
|
+
statusDot.classList.toggle('active', active);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Get current theme
|
|
289
|
+
* @returns {string} Current theme ('light' or 'dark')
|
|
290
|
+
*/
|
|
291
|
+
getCurrentTheme() {
|
|
292
|
+
return document.body.getAttribute('data-theme') || 'dark';
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Destroy header component
|
|
297
|
+
*/
|
|
298
|
+
destroy() {
|
|
299
|
+
this.stopUpdateInterval();
|
|
300
|
+
this.container.innerHTML = '';
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Export for module use
|
|
305
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
306
|
+
module.exports = HeaderComponent;
|
|
307
|
+
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
<script src="services/StateService.js"></script>
|
|
13
13
|
|
|
14
14
|
<!-- Component Scripts -->
|
|
15
|
+
<script src="components/HeaderComponent.js"></script>
|
|
15
16
|
<script src="components/Charts.js"></script>
|
|
16
17
|
<!-- Dashboard.js removed - deprecated architecture -->
|
|
17
18
|
<script src="components/SessionTimer.js"></script>
|
|
@@ -2644,6 +2645,7 @@
|
|
|
2644
2645
|
flex: 1;
|
|
2645
2646
|
display: flex;
|
|
2646
2647
|
flex-direction: column;
|
|
2648
|
+
margin-left: 56px;
|
|
2647
2649
|
transition: margin-left 0.3s ease;
|
|
2648
2650
|
}
|
|
2649
2651
|
|
|
@@ -2662,7 +2664,9 @@
|
|
|
2662
2664
|
display: flex;
|
|
2663
2665
|
flex-direction: column;
|
|
2664
2666
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
2665
|
-
position:
|
|
2667
|
+
position: fixed;
|
|
2668
|
+
top: 0;
|
|
2669
|
+
left: 0;
|
|
2666
2670
|
z-index: 1000;
|
|
2667
2671
|
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
|
|
2668
2672
|
overflow: visible;
|
|
@@ -2673,6 +2677,10 @@
|
|
|
2673
2677
|
background: var(--bg-secondary);
|
|
2674
2678
|
border-right: 1px solid var(--text-accent);
|
|
2675
2679
|
box-shadow: 4px 0 16px rgba(213, 116, 85, 0.1);
|
|
2680
|
+
position: fixed;
|
|
2681
|
+
top: 0;
|
|
2682
|
+
left: 0;
|
|
2683
|
+
height: 100vh;
|
|
2676
2684
|
}
|
|
2677
2685
|
|
|
2678
2686
|
.sidebar-header {
|
|
@@ -4616,32 +4624,7 @@
|
|
|
4616
4624
|
margin: 0 auto;
|
|
4617
4625
|
}
|
|
4618
4626
|
|
|
4619
|
-
/* App Layout Styles (App.js + Sidebar.js) */
|
|
4620
|
-
.app {
|
|
4621
|
-
display: flex;
|
|
4622
|
-
min-height: 100vh;
|
|
4623
|
-
background: var(--bg-primary);
|
|
4624
|
-
}
|
|
4625
|
-
|
|
4626
|
-
.app-sidebar {
|
|
4627
|
-
width: 60px;
|
|
4628
|
-
background: var(--bg-secondary);
|
|
4629
|
-
border-right: 1px solid var(--border-primary);
|
|
4630
|
-
transition: width 0.3s ease;
|
|
4631
|
-
}
|
|
4632
|
-
|
|
4633
|
-
.app-main {
|
|
4634
|
-
flex: 1;
|
|
4635
|
-
display: flex;
|
|
4636
|
-
flex-direction: column;
|
|
4637
|
-
min-width: 0;
|
|
4638
|
-
}
|
|
4639
|
-
|
|
4640
|
-
.app-content {
|
|
4641
|
-
flex: 1;
|
|
4642
|
-
padding: 20px;
|
|
4643
|
-
overflow-y: auto;
|
|
4644
|
-
}
|
|
4627
|
+
/* App Layout Styles (App.js + Sidebar.js) - Duplicates removed, using definitions above */
|
|
4645
4628
|
|
|
4646
4629
|
/* Metrics Section */
|
|
4647
4630
|
.metrics-section {
|
|
@@ -409,6 +409,19 @@ class DataService {
|
|
|
409
409
|
this.setupWebSocketIntegration();
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
+
/**
|
|
413
|
+
* Get application version from backend
|
|
414
|
+
* @returns {Promise<Object>} Version information
|
|
415
|
+
*/
|
|
416
|
+
async getVersion() {
|
|
417
|
+
try {
|
|
418
|
+
return await this.cachedFetch('/api/version', 300000); // Cache for 5 minutes
|
|
419
|
+
} catch (error) {
|
|
420
|
+
console.error('Error fetching version:', error);
|
|
421
|
+
return { version: '1.13.2', name: 'claude-code-templates' }; // Fallback
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
412
425
|
/**
|
|
413
426
|
* Get cache statistics
|
|
414
427
|
* @returns {Object} Cache statistics
|
package/src/health-check.js
CHANGED
|
@@ -394,58 +394,62 @@ class HealthChecker {
|
|
|
394
394
|
}
|
|
395
395
|
|
|
396
396
|
checkAuthentication() {
|
|
397
|
+
const homeDir = os.homedir();
|
|
398
|
+
|
|
399
|
+
// Check for Claude Code OAuth authentication in ~/.claude.json
|
|
400
|
+
const claudeJsonPath = path.join(homeDir, '.claude.json');
|
|
401
|
+
|
|
397
402
|
try {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
403
|
+
if (fs.existsSync(claudeJsonPath)) {
|
|
404
|
+
const claudeConfig = JSON.parse(fs.readFileSync(claudeJsonPath, 'utf8'));
|
|
405
|
+
|
|
406
|
+
// Check for OAuth authentication
|
|
407
|
+
if (claudeConfig.oauthAccount && claudeConfig.oauthAccount.accountUuid) {
|
|
408
|
+
const email = claudeConfig.oauthAccount.emailAddress || 'OAuth user';
|
|
409
|
+
return {
|
|
410
|
+
status: 'pass',
|
|
411
|
+
message: `Authenticated via OAuth (${email})`
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Check for API key authentication
|
|
416
|
+
if (claudeConfig.apiKey) {
|
|
417
|
+
return {
|
|
418
|
+
status: 'pass',
|
|
419
|
+
message: 'Authenticated via API key'
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
}
|
|
404
423
|
|
|
405
|
-
|
|
424
|
+
// Check for environment variable API key
|
|
425
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
406
426
|
return {
|
|
407
427
|
status: 'pass',
|
|
408
|
-
message: 'Authenticated
|
|
428
|
+
message: 'Authenticated via ANTHROPIC_API_KEY environment variable'
|
|
409
429
|
};
|
|
410
430
|
}
|
|
411
431
|
|
|
412
|
-
//
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
for (const authPath of possibleAuthPaths) {
|
|
431
|
-
if (fs.existsSync(authPath)) {
|
|
432
|
-
try {
|
|
433
|
-
const stats = fs.statSync(authPath);
|
|
434
|
-
// Check if file was modified recently (within last 30 days)
|
|
435
|
-
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
|
436
|
-
if (stats.mtime > thirtyDaysAgo) {
|
|
437
|
-
return {
|
|
438
|
-
status: 'pass',
|
|
439
|
-
message: 'Authentication session found'
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
} catch (statError) {
|
|
443
|
-
// Continue to next path
|
|
444
|
-
}
|
|
445
|
-
}
|
|
432
|
+
// Try to check if we can make a simple claude command
|
|
433
|
+
try {
|
|
434
|
+
execSync('claude --version', {
|
|
435
|
+
encoding: 'utf8',
|
|
436
|
+
stdio: 'pipe',
|
|
437
|
+
timeout: 3000
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
status: 'warn',
|
|
442
|
+
message: 'Claude CLI available but authentication not configured'
|
|
443
|
+
};
|
|
444
|
+
} catch (cliError) {
|
|
445
|
+
return {
|
|
446
|
+
status: 'fail',
|
|
447
|
+
message: 'Claude CLI not available or not authenticated'
|
|
448
|
+
};
|
|
446
449
|
}
|
|
447
450
|
|
|
448
|
-
|
|
451
|
+
} catch (error) {
|
|
452
|
+
// If we can't read the config file, check if CLI is at least installed
|
|
449
453
|
try {
|
|
450
454
|
execSync('claude --version', {
|
|
451
455
|
encoding: 'utf8',
|
|
@@ -460,7 +464,7 @@ class HealthChecker {
|
|
|
460
464
|
} catch (cliError) {
|
|
461
465
|
return {
|
|
462
466
|
status: 'fail',
|
|
463
|
-
message: 'Claude CLI not available or
|
|
467
|
+
message: 'Claude CLI not available or authentication check failed'
|
|
464
468
|
};
|
|
465
469
|
}
|
|
466
470
|
}
|