Add SEO fields to Tasks model, improve content generation response handling, and enhance progress bar animation

- Added primary_keyword, secondary_keywords, tags, and categories fields to Tasks model
- Updated generate_content function to handle full JSON response with all SEO fields
- Improved progress bar animation: smooth 1% increments every 300ms
- Enhanced step detection for content generation vs clustering vs ideas
- Fixed progress modal to show correct messages for each function type
- Added comprehensive logging to Keywords and Tasks pages for AI functions
- Fixed error handling to show meaningful error messages instead of generic failures
This commit is contained in:
Gitea Deploy
2025-11-09 21:22:34 +00:00
parent 09d22ab0e2
commit 961362e088
17340 changed files with 10636 additions and 2248776 deletions

View File

@@ -32,14 +32,15 @@ const LayoutContent: React.FC = () => {
trackLoading('site-loading', true);
// Add timeout to prevent infinite loading
// Match API timeout (30s) + buffer for network delays
const timeoutId = setTimeout(() => {
if (isLoadingSite.current) {
console.error('AppLayout: Site loading timeout after 10 seconds');
console.error('AppLayout: Site loading timeout after 35 seconds');
trackLoading('site-loading', false);
isLoadingSite.current = false;
addError(new Error('Site loading timeout - check network connection'), 'AppLayout.loadActiveSite');
}
}, 10000);
}, 35000); // 35 seconds to match API timeout (30s) + buffer
loadActiveSite()
.catch((error) => {
@@ -69,14 +70,15 @@ const LayoutContent: React.FC = () => {
trackLoading('sector-loading', true);
// Add timeout to prevent infinite loading
// Match API timeout (30s) + buffer for network delays
const timeoutId = setTimeout(() => {
if (isLoadingSector.current) {
console.error('AppLayout: Sector loading timeout after 10 seconds');
console.error('AppLayout: Sector loading timeout after 35 seconds');
trackLoading('sector-loading', false);
isLoadingSector.current = false;
addError(new Error('Sector loading timeout - check network connection'), 'AppLayout.loadSectorsForSite');
}
}, 10000);
}, 35000); // 35 seconds to match API timeout (30s) + buffer
loadSectorsForSite(currentSiteId)
.catch((error) => {
@@ -99,27 +101,42 @@ const LayoutContent: React.FC = () => {
}
}, [activeSite?.id, activeSite?.is_active]); // Depend on both ID and is_active
// Refresh user data on mount and periodically to get latest account/plan changes
// Refresh user data on mount and when app version changes (after code updates)
// This ensures changes are reflected immediately without requiring re-login
useEffect(() => {
if (!isAuthenticated) return;
const refreshUserData = async () => {
const APP_VERSION = import.meta.env.VITE_APP_VERSION || '2.0.2';
const VERSION_STORAGE_KEY = 'igny8-app-version';
const refreshUserData = async (force = false) => {
const now = Date.now();
// Throttle: only refresh if last refresh was more than 30 seconds ago
if (now - lastUserRefresh.current < 30000) return;
// Throttle: only refresh if last refresh was more than 30 seconds ago (unless forced)
if (!force && now - lastUserRefresh.current < 30000) return;
try {
lastUserRefresh.current = now;
await refreshUser();
// Store current version after successful refresh
if (force) {
localStorage.setItem(VERSION_STORAGE_KEY, APP_VERSION);
}
} catch (error) {
// Silently fail - user might still be authenticated
console.debug('User data refresh failed (non-critical):', error);
}
};
// Refresh on mount
refreshUserData();
// Check if app version changed (indicates code update)
const storedVersion = localStorage.getItem(VERSION_STORAGE_KEY);
if (storedVersion !== APP_VERSION) {
// Force refresh on version change
refreshUserData(true);
} else {
// Normal refresh on mount
refreshUserData();
}
// Refresh when window becomes visible (user switches back to tab)
const handleVisibilityChange = () => {
@@ -134,7 +151,7 @@ const LayoutContent: React.FC = () => {
};
// Periodic refresh every 2 minutes
const intervalId = setInterval(refreshUserData, 120000);
const intervalId = setInterval(() => refreshUserData(), 120000);
document.addEventListener('visibilitychange', handleVisibilityChange);
window.addEventListener('focus', handleFocus);