Jelajahi Sumber

Fix SJF toggle disappearing from queue page (#879)

  The Shortest Job First toggle badge was rendered inside the Pending
  Queue section header, which only mounts when pendingItems.length > 0
  and the list view is selected. Clicking the toggle often lined up
  with the scheduler picking up the last pending item, which unmounted
  the whole section and took the toggle with it.

  Moved the toggle into the queue page header next to the list/timeline
  view switcher so it stays visible regardless of pending-item count,
  filters, or view mode. On mobile the view-mode switcher remains
  hidden (as before) but the SJF button is visible icon-only.
maziggy 4 bulan lalu
induk
melakukan
4d57c9cac4
4 mengubah file dengan 21 tambahan dan 20 penghapusan
  1. 1 0
      CHANGELOG.md
  2. 19 19
      frontend/src/pages/QueuePage.tsx
  3. 0 0
      static/assets/index-wUMtKBja.js
  4. 1 1
      static/index.html

+ 1 - 0
CHANGELOG.md

@@ -11,6 +11,7 @@ All notable changes to Bambuddy will be documented in this file.
 - **LDAP Default Fallback Group** — Settings → Authentication → LDAP → Advanced now has a "Default group" selector. When an LDAP user authenticates but is not listed in any mapped LDAP group, they are automatically assigned to this fallback group instead of being left without permissions. Previously such users could log in successfully but landed on empty pages because every permission check failed. Leave the setting empty to preserve the old behavior. A warning is logged each time the fallback is applied so administrators can spot missing group assignments.
 
 ### Fixed
+- **Shortest Job First Toggle Disappears After Clicking** ([#879](https://github.com/maziggy/bambuddy/issues/879)) — The SJF toggle badge on the queue page was rendered inside the Pending Queue section header, which is only shown when there is at least one pending item and the list view is active. Clicking the toggle often coincided with the scheduler starting the only pending print, at which point the Pending section unmounted and the toggle vanished along with it — making it look like the button had disappeared after clicking. The toggle has been moved to the top of the queue page, next to the list/timeline view switcher, so it stays reachable regardless of pending-item count, active filters, or the selected view mode.
 - **SpoolBuddy Update Fails in Docker with "no user exists for uid 1001"** — The SpoolBuddy remote-update flow shelled out to `ssh-keygen` to create its update keypair on first use. Inside the Docker container the process runs under an arbitrary PUID (default 1000, also seen as 1001) that is not listed in `/etc/passwd`, so `ssh-keygen` aborted at the `getpwuid()` home-directory lookup and the update button reported `ssh-keygen failed. no user exists for uid 1001`. The keypair is now generated in-process via the `cryptography` library (already a dependency), which has no user-database lookup and produces the same OpenSSH-format files. Native installs are unaffected — they already worked because the running user was always in `/etc/passwd`.
 - **Camera Stream "6 of 5" Reconnect Counter + ffmpeg Log Flood** ([#925](https://github.com/maziggy/bambuddy/issues/925)) — Two bugs surfaced while investigating camera reconnect behaviour. First, the camera page briefly displayed "Reconnecting attempt 6 of 5" before giving up, because the attempt counter could be incremented to the maximum while the reconnect banner was still rendering. The displayed value is now clamped to the configured maximum. Second, every failed ffmpeg spawn logged the full ~20-line ffmpeg version/configuration banner, producing hundreds of lines of noise per failed camera click (one reported click produced 555 log lines across 30 retries). A new stderr summarizer strips the ffmpeg banner before logging so only the actual error lines remain. The underlying "camera service stops accepting new connections after prolonged uptime" behaviour in the X1C firmware is still under investigation.
 - **LDAP POSIX Primary Group Ignored** — LDAP authentication only looked at groups that listed the user explicitly via `memberUid` (supplementary group membership). A user's POSIX primary group — referenced by the `gidNumber` attribute on the user object and matching the `gidNumber` on a `posixGroup` — was ignored entirely, so users whose role came from their primary group landed without the expected permissions. The authenticator now also searches for `posixGroup` entries whose `gidNumber` matches the user's primary `gidNumber`, and dedupes DNs case-insensitively before resolving the group mapping (LDAP DNs are case-insensitive by spec).

+ 19 - 19
frontend/src/pages/QueuePage.tsx

@@ -1157,9 +1157,9 @@ export function QueuePage() {
         )}
       </div>
 
-      {/* View Mode Toggle */}
-      <div className="hidden sm:flex items-center gap-3 mb-6">
-        <div className="flex items-center border border-bambu-dark-tertiary rounded-lg overflow-hidden">
+      {/* View Mode Toggle + SJF */}
+      <div className="flex items-center gap-3 mb-6">
+        <div className="hidden sm:flex items-center border border-bambu-dark-tertiary rounded-lg overflow-hidden">
           <button
             className={`p-2 transition-colors ${viewMode === 'list' ? 'bg-bambu-green text-white' : 'bg-bambu-dark text-bambu-gray hover:text-white'}`}
             onClick={() => setViewMode('list')}
@@ -1175,6 +1175,22 @@ export function QueuePage() {
             <GanttChart className="w-4 h-4" />
           </button>
         </div>
+        <button
+          onClick={() => {
+            const newValue = !(settings?.queue_shortest_first ?? false);
+            sjfMutation.mutate(newValue);
+          }}
+          className={`flex items-center gap-1 px-2 py-1.5 text-xs rounded-lg border transition-colors ${
+            settings?.queue_shortest_first
+              ? 'bg-bambu-green/20 border-bambu-green text-bambu-green'
+              : 'bg-bambu-dark-secondary border-bambu-dark-tertiary text-bambu-gray hover:text-white hover:border-bambu-gray'
+          }`}
+          title={t('queue.sjf.tooltip', 'Shortest Job First — scheduler prioritizes shorter prints')}
+        >
+          <Timer className="w-3.5 h-3.5" />
+          <span className="hidden sm:inline">{t('queue.sjf.label', 'SJF')}</span>
+          <span className={`w-1.5 h-1.5 rounded-full ${settings?.queue_shortest_first ? 'bg-bambu-green' : 'bg-bambu-gray'}`} />
+        </button>
       </div>
 
       {isLoading ? (
@@ -1248,22 +1264,6 @@ export function QueuePage() {
                   </span>
                 </h2>
                 <div className="flex items-center gap-2">
-                  <button
-                    onClick={() => {
-                      const newValue = !(settings?.queue_shortest_first ?? false);
-                      sjfMutation.mutate(newValue);
-                    }}
-                    className={`flex items-center gap-1 px-2 py-1.5 text-xs rounded-lg border transition-colors ${
-                      settings?.queue_shortest_first
-                        ? 'bg-bambu-green/20 border-bambu-green text-bambu-green'
-                        : 'bg-bambu-dark-secondary border-bambu-dark-tertiary text-bambu-gray hover:text-white hover:border-bambu-gray'
-                    }`}
-                    title={t('queue.sjf.tooltip', 'Shortest Job First — scheduler prioritizes shorter prints')}
-                  >
-                    <Timer className="w-3.5 h-3.5" />
-                    <span className="hidden sm:inline">{t('queue.sjf.label', 'SJF')}</span>
-                    <span className={`w-1.5 h-1.5 rounded-full ${settings?.queue_shortest_first ? 'bg-bambu-green' : 'bg-bambu-gray'}`} />
-                  </button>
                   <select
                     className="px-2 sm:px-3 py-1.5 text-xs sm:text-sm bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
                     value={pendingSortBy}

File diff ditekan karena terlalu besar
+ 0 - 0
static/assets/index-wUMtKBja.js


+ 1 - 1
static/index.html

@@ -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-D6dfDqxE.js"></script>
+    <script type="module" crossorigin src="/assets/index-wUMtKBja.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-Caj-77TJ.css">
   </head>
   <body>

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini