@qiaolei81/copilot-session-viewer 0.3.7 → 0.3.9
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/dist/server.min.js +96 -71
- package/package.json +1 -1
- package/public/js/homepage.min.js +8 -8
- package/public/js/session-detail.min.js +267 -75
- package/public/js/time-analyze.min.js +18 -40
- package/views/index.ejs +18 -1
- package/views/session-vue.ejs +579 -252
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
(()=>{var y=window.__PAGE_DATA||{},A=y.sessions||[],G=y.totalSessions||0,D=y.hasMore||!1,k=y.sourceHints||{},m=[...A],u={};u.copilot={offset:A.length,hasMore:D};var f=!1,S="sessionViewer.sourceFilter",$;try{$=localStorage.getItem(S)}catch{$=null}var i=$||"copilot";function g(){return u[i]||(u[i]={offset:0,hasMore:!0}),u[i]}async function
|
|
2
|
-
<div class="session-info-item workspace" title="${
|
|
1
|
+
(()=>{var y=window.__PAGE_DATA||{},A=y.sessions||[],G=y.totalSessions||0,D=y.hasMore||!1,k=y.sourceHints||{},m=[...A],u={};u.copilot={offset:A.length,hasMore:D};var f=!1,S="sessionViewer.sourceFilter",$;try{$=localStorage.getItem(S)}catch{$=null}var i=$||"copilot";function g(){return u[i]||(u[i]={offset:0,hasMore:!0}),u[i]}async function F(){let e=g();if(f||!e.hasMore)return;f=!0;let t=document.getElementById("loading-indicator");t.style.display="block",window.trackClick("LoadMoreClicked",{currentPage:Math.floor(e.offset/20)+1,offset:e.offset,source:i});try{let s=await fetch(`/api/sessions/load-more?offset=${g().offset}&limit=20&source=${encodeURIComponent(i)}`);if(!s.ok)throw new Error("Failed to load more sessions");let o=await s.json(),n=new Set(m.map(r=>r.id)),a=[];for(let r of o.sessions)n.has(r.id)||(m.push(r),a.push(r));g().offset+=o.sessions.length,g().hasMore=o.hasMore,await C(a),E()}catch(s){console.error("Error loading more sessions:",s)}finally{f=!1,t.style.display="none"}}function B(){return m.filter(e=>e.source===i)}function E(){let e=document.getElementById("sessions-container");e.innerHTML="";let t=B();if(t.length===0){e.innerHTML='<div style="text-align: center; color: #6e7681; padding: 40px; font-size: 14px;">No sessions found for this filter.</div>';return}let s=O(t);Object.keys(s).sort((n,a)=>a.localeCompare(n)).forEach(n=>{let a=document.createElement("div");a.className="date-group-header",a.textContent=_(s[n][0].createdAt),e.appendChild(a);let r=document.createElement("div");r.className="recent-list",s[n].forEach(h=>{r.innerHTML+=R(h)}),e.appendChild(r)})}function z(){let e=window.pageYOffset||document.documentElement.scrollTop,t=window.innerHeight,s=document.documentElement.scrollHeight;e+t>=s-500&&g().hasMore&&!f&&F()}var w;function N(){w||(w=setTimeout(()=>{z(),w=null},100))}function P(e){e.preventDefault();let t=document.getElementById("sessionInput").value.trim();t&&(window.location.href=`/session/${t}`)}document.getElementById("sessionForm").addEventListener("submit",P);var M=document.getElementById("fileInput"),d=document.getElementById("importLink"),b=document.getElementById("importStatus");d.addEventListener("click",e=>{e.preventDefault(),M.click()});M.addEventListener("change",async e=>{let t=e.target.files[0];if(t){if(!t.name.endsWith(".zip")){p("error","\u274C Please select a .zip file");return}d.style.pointerEvents="none",d.style.opacity="0.5",d.textContent="Importing...",p("loading","Uploading and extracting session...");try{let s=new FormData;s.append("zipFile",t);let o=await fetch("/session/import",{method:"POST",body:s}),n=await o.json();o.ok?(p("success",`\u2705 Session ${n.sessionId} imported successfully!`),setTimeout(()=>{window.location.reload()},1500)):(p("error",`\u274C Import failed: ${n.error}`),d.style.pointerEvents="auto",d.style.opacity="1",d.textContent="Import session from zip")}catch(s){p("error",`\u274C Import failed: ${s.message}`),d.style.pointerEvents="auto",d.style.opacity="1",d.textContent="Import session from zip"}finally{M.value=""}}});function p(e,t){b.className=`import-status ${e}`,b.textContent=t}function Z(e){if(!e||e<0)return"\u2014";let t=Math.floor(e/1e3),s=Math.floor(t/60),o=Math.floor(s/60);if(o>0){let n=s%60;return`${o}h ${n}m`}else if(s>0){let n=t%60;return`${s}m ${n}s`}else return`${t}s`}function _(e){let t=new Date(e),s=t.getFullYear(),o=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0");return`${s}/${o}/${n}`}function j(e){if(!e)return"Unknown";let t=new Date(e),s=t.getFullYear(),o=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0");return`${s}-${o}-${n}`}function O(e){let t={};return e.forEach(s=>{let o=j(s.createdAt);t[o]||(t[o]=[]),t[o].push(s)}),t}function R(e){let t="",s=e.sourceBadgeClass||"source-copilot",o=e.sourceName||"Copilot";if(t+=`<span class="status-badge ${s}" title="${o}">${o}</span>`,e.sessionStatus==="wip"&&(t+='<span class="status-badge wip" title="Session in progress">\u{1F504} WIP</span>'),e.isImported&&(t+='<span class="status-badge imported" title="Imported session">\u{1F4E5}</span>'),e.hasInsight&&(t+='<span class="status-badge insight" title="Has Agent Review">\u{1F4A1}</span>'),e.selectedModel){let v=e.selectedModel.replace("claude-","").replace("gpt-","").replace("gemini-",""),c="model-other";e.selectedModel.includes("claude")?c="model-claude":e.selectedModel.includes("gpt")?c="model-gpt":e.selectedModel.includes("gemini")&&(c="model-gemini"),t+=`<span class="status-badge model ${c}" title="Model: ${l(e.selectedModel)}">${l(v)}</span>`}e.source==="modernize"&&e.modernizeVersion?t+=`<span class="status-badge version" title="Modernize version">${l(e.modernizeVersion)}</span>`:e.copilotVersion&&(t+=`<span class="status-badge version" title="CLI version">${l(e.copilotVersion)}</span>`),e.agentName&&(t+=`<span class="status-badge agent" title="Agent: ${l(e.agentName)}">\u{1F916} ${l(e.agentName)}</span>`);let n="";if(e.summary&&e.summary!=="No summary"&&e.summary!=="Legacy session"){let v=e.summary.replace(/"/g,"""),c=l(e.summary).replace(/\n+/g," ");n=`<div class="session-summary" title="${v}">${c}</div>`}else n='<div class="session-summary" style="color: #6e7681; font-style: italic;">No summary available</div>';let a="";e.workspace&&e.workspace.cwd&&(a=`
|
|
2
|
+
<div class="session-info-item workspace" title="${l(e.workspace.cwd)}">
|
|
3
3
|
<svg viewBox="0 0 16 16" fill="currentColor"><path d="M1.75 1A1.75 1.75 0 000 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0016 13.25v-8.5A1.75 1.75 0 0014.25 3H7.5a.25.25 0 01-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75z"></path></svg>
|
|
4
|
-
<span class="session-info-value">${
|
|
4
|
+
<span class="session-info-value">${l(e.workspace.cwd)}</span>
|
|
5
5
|
</div>
|
|
6
6
|
`);let r=e.createdAt?new Date(e.createdAt).toLocaleString("en-US",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!1}):"unknown",h="";e.duration&&(h=`
|
|
7
7
|
<div class="session-info-item">
|
|
8
8
|
<svg viewBox="0 0 16 16" fill="currentColor"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM7.25 12.5v-5A.75.75 0 0 1 8 6.75h2.5a.75.75 0 0 1 0 1.5H8.75v4.25a.75.75 0 0 1-1.5 0Z"></path></svg>
|
|
9
|
-
<span class="session-info-value">${
|
|
9
|
+
<span class="session-info-value">${Z(e.duration)}</span>
|
|
10
10
|
</div>
|
|
11
|
-
`);let T=e.sessionStatus==="wip"?" recent-item-wip":"",I="";return e.tags&&e.tags.length>0&&(I=`<div class="session-tags">${e.tags.map(
|
|
12
|
-
<a href="/session/${e.id}" class="recent-item${T}" onclick="trackClick('SessionCardClicked', { sessionId: '${
|
|
11
|
+
`);let T=e.sessionStatus==="wip"?" recent-item-wip":"",I="";return e.tags&&e.tags.length>0&&(I=`<div class="session-tags">${e.tags.map(c=>`<span class="session-tag" style="background-color: ${V(c)}" title="${l(c)}">${l(c)}</span>`).join("")}</div>`),`
|
|
12
|
+
<a href="/session/${e.id}" class="recent-item${T}" onclick="trackClick('SessionCardClicked', { sessionId: '${l(e.id)}', source: '${l(e.source||"unknown")}' })">
|
|
13
13
|
<div class="session-id">
|
|
14
|
-
<span class="session-id-text" title="${
|
|
14
|
+
<span class="session-id-text" title="${l(e.id)}">${l(e.id)}</span>
|
|
15
15
|
</div>
|
|
16
16
|
<div class="session-badges-tags">
|
|
17
17
|
<div class="session-badges">${t}</div>
|
|
@@ -32,4 +32,4 @@
|
|
|
32
32
|
</div>
|
|
33
33
|
</div>
|
|
34
34
|
</a>
|
|
35
|
-
`}function
|
|
35
|
+
`}function l(e){let t=document.createElement("div");return t.textContent=e,t.innerHTML}var L=["#3b82f6","#10b981","#f59e0b","#ef4444","#8b5cf6","#ec4899","#06b6d4","#f97316"];function V(e){let t=0;for(let s=0;s<e.length;s++)t=e.charCodeAt(s)+((t<<5)-t);return L[Math.abs(t)%L.length]}async function U(e){try{let t=e.map(n=>fetch(`/api/sessions/${n}/tags`).then(a=>a.ok?a.json():{tags:[]}).then(a=>({id:n,tags:a.tags||[]})).catch(()=>({id:n,tags:[]}))),s=await Promise.all(t),o={};return s.forEach(({id:n,tags:a})=>{o[n]=a}),o}catch(t){return console.error("Error loading session tags:",t),{}}}async function C(e){let t=e.map(o=>o.id),s=await U(t);e.forEach(o=>{o.tags=s[o.id]||[]})}function H(e){let t=document.getElementById("sourceHint");t&&k[e]?t.innerHTML='Sessions from <span class="hint-code">'+k[e]+"</span>":t&&(t.textContent="")}async function x(e){if(u[e]||(u[e]={offset:0,hasMore:!0}),u[e].offset===0&&!f){f=!0;let t=document.getElementById("sessions-container");t.innerHTML='<div style="text-align: center; color: #6e7681; padding: 40px; font-size: 14px;">\u23F3 Loading...</div>',document.getElementById("loading-indicator").style.display="none";try{let s=await fetch(`/api/sessions/load-more?offset=0&limit=20&source=${encodeURIComponent(e)}`);if(s.ok){let o=await s.json(),n=new Set(m.map(r=>r.id)),a=[];for(let r of o.sessions||[])n.has(r.id)||(m.push(r),a.push(r));u[e].offset=(o.sessions||[]).length,u[e].hasMore=o.hasMore,await C(a)}}catch(s){console.error("Failed to load sessions for source:",e,s)}finally{f=!1}}E()}function Y(){let e=document.querySelectorAll(".filter-pill");if(!new Set([...e].map(s=>s.getAttribute("data-source"))).has(i)){i="copilot";try{localStorage.setItem(S,i)}catch{}}e.forEach(s=>{s.classList.toggle("active",s.getAttribute("data-source")===i)}),H(i),e.forEach(s=>{s.addEventListener("click",async()=>{e.forEach(o=>o.classList.remove("active")),s.classList.add("active"),i=s.getAttribute("data-source");try{localStorage.setItem(S,i)}catch{}H(i),window.trackClick("FilterPillClicked",{pillName:s.textContent.trim(),dataSource:i}),await x(i)})})}document.addEventListener("DOMContentLoaded",async function(){await C(m),window.addEventListener("scroll",N),Y(),i==="copilot"?E():await x(i)});})();
|