coderadar 0.1.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/bin/coderadar.js +2 -0
- package/dist/collector.d.ts +12 -0
- package/dist/collector.d.ts.map +1 -0
- package/dist/collector.js +253 -0
- package/dist/collector.js.map +1 -0
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +64 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/generate.d.ts +8 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +44 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +57 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/sync.d.ts +8 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +90 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +67 -0
- package/dist/index.js.map +1 -0
- package/dist/output/html-generator.d.ts +11 -0
- package/dist/output/html-generator.d.ts.map +1 -0
- package/dist/output/html-generator.js +106 -0
- package/dist/output/html-generator.js.map +1 -0
- package/package.json +61 -0
- package/templates/app.js +1294 -0
- package/templates/styles.css +489 -0
- package/templates/template.html +325 -0
package/templates/app.js
ADDED
|
@@ -0,0 +1,1294 @@
|
|
|
1
|
+
(function(){
|
|
2
|
+
'use strict';
|
|
3
|
+
var PROJECTS=%%DATA%%,LAST_SESSION=%%LAST_SESSION%%,RECENT_SESSIONS=%%RECENT_SESSIONS%%,INSIGHTS=%%INSIGHTS%%,SEARCH_INDEX=%%SEARCH_INDEX%%,GENERATED='%%TIMESTAMP%%',PC_NAME='%%PCNAME%%',STAT_TOTAL=%%TOTAL%%,STAT_ACTIVE=%%ACTIVE%%,STAT_UNDOC=%%UNDOC%%,STAT_DIRTY=%%DIRTY%%,STAT_COMMITS=%%COMMITS%%,STAT_HEALTH=%%HEALTH%%,STACK_STATS=%%STACKS%%,TIMELINE_DATA=%%TIMELINE%%,CHART_PROJECTS=%%CHART_PROJECTS%%,CHART_PROJECTS_TIME=%%CHART_PROJECTS_TIME%%,CHART_WEEKLY_LABELS=%%CHART_WEEKLY_LABELS%%,CHART_WEEKLY_VALUES=%%CHART_WEEKLY_VALUES%%,CHART_WEEKLY_HOURS=%%CHART_WEEKLY_HOURS%%,CHART_TAGS=%%CHART_TAGS%%,UNSYNCED_COUNT=%%UNSYNCED%%;
|
|
4
|
+
var PLUGINS=%%PLUGINS%%,PLUGIN_COUNTS=%%PLUGIN_COUNTS%%,MARKETPLACES=%%MARKETPLACES%%;
|
|
5
|
+
var COST_DAILY=%%COST_DAILY%%,COST_TOTALS=%%COST_TOTALS%%,COST_MODELS=%%COST_MODELS%%;
|
|
6
|
+
var COST_HOURLY=%%COST_HOURLY%%,LAST_MODEL='%%LAST_MODEL%%';
|
|
7
|
+
var DISK_SUMMARY=%%DISK_SUMMARY%%,DISK_PROJECTS=%%DISK_PROJECTS%%,DISK_DEV_PROJECTS=%%DISK_DEV_PROJECTS%%;
|
|
8
|
+
var STORE_KEY='coderadar-v3',store={};
|
|
9
|
+
var costChartsLazy=null,costChartsLazyDone=false,diskChartsLazy=null,diskChartsLazyDone=false;
|
|
10
|
+
var dashboardChartsInit=null;
|
|
11
|
+
try{store=JSON.parse(localStorage.getItem(STORE_KEY))||{}}catch(e){store={}}
|
|
12
|
+
function save(){localStorage.setItem(STORE_KEY,JSON.stringify(store))}
|
|
13
|
+
if(!store.favorites)store.favorites=[];
|
|
14
|
+
if(!store.projectNotes)store.projectNotes={};
|
|
15
|
+
if(!store.theme)store.theme=window.matchMedia&&window.matchMedia('(prefers-color-scheme:light)').matches?'light':'dark';
|
|
16
|
+
if(!store.prompts)store.prompts=[{id:gid(),name:'Continue',cmd:'Lis PROGRESS.md, implemente la prochaine tache.'},{id:gid(),name:'Audit',cmd:'Audit securite, perf, accessibilite. Priorise.'},{id:gid(),name:'Init',cmd:'Cree CLAUDE.md et PROGRESS.md.'},{id:gid(),name:'SQL AMOA',cmd:'/sql [objectif] sur [tables]'},{id:gid(),name:'PowerShell',cmd:'/powershell [tache]'}];
|
|
17
|
+
if(!store.links)store.links=[{id:gid(),name:'GitHub',url:'https://github.com',ico:'GH'},{id:gid(),name:'Claude',url:'https://claude.ai',ico:'AI'},{id:gid(),name:'Vercel',url:'https://vercel.com/dashboard',ico:'VL'}];
|
|
18
|
+
if(!store.notes)store.notes='';
|
|
19
|
+
save();
|
|
20
|
+
function applyTheme(){var isLight=store.theme==='light';document.documentElement.classList.toggle('light',isLight);document.getElementById('theme-icon-sun').style.display=isLight?'block':'none';document.getElementById('theme-icon-moon').style.display=isLight?'none':'block';document.getElementById('theme-color-meta').content=isLight?'#f8fafc':'#8b5cf6'}
|
|
21
|
+
applyTheme();
|
|
22
|
+
function gid(){return Date.now().toString(36)+Math.random().toString(36).slice(2,6)}
|
|
23
|
+
function toast(m){var c=document.getElementById('toasts'),t=document.createElement('div');t.className='toast';t.textContent=m;c.appendChild(t);setTimeout(function(){t.remove()},2000)}
|
|
24
|
+
function copy(t){navigator.clipboard.writeText(t).then(function(){toast('Copie!')}).catch(function(){toast('Copie!')})}
|
|
25
|
+
function downloadCSV(rows,filename){var csv=rows.map(function(r){return r.map(function(c){return '"'+(c+'').replace(/"/g,'""')+'"'}).join(',')}).join('\n');var b=new Blob(['\ufeff'+csv],{type:'text/csv;charset=utf-8'});var u=URL.createObjectURL(b);var a=document.createElement('a');a.href=u;a.download=filename;a.click();URL.revokeObjectURL(u);toast('CSV exporte')}
|
|
26
|
+
var compareSet=new Set();
|
|
27
|
+
function updateCompareFab(){var fab=document.getElementById('compare-fab'),cnt=document.getElementById('compare-count');if(fab){fab.style.display=compareSet.size>=2?'':'none'};if(cnt)cnt.textContent=compareSet.size}
|
|
28
|
+
function launchClaude(path,action){var a=action||'open';var url='claude-code://'+a+'?path='+encodeURIComponent(path);window.location.href=url;toast('Lancement Claude Code...')}
|
|
29
|
+
function claudeAction(e,path,action){if(e&&(e.ctrlKey||e.metaKey)){copy('cd "'+path+'" && claude --dangerously-skip-permissions'+(action==='resume'?' --resume':''));toast('Commande copiee (Ctrl+clic)')}else{launchClaude(path,action)}}
|
|
30
|
+
|
|
31
|
+
// ---- Plugin Catalog ----
|
|
32
|
+
var pluginTypeFilter='all',pluginMarketplaceFilter='all',pluginSearchQuery='';
|
|
33
|
+
function escH(s){if(!s)return '';return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"')}
|
|
34
|
+
function renderPlugins(){
|
|
35
|
+
var grid=document.getElementById('plugins-grid');if(!grid)return;
|
|
36
|
+
if(!PLUGINS||PLUGINS.length===0){grid.textContent='Aucun plugin installe';return}
|
|
37
|
+
var q=pluginSearchQuery.toLowerCase();
|
|
38
|
+
var filtered=PLUGINS.filter(function(p){
|
|
39
|
+
if(pluginTypeFilter==='active')return p.enabled;
|
|
40
|
+
if(pluginTypeFilter!=='all'&&p.type!==pluginTypeFilter)return false;
|
|
41
|
+
if(pluginMarketplaceFilter!=='all'&&p.marketplace!==pluginMarketplaceFilter)return false;
|
|
42
|
+
if(q){var hay=(p.name+' '+p.description+' '+p.shortName+' '+(p.author||'')+' '+(p.marketplace||'')).toLowerCase();if(hay.indexOf(q)===-1)return false}
|
|
43
|
+
return true;
|
|
44
|
+
});
|
|
45
|
+
if(filtered.length===0){grid.textContent='Aucun plugin ne correspond aux filtres';return}
|
|
46
|
+
// All data is server-generated at build time (not user input), escaped via escH
|
|
47
|
+
var html='';
|
|
48
|
+
filtered.forEach(function(p){
|
|
49
|
+
var cls='pl-card'+(p.enabled?'':' disabled');
|
|
50
|
+
var badges='';
|
|
51
|
+
if(p.commands&&p.commands.length)badges+='<span class="pl-badge">'+p.commands.length+' cmd</span>';
|
|
52
|
+
if(p.agents&&p.agents.length)badges+='<span class="pl-badge">'+p.agents.length+' agent</span>';
|
|
53
|
+
if(p.skills&&p.skills.length)badges+='<span class="pl-badge">'+p.skills.length+' skill</span>';
|
|
54
|
+
if(p.hasMcp)badges+='<span class="pl-badge highlight">MCP</span>';
|
|
55
|
+
if(p.hasHooks)badges+='<span class="pl-badge highlight">Hooks</span>';
|
|
56
|
+
var pidx=PLUGINS.indexOf(p);
|
|
57
|
+
html+='<div class="'+cls+'" data-type="'+escH(p.type)+'">'
|
|
58
|
+
+'<div class="pl-top">'
|
|
59
|
+
+'<div class="pl-status '+(p.enabled?'on':'off')+'"></div>'
|
|
60
|
+
+'<div class="pl-name" title="'+escH(p.name)+'">'+escH(p.name)+'</div>'
|
|
61
|
+
+'<span class="pl-version">v'+escH(p.version)+'</span>'
|
|
62
|
+
+'<span class="pl-type-badge" data-t="'+escH(p.type)+'">'+escH(p.type)+'</span>'
|
|
63
|
+
+'</div>'
|
|
64
|
+
+'<div class="pl-desc">'+escH(p.description)+'</div>'
|
|
65
|
+
+'<div class="pl-meta">'
|
|
66
|
+
+(p.author?'<span class="pl-badge">'+escH(p.author)+'</span>':'')
|
|
67
|
+
+badges
|
|
68
|
+
+'<span class="pl-marketplace">'+escH(p.marketplace)+'</span>'
|
|
69
|
+
+'</div>'
|
|
70
|
+
+'<div class="pl-actions">'
|
|
71
|
+
+'<button onclick="showPluginDetail(PLUGINS['+pidx+'])">Details</button>'
|
|
72
|
+
+'<button class="primary" onclick="launchPlugin(PLUGINS['+pidx+'])">Utiliser</button>'
|
|
73
|
+
+(p.homepage||p.repository?'<button onclick="window.open(\''+escH(p.homepage||p.repository)+'\',\'_blank\')">Docs</button>':'')
|
|
74
|
+
+'</div>'
|
|
75
|
+
+'</div>';
|
|
76
|
+
});
|
|
77
|
+
// Safe: all values are escaped via escH, data is build-time generated
|
|
78
|
+
grid.insertAdjacentHTML('afterbegin','');grid.textContent='';
|
|
79
|
+
var tmp=document.createElement('div');tmp.insertAdjacentHTML('afterbegin',html);
|
|
80
|
+
while(tmp.firstChild)grid.appendChild(tmp.firstChild);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function showPluginDetail(p){
|
|
84
|
+
var bg=document.getElementById('modal-bg'),modal=document.getElementById('modal');
|
|
85
|
+
// Build detail view using DOM-safe escaped content (build-time data only)
|
|
86
|
+
var parts=[];
|
|
87
|
+
parts.push('<div style="display:flex;align-items:center;gap:.5rem;margin-bottom:1rem">');
|
|
88
|
+
parts.push('<div class="pl-status '+(p.enabled?'on':'off')+'" style="width:10px;height:10px"></div>');
|
|
89
|
+
parts.push('<strong style="font-size:1.1rem">'+escH(p.name)+'</strong>');
|
|
90
|
+
parts.push('<span class="pl-version">v'+escH(p.version)+'</span>');
|
|
91
|
+
parts.push('<span class="pl-type-badge" data-t="'+escH(p.type)+'">'+escH(p.type)+'</span>');
|
|
92
|
+
parts.push('<span style="margin-left:auto;font-size:.7rem;color:var(--dim)">'+(p.enabled?'Actif':'Inactif')+'</span>');
|
|
93
|
+
parts.push('</div>');
|
|
94
|
+
parts.push('<div style="font-size:.85rem;color:var(--mut);margin-bottom:1rem">'+escH(p.description)+'</div>');
|
|
95
|
+
var meta=[];
|
|
96
|
+
if(p.author)meta.push('<b>Auteur:</b> '+escH(p.author));
|
|
97
|
+
meta.push('<b>Marketplace:</b> '+escH(p.marketplace));
|
|
98
|
+
if(p.license)meta.push('<b>Licence:</b> '+escH(p.license));
|
|
99
|
+
parts.push('<div style="font-size:.75rem;color:var(--dim);display:flex;flex-wrap:wrap;gap:.75rem;margin-bottom:.75rem">'+meta.join(' ')+'</div>');
|
|
100
|
+
if(p.keywords&&p.keywords.length){
|
|
101
|
+
parts.push('<div class="pl-keywords">');
|
|
102
|
+
p.keywords.forEach(function(k){parts.push('<span>'+escH(k)+'</span>')});
|
|
103
|
+
parts.push('</div>');
|
|
104
|
+
}
|
|
105
|
+
if(p.commands&&p.commands.length){
|
|
106
|
+
parts.push('<div class="pl-detail-section"><h4>Commands ('+p.commands.length+')</h4>');
|
|
107
|
+
p.commands.forEach(function(c){
|
|
108
|
+
var cmdStr='/'+p.shortName+':'+c.name;
|
|
109
|
+
parts.push('<div class="pl-detail-item"><div class="item-name"><span>'+escH(cmdStr)+'</span>');
|
|
110
|
+
parts.push('<button onclick="copy(\''+cmdStr.replace(/'/g,"\\'")+'\');toast(\'Commande copiee!\')">Copier</button></div>');
|
|
111
|
+
if(c.description)parts.push('<div class="item-desc">'+escH(c.description)+'</div>');
|
|
112
|
+
if(c.argumentHint)parts.push('<div class="item-meta">Args: '+escH(c.argumentHint)+'</div>');
|
|
113
|
+
parts.push('</div>');
|
|
114
|
+
});
|
|
115
|
+
parts.push('</div>');
|
|
116
|
+
}
|
|
117
|
+
if(p.agents&&p.agents.length){
|
|
118
|
+
parts.push('<div class="pl-detail-section"><h4>Agents ('+p.agents.length+')</h4>');
|
|
119
|
+
p.agents.forEach(function(a){
|
|
120
|
+
parts.push('<div class="pl-detail-item"><div class="item-name">'+escH(a.name)+'</div>');
|
|
121
|
+
if(a.description)parts.push('<div class="item-desc">'+escH(a.description)+'</div>');
|
|
122
|
+
parts.push('<div class="item-meta">'+(a.model?'Model: '+escH(a.model)+' ':'')+(a.tools?'Tools: '+escH(a.tools):'')+'</div>');
|
|
123
|
+
parts.push('</div>');
|
|
124
|
+
});
|
|
125
|
+
parts.push('</div>');
|
|
126
|
+
}
|
|
127
|
+
if(p.skills&&p.skills.length){
|
|
128
|
+
parts.push('<div class="pl-detail-section"><h4>Skills ('+p.skills.length+')</h4>');
|
|
129
|
+
p.skills.forEach(function(s){
|
|
130
|
+
parts.push('<div class="pl-detail-item"><div class="item-name"><span>/'+escH(s.name)+'</span>');
|
|
131
|
+
parts.push('<button onclick="copy(\'/'+s.name.replace(/'/g,"\\'")+'\');toast(\'Skill copiee!\')">Copier</button></div>');
|
|
132
|
+
if(s.description)parts.push('<div class="item-desc">'+escH(s.description)+'</div>');
|
|
133
|
+
parts.push('</div>');
|
|
134
|
+
});
|
|
135
|
+
parts.push('</div>');
|
|
136
|
+
}
|
|
137
|
+
if(p.mcpServers&&p.mcpServers.length){
|
|
138
|
+
parts.push('<div class="pl-detail-section"><h4>MCP Servers ('+p.mcpServers.length+')</h4>');
|
|
139
|
+
p.mcpServers.forEach(function(m){
|
|
140
|
+
parts.push('<div class="pl-detail-item"><div class="item-name">'+escH(m.name)+'</div>');
|
|
141
|
+
parts.push('<div class="item-meta">'+escH(m.command)+' '+escH(m.args)+' ('+escH(m.type)+')</div>');
|
|
142
|
+
parts.push('</div>');
|
|
143
|
+
});
|
|
144
|
+
parts.push('</div>');
|
|
145
|
+
}
|
|
146
|
+
if(p.hooks&&p.hooks.length){
|
|
147
|
+
parts.push('<div class="pl-detail-section"><h4>Hooks ('+p.hooks.length+')</h4>');
|
|
148
|
+
p.hooks.forEach(function(hk){
|
|
149
|
+
parts.push('<div class="pl-detail-item"><div class="item-name">'+escH(hk.event)+'</div>');
|
|
150
|
+
if(hk.matcher)parts.push('<div class="item-meta">Matcher: '+escH(hk.matcher)+'</div>');
|
|
151
|
+
parts.push('</div>');
|
|
152
|
+
});
|
|
153
|
+
parts.push('</div>');
|
|
154
|
+
}
|
|
155
|
+
var links=[];
|
|
156
|
+
if(p.homepage)links.push('<a href="'+escH(p.homepage)+'" target="_blank" rel="noopener" style="color:var(--ac);font-size:.8rem">Homepage</a>');
|
|
157
|
+
if(p.repository)links.push('<a href="'+escH(p.repository)+'" target="_blank" rel="noopener" style="color:var(--ac);font-size:.8rem">Repository</a>');
|
|
158
|
+
if(links.length)parts.push('<div style="margin-top:1rem;display:flex;gap:1rem">'+links.join('')+'</div>');
|
|
159
|
+
// Safe: all content is build-time data escaped via escH
|
|
160
|
+
var tmp=document.createElement('div');tmp.insertAdjacentHTML('afterbegin',parts.join(''));
|
|
161
|
+
modal.textContent='';while(tmp.firstChild)modal.appendChild(tmp.firstChild);
|
|
162
|
+
bg.classList.add('open');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function launchPlugin(p){
|
|
166
|
+
var cmd='';
|
|
167
|
+
if(p.commands&&p.commands.length===1)cmd='/'+p.shortName+':'+p.commands[0].name;
|
|
168
|
+
else if(p.skills&&p.skills.length===1)cmd='/'+p.skills[0].name;
|
|
169
|
+
else if(p.commands&&p.commands.length)cmd='/'+p.shortName+':'+p.commands[0].name;
|
|
170
|
+
else cmd=p.shortName;
|
|
171
|
+
copy(cmd);toast('Commande copiee: '+cmd);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function initPluginCatalog(){
|
|
175
|
+
var el=document.getElementById('stat-plugins');
|
|
176
|
+
if(el&&PLUGIN_COUNTS)el.textContent=PLUGIN_COUNTS.active+'/'+PLUGIN_COUNTS.total;
|
|
177
|
+
var hdr=document.getElementById('plugins-header-count');
|
|
178
|
+
if(hdr&&PLUGIN_COUNTS)hdr.textContent='('+PLUGIN_COUNTS.active+'/'+PLUGIN_COUNTS.total+' actifs)';
|
|
179
|
+
var mkFilters=document.getElementById('plugin-marketplace-filters');
|
|
180
|
+
if(mkFilters&&PLUGINS&&PLUGINS.length){
|
|
181
|
+
var mks={};PLUGINS.forEach(function(p){if(p.marketplace)mks[p.marketplace]=(mks[p.marketplace]||0)+1});
|
|
182
|
+
var keys=Object.keys(mks).sort();
|
|
183
|
+
if(keys.length>1){
|
|
184
|
+
var bh='<button class="plugin-filter-btn active" data-pmk="all">Tous</button>';
|
|
185
|
+
keys.forEach(function(k){bh+='<button class="plugin-filter-btn" data-pmk="'+escH(k)+'">'+escH(k)+' ('+mks[k]+')</button>'});
|
|
186
|
+
// Safe: marketplace names are build-time data
|
|
187
|
+
mkFilters.textContent='';var t2=document.createElement('div');t2.insertAdjacentHTML('afterbegin',bh);
|
|
188
|
+
while(t2.firstChild)mkFilters.appendChild(t2.firstChild);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
document.querySelectorAll('[data-pf]').forEach(function(btn){
|
|
192
|
+
btn.addEventListener('click',function(){
|
|
193
|
+
document.querySelectorAll('[data-pf]').forEach(function(b){b.classList.remove('active')});
|
|
194
|
+
btn.classList.add('active');pluginTypeFilter=btn.getAttribute('data-pf');renderPlugins();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
document.querySelectorAll('[data-pmk]').forEach(function(btn){
|
|
198
|
+
btn.addEventListener('click',function(){
|
|
199
|
+
document.querySelectorAll('[data-pmk]').forEach(function(b){b.classList.remove('active')});
|
|
200
|
+
btn.classList.add('active');pluginMarketplaceFilter=btn.getAttribute('data-pmk');renderPlugins();
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
var si=document.getElementById('plugin-search');
|
|
204
|
+
if(si)si.addEventListener('input',function(){pluginSearchQuery=si.value;renderPlugins()});
|
|
205
|
+
renderPlugins();
|
|
206
|
+
}
|
|
207
|
+
window.showPluginDetail=showPluginDetail;window.launchPlugin=launchPlugin;window.copy=copy;window.toast=toast;window.PLUGINS=PLUGINS;window.filterPlugins=filterPlugins;
|
|
208
|
+
function filterPlugins(term){
|
|
209
|
+
pluginSearchQuery=term||'';
|
|
210
|
+
var si=document.getElementById('plugin-search');if(si)si.value=term||'';
|
|
211
|
+
renderPlugins();
|
|
212
|
+
}
|
|
213
|
+
// ---- End Plugin Catalog ----
|
|
214
|
+
|
|
215
|
+
// ---- Tab Router ----
|
|
216
|
+
var TAB_IDS=['dashboard','projets','couts','plugins','outils'];
|
|
217
|
+
var activeTab='dashboard';
|
|
218
|
+
var tabInitialized={dashboard:false,projets:false,couts:false,plugins:false,outils:false};
|
|
219
|
+
var lazyChartCallbacks={dashboard:null,couts:null};
|
|
220
|
+
function updateStatsBar(collapsed){
|
|
221
|
+
var bar=document.getElementById('stats-bar'),toggle=document.getElementById('stats-toggle');
|
|
222
|
+
if(!bar)return;
|
|
223
|
+
bar.classList.toggle('collapsed',collapsed);
|
|
224
|
+
if(toggle)toggle.classList.toggle('flipped',collapsed);
|
|
225
|
+
}
|
|
226
|
+
function switchTab(tabId){
|
|
227
|
+
if(TAB_IDS.indexOf(tabId)===-1)tabId='dashboard';
|
|
228
|
+
activeTab=tabId;
|
|
229
|
+
document.querySelectorAll('.tab-nav').forEach(function(b){b.classList.toggle('active',b.dataset.tab===tabId)});
|
|
230
|
+
document.querySelectorAll('.tab-panel').forEach(function(p){p.classList.toggle('active',p.id==='panel-'+tabId)});
|
|
231
|
+
if(!tabInitialized[tabId]){
|
|
232
|
+
tabInitialized[tabId]=true;
|
|
233
|
+
if(lazyChartCallbacks[tabId]){var cb=lazyChartCallbacks[tabId];setTimeout(cb,50)}
|
|
234
|
+
}
|
|
235
|
+
// Auto-collapse stats bar on non-dashboard tabs
|
|
236
|
+
store.statsBarManual=null;
|
|
237
|
+
updateStatsBar(tabId!=='dashboard');
|
|
238
|
+
// Contextual search placeholder
|
|
239
|
+
var placeholders={dashboard:'Rechercher dans les sessions (/)',projets:'Rechercher un projet (/)',couts:'Rechercher dans les sessions (/)',plugins:'Rechercher un plugin (/)',outils:'Rechercher (/)'}
|
|
240
|
+
var sEl=document.getElementById('search');if(sEl)sEl.placeholder=placeholders[tabId]||'Rechercher (/)';
|
|
241
|
+
compareSet.clear();updateCompareFab();
|
|
242
|
+
store.lastTab=tabId;save();
|
|
243
|
+
if(location.hash!=='#'+tabId)history.replaceState(null,'','#'+tabId);
|
|
244
|
+
}
|
|
245
|
+
function initTabRouter(){
|
|
246
|
+
var hash=location.hash.replace('#','');
|
|
247
|
+
var saved=store.lastTab||'dashboard';
|
|
248
|
+
var initial=TAB_IDS.indexOf(hash)!==-1?hash:saved;
|
|
249
|
+
// Mark dashboard as initialized since it's the default visible panel
|
|
250
|
+
tabInitialized.dashboard=true;
|
|
251
|
+
switchTab(initial);
|
|
252
|
+
document.getElementById('tab-bar').addEventListener('click',function(e){var btn=e.target.closest('.tab-nav');if(btn)switchTab(btn.dataset.tab)});
|
|
253
|
+
window.addEventListener('hashchange',function(){var h=location.hash.replace('#','');if(TAB_IDS.indexOf(h)!==-1)switchTab(h)});
|
|
254
|
+
// Stats bar toggle
|
|
255
|
+
var statsToggle=document.getElementById('stats-toggle');
|
|
256
|
+
if(statsToggle)statsToggle.addEventListener('click',function(){
|
|
257
|
+
var bar=document.getElementById('stats-bar');if(!bar)return;
|
|
258
|
+
var isCollapsed=bar.classList.contains('collapsed');
|
|
259
|
+
store.statsBarManual=isCollapsed?false:true;
|
|
260
|
+
updateStatsBar(!isCollapsed);
|
|
261
|
+
save();
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function getGitHubRepo(projectPath){var p=PROJECTS.find(function(x){return x.path===projectPath});if(p&&p.githubUrl){var m=p.githubUrl.match(/github\.com\/([^\/]+\/[^\/]+)/);if(m)return m[1]}return null}
|
|
266
|
+
function createGitHubIssue(projectPath,title,body,sessionId){var repo=getGitHubRepo(projectPath);if(!repo){toast('Pas de repo GitHub');return}var url='https://github.com/'+repo+'/issues/new?title='+encodeURIComponent(title)+'&body='+encodeURIComponent(body+'\n\n---\nSession: `'+sessionId+'`');window.open(url,'_blank')}
|
|
267
|
+
function isFav(id){return store.favorites.indexOf(id)!==-1}
|
|
268
|
+
function toggleFav(id){var i=store.favorites.indexOf(id);if(i===-1)store.favorites.push(id);else store.favorites.splice(i,1);save()}
|
|
269
|
+
document.getElementById('pc-name').textContent=' '+PC_NAME;
|
|
270
|
+
// Age indicator - parse GENERATED timestamp (dd/MM/yyyy HH:mm:ss)
|
|
271
|
+
var syncEl=document.getElementById('sync-time');
|
|
272
|
+
function updateAge(){var p=GENERATED.match(/(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2}):(\d{2})/);if(!p){syncEl.textContent=GENERATED;return}var gen=new Date(+p[3],+p[2]-1,+p[1],+p[4],+p[5],+p[6]);var diff=Math.floor((Date.now()-gen.getTime())/1000);var txt;if(diff<60)txt='< 1 min';else if(diff<3600)txt=Math.floor(diff/60)+' min';else if(diff<86400)txt=Math.floor(diff/3600)+'h'+String(Math.floor((diff%3600)/60)).padStart(2,'0');else txt=Math.floor(diff/86400)+'j';syncEl.textContent='Genere il y a '+txt;syncEl.title='Genere le '+GENERATED;if(diff>3600)syncEl.style.color='var(--warn)';else syncEl.style.color=''}
|
|
273
|
+
updateAge();setInterval(updateAge,60000);
|
|
274
|
+
document.getElementById('btn-regen').addEventListener('click',function(){copy('cd '+location.href.replace(/[^/\\]*$/,'').replace('file:///','')+'&& .\\generate.ps1');toast('Commande copiee! Collez dans un terminal PowerShell.')});
|
|
275
|
+
document.getElementById('stat-total').textContent=STAT_TOTAL;
|
|
276
|
+
document.getElementById('stat-active').textContent=STAT_ACTIVE;
|
|
277
|
+
document.getElementById('stat-undoc').textContent=STAT_UNDOC;
|
|
278
|
+
document.getElementById('stat-dirty').textContent=STAT_DIRTY;
|
|
279
|
+
document.getElementById('stat-commits').textContent=STAT_COMMITS;
|
|
280
|
+
document.getElementById('stat-health').textContent=STAT_HEALTH+'%';
|
|
281
|
+
initPluginCatalog();
|
|
282
|
+
var stacksEl=document.getElementById('stat-stacks');
|
|
283
|
+
STACK_STATS.forEach(function(s){var sp=document.createElement('span');sp.className='stat-stack';sp.textContent=s.name+'('+s.count+')';stacksEl.appendChild(sp)});
|
|
284
|
+
var stackSet={};PROJECTS.forEach(function(p){if(p.stack)stackSet[p.stack]=true});
|
|
285
|
+
var fsEl=document.getElementById('filter-stack');
|
|
286
|
+
Object.keys(stackSet).forEach(function(s){var b=document.createElement('button');b.className='filter-btn';b.dataset.stack=s;b.textContent=s;fsEl.appendChild(b)});
|
|
287
|
+
var projEl=document.getElementById('projects'),curFilter='all',curStack='',curClaudeFilter='all',searchTerm='';
|
|
288
|
+
function clearEl(el){while(el.firstChild)el.removeChild(el.firstChild)}
|
|
289
|
+
function renderProjects(){
|
|
290
|
+
clearEl(projEl);
|
|
291
|
+
var sorted=PROJECTS.slice().sort(function(a,b){return (isFav(a.pathId)?0:1)-(isFav(b.pathId)?0:1)});
|
|
292
|
+
sorted.forEach(function(p,idx){
|
|
293
|
+
var show=true;
|
|
294
|
+
if(curFilter==='active'&&p.status!=='active')show=false;
|
|
295
|
+
if(curFilter==='fav'&&!isFav(p.pathId))show=false;
|
|
296
|
+
if(curFilter==='undoc'&&p.hasClaudeMd)show=false;
|
|
297
|
+
if(curFilter==='dirty'&&p.uncommitted===0)show=false;
|
|
298
|
+
if(curClaudeFilter!=='all'){var maxDays=parseInt(curClaudeFilter);if(p.claudeSessionDays>maxDays)show=false;}
|
|
299
|
+
if(curStack&&p.stack!==curStack)show=false;
|
|
300
|
+
if(searchTerm&&p.name.toLowerCase().indexOf(searchTerm)===-1)show=false;
|
|
301
|
+
var card=document.createElement('div');
|
|
302
|
+
var bc='';if(!p.hasClaudeMd)bc=' err-border';else if(p.uncommitted>0)bc=' warn-border';
|
|
303
|
+
card.className='p-card'+bc+(isFav(p.pathId)?' fav':'')+(show?'':' hidden');
|
|
304
|
+
card.dataset.pathid=p.pathId;
|
|
305
|
+
var chk=document.createElement('input');chk.type='checkbox';chk.className='p-check';chk.checked=compareSet.has(p.pathId);chk.addEventListener('change',(function(pid,cb){return function(){if(cb.checked)compareSet.add(pid);else compareSet.delete(pid);updateCompareFab()}})(p.pathId,chk));card.appendChild(chk);
|
|
306
|
+
var fav=document.createElement('button');fav.className='p-fav'+(isFav(p.pathId)?' active':'');fav.textContent='*';fav.addEventListener('click',function(e){e.stopPropagation();toggleFav(p.pathId);renderProjects()});card.appendChild(fav);
|
|
307
|
+
var top=document.createElement('div');top.className='p-top';
|
|
308
|
+
var idxS=document.createElement('span');idxS.className='p-idx';idxS.textContent=idx<9?(idx+1):'';
|
|
309
|
+
var nm=document.createElement('span');nm.className='p-name';nm.textContent=p.name;nm.title=p.path;
|
|
310
|
+
var st=document.createElement('span');st.className='p-stack';st.textContent=p.stack||'?';
|
|
311
|
+
var hl=document.createElement('div');hl.className='p-health';hl.title=p.healthScore+'%';
|
|
312
|
+
var hf=document.createElement('div');hf.className='p-health-fill';hf.style.width=p.healthScore+'%';hf.style.background=p.healthScore>=70?'var(--ok)':p.healthScore>=40?'var(--warn)':'var(--err)';
|
|
313
|
+
hl.appendChild(hf);top.appendChild(idxS);top.appendChild(nm);top.appendChild(st);top.appendChild(hl);card.appendChild(top);
|
|
314
|
+
var info=document.createElement('div');info.className='p-info';
|
|
315
|
+
if(p.branch){var t=document.createElement('span');t.className='tag';t.textContent=p.branch;info.appendChild(t)}
|
|
316
|
+
if(p.lastCommitAge){var t=document.createElement('span');t.className='tag';t.textContent=p.lastCommitAge;info.appendChild(t)}
|
|
317
|
+
if(p.uncommitted>0){var t=document.createElement('span');t.className='tag changed';t.textContent=p.uncommitted+'ch';info.appendChild(t)}
|
|
318
|
+
var dt=document.createElement('span');dt.className='tag '+(p.hasClaudeMd?'ok':'bad');dt.textContent=p.hasClaudeMd?'DOC':'NO DOC';info.appendChild(dt);
|
|
319
|
+
if(p.hasProgressMd){var t=document.createElement('span');t.className='tag ok';t.textContent='PROG';info.appendChild(t)}
|
|
320
|
+
if(p.prCount>0){var t=document.createElement('span');t.className='tag gh';t.textContent=p.prCount+'PR';info.appendChild(t)}
|
|
321
|
+
if(p.lastSessionAge){var t=document.createElement('span');t.className='tag';t.style.borderColor='rgba(139,92,246,.3)';t.style.color='var(--ac)';t.textContent='S:'+p.lastSessionAge;t.title='Derniere session';info.appendChild(t)}
|
|
322
|
+
card.appendChild(info);
|
|
323
|
+
if(p.lastCommit){var cm=document.createElement('div');cm.className='p-commit';cm.textContent=p.lastCommit;card.appendChild(cm)}
|
|
324
|
+
if(p.nextTask){var nt=document.createElement('div');nt.className='p-next';nt.textContent=p.nextTask;card.appendChild(nt)}
|
|
325
|
+
var acts=document.createElement('div');acts.className='p-actions';
|
|
326
|
+
var lb=document.createElement('button');lb.className='p-btn primary';lb.textContent='Lancer';lb.title='Clic = lancer | Ctrl+clic = copier';lb.addEventListener('click',function(e){claudeAction(e,p.path,'open')});acts.appendChild(lb);
|
|
327
|
+
if(!p.hasClaudeMd){var ib=document.createElement('button');ib.className='p-btn ghost';ib.textContent='Init';ib.style.borderColor='var(--warn)';ib.style.color='var(--warn)';ib.addEventListener('click',function(){copy(p.launchCmd.replace('claude --dangerously-skip-permissions','claude --dangerously-skip-permissions -p "Cree CLAUDE.md et PROGRESS.md"'))});acts.appendChild(ib)}
|
|
328
|
+
if(p.githubUrl){var gb=document.createElement('button');gb.className='p-btn ghost';gb.textContent='GH';gb.addEventListener('click',function(){window.open(p.githubUrl,'_blank')});acts.appendChild(gb)}
|
|
329
|
+
if(p.uncommitted>0){var cb=document.createElement('button');cb.className='p-btn ghost';cb.textContent='Commit';cb.style.borderColor='var(--warn)';cb.style.color='var(--warn)';cb.addEventListener('click',function(){copy(p.launchCmd.replace('claude --dangerously-skip-permissions','claude --dangerously-skip-permissions -p "/commit"'))});acts.appendChild(cb)}
|
|
330
|
+
if(p.lastSessionId){var rb=document.createElement('button');rb.className='p-btn ghost';rb.textContent='R';rb.title='Reprendre session | Ctrl+clic = copier';rb.style.borderColor='var(--ac)';rb.style.color='var(--ac)';rb.addEventListener('click',function(e){claudeAction(e,p.path,'resume')});acts.appendChild(rb)}
|
|
331
|
+
var nb=document.createElement('button');nb.className='p-btn ghost p-note-btn';nb.textContent='N';nb.addEventListener('click',function(){openNoteModal(p)});acts.appendChild(nb);
|
|
332
|
+
card.appendChild(acts);projEl.appendChild(card);
|
|
333
|
+
})}
|
|
334
|
+
renderProjects();
|
|
335
|
+
document.getElementById('filter-status').addEventListener('click',function(e){var b=e.target.closest('.filter-btn');if(!b)return;this.querySelectorAll('.filter-btn').forEach(function(x){x.classList.remove('active')});b.classList.add('active');curFilter=b.dataset.filter;renderProjects()});
|
|
336
|
+
document.getElementById('filter-stack').addEventListener('click',function(e){var b=e.target.closest('.filter-btn');if(!b)return;if(b.classList.contains('active')){b.classList.remove('active');curStack=''}else{this.querySelectorAll('.filter-btn').forEach(function(x){x.classList.remove('active')});b.classList.add('active');curStack=b.dataset.stack}renderProjects()});
|
|
337
|
+
document.getElementById('filter-claude').addEventListener('click',function(e){var b=e.target.closest('.filter-btn');if(!b)return;this.querySelectorAll('.filter-btn').forEach(function(x){x.classList.remove('active')});b.classList.add('active');curClaudeFilter=b.dataset.claude;renderProjects()});
|
|
338
|
+
document.getElementById('btn-csv-projects').addEventListener('click',function(){
|
|
339
|
+
var rows=[['Nom','Stack','Statut','Sante','Branche','Uncommitted','Dernier Commit','Derniere Session Claude']];
|
|
340
|
+
PROJECTS.forEach(function(p){
|
|
341
|
+
var show=true;
|
|
342
|
+
if(curFilter==='active'&&p.status!=='active')show=false;
|
|
343
|
+
if(curFilter==='fav'&&!isFav(p.pathId))show=false;
|
|
344
|
+
if(curFilter==='undoc'&&p.hasClaudeMd)show=false;
|
|
345
|
+
if(curFilter==='dirty'&&p.uncommitted===0)show=false;
|
|
346
|
+
if(curClaudeFilter!=='all'){var maxDays=parseInt(curClaudeFilter);if(p.claudeSessionDays>maxDays)show=false}
|
|
347
|
+
if(curStack&&p.stack!==curStack)show=false;
|
|
348
|
+
if(searchTerm&&p.name.toLowerCase().indexOf(searchTerm)===-1)show=false;
|
|
349
|
+
if(show)rows.push([p.name,p.stack||'',p.status||'',p.healthScore||0,p.branch||'',p.uncommitted||0,p.lastCommit||'',p.lastSessionAge||''])});
|
|
350
|
+
downloadCSV(rows,'coderadar-projets-'+new Date().toISOString().slice(0,10)+'.csv')});
|
|
351
|
+
document.getElementById('compare-fab').addEventListener('click',function(){
|
|
352
|
+
var projects=PROJECTS.filter(function(p){return compareSet.has(p.pathId)});
|
|
353
|
+
if(projects.length<2)return;
|
|
354
|
+
var modal=document.getElementById('modal');
|
|
355
|
+
var metrics=[
|
|
356
|
+
{label:'Stack',fn:function(p){return p.stack||'-'}},
|
|
357
|
+
{label:'Statut',fn:function(p){return p.status||'-'}},
|
|
358
|
+
{label:'Sante',fn:function(p){return (p.healthScore||0)+'%'}},
|
|
359
|
+
{label:'Branche',fn:function(p){return p.branch||'-'}},
|
|
360
|
+
{label:'Uncommitted',fn:function(p){return p.uncommitted||0}},
|
|
361
|
+
{label:'Dernier commit',fn:function(p){return p.lastCommitAge||'-'}},
|
|
362
|
+
{label:'Session Claude',fn:function(p){return p.lastSessionAge||'-'}},
|
|
363
|
+
{label:'CLAUDE.md',fn:function(p){return p.hasClaudeMd?'Oui':'Non'}},
|
|
364
|
+
{label:'PROGRESS.md',fn:function(p){return p.hasProgressMd?'Oui':'Non'}}];
|
|
365
|
+
var h='<h3 style="margin:0 0 .75rem">Comparaison</h3><table class="compare-table"><thead><tr><th></th>';
|
|
366
|
+
projects.forEach(function(p){h+='<th>'+escH(p.name)+'</th>'});
|
|
367
|
+
h+='</tr></thead><tbody>';
|
|
368
|
+
metrics.forEach(function(m){h+='<tr><td class="metric-label">'+m.label+'</td>';projects.forEach(function(p){h+='<td>'+escH(m.fn(p)+'')+'</td>'});h+='</tr>'});
|
|
369
|
+
h+='</tbody></table><div class="modal-actions"><button class="cancel" id="compare-close">Fermer</button></div>';
|
|
370
|
+
clearEl(modal);var tmp=document.createElement('div');tmp.insertAdjacentHTML('afterbegin',h);while(tmp.firstChild)modal.appendChild(tmp.firstChild);
|
|
371
|
+
modal.style.maxWidth='700px';
|
|
372
|
+
document.getElementById('compare-close').addEventListener('click',function(){modal.style.maxWidth='';closeModal()});
|
|
373
|
+
openModal()});
|
|
374
|
+
// Semantic search with Fuse.js
|
|
375
|
+
var searchEl=document.getElementById('search'),searchResultsEl=document.getElementById('search-results'),fuse=null;
|
|
376
|
+
if(typeof Fuse!=='undefined'&&SEARCH_INDEX&&SEARCH_INDEX.length>0){
|
|
377
|
+
fuse=new Fuse(SEARCH_INDEX,{keys:[{name:'summary',weight:0.4},{name:'keyPoints',weight:0.3},{name:'tags',weight:0.2},{name:'project',weight:0.1}],threshold:0.4,includeMatches:true,includeScore:true,minMatchCharLength:2,ignoreLocation:true});
|
|
378
|
+
}
|
|
379
|
+
function createHighlightedSpan(text,indices){
|
|
380
|
+
var span=document.createElement('span');
|
|
381
|
+
if(!indices||indices.length===0){span.textContent=text;return span}
|
|
382
|
+
var lastIdx=0;
|
|
383
|
+
indices.forEach(function(pair){
|
|
384
|
+
if(pair[0]>lastIdx)span.appendChild(document.createTextNode(text.slice(lastIdx,pair[0])));
|
|
385
|
+
var mark=document.createElement('mark');mark.textContent=text.slice(pair[0],pair[1]+1);span.appendChild(mark);
|
|
386
|
+
lastIdx=pair[1]+1;
|
|
387
|
+
});
|
|
388
|
+
if(lastIdx<text.length)span.appendChild(document.createTextNode(text.slice(lastIdx)));
|
|
389
|
+
return span;
|
|
390
|
+
}
|
|
391
|
+
function renderSearchResults(query){
|
|
392
|
+
if(!query||query.length<2||!fuse){searchResultsEl.classList.remove('active');searchTerm=query.toLowerCase();renderProjects();return}
|
|
393
|
+
var results=fuse.search(query).slice(0,15);
|
|
394
|
+
clearEl(searchResultsEl);
|
|
395
|
+
if(results.length===0){var empty=document.createElement('div');empty.className='sr-empty';empty.textContent='Aucun resultat pour "'+query+'"';searchResultsEl.appendChild(empty);searchResultsEl.classList.add('active');return}
|
|
396
|
+
var header=document.createElement('div');header.className='search-results-header';var hLeft=document.createElement('span');hLeft.textContent=results.length+' resultat(s)';var hRight=document.createElement('span');hRight.textContent='Esc pour fermer';header.appendChild(hLeft);header.appendChild(hRight);searchResultsEl.appendChild(header);
|
|
397
|
+
results.forEach(function(r){
|
|
398
|
+
var item=r.item;
|
|
399
|
+
var resultEl=document.createElement('div');resultEl.className='search-result';resultEl.dataset.id=item.id;resultEl.dataset.path=item.path||'';
|
|
400
|
+
var headerEl=document.createElement('div');headerEl.className='sr-header';
|
|
401
|
+
var projEl=document.createElement('span');projEl.className='sr-project';projEl.textContent=item.project;headerEl.appendChild(projEl);
|
|
402
|
+
var dateEl=document.createElement('span');dateEl.className='sr-date';dateEl.textContent=item.date;headerEl.appendChild(dateEl);
|
|
403
|
+
if(item.tags&&item.tags.length>0){var tagsEl=document.createElement('div');tagsEl.className='sr-tags';item.tags.slice(0,3).forEach(function(t){var tagEl=document.createElement('span');tagEl.className='sr-tag';tagEl.textContent=t;tagsEl.appendChild(tagEl)});headerEl.appendChild(tagsEl)}
|
|
404
|
+
resultEl.appendChild(headerEl);
|
|
405
|
+
var summaryText=item.summary||'';var summaryIndices=null;var kpText='';var kpIndices=null;
|
|
406
|
+
r.matches.forEach(function(m){
|
|
407
|
+
if(m.key==='summary')summaryIndices=m.indices;
|
|
408
|
+
if(m.key==='keyPoints'&&item.keyPoints&&item.keyPoints[m.refIndex]){kpText=item.keyPoints[m.refIndex];kpIndices=m.indices}
|
|
409
|
+
});
|
|
410
|
+
if(summaryText){if(summaryText.length>200)summaryText=summaryText.substring(0,200)+'...';var sumEl=document.createElement('div');sumEl.className='sr-summary';sumEl.appendChild(createHighlightedSpan(summaryText,summaryIndices));resultEl.appendChild(sumEl)}
|
|
411
|
+
if(kpText){var kpEl=document.createElement('div');kpEl.className='sr-keypoint';kpEl.appendChild(createHighlightedSpan(kpText,kpIndices));resultEl.appendChild(kpEl)}
|
|
412
|
+
resultEl.addEventListener('click',function(e){claudeAction(e,item.path,'resume');searchResultsEl.classList.remove('active');searchEl.value=''});
|
|
413
|
+
searchResultsEl.appendChild(resultEl);
|
|
414
|
+
});
|
|
415
|
+
searchResultsEl.classList.add('active');
|
|
416
|
+
}
|
|
417
|
+
var searchDebounce;
|
|
418
|
+
searchEl.addEventListener('input',function(){
|
|
419
|
+
var v=this.value.trim();
|
|
420
|
+
clearTimeout(searchDebounce);
|
|
421
|
+
searchTerm=v.toLowerCase();
|
|
422
|
+
if(activeTab==='projets'){renderProjects();return}
|
|
423
|
+
if(activeTab==='plugins'){filterPlugins(searchTerm);return}
|
|
424
|
+
searchDebounce=setTimeout(function(){renderSearchResults(v)},150);
|
|
425
|
+
renderProjects();
|
|
426
|
+
});
|
|
427
|
+
searchEl.addEventListener('blur',function(){setTimeout(function(){searchResultsEl.classList.remove('active')},200)});
|
|
428
|
+
searchEl.addEventListener('focus',function(){if(this.value.trim().length>=2)renderSearchResults(this.value.trim())});
|
|
429
|
+
if(LAST_SESSION){var lsc=document.getElementById('last-session-card');lsc.style.display='flex';document.getElementById('ls-name').textContent=LAST_SESSION.name;document.getElementById('ls-title').textContent=LAST_SESSION.title?'"'+LAST_SESSION.title+'"':'';document.getElementById('ls-date').textContent=LAST_SESSION.date;lsc.addEventListener('click',function(e){claudeAction(e,LAST_SESSION.path,'resume')})}
|
|
430
|
+
if(RECENT_SESSIONS&&RECENT_SESSIONS.length>0){document.getElementById('recent-sessions-section').style.display='block';document.getElementById('session-count').textContent='('+RECENT_SESSIONS.length+')';var rsEl=document.getElementById('recent-sessions');RECENT_SESSIONS.forEach(function(s){var item=document.createElement('div');item.className='rs-item';var sum=document.createElement('span');sum.className='rs-summary';sum.textContent=s.summary;item.appendChild(sum);var meta=document.createElement('span');meta.className='rs-meta';var dt=document.createElement('span');dt.className='rs-date';dt.textContent=s.date;meta.appendChild(dt);var ms=document.createElement('span');ms.className='rs-msgs';ms.textContent=s.messages+' msgs';meta.appendChild(ms);item.appendChild(meta);item.addEventListener('click',function(){copy('claude --dangerously-skip-permissions --resume '+s.id);toast('Session copiee')});rsEl.appendChild(item)})}
|
|
431
|
+
// Always show insights panel (coach can generate suggestions from PROJECTS alone)
|
|
432
|
+
document.getElementById('insights-panel').style.display='grid';
|
|
433
|
+
if(INSIGHTS&&(INSIGHTS.wipSessions.length>0||INSIGHTS.keyPoints.length>0||INSIGHTS.topTags.length>0)){var wipEl=document.getElementById('wip-list');INSIGHTS.wipSessions.forEach(function(w){var d=document.createElement('div');d.className='wip-item';var hdr=document.createElement('div');hdr.style.cssText='display:flex;justify-content:space-between;align-items:center';var p=document.createElement('div');p.className='wip-proj';p.textContent=w.project+(w.daysAgo>0?' ('+w.daysAgo+'j)':' (auj)');hdr.appendChild(p);if(w.projectPath&&getGitHubRepo(w.projectPath)&&w.nextSteps&&w.nextSteps[0]){var ghBtn=document.createElement('button');ghBtn.className='wip-gh-btn';ghBtn.innerHTML='<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>';ghBtn.title='Creer issue GitHub';ghBtn.addEventListener('click',function(e){e.stopPropagation();var title='[WIP] '+w.nextSteps[0];var body='## Contexte\\n\\nProjet: **'+w.project+'**\\n\\n## Prochaine etape\\n\\n'+w.nextSteps[0]+(w.summary?'\\n\\n## Resume de session\\n\\n'+w.summary:'');createGitHubIssue(w.projectPath,title,body,w.sessionId)});hdr.appendChild(ghBtn)}d.appendChild(hdr);if(w.nextSteps&&w.nextSteps[0]){var n=document.createElement('div');n.className='wip-next';n.textContent='> '+w.nextSteps[0];d.appendChild(n)}d.addEventListener('click',function(e){if(w.projectPath){claudeAction(e,w.projectPath,'resume')}else{copy('claude --dangerously-skip-permissions --resume '+w.sessionId);toast('Session copiee')}});wipEl.appendChild(d)});var kpEl=document.getElementById('keypoints-list');INSIGHTS.keyPoints.forEach(function(k){var d=document.createElement('div');d.className='kp-item';var b=document.createElement('span');b.className='kp-bullet';b.textContent='├óÔé¼┬ó';d.appendChild(b);var t=document.createElement('span');t.className='kp-text';t.textContent=k.point;d.appendChild(t);var p=document.createElement('span');p.className='kp-proj';p.textContent=k.project;d.appendChild(p);kpEl.appendChild(d)});var tagEl=document.getElementById('tag-cloud');INSIGHTS.topTags.forEach(function(t){var s=document.createElement('span');s.className='tag-pill';s.textContent=t.tag;var c=document.createElement('span');c.className='tag-count';c.textContent=t.count;s.appendChild(c);tagEl.appendChild(s)})}
|
|
434
|
+
renderAICoach();
|
|
435
|
+
// AI Coach - Intelligent suggestions
|
|
436
|
+
function renderAICoach(){
|
|
437
|
+
var coachEl=document.getElementById('coach-list');if(!coachEl)return;
|
|
438
|
+
var suggestions=[];
|
|
439
|
+
// 1. Projets abandonnes (pas de session depuis >14 jours)
|
|
440
|
+
var abandonedProjects=PROJECTS.filter(function(p){return p.claudeSessionDays>14&&p.claudeSessionDays<9999&&p.status!=='idle'});
|
|
441
|
+
abandonedProjects.slice(0,2).forEach(function(p){suggestions.push({type:'warning',icon:'!',text:'Tu n\'as pas touche '+p.name+' depuis '+p.claudeSessionDays+' jours. Reprendre ou archiver?'})});
|
|
442
|
+
// 2. Trop de projets WIP
|
|
443
|
+
var wipCount=INSIGHTS&&INSIGHTS.wipSessions?INSIGHTS.wipSessions.length:0;
|
|
444
|
+
if(wipCount>3){suggestions.push({type:'warning',icon:'!',text:'Tu as '+wipCount+' projets en cours simultanes. Priorise pour eviter la dispersion.'})}
|
|
445
|
+
// 3. Patterns de travail (jours les plus actifs)
|
|
446
|
+
var dayActivity={0:0,1:0,2:0,3:0,4:0,5:0,6:0};
|
|
447
|
+
var dayNames=['dimanche','lundi','mardi','mercredi','jeudi','vendredi','samedi'];
|
|
448
|
+
if(TIMELINE_DATA&&TIMELINE_DATA.length>0){
|
|
449
|
+
TIMELINE_DATA.forEach(function(s){var d=new Date(s.date);dayActivity[d.getDay()]++});
|
|
450
|
+
var maxDay=0,maxCount=0;for(var i=0;i<7;i++){if(dayActivity[i]>maxCount){maxCount=dayActivity[i];maxDay=i}}
|
|
451
|
+
if(maxCount>5&&(maxDay===0||maxDay===6)){suggestions.push({type:'info',icon:'i',text:'Tu travailles beaucoup le '+dayNames[maxDay]+'. Pense a prendre des pauses le weekend!'})}}
|
|
452
|
+
// 4. Sessions courtes (projets avec bcp de sessions mais peu de progression)
|
|
453
|
+
var projectSessionCounts={};
|
|
454
|
+
if(TIMELINE_DATA&&TIMELINE_DATA.length>7){
|
|
455
|
+
TIMELINE_DATA.forEach(function(s){projectSessionCounts[s.project]=(projectSessionCounts[s.project]||0)+1});
|
|
456
|
+
Object.keys(projectSessionCounts).forEach(function(proj){
|
|
457
|
+
if(projectSessionCounts[proj]>5){
|
|
458
|
+
var sessionsThisWeek=TIMELINE_DATA.filter(function(s){return s.project===proj&&(new Date()-new Date(s.date))<7*24*60*60*1000}).length;
|
|
459
|
+
if(sessionsThisWeek>3){suggestions.push({type:'info',icon:'i',text:'Beaucoup de sessions sur '+proj+' cette semaine. Probleme de focus?'})}}})}
|
|
460
|
+
// 5. Felicitations
|
|
461
|
+
var weekSessions=TIMELINE_DATA?TIMELINE_DATA.filter(function(s){return(new Date()-new Date(s.date))<7*24*60*60*1000}).length:0;
|
|
462
|
+
if(weekSessions>=10){suggestions.push({type:'success',icon:'*',text:'Bravo! '+weekSessions+' sessions cette semaine, tu es productif!'})}
|
|
463
|
+
else if(weekSessions>=5){suggestions.push({type:'success',icon:'*',text:'Belle semaine avec '+weekSessions+' sessions. Continue!'})}
|
|
464
|
+
// 6. Projets sans documentation
|
|
465
|
+
var undocActive=PROJECTS.filter(function(p){return!p.hasClaudeMd&&p.status==='active'});
|
|
466
|
+
if(undocActive.length>0){suggestions.push({type:'warning',icon:'!',text:undocActive.length+' projet(s) actif(s) sans CLAUDE.md. Ajoute la doc pour une meilleure continuite.'})}
|
|
467
|
+
// Render suggestions (max 3)
|
|
468
|
+
clearEl(coachEl);
|
|
469
|
+
if(suggestions.length===0){var empty=document.createElement('div');empty.className='coach-empty';empty.textContent='Aucune suggestion pour le moment. Continue comme ca!';coachEl.appendChild(empty);return}
|
|
470
|
+
suggestions.slice(0,3).forEach(function(s){
|
|
471
|
+
var item=document.createElement('div');item.className='coach-item';
|
|
472
|
+
var icon=document.createElement('div');icon.className='coach-icon '+s.type;icon.textContent=s.icon;item.appendChild(icon);
|
|
473
|
+
var txt=document.createElement('div');txt.className='coach-text';txt.textContent=s.text;item.appendChild(txt);
|
|
474
|
+
coachEl.appendChild(item)})}
|
|
475
|
+
// Render Wisdom Patterns
|
|
476
|
+
renderPatterns();
|
|
477
|
+
function renderPatterns(){
|
|
478
|
+
var patternsEl=document.getElementById('patterns-list');if(!patternsEl)return;
|
|
479
|
+
clearEl(patternsEl);
|
|
480
|
+
if(!INSIGHTS||!INSIGHTS.wisdom||INSIGHTS.wisdom.length===0){
|
|
481
|
+
var empty=document.createElement('div');empty.className='pattern-empty';empty.textContent='Pas assez de donnees pour detecter des patterns.';patternsEl.appendChild(empty);return}
|
|
482
|
+
INSIGHTS.wisdom.forEach(function(w){
|
|
483
|
+
var item=document.createElement('div');item.className='pattern-item';
|
|
484
|
+
var icon=document.createElement('div');icon.className='pattern-icon';icon.textContent=w.icon;item.appendChild(icon);
|
|
485
|
+
var txt=document.createElement('div');txt.className='pattern-text';txt.textContent=w.text;item.appendChild(txt);
|
|
486
|
+
patternsEl.appendChild(item)})}
|
|
487
|
+
// Hide empty insight cards
|
|
488
|
+
['wip-list','keypoints-list','tag-cloud'].forEach(function(id){
|
|
489
|
+
var el=document.getElementById(id);
|
|
490
|
+
if(el&&el.childElementCount===0){var card=el.closest('.insight-card');if(card)card.style.display='none'}
|
|
491
|
+
});
|
|
492
|
+
// Timeline v2 rendering
|
|
493
|
+
if(TIMELINE_DATA&&TIMELINE_DATA.length>0){
|
|
494
|
+
document.getElementById('timeline-section').style.display='block';
|
|
495
|
+
var tlList=document.getElementById('timeline-list'),tlScroll=document.getElementById('timeline-scroll'),tlLegend=document.getElementById('timeline-legend'),tlFilters=document.getElementById('timeline-filters'),miniTip=document.getElementById('timeline-mini-tip');
|
|
496
|
+
var dayGroups={},projectSet={},activeFilter=null;
|
|
497
|
+
TIMELINE_DATA.forEach(function(s){if(!dayGroups[s.date])dayGroups[s.date]=[];dayGroups[s.date].push(s);var pKey=s.realProject||s.project;projectSet[pKey]={color:s.color,displayName:s.project}});
|
|
498
|
+
var sortedDates=Object.keys(dayGroups).sort().reverse();
|
|
499
|
+
var weekDays=['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'];
|
|
500
|
+
function getProjectInitials(name){var clean=name.replace(/^System32\s*->\s*/,'');var parts=clean.split(/[-_\s]/);if(parts.length>=2)return(parts[0][0]+parts[1][0]).toUpperCase();return clean.substring(0,2).toUpperCase()}
|
|
501
|
+
function renderTimeline(filter){
|
|
502
|
+
while(tlList.firstChild)tlList.removeChild(tlList.firstChild);while(tlScroll.firstChild)tlScroll.removeChild(tlScroll.firstChild);
|
|
503
|
+
var filteredDates=sortedDates;
|
|
504
|
+
sortedDates.forEach(function(date){
|
|
505
|
+
var d=new Date(date);var sessions=dayGroups[date].filter(function(s){if(!filter)return true;var pKey=s.realProject||s.project;return pKey===filter||s.project.includes(filter)});
|
|
506
|
+
if(sessions.length===0)return;
|
|
507
|
+
// List view - day header
|
|
508
|
+
var dayHeader=document.createElement('div');dayHeader.className='timeline-day-header';dayHeader.textContent=d.getDate()+'/'+(d.getMonth()+1)+' '+weekDays[d.getDay()]+' ('+sessions.length+')';tlList.appendChild(dayHeader);
|
|
509
|
+
// Dots view - day card
|
|
510
|
+
var dayEl=document.createElement('div');dayEl.className='timeline-day';
|
|
511
|
+
var dtEl=document.createElement('div');dtEl.className='timeline-date';dtEl.textContent=d.getDate()+'/'+(d.getMonth()+1);dayEl.appendChild(dtEl);
|
|
512
|
+
var dotsEl=document.createElement('div');dotsEl.className='timeline-dots';
|
|
513
|
+
sessions.forEach(function(s){
|
|
514
|
+
var pKey=s.realProject||s.project;var initials=getProjectInitials(s.project);var time=s.timestamp.split('T')[1].substring(0,5);
|
|
515
|
+
// List row
|
|
516
|
+
var row=document.createElement('div');row.className='timeline-row';row.title='Clic: copier resume | Dblclic: replay';
|
|
517
|
+
var rowTime=document.createElement('span');rowTime.className='timeline-row-time';rowTime.textContent=time;row.appendChild(rowTime);
|
|
518
|
+
var rowDot=document.createElement('div');rowDot.className='timeline-row-dot';rowDot.style.backgroundColor=s.color;row.appendChild(rowDot);
|
|
519
|
+
var rowProj=document.createElement('span');rowProj.className='timeline-row-project';rowProj.textContent=s.project;row.appendChild(rowProj);
|
|
520
|
+
var rowSum=document.createElement('span');rowSum.className='timeline-row-summary';rowSum.textContent=s.summary||'(pas de resume)';row.appendChild(rowSum);
|
|
521
|
+
var rowActions=document.createElement('div');rowActions.className='timeline-row-actions';
|
|
522
|
+
var btnLaunch=document.createElement('button');btnLaunch.className='timeline-row-btn';btnLaunch.textContent='Lancer';btnLaunch.addEventListener('click',function(e){e.stopPropagation();if(s.projectPath){claudeAction(e,s.projectPath,'resume')}else{copy('claude --dangerously-skip-permissions --resume '+s.sessionId);toast('Session copiee')}});rowActions.appendChild(btnLaunch);
|
|
523
|
+
var btnReplay=document.createElement('button');btnReplay.className='timeline-row-btn';btnReplay.textContent='Replay';btnReplay.addEventListener('click',function(e){e.stopPropagation();if(typeof openReplayModal==='function')openReplayModal(s.sessionId,'',s.summary)});rowActions.appendChild(btnReplay);
|
|
524
|
+
row.appendChild(rowActions);
|
|
525
|
+
row.addEventListener('click',function(e){if(s.projectPath){claudeAction(e,s.projectPath,'resume')}else{copy('claude --dangerously-skip-permissions --resume '+s.sessionId);toast('Session copiee')}});
|
|
526
|
+
row.addEventListener('dblclick',function(){if(typeof openReplayModal==='function')openReplayModal(s.sessionId,'',s.summary)});
|
|
527
|
+
tlList.appendChild(row);
|
|
528
|
+
// Dot for compact view
|
|
529
|
+
var dot=document.createElement('div');dot.className='timeline-dot';dot.style.backgroundColor=s.color;dot.textContent=initials;dot.dataset.project=s.project;dot.dataset.time=time;
|
|
530
|
+
dot.addEventListener('mouseenter',function(e){while(miniTip.firstChild)miniTip.removeChild(miniTip.firstChild);var tp=document.createElement('span');tp.className='timeline-mini-tip-proj';tp.textContent=s.project;miniTip.appendChild(tp);var tt=document.createElement('span');tt.className='timeline-mini-tip-time';tt.textContent=time;miniTip.appendChild(tt);miniTip.style.left=(e.clientX+10)+'px';miniTip.style.top=(e.clientY-30)+'px';miniTip.classList.add('show')});
|
|
531
|
+
dot.addEventListener('mouseleave',function(){miniTip.classList.remove('show')});
|
|
532
|
+
dot.addEventListener('click',function(e){if(s.projectPath){claudeAction(e,s.projectPath,'resume')}else{copy('claude --dangerously-skip-permissions --resume '+s.sessionId);toast('Session copiee')}});
|
|
533
|
+
dot.addEventListener('dblclick',function(){if(typeof openReplayModal==='function')openReplayModal(s.sessionId,'',s.summary)});
|
|
534
|
+
dotsEl.appendChild(dot)});
|
|
535
|
+
dayEl.appendChild(dotsEl);tlScroll.appendChild(dayEl)})}
|
|
536
|
+
renderTimeline(null);
|
|
537
|
+
// Legend with filter functionality
|
|
538
|
+
Object.keys(projectSet).sort().forEach(function(p){var item=document.createElement('div');item.className='timeline-legend-item';item.dataset.project=p;var dot=document.createElement('div');dot.className='timeline-legend-dot';dot.style.backgroundColor=projectSet[p].color;item.appendChild(dot);var name=document.createElement('span');name.textContent=p.length>20?p.substring(0,18)+'..':p;name.title=p;item.appendChild(name);
|
|
539
|
+
item.addEventListener('click',function(){if(activeFilter===p){activeFilter=null;document.querySelectorAll('.timeline-legend-item').forEach(function(x){x.classList.remove('active','dimmed')});renderTimeline(null)}else{activeFilter=p;document.querySelectorAll('.timeline-legend-item').forEach(function(x){x.classList.remove('active');x.classList.add('dimmed')});this.classList.remove('dimmed');this.classList.add('active');renderTimeline(p)}});
|
|
540
|
+
tlLegend.appendChild(item)});
|
|
541
|
+
// GitHub-style heatmap
|
|
542
|
+
var heatmapEl=document.getElementById('timeline-heatmap-view');
|
|
543
|
+
function buildHeatmap(){
|
|
544
|
+
while(heatmapEl.firstChild)heatmapEl.removeChild(heatmapEl.firstChild);
|
|
545
|
+
var sessionsByDate={};var totalSessions=0;var maxPerDay=0;var activeDays=0;var currentStreak=0;var longestStreak=0;var tempStreak=0;
|
|
546
|
+
TIMELINE_DATA.forEach(function(s){if(!sessionsByDate[s.date])sessionsByDate[s.date]=0;sessionsByDate[s.date]++;totalSessions++;if(sessionsByDate[s.date]>maxPerDay)maxPerDay=sessionsByDate[s.date]});
|
|
547
|
+
// Build 60 days grid (going back from today)
|
|
548
|
+
var today=new Date();today.setHours(0,0,0,0);
|
|
549
|
+
var startDate=new Date(today);startDate.setDate(startDate.getDate()-59);
|
|
550
|
+
// Align to Sunday
|
|
551
|
+
while(startDate.getDay()!==0)startDate.setDate(startDate.getDate()-1);
|
|
552
|
+
var wrapper=document.createElement('div');wrapper.className='heatmap-wrapper';
|
|
553
|
+
// Day labels
|
|
554
|
+
var daysLabels=document.createElement('div');daysLabels.className='heatmap-days';
|
|
555
|
+
['','Lun','','Mer','','Ven',''].forEach(function(d){var lbl=document.createElement('div');lbl.className='heatmap-day-label';lbl.textContent=d;daysLabels.appendChild(lbl)});
|
|
556
|
+
wrapper.appendChild(daysLabels);
|
|
557
|
+
// Grid
|
|
558
|
+
var grid=document.createElement('div');grid.className='heatmap-grid';
|
|
559
|
+
var currentDate=new Date(startDate);var weekEl=null;var months=[];var lastMonth=-1;
|
|
560
|
+
while(currentDate<=today){
|
|
561
|
+
if(currentDate.getDay()===0){weekEl=document.createElement('div');weekEl.className='heatmap-week';grid.appendChild(weekEl);
|
|
562
|
+
if(currentDate.getMonth()!==lastMonth){months.push({month:currentDate.toLocaleDateString('fr-FR',{month:'short'}),week:grid.children.length-1});lastMonth=currentDate.getMonth()}}
|
|
563
|
+
var dateStr=currentDate.toISOString().slice(0,10);
|
|
564
|
+
var count=sessionsByDate[dateStr]||0;
|
|
565
|
+
var level=count===0?0:count===1?1:count===2?2:count<=4?3:4;
|
|
566
|
+
var cell=document.createElement('div');cell.className='heatmap-cell l'+level;cell.dataset.date=dateStr;cell.dataset.count=count;
|
|
567
|
+
cell.title=currentDate.toLocaleDateString('fr-FR',{weekday:'short',day:'numeric',month:'short'})+': '+count+' session'+(count!==1?'s':'');
|
|
568
|
+
cell.addEventListener('click',function(){var d=this.dataset.date;if(sessionsByDate[d]){activeFilter=null;document.querySelectorAll('.timeline-legend-item').forEach(function(x){x.classList.remove('active','dimmed')});renderTimeline(null);
|
|
569
|
+
document.querySelectorAll('.timeline-view-btn').forEach(function(b){b.classList.remove('active')});document.querySelector('[data-view="list"]').classList.add('active');
|
|
570
|
+
heatmapEl.classList.remove('active');document.getElementById('timeline-list-view').classList.remove('hidden');document.getElementById('timeline-dots-view').classList.remove('active');
|
|
571
|
+
setTimeout(function(){var header=document.querySelector('.timeline-day-header');if(header){var headers=document.querySelectorAll('.timeline-day-header');for(var h of headers){if(h.textContent.includes(new Date(d).getDate()+'/')){h.scrollIntoView({behavior:'smooth',block:'start'});break}}}},100)}});
|
|
572
|
+
if(weekEl)weekEl.appendChild(cell);
|
|
573
|
+
// Stats
|
|
574
|
+
if(count>0){activeDays++;tempStreak++;if(tempStreak>longestStreak)longestStreak=tempStreak}else{tempStreak=0}
|
|
575
|
+
if(dateStr===today.toISOString().slice(0,10)||dateStr===new Date(today.getTime()-86400000).toISOString().slice(0,10)){if(count>0)currentStreak=tempStreak}
|
|
576
|
+
currentDate.setDate(currentDate.getDate()+1)}
|
|
577
|
+
wrapper.appendChild(grid);heatmapEl.appendChild(wrapper);
|
|
578
|
+
// Legend
|
|
579
|
+
var legend=document.createElement('div');legend.className='heatmap-legend';
|
|
580
|
+
var legendLabel=document.createElement('span');legendLabel.className='heatmap-legend-label';legendLabel.textContent='Moins';legend.appendChild(legendLabel);
|
|
581
|
+
var legendCells=document.createElement('div');legendCells.className='heatmap-legend-cells';
|
|
582
|
+
[0,1,2,3,4].forEach(function(l){var c=document.createElement('div');c.className='heatmap-legend-cell l'+l;legendCells.appendChild(c)});
|
|
583
|
+
legend.appendChild(legendCells);
|
|
584
|
+
var legendLabel2=document.createElement('span');legendLabel2.textContent='Plus';legend.appendChild(legendLabel2);
|
|
585
|
+
heatmapEl.appendChild(legend);
|
|
586
|
+
// Stats
|
|
587
|
+
var stats=document.createElement('div');stats.className='heatmap-stats';
|
|
588
|
+
[{v:totalSessions,l:'sessions'},{v:activeDays,l:'jours actifs'},{v:currentStreak,l:'streak actuel'},{v:longestStreak,l:'meilleur streak'}].forEach(function(s){
|
|
589
|
+
var stat=document.createElement('div');stat.className='heatmap-stat';
|
|
590
|
+
var val=document.createElement('div');val.className='heatmap-stat-value';val.textContent=s.v;stat.appendChild(val);
|
|
591
|
+
var lbl=document.createElement('div');lbl.className='heatmap-stat-label';lbl.textContent=s.l;stat.appendChild(lbl);
|
|
592
|
+
stats.appendChild(stat)});
|
|
593
|
+
heatmapEl.appendChild(stats)}
|
|
594
|
+
buildHeatmap();
|
|
595
|
+
// View toggle
|
|
596
|
+
document.querySelectorAll('.timeline-view-btn').forEach(function(btn){btn.addEventListener('click',function(){document.querySelectorAll('.timeline-view-btn').forEach(function(b){b.classList.remove('active')});this.classList.add('active');var view=this.dataset.view;
|
|
597
|
+
document.getElementById('timeline-heatmap-view').classList.toggle('active',view==='heatmap');
|
|
598
|
+
document.getElementById('timeline-list-view').classList.toggle('hidden',view!=='list');
|
|
599
|
+
document.getElementById('timeline-dots-view').classList.toggle('active',view==='dots')})})}
|
|
600
|
+
// Charts rendering - lazy init for tab system (Chart.js needs visible canvas)
|
|
601
|
+
if(typeof Chart!=='undefined'&&(CHART_PROJECTS.length>0||CHART_WEEKLY_VALUES.length>0||CHART_TAGS.length>0)){
|
|
602
|
+
document.getElementById('charts-section').style.display='block';
|
|
603
|
+
var dashboardChartsRendered=false;
|
|
604
|
+
dashboardChartsInit=function(){
|
|
605
|
+
if(dashboardChartsRendered)return;dashboardChartsRendered=true;
|
|
606
|
+
var chartDefaults={responsive:true,maintainAspectRatio:false,plugins:{legend:{display:false}}};
|
|
607
|
+
var isDark=store.theme!=='light';Chart.defaults.color=isDark?'#a1a1aa':'#64748b';Chart.defaults.borderColor=isDark?'rgba(255,255,255,.1)':'rgba(0,0,0,.1)';
|
|
608
|
+
if(CHART_PROJECTS_TIME&&CHART_PROJECTS_TIME.length>0){new Chart(document.getElementById('chart-time'),{type:'bar',data:{labels:CHART_PROJECTS_TIME.map(function(p){return p.name}),datasets:[{data:CHART_PROJECTS_TIME.map(function(p){return p.hours}),backgroundColor:CHART_PROJECTS_TIME.map(function(p){return p.color||'#8b5cf6'}),borderRadius:4}]},options:Object.assign({},chartDefaults,{indexAxis:'y',scales:{x:{grid:{display:false},title:{display:true,text:'heures',font:{size:10},color:'#888'}},y:{grid:{display:false}}},plugins:{legend:{display:false},tooltip:{callbacks:{label:function(ctx){var d=CHART_PROJECTS_TIME[ctx.dataIndex];return d.hours+'h ('+d.sessions+' sessions)'}}}}})})}
|
|
609
|
+
if(CHART_WEEKLY_HOURS&&CHART_WEEKLY_HOURS.length>0){new Chart(document.getElementById('chart-hours'),{type:'bar',data:{labels:CHART_WEEKLY_LABELS,datasets:[{data:CHART_WEEKLY_HOURS,backgroundColor:'rgba(139,92,246,.7)',borderRadius:4}]},options:Object.assign({},chartDefaults,{scales:{x:{grid:{display:false}},y:{beginAtZero:true,title:{display:true,text:'heures',font:{size:10},color:'#888'}}},plugins:{legend:{display:false},tooltip:{callbacks:{label:function(ctx){return ctx.raw+'h'}}}}})})}
|
|
610
|
+
if(CHART_PROJECTS.length>0){new Chart(document.getElementById('chart-projects'),{type:'bar',data:{labels:CHART_PROJECTS.map(function(p){return p.name}),datasets:[{data:CHART_PROJECTS.map(function(p){return p.count}),backgroundColor:CHART_PROJECTS.map(function(p){return p.color}),borderRadius:4}]},options:Object.assign({},chartDefaults,{indexAxis:'y',scales:{x:{grid:{display:false}},y:{grid:{display:false}}}})})}
|
|
611
|
+
if(CHART_TAGS.length>0){new Chart(document.getElementById('chart-tags'),{type:'doughnut',data:{labels:CHART_TAGS.map(function(t){return t.tag}),datasets:[{data:CHART_TAGS.map(function(t){return t.count}),backgroundColor:['#8b5cf6','#3b82f6','#22c55e','#eab308','#ef4444','#ec4899'],borderWidth:0}]},options:Object.assign({},chartDefaults,{cutout:'60%',plugins:{legend:{display:true,position:'right',labels:{boxWidth:10,padding:8,font:{size:10}}}}})})}else{var cte=document.getElementById('chart-tags');if(cte){var wp=cte.parentElement;while(wp.firstChild)wp.removeChild(wp.firstChild);var msg=document.createElement('div');msg.style.cssText='display:flex;align-items:center;justify-content:center;height:100%;color:var(--dim);font-size:.75rem;font-style:italic';msg.textContent='Pas de donnees';wp.appendChild(msg)}}
|
|
612
|
+
}
|
|
613
|
+
lazyChartCallbacks.dashboard=dashboardChartsInit;
|
|
614
|
+
// If dashboard is the initial tab, render charts immediately
|
|
615
|
+
if(activeTab==='dashboard')dashboardChartsInit();
|
|
616
|
+
}
|
|
617
|
+
// === COST SECTION ===
|
|
618
|
+
if(COST_DAILY&&COST_DAILY.length>0){
|
|
619
|
+
var costCurrency='USD',costRates={USD:1},costCharts=[];
|
|
620
|
+
var currencySymbols={USD:'$',EUR:'\u20ac',GBP:'\u00a3',CHF:'Fr',JPY:'\u00a5',CAD:'C$',AUD:'A$',CNY:'\u00a5',INR:'\u20b9',BRL:'R$',MXN:'Mx$',PLN:'z\u0142',SEK:'kr',NOK:'kr',DKK:'kr',KRW:'\u20a9'};
|
|
621
|
+
var modelKeys=Object.keys(COST_MODELS||{});
|
|
622
|
+
var topModel='',topCost=0;
|
|
623
|
+
modelKeys.forEach(function(k){if(COST_MODELS[k]>topCost){topCost=COST_MODELS[k];topModel=k}});
|
|
624
|
+
(function(){try{fetch('https://open.er-api.com/v6/latest/USD').then(function(r){return r.json()}).then(function(d){if(d.rates){costRates=d.rates;costRates.USD=1}}).catch(function(){var sel=document.getElementById('cost-currency-btn');if(sel)sel.title='Taux hors-ligne: USD uniquement'})}catch(e){}})()
|
|
625
|
+
function formatCost(usd){var r=costRates[costCurrency]||1;var v=usd*r;var sym=currencySymbols[costCurrency]||costCurrency;if(costCurrency==='JPY'||costCurrency==='KRW')return sym+Math.round(v);return sym+v.toFixed(2)}
|
|
626
|
+
function formatTokens(n){if(n>=1e9)return(n/1e9).toFixed(1)+'B';if(n>=1e6)return(n/1e6).toFixed(1)+'M';if(n>=1e3)return(n/1e3).toFixed(1)+'K';return n.toString()}
|
|
627
|
+
function makeTd(text){var td=document.createElement('td');td.textContent=text;return td}
|
|
628
|
+
var PLAN_COST=200;
|
|
629
|
+
var costPeriod=30;
|
|
630
|
+
function getFilteredCostDaily(){
|
|
631
|
+
if(costPeriod===0)return COST_DAILY;
|
|
632
|
+
var cutoff=new Date();cutoff.setDate(cutoff.getDate()-costPeriod);
|
|
633
|
+
var cs=cutoff.toISOString().slice(0,10);
|
|
634
|
+
return COST_DAILY.filter(function(d){return d.date>=cs});
|
|
635
|
+
}
|
|
636
|
+
function renderCostSection(){
|
|
637
|
+
var filtered=getFilteredCostDaily();
|
|
638
|
+
var days=filtered.length;
|
|
639
|
+
var total=0;filtered.forEach(function(d){total+=d.totalCost||0});
|
|
640
|
+
var avg=days>0?total/days:0;
|
|
641
|
+
var tokens=0;filtered.forEach(function(d){tokens+=d.totalTokens||0});
|
|
642
|
+
var shortModel=topModel.replace(/^claude-/,'').replace(/-\d{8}$/,'');
|
|
643
|
+
var planV=PLAN_COST*(costRates[costCurrency]||1);
|
|
644
|
+
document.getElementById('cost-plan').textContent=formatCost(PLAN_COST);
|
|
645
|
+
document.getElementById('cost-total').textContent=formatCost(total);
|
|
646
|
+
document.getElementById('cost-total').className='cost-val';
|
|
647
|
+
var roi=PLAN_COST>0?total/PLAN_COST:0;
|
|
648
|
+
var roiEl=document.getElementById('cost-roi');
|
|
649
|
+
roiEl.textContent='x'+roi.toFixed(1);
|
|
650
|
+
roiEl.className='cost-val'+(roi>=5?' ok':roi>=2?' warn':' err');
|
|
651
|
+
var avgEl=document.getElementById('cost-avg');
|
|
652
|
+
avgEl.textContent=formatCost(avg);
|
|
653
|
+
avgEl.className='cost-val';
|
|
654
|
+
document.getElementById('cost-tokens').textContent=formatTokens(tokens);
|
|
655
|
+
var realDaily=days>0?PLAN_COST/30:0;
|
|
656
|
+
document.getElementById('cost-real-daily').textContent=formatCost(realDaily);
|
|
657
|
+
document.getElementById('cost-real-daily').className='cost-val ok';
|
|
658
|
+
var savings=total>PLAN_COST?total-PLAN_COST:0;
|
|
659
|
+
var savEl=document.getElementById('cost-savings');
|
|
660
|
+
savEl.textContent=formatCost(savings);
|
|
661
|
+
savEl.className='cost-val'+(savings>0?' ok':'');
|
|
662
|
+
document.getElementById('cost-top-model').textContent=shortModel||'-';
|
|
663
|
+
document.getElementById('cost-top-model').title=topModel;
|
|
664
|
+
if(LAST_MODEL){var sl=LAST_MODEL.replace(/^claude-/,'').replace(/-\d{8}$/,'');document.getElementById('cost-last-model').textContent='Dernier: '+sl;document.getElementById('cost-last-model').title=LAST_MODEL}
|
|
665
|
+
document.getElementById('cost-roi-text').textContent='ROI x'+roi.toFixed(1)+' | Tu consommes '+formatCost(total)+' de valeur API pour '+formatCost(PLAN_COST)+' de forfait (economie: '+formatCost(savings)+')';
|
|
666
|
+
var statCost=document.getElementById('stat-cost');
|
|
667
|
+
if(statCost){statCost.textContent='x'+roi.toFixed(1);statCost.className='stat-val'+(roi>=5?' ok':roi>=2?' warn':' err')}
|
|
668
|
+
var tbody=document.getElementById('cost-table-body');
|
|
669
|
+
while(tbody.firstChild)tbody.removeChild(tbody.firstChild);
|
|
670
|
+
var recent=filtered.slice(-10).reverse();
|
|
671
|
+
recent.forEach(function(d){
|
|
672
|
+
var tr=document.createElement('tr');
|
|
673
|
+
tr.appendChild(makeTd(d.date));
|
|
674
|
+
tr.appendChild(makeTd(formatCost(d.totalCost||0)));
|
|
675
|
+
tr.appendChild(makeTd(formatTokens(d.totalTokens||0)));
|
|
676
|
+
tr.appendChild(makeTd(formatTokens(d.inputTokens||0)));
|
|
677
|
+
tr.appendChild(makeTd(formatTokens(d.outputTokens||0)));
|
|
678
|
+
tr.appendChild(makeTd(formatTokens((d.cacheCreationTokens||0)+(d.cacheReadTokens||0))));
|
|
679
|
+
tbody.appendChild(tr)});
|
|
680
|
+
document.getElementById('cost-section').style.display='block'}
|
|
681
|
+
function renderCostCharts(){
|
|
682
|
+
costCharts.forEach(function(c){c.destroy()});costCharts=[];
|
|
683
|
+
var filtered=getFilteredCostDaily();
|
|
684
|
+
var isDk=store.theme!=='light';
|
|
685
|
+
var labels=filtered.map(function(d){return d.date.slice(5)});
|
|
686
|
+
var costs=filtered.map(function(d){var v=d.totalCost||0;return v*(costRates[costCurrency]||1)});
|
|
687
|
+
// 1. Daily cost (area)
|
|
688
|
+
var ctx1=document.getElementById('chart-cost-daily');
|
|
689
|
+
var g1=ctx1.getContext('2d');
|
|
690
|
+
var grad=g1.createLinearGradient(0,0,0,220);grad.addColorStop(0,'rgba(139,92,246,.4)');grad.addColorStop(1,'rgba(139,92,246,.02)');
|
|
691
|
+
costCharts.push(new Chart(ctx1,{type:'line',data:{labels:labels,datasets:[{data:costs,borderColor:'#8b5cf6',backgroundColor:grad,fill:true,tension:.3,pointRadius:2,pointHoverRadius:5,borderWidth:2}]},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{display:false},tooltip:{callbacks:{label:function(c){return formatCost(filtered[c.dataIndex].totalCost||0)}}}},scales:{x:{grid:{display:false},ticks:{font:{size:9},maxRotation:45}},y:{grid:{color:isDk?'rgba(255,255,255,.06)':'rgba(0,0,0,.06)'},ticks:{font:{size:9},callback:function(v){return (currencySymbols[costCurrency]||costCurrency)+v.toFixed(0)}}}}}}));
|
|
692
|
+
// 2. Tokens stacked bar
|
|
693
|
+
var inp=filtered.map(function(d){return d.inputTokens||0});
|
|
694
|
+
var out=filtered.map(function(d){return d.outputTokens||0});
|
|
695
|
+
var cc=filtered.map(function(d){return d.cacheCreationTokens||0});
|
|
696
|
+
var cr=filtered.map(function(d){return d.cacheReadTokens||0});
|
|
697
|
+
costCharts.push(new Chart(document.getElementById('chart-cost-tokens'),{type:'bar',data:{labels:labels,datasets:[{label:'Input',data:inp,backgroundColor:'#8b5cf6'},{label:'Output',data:out,backgroundColor:'#3b82f6'},{label:'Cache Create',data:cc,backgroundColor:'#22c55e'},{label:'Cache Read',data:cr,backgroundColor:'#eab308'}]},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{display:true,position:'bottom',labels:{boxWidth:8,padding:6,font:{size:9}}}},scales:{x:{stacked:true,grid:{display:false},ticks:{font:{size:9},maxRotation:45}},y:{stacked:true,grid:{color:isDk?'rgba(255,255,255,.06)':'rgba(0,0,0,.06)'},ticks:{font:{size:9},callback:function(v){return formatTokens(v)}}}}}}));
|
|
698
|
+
// 3. Cost by model (doughnut) - recalculate from filtered data
|
|
699
|
+
var fModels={};filtered.forEach(function(d){if(d.models){Object.keys(d.models).forEach(function(k){fModels[k]=(fModels[k]||0)+d.models[k]})}});
|
|
700
|
+
var fModelKeys=Object.keys(fModels);if(fModelKeys.length===0){fModels=COST_MODELS||{};fModelKeys=modelKeys}
|
|
701
|
+
var mLabels=[],mData=[],mColors=['#8b5cf6','#3b82f6','#22c55e','#eab308','#ef4444','#ec4899','#f97316','#06b6d4'];
|
|
702
|
+
fModelKeys.sort(function(a,b){return (fModels[b]||0)-(fModels[a]||0)});
|
|
703
|
+
fModelKeys.forEach(function(k){mLabels.push(k.replace(/^claude-/,'').replace(/-\d{8}$/,''));var v=fModels[k]||0;mData.push(v*(costRates[costCurrency]||1))});
|
|
704
|
+
costCharts.push(new Chart(document.getElementById('chart-cost-models'),{type:'doughnut',data:{labels:mLabels,datasets:[{data:mData,backgroundColor:mColors.slice(0,mLabels.length),borderWidth:0}]},options:{responsive:true,maintainAspectRatio:false,cutout:'60%',plugins:{legend:{display:true,position:'right',labels:{boxWidth:8,padding:6,font:{size:9}}},tooltip:{callbacks:{label:function(c){return c.label+': '+formatCost(mData[c.dataIndex]/(costRates[costCurrency]||1))}}}}}}));
|
|
705
|
+
// 4. Forfait vs Valeur API (horizontal bar)
|
|
706
|
+
var days=filtered.length;
|
|
707
|
+
var total=0;filtered.forEach(function(d){total+=d.totalCost||0});
|
|
708
|
+
var proj=days>0?(total/days)*30:0;
|
|
709
|
+
var projV=proj*(costRates[costCurrency]||1);
|
|
710
|
+
var planBar=PLAN_COST*(costRates[costCurrency]||1);
|
|
711
|
+
var maxV=Math.max(projV,planBar)*1.2;
|
|
712
|
+
costCharts.push(new Chart(document.getElementById('chart-cost-plan'),{type:'bar',data:{labels:['Forfait Max x20','Valeur API/mois','Economie'],datasets:[{data:[planBar,projV,Math.max(projV-planBar,0)],backgroundColor:['#3b82f6','#8b5cf6','#22c55e'],borderRadius:4}]},options:{responsive:true,maintainAspectRatio:false,indexAxis:'y',plugins:{legend:{display:false},tooltip:{callbacks:{label:function(c){return formatCost(c.raw/(costRates[costCurrency]||1))+'/mois'}}}},scales:{x:{max:maxV,grid:{color:isDk?'rgba(255,255,255,.06)':'rgba(0,0,0,.06)'},ticks:{font:{size:9},callback:function(v){return (currencySymbols[costCurrency]||costCurrency)+v.toFixed(0)}}},y:{grid:{display:false},ticks:{font:{size:10}}}}}}));
|
|
713
|
+
// 5. Hourly activity timeline (bar chart with real JSONL data)
|
|
714
|
+
if(COST_HOURLY&&COST_HOURLY.length>0){
|
|
715
|
+
var hLabels=COST_HOURLY.map(function(h){var p=h.hour.split(' ');return p[0].slice(5)+' '+p[1].slice(0,5)});
|
|
716
|
+
var hCosts=COST_HOURLY.map(function(h){var v=h.cost||0;return v*(costRates[costCurrency]||1)});
|
|
717
|
+
var hTokens=COST_HOURLY.map(function(h){return h.tokens||0});
|
|
718
|
+
var hCostColors=COST_HOURLY.map(function(h){var c=h.cost||0;return c>10?'#ef4444':c>3?'#eab308':c>0.5?'#8b5cf6':'#3b82f6'});
|
|
719
|
+
var hGrid=isDk?'rgba(255,255,255,.06)':'rgba(0,0,0,.06)';
|
|
720
|
+
costCharts.push(new Chart(document.getElementById('chart-cost-hourly'),{type:'bar',data:{labels:hLabels,datasets:[{label:'Valeur API',data:hCosts,backgroundColor:hCostColors,borderRadius:2,yAxisID:'y'},{label:'Tokens',data:hTokens,type:'line',borderColor:'#22c55e',backgroundColor:'rgba(34,197,94,.1)',fill:true,tension:.3,pointRadius:0,borderWidth:1.5,yAxisID:'y1'}]},options:{responsive:true,maintainAspectRatio:false,interaction:{mode:'index',intersect:false},plugins:{legend:{display:true,position:'bottom',labels:{boxWidth:8,padding:8,font:{size:9}}},tooltip:{callbacks:{label:function(c){if(c.datasetIndex===1)return formatTokens(c.raw)+' tokens ('+COST_HOURLY[c.dataIndex].messages+' msgs)';return formatCost(c.raw/(costRates[costCurrency]||1))}}}},scales:{x:{grid:{display:false},ticks:{font:{size:10},maxRotation:45,autoSkip:true,maxTicksLimit:24}},y:{position:'left',grid:{color:hGrid},ticks:{font:{size:11},callback:function(v){return (currencySymbols[costCurrency]||costCurrency)+v.toFixed(0)}},title:{display:true,text:'Valeur API',font:{size:11},color:'#888'}},y1:{position:'right',grid:{display:false},ticks:{font:{size:11},callback:function(v){return formatTokens(v)}},title:{display:true,text:'Tokens',font:{size:11},color:'#888'}}}}}));
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
renderCostSection();
|
|
724
|
+
costChartsLazy=function(){if(!costChartsLazyDone){costChartsLazyDone=true;renderCostCharts()}};
|
|
725
|
+
document.getElementById('cost-currency-btn').addEventListener('change',function(e){
|
|
726
|
+
e.stopPropagation();
|
|
727
|
+
costCurrency=this.value;
|
|
728
|
+
renderCostSection();if(costChartsLazyDone)renderCostCharts()});
|
|
729
|
+
document.getElementById('cost-period-bar').addEventListener('click',function(e){
|
|
730
|
+
var btn=e.target.closest('.filter-btn');if(!btn)return;
|
|
731
|
+
costPeriod=parseInt(btn.dataset.period);
|
|
732
|
+
this.querySelectorAll('.filter-btn').forEach(function(b){b.classList.remove('active')});
|
|
733
|
+
btn.classList.add('active');
|
|
734
|
+
renderCostSection();if(costChartsLazyDone)renderCostCharts();
|
|
735
|
+
});
|
|
736
|
+
document.getElementById('btn-csv-costs').addEventListener('click',function(){
|
|
737
|
+
var filtered=getFilteredCostDaily();
|
|
738
|
+
var rows=[['Date','Cout USD','Tokens','Input','Output','Cache Creation','Cache Read']];
|
|
739
|
+
filtered.forEach(function(d){rows.push([d.date,(d.totalCost||0).toFixed(2),d.totalTokens||0,d.inputTokens||0,d.outputTokens||0,d.cacheCreationTokens||0,d.cacheReadTokens||0])});
|
|
740
|
+
var suffix=costPeriod===0?'all':costPeriod+'j';
|
|
741
|
+
downloadCSV(rows,'coderadar-couts-'+suffix+'-'+new Date().toISOString().slice(0,10)+'.csv');
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
// === DISK SECTION ===
|
|
745
|
+
if(DISK_SUMMARY&&DISK_SUMMARY.driveFree){
|
|
746
|
+
function formatDiskSize(bytes){if(!bytes||bytes===0)return '0 B';if(bytes>=1099511627776)return(bytes/1099511627776).toFixed(1)+' TB';if(bytes>=1073741824)return(bytes/1073741824).toFixed(1)+' GB';if(bytes>=1048576)return(bytes/1048576).toFixed(1)+' MB';if(bytes>=1024)return(bytes/1024).toFixed(1)+' KB';return bytes+' B'}
|
|
747
|
+
function decodeDirName(n){try{return decodeURIComponent(n.replace(/-/g,'%').replace(/%(%)/g,'%25$1'))}catch(e){return n.replace(/-/g,'\\')}}
|
|
748
|
+
var diskCharts=[];
|
|
749
|
+
function renderDiskSection(){
|
|
750
|
+
var free=DISK_SUMMARY.driveFree;var total=DISK_SUMMARY.driveTotal;var used=DISK_SUMMARY.driveUsed;
|
|
751
|
+
var pct=total>0?Math.round(used/total*100):0;
|
|
752
|
+
// Gauge bar
|
|
753
|
+
var gaugeFill=document.getElementById('disk-gauge-fill');
|
|
754
|
+
var gaugeText=document.getElementById('disk-gauge-text');
|
|
755
|
+
gaugeFill.style.width=pct+'%';
|
|
756
|
+
gaugeFill.className='disk-gauge-fill'+(pct>85?' err':pct>70?' warn':' ok');
|
|
757
|
+
gaugeText.textContent=formatDiskSize(used)+' / '+formatDiskSize(total)+' ('+pct+'%)';
|
|
758
|
+
// Stat cards
|
|
759
|
+
var freeGB=free/1073741824;
|
|
760
|
+
var freeEl=document.getElementById('disk-free');
|
|
761
|
+
freeEl.textContent=formatDiskSize(free);
|
|
762
|
+
freeEl.className='disk-val'+(freeGB>100?' ok':freeGB>50?' warn':' err');
|
|
763
|
+
document.getElementById('disk-claude-total').textContent=formatDiskSize(DISK_SUMMARY.claudeTotal);
|
|
764
|
+
var dirs=DISK_SUMMARY.claudeDirs||[];
|
|
765
|
+
var pluginSize=0,sessionSize=0;
|
|
766
|
+
dirs.forEach(function(d){if(d.name==='Plugins MCP')pluginSize=d.sizeBytes;if(d.name==='Sessions Projets')sessionSize=d.sizeBytes});
|
|
767
|
+
document.getElementById('disk-plugins').textContent=formatDiskSize(pluginSize);
|
|
768
|
+
document.getElementById('disk-sessions').textContent=formatDiskSize(sessionSize);
|
|
769
|
+
// Stat bar
|
|
770
|
+
var statDisk=document.getElementById('stat-disk');
|
|
771
|
+
if(statDisk){statDisk.textContent=formatDiskSize(free);statDisk.className='stat-val'+(freeGB>100?' ok':freeGB>50?' warn':' err')}
|
|
772
|
+
// Table
|
|
773
|
+
var tbody=document.getElementById('disk-table-body');
|
|
774
|
+
while(tbody.firstChild)tbody.removeChild(tbody.firstChild);
|
|
775
|
+
var ct=DISK_SUMMARY.claudeTotal||1;
|
|
776
|
+
dirs.sort(function(a,b){return(b.sizeBytes||0)-(a.sizeBytes||0)});
|
|
777
|
+
dirs.forEach(function(d){
|
|
778
|
+
var tr=document.createElement('tr');
|
|
779
|
+
var td1=document.createElement('td');td1.textContent=d.name;tr.appendChild(td1);
|
|
780
|
+
var td2=document.createElement('td');td2.textContent=formatDiskSize(d.sizeBytes);td2.style.fontWeight='600';tr.appendChild(td2);
|
|
781
|
+
var td3=document.createElement('td');td3.textContent=(d.files||0).toLocaleString();tr.appendChild(td3);
|
|
782
|
+
var td4=document.createElement('td');td4.textContent=ct>0?((d.sizeBytes/ct)*100).toFixed(1)+'%':'0%';tr.appendChild(td4);
|
|
783
|
+
var td5=document.createElement('td');td5.textContent=d.path;td5.style.fontSize='.65rem';td5.style.color='var(--dim)';tr.appendChild(td5);
|
|
784
|
+
tbody.appendChild(tr)});
|
|
785
|
+
document.getElementById('disk-section').style.display='block'}
|
|
786
|
+
function renderDiskCharts(){
|
|
787
|
+
diskCharts.forEach(function(c){c.destroy()});diskCharts=[];
|
|
788
|
+
var isDk=store.theme!=='light';
|
|
789
|
+
var gridColor=isDk?'rgba(255,255,255,.06)':'rgba(0,0,0,.06)';
|
|
790
|
+
var dColors=['#8b5cf6','#3b82f6','#22c55e','#eab308','#ef4444','#ec4899','#f97316','#06b6d4'];
|
|
791
|
+
// 1. Doughnut - Claude Code breakdown
|
|
792
|
+
var dirs=DISK_SUMMARY.claudeDirs||[];
|
|
793
|
+
dirs.sort(function(a,b){return(b.sizeBytes||0)-(a.sizeBytes||0)});
|
|
794
|
+
var dLabels=dirs.map(function(d){return d.name});
|
|
795
|
+
var dData=dirs.map(function(d){return d.sizeBytes||0});
|
|
796
|
+
diskCharts.push(new Chart(document.getElementById('chart-disk-breakdown'),{type:'doughnut',data:{labels:dLabels,datasets:[{data:dData,backgroundColor:dColors.slice(0,dLabels.length),borderWidth:0}]},options:{responsive:true,maintainAspectRatio:false,cutout:'60%',plugins:{legend:{display:true,position:'right',labels:{boxWidth:8,padding:6,font:{size:9}}},tooltip:{callbacks:{label:function(c){return c.label+': '+formatDiskSize(c.raw)}}}}}}));
|
|
797
|
+
// 2. Bar horizontal - Top 10 sessions Claude
|
|
798
|
+
var sp=(DISK_PROJECTS||[]).slice(0,10);
|
|
799
|
+
if(sp.length>0){
|
|
800
|
+
var sLabels=sp.map(function(p){var parts=p.name.split('-');return parts.length>2?decodeDirName(parts.slice(0,-1).join('-')):p.name.substring(0,30)});
|
|
801
|
+
var sData=sp.map(function(p){return p.sizeBytes||0});
|
|
802
|
+
diskCharts.push(new Chart(document.getElementById('chart-disk-sessions'),{type:'bar',data:{labels:sLabels,datasets:[{data:sData,backgroundColor:'#8b5cf6',borderRadius:4}]},options:{responsive:true,maintainAspectRatio:false,indexAxis:'y',plugins:{legend:{display:false},tooltip:{callbacks:{label:function(c){return formatDiskSize(c.raw)}}}},scales:{x:{grid:{color:gridColor},ticks:{font:{size:9},callback:function(v){return formatDiskSize(v)}}},y:{grid:{display:false},ticks:{font:{size:9}}}}}}));}
|
|
803
|
+
// 3. Bar horizontal - Top 10 projets dev
|
|
804
|
+
var dp=(DISK_DEV_PROJECTS||[]).slice(0,10);
|
|
805
|
+
if(dp.length>0){
|
|
806
|
+
var dpLabels=dp.map(function(p){return p.name});
|
|
807
|
+
var dpData=dp.map(function(p){return p.sizeBytes||0});
|
|
808
|
+
var dpColors=dp.map(function(p){return p.source==='source/repos'?'#3b82f6':'#22c55e'});
|
|
809
|
+
diskCharts.push(new Chart(document.getElementById('chart-disk-devprojects'),{type:'bar',data:{labels:dpLabels,datasets:[{data:dpData,backgroundColor:dpColors,borderRadius:4}]},options:{responsive:true,maintainAspectRatio:false,indexAxis:'y',plugins:{legend:{display:false},tooltip:{callbacks:{label:function(c){return dp[c.dataIndex].source+': '+formatDiskSize(c.raw)}}}},scales:{x:{grid:{color:gridColor},ticks:{font:{size:9},callback:function(v){return formatDiskSize(v)}}},y:{grid:{display:false},ticks:{font:{size:9}}}}}}));}
|
|
810
|
+
// 4. Stacked bar - Disk usage C:
|
|
811
|
+
var usedBytes=DISK_SUMMARY.driveUsed||0;
|
|
812
|
+
var freeBytes=DISK_SUMMARY.driveFree||0;
|
|
813
|
+
diskCharts.push(new Chart(document.getElementById('chart-disk-gauge'),{type:'bar',data:{labels:['C:'],datasets:[{label:'Utilise',data:[usedBytes],backgroundColor:'#ef4444',borderRadius:0},{label:'Libre',data:[freeBytes],backgroundColor:'#22c55e',borderRadius:0}]},options:{responsive:true,maintainAspectRatio:false,indexAxis:'y',plugins:{legend:{display:true,position:'bottom',labels:{boxWidth:10,padding:8,font:{size:10}}},tooltip:{callbacks:{label:function(c){return c.dataset.label+': '+formatDiskSize(c.raw)}}}},scales:{x:{stacked:true,grid:{color:gridColor},ticks:{font:{size:9},callback:function(v){return formatDiskSize(v)}}},y:{stacked:true,grid:{display:false},ticks:{font:{size:11,weight:'bold'}}}}}}));
|
|
814
|
+
}
|
|
815
|
+
renderDiskSection();
|
|
816
|
+
diskChartsLazy=function(){if(!diskChartsLazyDone){diskChartsLazyDone=true;renderDiskCharts()}};
|
|
817
|
+
}
|
|
818
|
+
// Register lazy chart callback for couts tab
|
|
819
|
+
lazyChartCallbacks.couts=function(){
|
|
820
|
+
if(costChartsLazy)costChartsLazy();
|
|
821
|
+
if(diskChartsLazy)diskChartsLazy();
|
|
822
|
+
};
|
|
823
|
+
if(activeTab==='couts'){if(costChartsLazy)costChartsLazy();if(diskChartsLazy)diskChartsLazy()}
|
|
824
|
+
if(!store.quickNotes)store.quickNotes=[];
|
|
825
|
+
function renderQuickNotes(){var el=document.getElementById('quick-notes');el.textContent=store.quickNotes.length>0?store.quickNotes.slice(-3).map(function(n){return n.text}).join(' | '):''}
|
|
826
|
+
renderQuickNotes();
|
|
827
|
+
document.getElementById('quick-save').addEventListener('click',function(){var inp=document.getElementById('quick-input');var v=inp.value.trim();if(!v)return;store.quickNotes.push({text:v,date:new Date().toISOString().slice(0,10)});save();inp.value='';renderQuickNotes();toast('Insight sauve')});
|
|
828
|
+
document.getElementById('quick-input').addEventListener('keypress',function(e){if(e.key==='Enter'){e.preventDefault();document.getElementById('quick-save').click()}});
|
|
829
|
+
document.querySelectorAll('.collapsible-head').forEach(function(h){h.addEventListener('click',function(e){if(e.target.closest('.tabs')||e.target.closest('.add-btn'))return;this.closest('.collapsible').classList.toggle('closed')})});
|
|
830
|
+
document.getElementById('ref-tabs').addEventListener('click',function(e){var t=e.target.closest('.tab');if(!t)return;e.stopPropagation();document.querySelectorAll('.tab').forEach(function(x){x.classList.remove('active')});document.querySelectorAll('.ref-content').forEach(function(x){x.classList.remove('active')});t.classList.add('active');document.getElementById('ref-'+t.dataset.tab).classList.add('active')});
|
|
831
|
+
function renderPrompts(){var el=document.getElementById('prompts');clearEl(el);store.prompts.forEach(function(p){var c=document.createElement('div');c.className='prompt';c.addEventListener('click',function(){copy(p.cmd)});var d=document.createElement('button');d.className='prompt-del';d.textContent='x';d.addEventListener('click',function(e){e.stopPropagation();store.prompts=store.prompts.filter(function(x){return x.id!==p.id});save();renderPrompts()});var h=document.createElement('h4');h.textContent=p.name;var pp=document.createElement('p');pp.textContent=p.cmd;c.appendChild(d);c.appendChild(h);c.appendChild(pp);el.appendChild(c)})}
|
|
832
|
+
renderPrompts();
|
|
833
|
+
function renderLinks(){var el=document.getElementById('links');clearEl(el);store.links.forEach(function(l){var a=document.createElement('a');a.className='link';a.href=l.url;a.target='_blank';a.rel='noopener';var i=document.createElement('span');i.style.cssText='font-size:.6rem;font-weight:700;opacity:.6';i.textContent=l.ico;a.appendChild(i);a.appendChild(document.createTextNode(' '+l.name));el.appendChild(a)})}
|
|
834
|
+
renderLinks();
|
|
835
|
+
var notesEl=document.getElementById('notes');notesEl.value=store.notes;
|
|
836
|
+
var nt;notesEl.addEventListener('input',function(){var v=this.value;clearTimeout(nt);nt=setTimeout(function(){store.notes=v;save()},400)});
|
|
837
|
+
var modalBg=document.getElementById('modal-bg');
|
|
838
|
+
function openModal(){modalBg.classList.add('open')}
|
|
839
|
+
function closeModal(){document.getElementById('modal').style.maxWidth='';modalBg.classList.remove('open')}
|
|
840
|
+
modalBg.addEventListener('click',function(e){if(e.target===this)closeModal()});
|
|
841
|
+
function openNoteModal(p){var m=document.getElementById('modal');clearEl(m);var h=document.createElement('h3');h.textContent=p.name;m.appendChild(h);var f=document.createElement('div');f.className='modal-field';var lb=document.createElement('label');lb.textContent='Notes';f.appendChild(lb);var ta=document.createElement('textarea');ta.id='note-c';ta.rows=4;ta.value=store.projectNotes[p.pathId]||'';f.appendChild(ta);m.appendChild(f);if(p.sessionHistory&&p.sessionHistory.length>0){var sh=document.createElement('div');sh.className='modal-field';var slb=document.createElement('label');slb.textContent='Sessions ('+p.sessionHistory.length+')';sh.appendChild(slb);var sl=document.createElement('div');sl.style.cssText='display:flex;flex-direction:column;gap:.3rem;margin-top:.3rem';p.sessionHistory.forEach(function(s){var si=document.createElement('div');si.style.cssText='display:flex;align-items:center;padding:.35rem .5rem;background:var(--bg);border:1px solid var(--bd);border-radius:5px;font-size:.7rem;gap:.4rem';var statusColors={done:'#22c55e',wip:'#f59e0b',blocked:'#ef4444'};if(s.status&&statusColors[s.status]){var badge=document.createElement('span');badge.style.cssText='padding:2px 6px;border-radius:3px;font-size:.6rem;font-weight:600;color:white;background:'+statusColors[s.status];badge.textContent=s.status.toUpperCase();si.appendChild(badge)}var st=document.createElement('span');st.style.cssText='flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer';st.textContent=s.title||'Session sans resume';st.title='Clic = reprendre session';st.addEventListener('click',function(){copy('cd "'+p.path+'" && claude --dangerously-skip-permissions --resume '+s.id);closeModal();toast('Session copiee')});si.appendChild(st);var sd=document.createElement('span');sd.style.cssText='color:var(--dim);font-size:.6rem';sd.textContent=s.date;si.appendChild(sd);var rpb=document.createElement('button');rpb.style.cssText='padding:2px 8px;border:1px solid var(--ok);background:transparent;color:var(--ok);border-radius:3px;font-size:.6rem;cursor:pointer';rpb.textContent='Replay';rpb.title='Voir le replay de la session';rpb.addEventListener('click',function(e){e.stopPropagation();closeModal();if(typeof openReplayModal==='function')openReplayModal(s.id,p.path,s.title)});si.appendChild(rpb);if(!s.hasSummary){var rb=document.createElement('button');rb.style.cssText='padding:2px 8px;border:1px solid var(--ac);background:transparent;color:var(--ac);border-radius:3px;font-size:.6rem;cursor:pointer';rb.textContent='IA';rb.title='Generer resume IA';rb.addEventListener('click',function(e){e.stopPropagation();copy('cd "'+p.path+'" && powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\\source\\repos\\coderadar\\summarize-session.ps1" -SessionId "'+s.id+'" -ProjectPath "'+p.path+'"');toast('Commande copiee - colle dans terminal')});si.appendChild(rb)}sl.appendChild(si)});sh.appendChild(sl);m.appendChild(sh)}var a=document.createElement('div');a.className='modal-actions';var cb=document.createElement('button');cb.className='cancel';cb.textContent='Fermer';cb.addEventListener('click',closeModal);var sb=document.createElement('button');sb.className='save';sb.textContent='Sauver note';sb.addEventListener('click',function(){store.projectNotes[p.pathId]=document.getElementById('note-c').value;save();closeModal();toast('Note sauvee')});a.appendChild(cb);a.appendChild(sb);m.appendChild(a);openModal()}
|
|
842
|
+
document.getElementById('btn-add-prompt').addEventListener('click',function(e){e.stopPropagation();var m=document.getElementById('modal');clearEl(m);var h=document.createElement('h3');h.textContent='Nouveau prompt';m.appendChild(h);var f1=document.createElement('div');f1.className='modal-field';var l1=document.createElement('label');l1.textContent='Nom';f1.appendChild(l1);var i1=document.createElement('input');i1.id='mp-n';f1.appendChild(i1);m.appendChild(f1);var f2=document.createElement('div');f2.className='modal-field';var l2=document.createElement('label');l2.textContent='Prompt';f2.appendChild(l2);var i2=document.createElement('textarea');i2.id='mp-c';i2.rows=3;f2.appendChild(i2);m.appendChild(f2);var a=document.createElement('div');a.className='modal-actions';var cb=document.createElement('button');cb.className='cancel';cb.textContent='Annuler';cb.addEventListener('click',closeModal);var sb=document.createElement('button');sb.className='save';sb.textContent='Ajouter';sb.addEventListener('click',function(){var n=document.getElementById('mp-n').value.trim(),c=document.getElementById('mp-c').value.trim();if(!n||!c)return;store.prompts.push({id:gid(),name:n,cmd:c});save();closeModal();renderPrompts();toast('Ajoute')});a.appendChild(cb);a.appendChild(sb);m.appendChild(a);openModal()});
|
|
843
|
+
document.getElementById('btn-add-link').addEventListener('click',function(e){e.stopPropagation();var m=document.getElementById('modal');clearEl(m);var h=document.createElement('h3');h.textContent='Nouveau lien';m.appendChild(h);var f1=document.createElement('div');f1.className='modal-field';var l1=document.createElement('label');l1.textContent='Nom';f1.appendChild(l1);var i1=document.createElement('input');i1.id='ml-n';f1.appendChild(i1);m.appendChild(f1);var f2=document.createElement('div');f2.className='modal-field';var l2=document.createElement('label');l2.textContent='URL';f2.appendChild(l2);var i2=document.createElement('input');i2.id='ml-u';i2.placeholder='https://';f2.appendChild(i2);m.appendChild(f2);var a=document.createElement('div');a.className='modal-actions';var cb=document.createElement('button');cb.className='cancel';cb.textContent='Annuler';cb.addEventListener('click',closeModal);var sb=document.createElement('button');sb.className='save';sb.textContent='Ajouter';sb.addEventListener('click',function(){var n=document.getElementById('ml-n').value.trim(),u=document.getElementById('ml-u').value.trim();if(!n||!u)return;store.links.push({id:gid(),name:n,url:u,ico:n.substring(0,2).toUpperCase()});save();closeModal();renderLinks();toast('Ajoute')});a.appendChild(cb);a.appendChild(sb);m.appendChild(a);openModal()});
|
|
844
|
+
document.getElementById('btn-theme').addEventListener('click',function(){store.theme=store.theme==='light'?'dark':'light';save();applyTheme()});
|
|
845
|
+
document.getElementById('btn-export').addEventListener('click',function(){var d=JSON.stringify(store,null,2),b=new Blob([d],{type:'application/json'}),u=URL.createObjectURL(b),a=document.createElement('a');a.href=u;a.download='coderadar-'+new Date().toISOString().slice(0,10)+'.json';a.click();URL.revokeObjectURL(u);toast('Exporte')});
|
|
846
|
+
document.getElementById('btn-import').addEventListener('click',function(){document.getElementById('import-file').click()});
|
|
847
|
+
document.getElementById('import-file').addEventListener('change',function(e){var f=e.target.files[0];if(!f)return;var r=new FileReader();r.onload=function(ev){try{var d=JSON.parse(ev.target.result);Object.assign(store,d);save();renderProjects();renderPrompts();renderLinks();notesEl.value=store.notes;applyTheme();toast('Importe')}catch(err){toast('Erreur')}};r.readAsText(f);e.target.value=''});
|
|
848
|
+
document.getElementById('btn-help').addEventListener('click',function(){var m=document.getElementById('modal');clearEl(m);var h=document.createElement('h3');h.textContent='Raccourcis';m.appendChild(h);var t=document.createElement('div');t.style.fontSize='.8rem';t.style.lineHeight='1.8';t.textContent='Alt+1-5: Onglets (Dashboard/Projets/Couts/Plugins/Outils) | 1-9: Lancer projet (auto-switch Projets, Ctrl = copier) | /: Recherche | T: Theme | V: Resume vocal | W: Rapport Hebdo | O: Export Obsidian | M: Sync Memory | R: Reload | Esc: Fermer';m.appendChild(t);var a=document.createElement('div');a.className='modal-actions';var cb=document.createElement('button');cb.className='save';cb.textContent='OK';cb.addEventListener('click',closeModal);a.appendChild(cb);m.appendChild(a);openModal()});
|
|
849
|
+
// Sync Memory Button - claude-mem integration
|
|
850
|
+
var syncMemBtn=document.getElementById('btn-sync-mem'),syncBadge=document.getElementById('sync-badge');
|
|
851
|
+
if(UNSYNCED_COUNT>0){syncBadge.textContent=UNSYNCED_COUNT;syncBadge.style.display='flex';document.getElementById('sync-label').textContent='Sync ('+UNSYNCED_COUNT+')';syncMemBtn.style.borderColor='var(--ac)'}
|
|
852
|
+
syncMemBtn.addEventListener('click',function(){
|
|
853
|
+
if(syncMemBtn.classList.contains('syncing')){toast('Synchronisation en cours...');return}
|
|
854
|
+
syncMemBtn.classList.add('syncing');
|
|
855
|
+
var m=document.getElementById('modal');clearEl(m);
|
|
856
|
+
var h=document.createElement('h3');h.textContent='Sync Memory';m.appendChild(h);
|
|
857
|
+
var info=document.createElement('div');info.style.cssText='font-size:.85rem;line-height:1.6;margin-bottom:1rem';
|
|
858
|
+
var p1=document.createElement('p');var b1=document.createElement('strong');b1.textContent=UNSYNCED_COUNT;p1.appendChild(b1);p1.appendChild(document.createTextNode(' resumes de sessions a synchroniser avec claude-mem.'));info.appendChild(p1);var p2=document.createElement('p');p2.style.cssText='margin-top:.5rem;color:var(--dim)';p2.textContent='La synchronisation stocke les insights de vos sessions dans la memoire persistante de Claude.';info.appendChild(p2);
|
|
859
|
+
m.appendChild(info);
|
|
860
|
+
var cmdDiv=document.createElement('div');cmdDiv.style.cssText='background:var(--s1);padding:.75rem;border-radius:6px;font-family:monospace;font-size:.75rem;margin-bottom:1rem;word-break:break-all';
|
|
861
|
+
var cmd='powershell -ExecutionPolicy Bypass -File "'+window.location.href.replace('index.html','').replace('file:///','').replace(/\//g,'\\\\')+'sync-to-memory.ps1"';
|
|
862
|
+
cmdDiv.textContent=cmd;m.appendChild(cmdDiv);
|
|
863
|
+
var actions=document.createElement('div');actions.className='modal-actions';
|
|
864
|
+
var copyBtn=document.createElement('button');copyBtn.className='save';copyBtn.textContent='Copier commande';
|
|
865
|
+
copyBtn.addEventListener('click',function(){copy(cmd);toast('Commande copiee - collez dans PowerShell')});actions.appendChild(copyBtn);
|
|
866
|
+
var closeBtn=document.createElement('button');closeBtn.className='btn-copy';closeBtn.textContent='Fermer';
|
|
867
|
+
closeBtn.addEventListener('click',function(){closeModal();syncMemBtn.classList.remove('syncing')});actions.appendChild(closeBtn);
|
|
868
|
+
m.appendChild(actions);openModal();syncMemBtn.classList.remove('syncing')
|
|
869
|
+
});
|
|
870
|
+
// Weekly Report Functions
|
|
871
|
+
function formatDateFr(d){var j=d.getDate(),m=d.getMonth(),months=['Jan','Fev','Mar','Avr','Mai','Juin','Juil','Aout','Sep','Oct','Nov','Dec'];return j+' '+months[m]+' '+d.getFullYear()}
|
|
872
|
+
function generateWeeklyReport(){
|
|
873
|
+
var now=new Date(),weekAgo=new Date(now.getTime()-7*24*60*60*1000);
|
|
874
|
+
var dateStart=formatDateFr(weekAgo),dateEnd=formatDateFr(now);
|
|
875
|
+
var weekSessions=TIMELINE_DATA.filter(function(s){var d=new Date(s.date);return d>=weekAgo&&d<=now});
|
|
876
|
+
var projectGroups={};weekSessions.forEach(function(s){if(!projectGroups[s.project])projectGroups[s.project]=[];projectGroups[s.project].push(s)});
|
|
877
|
+
var totalSessions=weekSessions.length,totalMins=0;weekSessions.forEach(function(s){totalMins+=s.stats&&s.stats.duration?s.stats.duration:0});var totalHours=(totalMins/60).toFixed(1);
|
|
878
|
+
var allTags={};weekSessions.forEach(function(s){if(s.tags)s.tags.forEach(function(t){allTags[t]=(allTags[t]||0)+1})});
|
|
879
|
+
var html='<h1>Rapport Hebdomadaire</h1>';
|
|
880
|
+
html+='<p style="color:#4a5568;margin-bottom:1rem"><strong>'+dateStart+' - '+dateEnd+'</strong></p>';
|
|
881
|
+
html+='<p style="color:#718096;font-size:.9rem">Guillaume Beylouneh - Developpeur Freelance</p>';
|
|
882
|
+
var projNames=Object.keys(projectGroups).sort(function(a,b){return projectGroups[b].length-projectGroups[a].length});
|
|
883
|
+
projNames.forEach(function(proj){
|
|
884
|
+
html+='<h2>'+escH(proj)+' ('+projectGroups[proj].length+' sessions)</h2><ul>';
|
|
885
|
+
projectGroups[proj].forEach(function(s){var sum=s.summary||'Session de developpement';html+='<li><strong>'+escH(s.date.split('T')[0].split('-').reverse().join('/'))+'</strong> - '+escH(sum)+'</li>'});
|
|
886
|
+
html+='</ul>'});
|
|
887
|
+
html+='<div class="total"><strong>Total:</strong> '+totalSessions+' sessions | Temps estime: '+totalHours+' heures</div>';
|
|
888
|
+
if(Object.keys(allTags).length>0){html+='<h3>Tags utilises</h3><div class="tags">';Object.keys(allTags).sort(function(a,b){return allTags[b]-allTags[a]}).forEach(function(t){html+='<span class="tag">'+escH(t)+' ('+allTags[t]+')</span>'});html+='</div>'}
|
|
889
|
+
html+='<div class="meta">Genere le '+new Date().toLocaleString('fr-FR')+' via CodeRadar</div>';
|
|
890
|
+
return{html:html,markdown:generateMarkdown(dateStart,dateEnd,projectGroups,totalSessions,totalHours,allTags),dateStart:dateStart,dateEnd:dateEnd}}
|
|
891
|
+
function generateMarkdown(ds,de,groups,total,hours,tags){
|
|
892
|
+
var md='# Rapport Hebdomadaire\\n\\n';
|
|
893
|
+
md+='**'+ds+' - '+de+'**\\n\\n';
|
|
894
|
+
md+='Guillaume Beylouneh - Developpeur Freelance\\n\\n---\\n\\n';
|
|
895
|
+
Object.keys(groups).forEach(function(p){md+='## '+p+' ('+groups[p].length+' sessions)\\n\\n';groups[p].forEach(function(s){var sum=s.summary||'Session de developpement';md+='- **'+s.date.split('T')[0].split('-').reverse().join('/')+'** - '+sum+'\\n'});md+='\\n'});
|
|
896
|
+
md+='---\\n\\n**Total:** '+total+' sessions | Temps estime: '+hours+' heures\\n\\n';
|
|
897
|
+
if(Object.keys(tags).length>0){md+='**Tags:** '+Object.keys(tags).map(function(t){return t+' ('+tags[t]+')'}).join(', ')+'\\n\\n'}
|
|
898
|
+
md+='---\\n\\n*Genere le '+new Date().toLocaleString('fr-FR')+' via CodeRadar*';
|
|
899
|
+
return md}
|
|
900
|
+
function downloadPDF(html,filename){
|
|
901
|
+
if(typeof html2pdf==='undefined'){toast('html2pdf non charge');return}
|
|
902
|
+
var el=document.createElement('div');el.innerHTML=html;el.style.cssText='padding:20px;font-family:Arial,sans-serif;background:white;color:#1a1a1a';
|
|
903
|
+
var opt={margin:[10,10,10,10],filename:filename,image:{type:'jpeg',quality:.98},html2canvas:{scale:2,useCORS:true},jsPDF:{unit:'mm',format:'a4',orientation:'portrait'}};
|
|
904
|
+
html2pdf().set(opt).from(el).save().then(function(){toast('PDF telecharge')}).catch(function(){toast('Erreur PDF')})}
|
|
905
|
+
function openReportModal(){
|
|
906
|
+
var report=generateWeeklyReport();
|
|
907
|
+
var m=document.getElementById('modal');m.className='modal report-modal';clearEl(m);
|
|
908
|
+
var h=document.createElement('h3');h.textContent='Rapport Hebdomadaire';m.appendChild(h);
|
|
909
|
+
var preview=document.createElement('div');preview.className='report-preview';preview.id='report-preview';preview.innerHTML=report.html;m.appendChild(preview);
|
|
910
|
+
var actions=document.createElement('div');actions.className='report-actions';
|
|
911
|
+
var pdfBtn=document.createElement('button');pdfBtn.className='btn-pdf';pdfBtn.textContent='Telecharger PDF';pdfBtn.addEventListener('click',function(){var fn='Rapport_'+report.dateStart.replace(/ /g,'')+'-'+report.dateEnd.replace(/ /g,'')+'.pdf';downloadPDF(report.html,fn)});actions.appendChild(pdfBtn);
|
|
912
|
+
var mdBtn=document.createElement('button');mdBtn.className='btn-md';mdBtn.textContent='Copier Markdown';mdBtn.addEventListener('click',function(){copy(report.markdown.replace(/\\\\n/g,'\\n'));toast('Markdown copie')});actions.appendChild(mdBtn);
|
|
913
|
+
var closeBtn=document.createElement('button');closeBtn.className='btn-copy';closeBtn.textContent='Fermer';closeBtn.addEventListener('click',function(){m.className='modal';closeModal()});actions.appendChild(closeBtn);
|
|
914
|
+
m.appendChild(actions);openModal()}
|
|
915
|
+
document.getElementById('btn-report').addEventListener('click',openReportModal);
|
|
916
|
+
// Obsidian Export
|
|
917
|
+
function formatObsidianDate(){var d=new Date();return d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+String(d.getDate()).padStart(2,'0')}
|
|
918
|
+
function formatObsidianDateFr(){var d=new Date(),j=d.getDate(),months=['Janvier','Fevrier','Mars','Avril','Mai','Juin','Juillet','Aout','Septembre','Octobre','Novembre','Decembre'];return j+' '+months[d.getMonth()]+' '+d.getFullYear()}
|
|
919
|
+
function generateObsidianExport(){
|
|
920
|
+
var today=formatObsidianDate();
|
|
921
|
+
var todaySessions=TIMELINE_DATA.filter(function(s){return s.date===today});
|
|
922
|
+
var projectGroups={};todaySessions.forEach(function(s){if(!projectGroups[s.project])projectGroups[s.project]=[];projectGroups[s.project].push(s)});
|
|
923
|
+
var allTags={};todaySessions.forEach(function(s){if(s.tags)s.tags.forEach(function(t){allTags[t]=true})});
|
|
924
|
+
var tagsList=Object.keys(allTags);
|
|
925
|
+
var md='---\n';
|
|
926
|
+
md+='date: '+today+'\n';
|
|
927
|
+
md+='tags: [coderadar, dev-log';
|
|
928
|
+
if(tagsList.length>0)md+=', '+tagsList.join(', ');
|
|
929
|
+
md+=']\n';
|
|
930
|
+
md+='---\n\n';
|
|
931
|
+
md+='# Journal de developpement - '+formatObsidianDateFr()+'\n\n';
|
|
932
|
+
md+='## Sessions du jour\n';
|
|
933
|
+
if(Object.keys(projectGroups).length===0){md+='\n*Aucune session enregistree aujourd\'hui.*\n\n';}else{
|
|
934
|
+
Object.keys(projectGroups).forEach(function(proj){
|
|
935
|
+
md+='\n### [['+proj+']]\n';
|
|
936
|
+
projectGroups[proj].forEach(function(s){
|
|
937
|
+
md+='- **Resume**: '+(s.summary||'Session de developpement')+'\n';
|
|
938
|
+
if(s.tags&&s.tags.length>0){md+='- **Tags**: '+s.tags.map(function(t){return '#'+t}).join(' ')+'\n';}
|
|
939
|
+
});
|
|
940
|
+
});}
|
|
941
|
+
if(INSIGHTS&&INSIGHTS.keyPoints&&INSIGHTS.keyPoints.length>0){
|
|
942
|
+
md+='\n## Insights\n';
|
|
943
|
+
INSIGHTS.keyPoints.slice(0,5).forEach(function(k){
|
|
944
|
+
md+='- '+k.point;if(k.project)md+=' ([['+k.project+']])';md+='\n';
|
|
945
|
+
});}
|
|
946
|
+
if(INSIGHTS&&INSIGHTS.wipSessions&&INSIGHTS.wipSessions.length>0){
|
|
947
|
+
md+='\n## Prochaines etapes\n';
|
|
948
|
+
INSIGHTS.wipSessions.slice(0,3).forEach(function(w){
|
|
949
|
+
if(w.nextSteps&&w.nextSteps.length>0){
|
|
950
|
+
md+='### [['+w.project+']]\n';
|
|
951
|
+
w.nextSteps.forEach(function(ns){md+='- [ ] [[TODO - '+ns.replace(/[^\w\s-]/g,'').substring(0,50)+']]\n';});
|
|
952
|
+
}
|
|
953
|
+
});}
|
|
954
|
+
md+='\n## Tags du jour\n';
|
|
955
|
+
if(tagsList.length>0){tagsList.forEach(function(t){md+='#'+t+' ';});md+='\n';}else{md+='*Aucun tag*\n';}
|
|
956
|
+
md+='\n---\n*Genere depuis [[CodeRadar]] le '+new Date().toLocaleString('fr-FR')+'*\n';
|
|
957
|
+
return md}
|
|
958
|
+
function openObsidianModal(){
|
|
959
|
+
var md=generateObsidianExport();
|
|
960
|
+
var m=document.getElementById('modal');m.className='modal report-modal';clearEl(m);
|
|
961
|
+
var h=document.createElement('h3');h.textContent='Export Obsidian';m.appendChild(h);
|
|
962
|
+
var desc=document.createElement('p');desc.style.cssText='font-size:.75rem;color:var(--mut);margin-bottom:.75rem';desc.textContent='Markdown formate pour Obsidian avec wikilinks et YAML frontmatter.';m.appendChild(desc);
|
|
963
|
+
var preview=document.createElement('pre');preview.style.cssText='background:var(--bg);border:1px solid var(--bd);border-radius:8px;padding:1rem;font-size:.7rem;overflow:auto;max-height:50vh;white-space:pre-wrap;font-family:monospace';preview.textContent=md;m.appendChild(preview);
|
|
964
|
+
var actions=document.createElement('div');actions.className='report-actions';
|
|
965
|
+
var copyBtn=document.createElement('button');copyBtn.className='btn-md';copyBtn.textContent='Copier dans le presse-papier';copyBtn.addEventListener('click',function(){copy(md);toast('Copie! Colle dans Obsidian')});actions.appendChild(copyBtn);
|
|
966
|
+
var dlBtn=document.createElement('button');dlBtn.className='btn-pdf';dlBtn.style.background='linear-gradient(135deg,#7c3aed,#6d28d9)';dlBtn.textContent='Telecharger .md';dlBtn.addEventListener('click',function(){var blob=new Blob([md],{type:'text/markdown;charset=utf-8'});var url=URL.createObjectURL(blob);var a=document.createElement('a');a.href=url;a.download='CodeRadar-'+formatObsidianDate()+'.md';a.click();URL.revokeObjectURL(url);toast('Fichier telecharge')});actions.appendChild(dlBtn);
|
|
967
|
+
var closeBtn=document.createElement('button');closeBtn.className='btn-copy';closeBtn.textContent='Fermer';closeBtn.addEventListener('click',function(){m.className='modal';closeModal()});actions.appendChild(closeBtn);
|
|
968
|
+
m.appendChild(actions);openModal()}
|
|
969
|
+
document.getElementById('btn-obsidian').addEventListener('click',openObsidianModal);
|
|
970
|
+
// Text-to-Speech - Advanced Podcast Generator
|
|
971
|
+
var ttsUtterance=null,ttsSpeaking=false;
|
|
972
|
+
var ttsConfig={scope:'today',project:'all',level:3};
|
|
973
|
+
var detailDescriptions={
|
|
974
|
+
1:'Flash: Chiffres cles uniquement (15 secondes)',
|
|
975
|
+
2:'Rapide: Stats et projets touches (30 secondes)',
|
|
976
|
+
3:'Standard: Details par projet, fichiers cles (2 minutes)',
|
|
977
|
+
4:'Detaille: Sessions, decisions, erreurs (5 minutes)',
|
|
978
|
+
5:'Complet: Tout inclus, commandes, apprentissages (10 minutes)'
|
|
979
|
+
};
|
|
980
|
+
function getTodayDate(){var d=new Date(),months=['janvier','fevrier','mars','avril','mai','juin','juillet','aout','septembre','octobre','novembre','decembre'];return d.getDate()+' '+months[d.getMonth()]+' '+d.getFullYear()}
|
|
981
|
+
function getDateRange(scope){
|
|
982
|
+
var now=new Date(),start,end=now.toISOString().slice(0,10);
|
|
983
|
+
if(scope==='today'){start=end;}
|
|
984
|
+
else if(scope==='week'){var d=new Date(now);d.setDate(d.getDate()-7);start=d.toISOString().slice(0,10);}
|
|
985
|
+
else if(scope==='month'){var d=new Date(now);d.setDate(d.getDate()-30);start=d.toISOString().slice(0,10);}
|
|
986
|
+
else{start='2000-01-01';}
|
|
987
|
+
return{start:start,end:end};
|
|
988
|
+
}
|
|
989
|
+
function filterSessions(scope,project){
|
|
990
|
+
var range=getDateRange(scope);
|
|
991
|
+
return TIMELINE_DATA.filter(function(s){
|
|
992
|
+
var inRange=s.date>=range.start&&s.date<=range.end;
|
|
993
|
+
var inProject=project==='all'||s.project===project;
|
|
994
|
+
return inRange&&inProject;
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
function formatDuration(mins){
|
|
998
|
+
if(mins<1)return 'quelques secondes';
|
|
999
|
+
if(mins<60)return Math.round(mins)+' minutes';
|
|
1000
|
+
var h=Math.floor(mins/60),m=Math.round(mins%60);
|
|
1001
|
+
if(m===0)return h+' heure'+(h>1?'s':'');
|
|
1002
|
+
return h+' heure'+(h>1?'s':'')+' et '+m+' minutes';
|
|
1003
|
+
}
|
|
1004
|
+
function buildSmartSummary(scope,project,level){
|
|
1005
|
+
var sessions=filterSessions(scope,project);
|
|
1006
|
+
var toolNames={'Read':'lectures de fichiers','Edit':'editions','Bash':'commandes shell','Grep':'recherches','Write':'ecritures','Task':'taches delegees','Glob':'recherches glob','WebFetch':'requetes web'};
|
|
1007
|
+
var scopeLabels={today:'aujourd\'hui',week:'cette semaine',month:'ce mois',all:'depuis le debut'};
|
|
1008
|
+
var text='';
|
|
1009
|
+
// LEVEL 1 - Flash: Chiffres uniquement
|
|
1010
|
+
var totalDuration=0,totalTools=0,totalFiles=0,sessionCount=sessions.length;
|
|
1011
|
+
var projectsMap={},allTools={},allFiles=[],allCommands=[];
|
|
1012
|
+
sessions.forEach(function(s){
|
|
1013
|
+
projectsMap[s.project]=projectsMap[s.project]||{sessions:[],duration:0,tools:{},files:[],commands:[]};
|
|
1014
|
+
projectsMap[s.project].sessions.push(s);
|
|
1015
|
+
if(s.stats){
|
|
1016
|
+
totalDuration+=s.stats.duration||0;
|
|
1017
|
+
projectsMap[s.project].duration+=s.stats.duration||0;
|
|
1018
|
+
if(s.stats.tools){s.stats.tools.forEach(function(t){
|
|
1019
|
+
var n=t.name.replace(/mcp__.*/,'MCP');
|
|
1020
|
+
allTools[n]=(allTools[n]||0)+t.count;
|
|
1021
|
+
projectsMap[s.project].tools[n]=(projectsMap[s.project].tools[n]||0)+t.count;
|
|
1022
|
+
totalTools+=t.count;
|
|
1023
|
+
});}
|
|
1024
|
+
if(s.stats.filesEdited){s.stats.filesEdited.forEach(function(f){
|
|
1025
|
+
var name=f.path.split(/[\/\\]/).pop();
|
|
1026
|
+
if(allFiles.indexOf(name)===-1)allFiles.push(name);
|
|
1027
|
+
if(projectsMap[s.project].files.indexOf(name)===-1)projectsMap[s.project].files.push(name);
|
|
1028
|
+
});}
|
|
1029
|
+
if(s.stats.commands){s.stats.commands.forEach(function(c){
|
|
1030
|
+
allCommands.push(c);
|
|
1031
|
+
projectsMap[s.project].commands.push(c);
|
|
1032
|
+
});}
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
totalFiles=allFiles.length;
|
|
1036
|
+
var projects=Object.keys(projectsMap);
|
|
1037
|
+
// Introduction
|
|
1038
|
+
text+='Bonjour Guillaume. ';
|
|
1039
|
+
if(project!=='all'){text+='Voici le resume de '+project+' '+scopeLabels[scope]+'. ';}
|
|
1040
|
+
else{text+='Voici ton podcast dev '+scopeLabels[scope]+'. ';}
|
|
1041
|
+
// Level 1 - Flash stats
|
|
1042
|
+
if(sessionCount===0){text+='Aucune session trouvee pour cette periode. ';return text;}
|
|
1043
|
+
text+=sessionCount+' session'+(sessionCount>1?'s':'')+', '+projects.length+' projet'+(projects.length>1?'s':'')+', '+formatDuration(totalDuration)+' de travail. ';
|
|
1044
|
+
if(level===1)return text;
|
|
1045
|
+
// Level 2 - Rapide: ajoute projets et outils
|
|
1046
|
+
text+='Projets: '+projects.join(', ')+'. ';
|
|
1047
|
+
var topTools=Object.keys(allTools).sort(function(a,b){return allTools[b]-allTools[a]}).slice(0,4);
|
|
1048
|
+
if(topTools.length>0){
|
|
1049
|
+
text+='Outils: ';
|
|
1050
|
+
topTools.forEach(function(t,i){
|
|
1051
|
+
var friendly=toolNames[t]||t.toLowerCase();
|
|
1052
|
+
text+=allTools[t]+' '+friendly+(i<topTools.length-1?', ':'. ');
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
if(level===2)return text;
|
|
1056
|
+
// Level 3 - Standard: details par projet
|
|
1057
|
+
text+='Voici le detail par projet. ';
|
|
1058
|
+
projects.forEach(function(p){
|
|
1059
|
+
var pd=projectsMap[p];
|
|
1060
|
+
text+=p+': '+pd.sessions.length+' session'+(pd.sessions.length>1?'s':'')+', '+formatDuration(pd.duration)+'. ';
|
|
1061
|
+
if(pd.files.length>0){text+='Fichiers: '+pd.files.slice(0,3).join(', ')+'. ';}
|
|
1062
|
+
});
|
|
1063
|
+
if(level===3)return text;
|
|
1064
|
+
// Level 4 - Detaille: resume de chaque session
|
|
1065
|
+
text+='Details des sessions. ';
|
|
1066
|
+
sessions.slice(0,10).forEach(function(s,i){
|
|
1067
|
+
if(s.summary&&s.summary.length>10){
|
|
1068
|
+
var cleanSummary=s.summary.replace(/[<>\[\]{}]/g,'').substring(0,100);
|
|
1069
|
+
text+=s.project+', session '+(i+1)+': '+cleanSummary+'. ';
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
// Add errors if any
|
|
1073
|
+
var errors=sessions.filter(function(s){return s.status==='error'||s.tags&&s.tags.indexOf('bug')>=0});
|
|
1074
|
+
if(errors.length>0){text+='Attention, '+errors.length+' session'+(errors.length>1?'s':'')+' avec erreurs. ';}
|
|
1075
|
+
// Key points from INSIGHTS
|
|
1076
|
+
if(INSIGHTS&&INSIGHTS.keyPoints&&INSIGHTS.keyPoints.length>0){
|
|
1077
|
+
text+='Points cles: ';
|
|
1078
|
+
INSIGHTS.keyPoints.slice(0,3).forEach(function(k){text+=k.point+'. ';});
|
|
1079
|
+
}
|
|
1080
|
+
if(level===4)return text;
|
|
1081
|
+
// Level 5 - Complet: tout
|
|
1082
|
+
if(allCommands.length>0){
|
|
1083
|
+
text+='Commandes executees: ';
|
|
1084
|
+
var uniqueCommands=[];
|
|
1085
|
+
allCommands.forEach(function(c){
|
|
1086
|
+
var short=c.split(' ').slice(0,2).join(' ');
|
|
1087
|
+
if(uniqueCommands.indexOf(short)===-1&&uniqueCommands.length<8)uniqueCommands.push(short);
|
|
1088
|
+
});
|
|
1089
|
+
text+=uniqueCommands.join(', ')+'. ';
|
|
1090
|
+
}
|
|
1091
|
+
// Files in detail
|
|
1092
|
+
if(allFiles.length>0){
|
|
1093
|
+
text+='Fichiers modifies: '+allFiles.slice(0,10).join(', ')+'. ';
|
|
1094
|
+
}
|
|
1095
|
+
// Next steps from INSIGHTS
|
|
1096
|
+
if(INSIGHTS&&INSIGHTS.wipSessions){
|
|
1097
|
+
text+='Prochaines etapes: ';
|
|
1098
|
+
INSIGHTS.wipSessions.slice(0,3).forEach(function(w){
|
|
1099
|
+
if(w.nextSteps&&w.nextSteps[0]){text+=w.project+', '+w.nextSteps[0]+'. ';}
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
// Tool usage breakdown
|
|
1103
|
+
text+='Repartition outils: ';
|
|
1104
|
+
Object.keys(allTools).sort(function(a,b){return allTools[b]-allTools[a]}).forEach(function(t,i){
|
|
1105
|
+
if(i<6){var friendly=toolNames[t]||t;text+=friendly+' '+allTools[t]+(i<5?', ':'. ');}
|
|
1106
|
+
});
|
|
1107
|
+
// Productivity tip
|
|
1108
|
+
if(totalDuration>120){text+='Tu as travaille plus de 2 heures. Pense a faire des pauses! ';}
|
|
1109
|
+
text+='Fin du podcast. Bonne continuation!';
|
|
1110
|
+
return text;
|
|
1111
|
+
}
|
|
1112
|
+
// TTS Player with full controls
|
|
1113
|
+
var ttsState={sentences:[],currentIdx:0,playing:false,paused:false,rate:1,voice:null,cancelling:false};
|
|
1114
|
+
function splitIntoSentences(text){return text.split(/(?<=[.!?])\s+/).filter(function(s){return s.trim().length>0})}
|
|
1115
|
+
function populateProjectSelector(){
|
|
1116
|
+
var select=document.getElementById('tts-project');
|
|
1117
|
+
select.innerHTML='<option value="all">Tous les projets</option>';
|
|
1118
|
+
var projects={};
|
|
1119
|
+
TIMELINE_DATA.forEach(function(s){projects[s.project]=true});
|
|
1120
|
+
Object.keys(projects).sort().forEach(function(p){
|
|
1121
|
+
var opt=document.createElement('option');
|
|
1122
|
+
opt.value=p;opt.textContent=p;
|
|
1123
|
+
select.appendChild(opt);
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
function updateDetailDescription(){
|
|
1127
|
+
var level=parseInt(document.getElementById('tts-detail').value);
|
|
1128
|
+
document.getElementById('tts-detail-desc').textContent=detailDescriptions[level];
|
|
1129
|
+
var labels=document.querySelectorAll('.tts-detail-labels span');
|
|
1130
|
+
labels.forEach(function(l){l.classList.remove('active');if(parseInt(l.dataset.level)===level)l.classList.add('active');});
|
|
1131
|
+
}
|
|
1132
|
+
function openTTSPlayer(){
|
|
1133
|
+
if(!('speechSynthesis' in window)){toast('TTS non supporte');return}
|
|
1134
|
+
populateProjectSelector();
|
|
1135
|
+
updateDetailDescription();
|
|
1136
|
+
document.getElementById('tts-body-content').style.display='none';
|
|
1137
|
+
document.getElementById('tts-modal-bg').classList.add('open');
|
|
1138
|
+
var voices=window.speechSynthesis.getVoices();
|
|
1139
|
+
ttsState.voice=voices.find(function(v){return v.lang.startsWith('fr')})||null;
|
|
1140
|
+
}
|
|
1141
|
+
function generatePodcast(){
|
|
1142
|
+
var scope=document.getElementById('tts-scope').value;
|
|
1143
|
+
var project=document.getElementById('tts-project').value;
|
|
1144
|
+
var level=parseInt(document.getElementById('tts-detail').value);
|
|
1145
|
+
ttsConfig={scope:scope,project:project,level:level};
|
|
1146
|
+
var text=buildSmartSummary(scope,project,level);
|
|
1147
|
+
ttsState.sentences=splitIntoSentences(text);
|
|
1148
|
+
ttsState.currentIdx=0;
|
|
1149
|
+
ttsState.playing=false;
|
|
1150
|
+
ttsState.paused=false;
|
|
1151
|
+
document.getElementById('tts-body-content').style.display='block';
|
|
1152
|
+
document.getElementById('tts-full-text').textContent=text;
|
|
1153
|
+
updateTTSDisplay();
|
|
1154
|
+
toast('Podcast genere: '+ttsState.sentences.length+' phrases');
|
|
1155
|
+
}
|
|
1156
|
+
function closeTTSPlayer(){
|
|
1157
|
+
ttsState.cancelling=true;
|
|
1158
|
+
window.speechSynthesis.cancel();
|
|
1159
|
+
ttsState.playing=false;
|
|
1160
|
+
ttsState.paused=false;
|
|
1161
|
+
document.getElementById('tts-modal-bg').classList.remove('open');
|
|
1162
|
+
document.getElementById('btn-tts').classList.remove('tts-active');
|
|
1163
|
+
}
|
|
1164
|
+
function updateTTSDisplay(){
|
|
1165
|
+
var progress=document.getElementById('tts-progress');
|
|
1166
|
+
var current=document.getElementById('tts-current');
|
|
1167
|
+
var counter=document.getElementById('tts-counter');
|
|
1168
|
+
var slider=document.getElementById('tts-slider');
|
|
1169
|
+
var playBtn=document.getElementById('tts-play');
|
|
1170
|
+
progress.style.width=((ttsState.currentIdx+1)/ttsState.sentences.length*100)+'%';
|
|
1171
|
+
current.textContent=ttsState.sentences[ttsState.currentIdx]||'';
|
|
1172
|
+
counter.textContent=(ttsState.currentIdx+1)+' / '+ttsState.sentences.length;
|
|
1173
|
+
slider.max=ttsState.sentences.length-1;
|
|
1174
|
+
slider.value=ttsState.currentIdx;
|
|
1175
|
+
playBtn.innerHTML=ttsState.playing&&!ttsState.paused?'❚❚':'▶';
|
|
1176
|
+
playBtn.title=ttsState.playing&&!ttsState.paused?'Pause':'Lecture';
|
|
1177
|
+
}
|
|
1178
|
+
function speakCurrentSentence(){
|
|
1179
|
+
if(ttsState.currentIdx>=ttsState.sentences.length){ttsState.playing=false;updateTTSDisplay();document.getElementById('btn-tts').classList.remove('tts-active');return}
|
|
1180
|
+
var utterance=new SpeechSynthesisUtterance(ttsState.sentences[ttsState.currentIdx]);
|
|
1181
|
+
utterance.lang='fr-FR';
|
|
1182
|
+
utterance.rate=ttsState.rate;
|
|
1183
|
+
utterance.pitch=1;
|
|
1184
|
+
if(ttsState.voice)utterance.voice=ttsState.voice;
|
|
1185
|
+
utterance.onend=function(){
|
|
1186
|
+
if(ttsState.playing&&!ttsState.paused){
|
|
1187
|
+
ttsState.currentIdx++;
|
|
1188
|
+
updateTTSDisplay();
|
|
1189
|
+
if(ttsState.currentIdx<ttsState.sentences.length){speakCurrentSentence()}
|
|
1190
|
+
else{ttsState.playing=false;updateTTSDisplay();document.getElementById('btn-tts').classList.remove('tts-active')}
|
|
1191
|
+
}};
|
|
1192
|
+
utterance.onerror=function(e){if(ttsState.cancelling){ttsState.cancelling=false;return}ttsState.playing=false;updateTTSDisplay();toast('Erreur TTS: '+(e.error||'inconnu'))};
|
|
1193
|
+
window.speechSynthesis.speak(utterance);
|
|
1194
|
+
}
|
|
1195
|
+
function ttsPlay(){
|
|
1196
|
+
if(ttsState.playing&&!ttsState.paused){
|
|
1197
|
+
ttsState.cancelling=true;
|
|
1198
|
+
window.speechSynthesis.cancel();
|
|
1199
|
+
ttsState.paused=true;
|
|
1200
|
+
updateTTSDisplay();
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
if(ttsState.paused){
|
|
1204
|
+
ttsState.paused=false;
|
|
1205
|
+
speakCurrentSentence();
|
|
1206
|
+
updateTTSDisplay();
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
ttsState.playing=true;
|
|
1210
|
+
ttsState.paused=false;
|
|
1211
|
+
document.getElementById('btn-tts').classList.add('tts-active');
|
|
1212
|
+
speakCurrentSentence();
|
|
1213
|
+
updateTTSDisplay();
|
|
1214
|
+
}
|
|
1215
|
+
function ttsStop(){
|
|
1216
|
+
ttsState.cancelling=true;
|
|
1217
|
+
window.speechSynthesis.cancel();
|
|
1218
|
+
ttsState.playing=false;
|
|
1219
|
+
ttsState.paused=false;
|
|
1220
|
+
ttsState.currentIdx=0;
|
|
1221
|
+
updateTTSDisplay();
|
|
1222
|
+
document.getElementById('btn-tts').classList.remove('tts-active');
|
|
1223
|
+
}
|
|
1224
|
+
function ttsPrev(){
|
|
1225
|
+
ttsState.cancelling=true;
|
|
1226
|
+
window.speechSynthesis.cancel();
|
|
1227
|
+
if(ttsState.currentIdx>0)ttsState.currentIdx--;
|
|
1228
|
+
updateTTSDisplay();
|
|
1229
|
+
if(ttsState.playing&&!ttsState.paused)speakCurrentSentence();
|
|
1230
|
+
}
|
|
1231
|
+
function ttsNext(){
|
|
1232
|
+
ttsState.cancelling=true;
|
|
1233
|
+
window.speechSynthesis.cancel();
|
|
1234
|
+
if(ttsState.currentIdx<ttsState.sentences.length-1)ttsState.currentIdx++;
|
|
1235
|
+
updateTTSDisplay();
|
|
1236
|
+
if(ttsState.playing&&!ttsState.paused)speakCurrentSentence();
|
|
1237
|
+
}
|
|
1238
|
+
function ttsSeek(idx){
|
|
1239
|
+
ttsState.cancelling=true;
|
|
1240
|
+
window.speechSynthesis.cancel();
|
|
1241
|
+
ttsState.currentIdx=parseInt(idx);
|
|
1242
|
+
updateTTSDisplay();
|
|
1243
|
+
if(ttsState.playing&&!ttsState.paused)speakCurrentSentence();
|
|
1244
|
+
}
|
|
1245
|
+
function ttsSetRate(rate){
|
|
1246
|
+
ttsState.rate=parseFloat(rate);
|
|
1247
|
+
document.getElementById('tts-rate-display').textContent=rate+'x';
|
|
1248
|
+
if(ttsState.playing&&!ttsState.paused){
|
|
1249
|
+
ttsState.cancelling=true;
|
|
1250
|
+
window.speechSynthesis.cancel();
|
|
1251
|
+
speakCurrentSentence();
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
function speakDailySummary(){openTTSPlayer()}
|
|
1255
|
+
if('speechSynthesis' in window){window.speechSynthesis.getVoices();window.speechSynthesis.onvoiceschanged=function(){var voices=window.speechSynthesis.getVoices();ttsState.voice=voices.find(function(v){return v.lang.startsWith('fr')})||null}}
|
|
1256
|
+
document.getElementById('btn-tts').addEventListener('click',speakDailySummary);
|
|
1257
|
+
document.getElementById('tts-close').addEventListener('click',closeTTSPlayer);
|
|
1258
|
+
document.getElementById('tts-modal-bg').addEventListener('click',function(e){if(e.target===this)closeTTSPlayer()});
|
|
1259
|
+
document.getElementById('tts-play').addEventListener('click',ttsPlay);
|
|
1260
|
+
document.getElementById('tts-stop').addEventListener('click',ttsStop);
|
|
1261
|
+
document.getElementById('tts-prev').addEventListener('click',ttsPrev);
|
|
1262
|
+
document.getElementById('tts-next').addEventListener('click',ttsNext);
|
|
1263
|
+
document.getElementById('tts-slider').addEventListener('input',function(){ttsSeek(this.value)});
|
|
1264
|
+
document.getElementById('tts-rate').addEventListener('change',function(){ttsSetRate(this.value)});
|
|
1265
|
+
document.getElementById('tts-detail').addEventListener('input',updateDetailDescription);
|
|
1266
|
+
document.getElementById('tts-generate').addEventListener('click',generatePodcast);
|
|
1267
|
+
document.addEventListener('keydown',function(e){if(e.target.tagName==='INPUT'||e.target.tagName==='TEXTAREA'){if(e.key==='Escape'){e.target.blur();searchResultsEl.classList.remove('active');document.getElementById('search').value='';searchTerm='';renderProjects()}return}if(e.key==='Escape'){searchResultsEl.classList.remove('active');closeModal();if(typeof closeReplayModal==='function')closeReplayModal();if(typeof closeTTSPlayer==='function')closeTTSPlayer();return}if(e.altKey&&e.key>='1'&&e.key<='5'){e.preventDefault();switchTab(TAB_IDS[parseInt(e.key)-1]);return}if(e.key==='/'){e.preventDefault();document.getElementById('search').focus();return}if(e.key==='t'||e.key==='T'){store.theme=store.theme==='light'?'dark':'light';save();applyTheme();return}if(e.key==='w'||e.key==='W'){openReportModal();return}if(e.key==='o'||e.key==='O'){openObsidianModal();return}if(e.key==='m'||e.key==='M'){document.getElementById('btn-sync-mem').click();return}if(e.key==='v'||e.key==='V'){speakDailySummary();return}if(e.key==='r'||e.key==='R'){location.reload();return}if(e.key>='1'&&e.key<='9'){if(activeTab!=='projets')switchTab('projets');var idx=parseInt(e.key)-1,cards=document.querySelectorAll('.p-card:not(.hidden)');if(cards[idx]){var pid=cards[idx].dataset.pathid,pr=PROJECTS.find(function(x){return x.pathId===pid});if(pr){if(e.ctrlKey||e.metaKey){copy(pr.launchCmd)}else{launchClaude(pr.path,'open')}}}}});
|
|
1268
|
+
// Session Replay Feature
|
|
1269
|
+
var replayModalBg=document.getElementById('replay-modal-bg'),replayBody=document.getElementById('replay-body'),replayControls=document.getElementById('replay-controls'),replaySlider=document.getElementById('replay-slider'),replayProgress=document.getElementById('replay-progress'),replayPlayBtn=document.getElementById('replay-play'),replayFileInput=document.getElementById('replay-file'),replayFolderPath=document.getElementById('replay-folder-path');
|
|
1270
|
+
var replayMessages=[],replayCurrentIdx=0,replayPlaying=false,replayInterval=null,replayCurrentSession=null;
|
|
1271
|
+
function openReplayModal(sessionId,projectPath,sessionTitle){replayCurrentSession={id:sessionId,path:projectPath,title:sessionTitle};document.getElementById('replay-title').textContent='Session Replay'+(sessionTitle?' - '+sessionTitle:'');document.getElementById('replay-meta').textContent=sessionId;var folderHint=projectPath?projectPath.replace(/\\/g,'/').replace(/^.*\.claude\//,'~/.claude/'):'~/.claude/projects/';replayFolderPath.textContent=folderHint+'/'+sessionId+'.jsonl';replayMessages=[];replayCurrentIdx=0;replayPlaying=false;clearEl(replayBody);var empty=document.createElement('div');empty.className='replay-empty';empty.innerHTML='<div class="replay-empty-icon">▶</div><div class="replay-empty-text">Chargez le fichier .jsonl pour visualiser la session</div><button class="replay-load-btn" id="replay-load-btn-inner">Charger fichier .jsonl</button><div class="replay-folder-info"><span>Fichier:</span><code>'+sessionId+'.jsonl</code></div>';replayBody.appendChild(empty);document.getElementById('replay-load-btn-inner').addEventListener('click',function(){replayFileInput.click()});replayControls.style.display='none';replayModalBg.classList.add('open')}
|
|
1272
|
+
function closeReplayModal(){replayModalBg.classList.remove('open');if(replayInterval){clearInterval(replayInterval);replayInterval=null}replayPlaying=false}
|
|
1273
|
+
document.getElementById('replay-close').addEventListener('click',closeReplayModal);
|
|
1274
|
+
replayModalBg.addEventListener('click',function(e){if(e.target===this)closeReplayModal()});
|
|
1275
|
+
document.getElementById('replay-load-btn').addEventListener('click',function(){replayFileInput.click()});
|
|
1276
|
+
function parseJsonlContent(content){var lines=content.split('\n').filter(function(l){return l.trim()});var messages=[];lines.forEach(function(line,idx){try{var obj=JSON.parse(line);if(obj.type==='user'||obj.type==='human'){messages.push({role:'user',content:extractReplayContent(obj),timestamp:obj.timestamp||'',idx:idx})}else if(obj.type==='assistant'||obj.type==='ai'){var txt=extractReplayContent(obj);var tools=extractReplayToolCalls(obj);if(txt||tools.length>0){messages.push({role:'assistant',content:txt,tools:tools,timestamp:obj.timestamp||'',idx:idx})}}else if(obj.type==='tool_result'||obj.type==='tool'){messages.push({role:'tool',content:obj.name||obj.tool_name||'tool',result:truncateReplayStr(JSON.stringify(obj.result||obj.content||obj.output||''),500),timestamp:obj.timestamp||'',idx:idx})}else if(obj.message){var role=obj.message.role||'unknown';if(role==='user'||role==='human'){messages.push({role:'user',content:extractReplayContent(obj.message),timestamp:obj.timestamp||'',idx:idx})}else if(role==='assistant'){var txt=extractReplayContent(obj.message);var tools=extractReplayToolCalls(obj.message);if(txt||tools.length>0){messages.push({role:'assistant',content:txt,tools:tools,timestamp:obj.timestamp||'',idx:idx})}}}}catch(e){}});return messages}
|
|
1277
|
+
function extractReplayContent(obj){if(typeof obj.content==='string')return obj.content;if(Array.isArray(obj.content)){return obj.content.filter(function(c){return c.type==='text'}).map(function(c){return c.text||''}).join('\n')}if(obj.text)return obj.text;return''}
|
|
1278
|
+
function extractReplayToolCalls(obj){var tools=[];if(Array.isArray(obj.content)){obj.content.forEach(function(c){if(c.type==='tool_use'){tools.push({name:c.name,params:truncateReplayStr(JSON.stringify(c.input||{}),200)})}})}if(obj.tool_calls){obj.tool_calls.forEach(function(t){tools.push({name:t.name||'tool',params:truncateReplayStr(JSON.stringify(t.arguments||t.input||{}),200)})})}return tools}
|
|
1279
|
+
function truncateReplayStr(s,max){return s.length>max?s.substring(0,max)+'...':s}
|
|
1280
|
+
function renderReplayMessages(upToIdx){clearEl(replayBody);for(var i=0;i<=upToIdx&&i<replayMessages.length;i++){var m=replayMessages[i];var msgEl=document.createElement('div');msgEl.className='replay-msg '+m.role;if(m.role!=='tool'){var roleEl=document.createElement('div');roleEl.className='replay-msg-role';roleEl.textContent=m.role==='user'?'Vous':'Claude';msgEl.appendChild(roleEl)}var contentEl=document.createElement('div');contentEl.className='replay-msg-content';if(m.role==='tool'){contentEl.textContent='[Tool] '+m.content+': '+m.result}else{contentEl.textContent=m.content||'(contenu vide)'}msgEl.appendChild(contentEl);if(m.tools&&m.tools.length>0){m.tools.forEach(function(t){var toolEl=document.createElement('div');toolEl.className='replay-tool-summary';toolEl.innerHTML='<div class="replay-tool-name">'+t.name+'</div><div class="replay-tool-params">'+t.params+'</div>';msgEl.appendChild(toolEl)})}if(m.timestamp){var timeEl=document.createElement('div');timeEl.className='replay-msg-time';timeEl.textContent=m.timestamp.split('T')[1]?m.timestamp.split('T')[1].substring(0,8):m.timestamp;msgEl.appendChild(timeEl)}replayBody.appendChild(msgEl)}replayBody.scrollTop=replayBody.scrollHeight;updateReplayProgress()}
|
|
1281
|
+
function updateReplayProgress(){replayProgress.textContent=(replayCurrentIdx+1)+' / '+replayMessages.length;replaySlider.max=replayMessages.length-1;replaySlider.value=replayCurrentIdx}
|
|
1282
|
+
function playReplay(){if(replayPlaying){replayPlaying=false;clearInterval(replayInterval);replayInterval=null;replayPlayBtn.innerHTML='▶';replayPlayBtn.classList.remove('active');return}if(replayCurrentIdx>=replayMessages.length-1){replayCurrentIdx=0}replayPlaying=true;replayPlayBtn.innerHTML='❚❚';replayPlayBtn.classList.add('active');var speed=parseInt(document.getElementById('replay-speed').value);replayInterval=setInterval(function(){if(replayCurrentIdx<replayMessages.length-1){replayCurrentIdx++;renderReplayMessages(replayCurrentIdx)}else{replayPlaying=false;clearInterval(replayInterval);replayInterval=null;replayPlayBtn.innerHTML='▶';replayPlayBtn.classList.remove('active')}},speed)}
|
|
1283
|
+
replayFileInput.addEventListener('change',function(e){var file=e.target.files[0];if(!file)return;var reader=new FileReader();reader.onload=function(ev){var content=ev.target.result;replayMessages=parseJsonlContent(content);if(replayMessages.length===0){toast('Aucun message trouve');return}replayCurrentIdx=0;renderReplayMessages(0);replayControls.style.display='flex';updateReplayProgress();toast(replayMessages.length+' messages charges')};reader.readAsText(file);e.target.value=''});
|
|
1284
|
+
replayPlayBtn.addEventListener('click',playReplay);
|
|
1285
|
+
document.getElementById('replay-prev').addEventListener('click',function(){if(replayCurrentIdx>0){replayCurrentIdx--;renderReplayMessages(replayCurrentIdx)}});
|
|
1286
|
+
document.getElementById('replay-next').addEventListener('click',function(){if(replayCurrentIdx<replayMessages.length-1){replayCurrentIdx++;renderReplayMessages(replayCurrentIdx)}});
|
|
1287
|
+
replaySlider.addEventListener('input',function(){replayCurrentIdx=parseInt(this.value);renderReplayMessages(replayCurrentIdx)});
|
|
1288
|
+
document.getElementById('replay-speed').addEventListener('change',function(){if(replayPlaying){clearInterval(replayInterval);var speed=parseInt(this.value);replayInterval=setInterval(function(){if(replayCurrentIdx<replayMessages.length-1){replayCurrentIdx++;renderReplayMessages(replayCurrentIdx)}else{replayPlaying=false;clearInterval(replayInterval);replayInterval=null;replayPlayBtn.innerHTML='▶';replayPlayBtn.classList.remove('active')}},speed)}});
|
|
1289
|
+
window.openReplayModal=openReplayModal;
|
|
1290
|
+
// Initialize tab router
|
|
1291
|
+
initTabRouter();
|
|
1292
|
+
if('serviceWorker' in navigator&&location.protocol!=='file:'){navigator.serviceWorker.register('service-worker.js').then(function(reg){console.log('SW registered:',reg.scope)}).catch(function(err){console.log('SW registration failed:',err)})}
|
|
1293
|
+
window.matchMedia('(prefers-color-scheme:light)').addEventListener('change',function(e){if(!localStorage.getItem(STORE_KEY)){store.theme=e.matches?'light':'dark';save();applyTheme()}});
|
|
1294
|
+
})();
|