diff --git a/internal/assets/static/css/style.css b/internal/assets/static/css/style.css
index de3d981..6166ea2 100644
--- a/internal/assets/static/css/style.css
+++ b/internal/assets/static/css/style.css
@@ -1941,6 +1941,26 @@ a {
background: var(--color-surface);
}
+button.cache-files-more,
+.analysis-files-toggle {
+ width: 100%;
+ border: none;
+ cursor: pointer;
+ font-family: inherit;
+}
+
+.analysis-files-toggle {
+ justify-content: center;
+ color: var(--color-text-muted);
+ background: var(--color-bg-tertiary);
+}
+
+button.cache-files-more:hover,
+.analysis-files-toggle:hover {
+ color: var(--color-text);
+ background: var(--color-bg-secondary);
+}
+
.cache-detail-actions {
display: flex;
gap: 12px;
diff --git a/internal/assets/static/js/app.js b/internal/assets/static/js/app.js
index e41fdd1..dfbdec0 100644
--- a/internal/assets/static/js/app.js
+++ b/internal/assets/static/js/app.js
@@ -206,6 +206,39 @@
// Store current analysis for wizard
let currentAnalysis = null;
let hasShownRevisionPicker = false; // Track if we've shown picker for this repo
+ let analysisFilesExpanded = false; // Toggle for the >20-file truncation on the Analyze card
+
+ function renderFileListRows(files, expanded) {
+ const visible = expanded ? files : files.slice(0, 20);
+ const rowsHtml = visible.map(f => `
+
+ ${escapeHtml(f.path || f.name)}
+ ${f.size_human || formatBytes(f.size)}
+
+ `).join('');
+
+ const remaining = files.length - 20;
+ const moreFiles = remaining > 0
+ ? ``
+ : '';
+
+ return rowsHtml + moreFiles;
+ }
+
+ // Toggle the full file list on the Analyze card and re-render in place.
+ // Selection filters (quant checkboxes) still apply; updateCLICommandFromSelections
+ // is the single source of truth for what's currently visible.
+ window.toggleAnalysisFilesExpanded = function() {
+ analysisFilesExpanded = !analysisFilesExpanded;
+ if (typeof updateCLICommandFromSelections === 'function' && currentAnalysis?.selectable_items?.length) {
+ updateCLICommandFromSelections();
+ } else if (currentAnalysis?.files) {
+ const container = $('#analysisFilesList');
+ if (container) container.innerHTML = renderFileListRows(currentAnalysis.files, analysisFilesExpanded);
+ }
+ };
async function analyzeRepo(forceType = null, revision = null) {
const input = $('#analyzeInput');
@@ -380,18 +413,9 @@
const resultDiv = $('#analyzeResult');
if (!resultDiv) return;
- const filesHtml = data.files?.slice(0, 20).map(f => `
-
- ${escapeHtml(f.path || f.name)}
- ${f.size_human || formatBytes(f.size)}
-
- `).join('') || '';
-
- const moreFiles = (data.files?.length || 0) > 20
- ? `
- ... and ${data.files.length - 20} more files
-
`
- : '';
+ analysisFilesExpanded = false; // Fresh analysis always starts collapsed
+ const filesHtml = renderFileListRows(data.files || [], analysisFilesExpanded);
+ const moreFiles = ''; // folded into renderFileListRows above
// Build type-specific info
let typeInfoHtml = '';
@@ -1388,10 +1412,44 @@
`;
}
+ // Cache-detail modal file list state (module-level so the toggle handler can reach it)
+ let cacheDetailFiles = null;
+ let cacheDetailFilesExpanded = false;
+
+ function renderCacheFileRows(files, expanded) {
+ const visible = expanded ? files : files.slice(0, 20);
+ const rowsHtml = visible.map(f => `
+
+
+ ${f.isLfs ? 'LFS' : ''}
+ ${escapeHtml(f.name)}
+
+ ${escapeHtml(f.sizeHuman)}
+
+ `).join('');
+
+ const remaining = files.length - 20;
+ const moreFiles = remaining > 0
+ ? ``
+ : '';
+
+ return rowsHtml + moreFiles;
+ }
+
+ window.toggleCacheDetailFilesExpanded = function() {
+ cacheDetailFilesExpanded = !cacheDetailFilesExpanded;
+ const list = $('.cache-files-list');
+ if (list && cacheDetailFiles) list.innerHTML = renderCacheFileRows(cacheDetailFiles, cacheDetailFilesExpanded);
+ };
+
window.showCacheDetails = async function(repo, type) {
try {
showModal('Repository Details', '');
const data = await api('GET', `/cache/${repo}`);
+ cacheDetailFiles = data.files || null;
+ cacheDetailFilesExpanded = false;
const typeIcon = data.type === 'model'
? `