Fix Aktivitätenstatus

Dieser Commit ist enthalten in:
Claude Project Manager
2025-07-08 10:33:20 +02:00
Ursprung 995682b6da
Commit d1667f9e0d
5 geänderte Dateien mit 196 neuen und 48 gelöschten Zeilen

Datei anzeigen

@ -5,9 +5,9 @@
## Project Overview
- **Path**: `C:/Users/hendr/Desktop/IntelSight/ClaudeProjectManager-main`
- **Files**: 220 files
- **Size**: 76.9 MB
- **Last Modified**: 2025-07-07 22:34
- **Files**: 227 files
- **Size**: 77.0 MB
- **Last Modified**: 2025-07-08 08:19
## Technology Stack
@ -196,3 +196,4 @@ This project is managed with Claude Project Manager. To work with this project:
- README updated on 2025-07-07 21:50:23
- README updated on 2025-07-07 22:12:28
- README updated on 2025-07-07 22:34:45
- README updated on 2025-07-08 08:19:16

Datei anzeigen

@ -51,12 +51,12 @@
"name": "ClaudeProjectManager-main",
"path": "C:/Users/hendr/Desktop/IntelSight/ClaudeProjectManager-main",
"created_at": "2025-07-07T21:38:23.820122",
"last_accessed": "2025-07-07T22:34:45.602409",
"last_accessed": "2025-07-08T08:19:16.600227",
"readme_path": "C:/Users/hendr/Desktop/IntelSight/ClaudeProjectManager-main\\CLAUDE_PROJECT_README.md",
"description": "",
"tags": [],
"gitea_repo": null
}
],
"last_updated": "2025-07-07T22:34:45.602409"
"last_updated": "2025-07-08T08:19:16.600227"
}

Datei anzeigen

@ -2966,10 +2966,16 @@ class MainWindow:
def update_activity_status(self):
"""Periodic update of activity status"""
from services.activity_sync import activity_service
from utils.logger import logger
logger.debug("Periodic activity status update triggered")
if activity_service.connected:
# Update display with current activities
logger.debug(f"Updating activity display with {len(activity_service.activities)} activities")
self.update_activity_display(activity_service.activities)
else:
logger.debug("Activity service not connected, skipping update")
# Schedule next update
self.root.after(5000, self.update_activity_status) # Update every 5 seconds

Datei anzeigen

