1. Timelapse viewer default speed changed to 2x

- frontend/src/components/TimelapseViewer.tsx:17 - Changed from 0.5 to 2

  2. Archive page: hide failed prints filter with persistence
  - Added hideFailed state initialized from localStorage.getItem('archiveHideFailed')
  - Added localStorage persistence via useEffect
  - Added "Hide Failed" toggle button (red styling when active) next to the Favorites button
  - Filter is automatically bypassed when viewing the "Failed Prints" collection
  - "Reset" button also clears this filter

  The filter state persists across page refreshes and browser sessions via localStorage.
This commit is contained in:
maziggy
2025-12-13 10:04:15 +01:00
parent c317ff1085
commit f5cec45dbf
4 changed files with 64 additions and 42 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ const SPEED_OPTIONS = [0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4];
export function TimelapseViewer({ src, title, downloadFilename, onClose }: TimelapseViewerProps) {
const videoRef = useRef<HTMLVideoElement>(null);
const [isPlaying, setIsPlaying] = useState(true);
const [playbackRate, setPlaybackRate] = useState(0.5); // Default to 0.5x for timelapse
const [playbackRate, setPlaybackRate] = useState(2); // Default to 2x for timelapse
const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(0);
+24 -2
View File
@@ -932,6 +932,7 @@ export function ArchivesPage() {
const [filterColors, setFilterColors] = useState<Set<string>>(new Set());
const [colorFilterMode, setColorFilterMode] = useState<'or' | 'and'>('or');
const [filterFavorites, setFilterFavorites] = useState(false);
const [hideFailed, setHideFailed] = useState(() => localStorage.getItem('archiveHideFailed') === 'true');
const [filterTag, setFilterTag] = useState<string | null>(null);
const [showUpload, setShowUpload] = useState(false);
const [uploadFiles, setUploadFiles] = useState<File[]>([]);
@@ -977,6 +978,11 @@ export function ArchivesPage() {
},
});
// Persist hideFailed filter to localStorage
useEffect(() => {
localStorage.setItem('archiveHideFailed', hideFailed.toString());
}, [hideFailed]);
const printerMap = new Map(printers?.map((p) => [p.id, p.name]) || []);
// Extract unique materials and colors from archives
@@ -1037,11 +1043,14 @@ export function ArchivesPage() {
// Favorites filter (only apply if not using favorites collection)
const matchesFavorites = collection === 'favorites' || !filterFavorites || a.is_favorite;
// Hide failed filter (don't apply when viewing failed collection)
const matchesHideFailed = collection === 'failed' || !hideFailed || a.status !== 'failed';
// Tag filter
const archiveTags = a.tags?.split(',').map(t => t.trim()) || [];
const matchesTag = !filterTag || archiveTags.includes(filterTag);
return matchesCollection && matchesSearch && matchesMaterial && matchesColor && matchesFavorites && matchesTag;
return matchesCollection && matchesSearch && matchesMaterial && matchesColor && matchesFavorites && matchesHideFailed && matchesTag;
})
.sort((a, b) => {
switch (sortBy) {
@@ -1108,10 +1117,11 @@ export function ArchivesPage() {
setFilterPrinter(null);
setFilterMaterial(null);
setFilterFavorites(false);
setHideFailed(false);
setFilterTag(null);
};
const hasTopFilters = search || filterPrinter || filterMaterial || filterFavorites || filterTag;
const hasTopFilters = search || filterPrinter || filterMaterial || filterFavorites || hideFailed || filterTag;
// Drag & drop handlers for page-wide upload
const handleDragOver = useCallback((e: React.DragEvent) => {
@@ -1434,6 +1444,18 @@ export function ArchivesPage() {
<Star className={`w-4 h-4 ${filterFavorites ? 'fill-yellow-400' : ''}`} />
<span className="text-sm hidden md:inline">Favorites</span>
</button>
<button
onClick={() => setHideFailed(!hideFailed)}
className={`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors flex-shrink-0 ${
hideFailed
? 'bg-red-500/20 border-red-500 text-red-400'
: 'bg-bambu-dark border-bambu-dark-tertiary text-bambu-gray hover:text-white'
}`}
title={hideFailed ? 'Show failed prints' : 'Hide failed prints'}
>
<AlertCircle className={`w-4 h-4 ${hideFailed ? '' : ''}`} />
<span className="text-sm hidden md:inline">Hide Failed</span>
</button>
{uniqueTags.length > 0 && (
<div className="flex items-center gap-2 flex-shrink-0">
<Tag className="w-4 h-4 text-bambu-gray hidden md:block" />
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -23,7 +23,7 @@
<!-- Splash screens for iOS -->
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
<script type="module" crossorigin src="/assets/index-DTaTSFw4.js"></script>
<script type="module" crossorigin src="/assets/index-BJKxvS2L.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CbCN6LSA.css">
</head>
<body>