@ -25,7 +25,9 @@ class ProjectTile(ctk.CTkFrame):
width=TILE_SIZE['width'],
height=TILE_SIZE['height'],
fg_color=COLORS['bg_vps'] if is_vps else COLORS['bg_tile'],
corner_radius=10
corner_radius=10,
border_width=3,
border_color=COLORS['bg_vps'] if is_vps else COLORS['bg_tile']
)
self.project = project
@ -38,6 +40,9 @@ class ProjectTile(ctk.CTkFrame):
self.is_vps = is_vps
self.is_running = is_running
self.is_selected = False
self.activity_animation_id = None
self.activity_pulse_value = 0
self.has_team_activity = False
self.grid_propagate(False)
self.setup_ui()
@ -582,39 +587,52 @@ pause
def _start_activity(self):
"""Start activity for this project"""
# Use main_window reference if available
if hasattr(self, 'main_window') and self.main_window:
self.main_window.start_activity(self.project)
return
# Otherwise try to find in widget hierarchy
widget = self
while widget:
if hasattr(widget, 'start_activity'):
widget.start_activity(self.project)
return
widget = widget.master if hasattr(widget, 'master') else None
from services.activity_sync import activity_service
# If not found, log error
logger.error("Could not find start_activity method in widget hierarchy")
logger.info(f"Starting activity for project: {self.project.name}")
# Update UI optimistically immediately
self.update_activity_status(True, activity_service.user_name, True)
success = activity_service.start_activity(
self.project.name,
self.project.path,
self.project.description if hasattr(self.project, 'description') else ""
)
logger.info(f"Activity start result for {self.project.name}: success={success}")
if not success:
# Revert on failure
logger.error(f"Failed to start activity for {self.project.name}, reverting UI")
self.update_activity_status(False)
from tkinter import messagebox
messagebox.showerror(
"Fehler",
"Aktivität konnte nicht gestartet werden."
)
def _stop_activity(self):
"""Stop current activity"""
# Use main_window reference if available
if hasattr(self, 'main_window') and self.main_window:
self.main_window.stop_activity()
return
# Otherwise try to find in widget hierarchy
widget = self
while widget:
if hasattr(widget, 'stop_activity'):
widget.stop_activity()
return
widget = widget.master if hasattr(widget, 'master') else None
from services.activity_sync import activity_service
# If not found, log error
logger.error("Could not find stop_activity method in widget hierarchy")
logger.info(f"Stopping activity for project: {self.project.name}")
# Update UI optimistically immediately
self.update_activity_status(False)
success = activity_service.stop_activity()
logger.info(f"Activity stop result: success={success}")
if not success:
# Revert on failure - check if we're still the active project
current = activity_service.get_current_activity()
if current and current.get('projectName') == self.project.name:
logger.error(f"Failed to stop activity for {self.project.name}, reverting UI")
self.update_activity_status(True, activity_service.user_name, True)
else:
logger.error(f"Failed to stop activity, but no current activity found")
def _toggle_activity(self):
"""Toggle activity for this project"""
@ -653,7 +671,17 @@ pause
def update_activity_status(self, is_active: bool = False, user_name: str = None, is_own_activity: bool = False):
"""Update activity indicator on tile"""
logger.debug(f"update_activity_status called for {self.project.name}: is_active={is_active}, user_name={user_name}, is_own_activity={is_own_activity}")
if is_active:
# Start border animation for team activity
if not is_own_activity:
self.has_team_activity = True
self._start_activity_animation()
else:
self.has_team_activity = False
self._stop_activity_animation()
# Show indicator with appropriate color
if is_own_activity:
# Green for own activity
@ -680,6 +708,10 @@ pause
# Hide indicator
self.activity_indicator.pack_forget()
# Stop border animation
self.has_team_activity = False
self._stop_activity_animation()
# Update activity button if exists
if hasattr(self, 'activity_button'):
self.activity_button.configure(text="")
@ -725,7 +757,16 @@ pause
"""Check if this project has active users"""
from services.activity_sync import activity_service
# Get all activities for this project
logger.debug(f"check_activity called for project: {self.project.name}")
# First check if this is our own current activity
current_activity = activity_service.get_current_activity()
is_own_current = (current_activity and
current_activity.get('projectName') == self.project.name)
logger.debug(f"Current activity check - is_own_current: {is_own_current}, current_activity: {current_activity}")
# Get all activities for this project from server
active_users = []
is_own_activity = False
has_other_users = False
@ -740,13 +781,76 @@ pause
else:
has_other_users = True
logger.debug(f"Server activities - active_users: {active_users}, is_own_activity: {is_own_activity}, has_other_users: {has_other_users}")
# If we have a local current activity, ensure it's included
if is_own_current:
is_own_activity = True
if activity_service.user_name not in active_users:
active_users.append(activity_service.user_name)
logger.debug(f"Added local user to active_users: {activity_service.user_name}")
if active_users:
# Show indicator with all active users
user_text = ", ".join(active_users)
# If both own and others are active, show as others (orange) to indicate collaboration
self.update_activity_status(True, user_text, is_own_activity and not has_other_users)
final_is_own = is_own_activity and not has_other_users
logger.info(f"Updating activity status for {self.project.name}: active=True, users={user_text}, is_own={final_is_own}")
self.update_activity_status(True, user_text, final_is_own)
else:
logger.info(f"Updating activity status for {self.project.name}: active=False")
self.update_activity_status(False)
def _start_activity_animation(self):
"""Start animated border for team activity"""
if self.activity_animation_id:
return # Animation already running
def animate():
if not self.has_team_activity:
self.activity_animation_id = None
return
# Calculate pulsing color
self.activity_pulse_value = (self.activity_pulse_value + 5) % 100
pulse = abs(50 - self.activity_pulse_value) / 50 # 0 to 1 pulsing
# Interpolate between orange and a brighter orange
base_color = COLORS['accent_warning'] # Orange
bright_factor = 0.3 + (0.7 * pulse) # Pulse between 0.3 and 1.0 brightness
# Create pulsing border color
if base_color.startswith('#'):
# Convert hex to RGB, apply brightness, convert back
r = int(base_color[1:3], 16)
g = int(base_color[3:5], 16)
b = int(base_color[5:7], 16)
# Apply brightness
r = min(255, int(r + (255 - r) * (1 - bright_factor)))
g = min(255, int(g + (255 - g) * (1 - bright_factor)))
b = min(255, int(b + (255 - b) * (1 - bright_factor)))
pulse_color = f"#{r:02x}{g:02x}{b:02x}"
else:
pulse_color = base_color
self.configure(border_color=pulse_color)
# Continue animation
self.activity_animation_id = self.after(50, animate)
animate()
def _stop_activity_animation(self):
"""Stop animated border"""
if self.activity_animation_id:
self.after_cancel(self.activity_animation_id)
self.activity_animation_id = None
# Reset border to default
default_color = COLORS['bg_vps'] if self.is_vps else COLORS['bg_tile']
self.configure(border_color=default_color)
class AddProjectTile(ctk.CTkFrame):
"""Special tile for adding new projects"""

Datei anzeigen

@ -85,10 +85,23 @@ class ActivitySyncService:
@self.sio.event
def activities_update(data):
"""Handle activities update from server"""
self.activities = data
logger.debug(f"Received activities update: {len(data)} activities")
logger.debug(f"Received raw activities update: {len(data)} items")
# Filter out inactive entries and ensure we only keep active ones
active_activities = [
activity for activity in data
if activity.get('isActive', False)
]
# Log details about the activities
for activity in active_activities:
logger.debug(f"Active: {activity.get('userName')} on {activity.get('projectName')}")
self.activities = active_activities
logger.info(f"Activities update: {len(active_activities)} active (of {len(data)} total)")
if self.on_activities_update:
self.on_activities_update(data)
self.on_activities_update(active_activities)
@self.sio.event
def connect_error(data):
@ -131,36 +144,57 @@ class ActivitySyncService:
def start_activity(self, project_name: str, project_path: str, description: str = ""):
"""Start a new activity"""
logger.debug(f"start_activity called for: {project_name}")
if not self.connected or not self.sio:
logger.warning("Not connected to activity server")
return False
try:
# Set current activity immediately
self.current_activity = {
'projectName': project_name,
'projectPath': project_path,
'userId': self.user_id,
'userName': self.user_name,
'isActive': True
}
logger.debug(f"Set current_activity: {self.current_activity}")
# Emit to server
self.sio.emit('activity-start', {
'projectName': project_name,
'projectPath': project_path,
'description': description
})
self.current_activity = {
'projectName': project_name,
'projectPath': project_path
}
logger.info(f"Started activity for project: {project_name}")
return True
except Exception as e:
logger.error(f"Failed to start activity: {e}")
self.current_activity = None
return False
def stop_activity(self):
"""Stop the current activity"""
logger.debug(f"stop_activity called, current: {self.current_activity}")
if not self.connected or not self.sio:
logger.warning("Not connected to activity server")
return False
try:
self.sio.emit('activity-stop')
# Store project name for logging
project_name = self.current_activity.get('projectName') if self.current_activity else 'None'
# Clear current activity immediately
self.current_activity = None
logger.info("Stopped current activity")
logger.debug("Cleared current_activity")
# Emit to server
self.sio.emit('activity-stop')
logger.info(f"Stopped activity for project: {project_name}")
return True
except Exception as e:
logger.error(f"Failed to stop activity: {e}")
@ -179,7 +213,9 @@ class ActivitySyncService:
)
if response.status_code == 200:
data = response.json()
return data.get('activities', [])
all_activities = data.get('activities', [])
# Filter to only return active activities
return [a for a in all_activities if a.get('isActive', False)]
else:
logger.error(f"Failed to fetch activities: {response.status_code}")
return []
@ -204,17 +240,18 @@ class ActivitySyncService:
def get_current_activity(self) -> Optional[Dict]:
"""Get current user's activity"""
logger.debug(f"get_current_activity called, returning: {self.current_activity}")
return self.current_activity
def _fetch_initial_activities(self):
"""Fetch initial activities after connection"""
try:
activities = self.get_activities()
activities = self.get_activities() # Already filtered to only active
if activities:
self.activities = activities
if self.on_activities_update:
self.on_activities_update(activities)
logger.info(f"Fetched {len(activities)} initial activities")
logger.info(f"Fetched {len(activities)} active activities")
except Exception as e:
logger.error(f"Failed to fetch initial activities: {e}")