Commit Graph
7174 Commits
Author SHA1 Message Date
Nariman Jelveh f2cc01202e fix(dashboard): open the Sort and View menus at their buttons from the keyboard
Enter or Space on either button fires a click with no coordinates, so the
menu opened at the top-left corner of the screen, far from the button.
A keyboard press now opens it below the button; a pointer click still
opens it at the pointer.
2026-10-23 15:11:27 -07:00
Nariman Jelveh e2feba41b9 perf(dashboard): lay out only the new row when an item is added to Files
Every item added to the open folder from elsewhere (another tab, an
upload, a move into it) restyled and re-truncated every row in the
listing, so a burst of adds was quadratic in the folder's size: 100 adds
into a 300-item folder took ~800ms of main-thread work. The added row now
takes the listing's column layout on its own (~130ms for the same burst).
2026-10-23 15:11:27 -07:00
Nariman Jelveh ae70800ca8 fix(dashboard): follow a username change in the Files tab
Changing the username, or saving a temporary account under a chosen
name, moves the home folder. The GUI rewrote data-path attributes and the
path globals, but the Files tab kept its current folder, back/forward
history, clipboard and drawn rows on the old path, so sorting, New
Folder, Upload, Up, Back and the breadcrumbs all failed with "This folder
couldn't be opened" until a reload. update_username_in_gui now announces
the change, and the Files tab moves its paths over and redraws.
2026-10-23 15:11:27 -07:00
Nariman Jelveh c292bc04cc fix(dashboard): make hover and press feedback visible in dark mode
Dark mode's hover color, #2a2a2a, was 1.05:1 against the #262626 cards
and #252525 sidebar, so hovering a notification or sidebar item and
pressing a touch-menu or drawer item showed next to nothing. #333 sits
as far off them as light mode's hover sits off white, and stays below
the selected item's #3d3d3d.
2026-10-23 15:11:26 -07:00
Nariman Jelveh c33edecb1a fix(dashboard): name the plan on self-hosted installs instead of "--"
A self-hosted install has no /marketplace/subscriptions/current route, and
Home treated its 404 like any failed read, leaving "Your Plan" at "--" for
good. A 404 now shows the plan every account starts on. The upgrade badge
and link, which have nothing to reach there, go too, unless the hosted
upgrade dialog is loaded.
2026-10-23 15:11:26 -07:00
Nariman Jelveh b3073990ec fix(dashboard): bring muted and tertiary text up to AA contrast
The muted and tertiary greys carry real information (form hints, file
dates and sizes, share "via" lines, the sidebar's team name,
notification text and times) but fell short of 4.5:1: 2.56:1 and 3.54:1
on white, 3.18:1 and 3.13:1 on dark cards. They now clear it on the
cards and the sidebar in both themes (light #5f6b7d / #707070, dark
#8b95a5 / #94949c). Disabled buttons keep the fainter grey through their
own token, so they still read as disabled.
2026-10-23 14:26:42 -07:00
Nariman Jelveh 3038ee0b84 fix(dashboard): keep collapsed-sidebar labels above the dashboard
The hover label is attached to body at z-index 1000, while the dashboard
window's z-index climbs with every click (focusWindow raises it). Over a
long session the window passed 1000 and the labels rendered behind it,
so hovering the collapsed sidebar showed nothing.
2026-10-23 14:25:58 -07:00
Nariman Jelveh 4644b63125 fix(dashboard): give primary buttons readable contrast
The dialogs' primary buttons, the share modal's Share and the photo
crop's Save were filled with the link color under white text: 4.07:1 in
light mode, 3.08:1 in dark, where hover lightened it further to 2.38:1.
They take their own fill now, #4a67f5 (4.62:1) darkening to #3d5bd9
(5.68:1) on hover in both themes; links keep their color.
2026-10-23 14:24:37 -07:00
Nariman Jelveh baecb7ba8f fix(dashboard): keep keyboard focus on the Usage table's Show more/less
The table redraws without the button that was pressed, so focus fell back
to the page and the next Tab started from the top. Focus now moves to the
button that replaces it, as the sort headers already do.
2026-10-23 14:24:18 -07:00
Nariman Jelveh eef34ce4c8 perf(dashboard): load usage and storage once when the dashboard opens
Home and Usage both load the monthly usage and the storage space when the
dashboard opens, whichever tab it opens on, so every open sent
/metering/usage and /df twice. Overlapping loads now share one request.
Nothing is cached: a load after the shared one settles fetches again.
2026-10-23 14:23:20 -07:00
Nariman Jelveh dc9ce4fffd fix(dashboard): refresh the Usage tab when the subscription changes
An upgrade from the Usage tab's own button, or a return from the billing
portal, refreshed Home behind it while the Usage meter and plan button
kept the old allowance until the user left the tab and came back. Usage
now handles puter:subscription:changed while it is showing.
2026-10-23 14:21:47 -07:00
Nariman Jelveh bb74a2e8de fix(dashboard): don't leave the sidebar collapse button shaded after a tap
Its hover style was the sidebar's only one not limited to devices that
hover, so on a wide touch screen (an iPad in landscape) the button kept
its hover shade after being tapped.
2026-10-23 14:21:13 -07:00
Nariman Jelveh c407eb0112 fix(dashboard): lighten the General access dropdown arrows in dark mode
The dark-mode chevron override covered the share modal's recipient
selects but not the two General access ones, which kept the darker
light-theme stroke on the dark card.
2026-10-23 14:20:28 -07:00
Nariman Jelveh 9a1269be7a fix(dashboard): give the API token field 16px text on touch screens
The coarse-pointer rule that sets the token field to 16px, as the other
dialog inputs are, came before the field's own 13px rule of the same
specificity, so the 13px won and iOS zoomed the page when the field was
focused. The touch rule now follows it.
2026-10-23 14:19:52 -07:00
Nariman Jelveh e18860f1e8 fix(dashboard): leave the temporary-account state once the account is saved
Saving a temporary account from the user menu promoted the user in place
without a reload, but Home kept its Save session warning (reopening the
save dialog for a saved account) and Account and Security stayed without
their password and email cards until the page was reloaded. The dashboard
now reacts to account-saved, which fires after the user is updated.
2026-10-23 14:19:37 -07:00
Nariman Jelveh 22cc279075 fix(dashboard): make the toast close button readable in dark mode
Dark mode gave the close button the card color and then inverted the
whole element, which turned the disc light grey and the cross white:
about 1.4:1. Without the background the invert gives the light-mode
button's mirror, a dark disc with a white cross.
2026-10-23 14:18:54 -07:00
Nariman Jelveh 485cd6468b fix(dashboard): stop the mobile drawer animating under reduced motion
The reduced-motion override for the drawer, its scrim and the menu button
came before the drawer rules it was meant to cancel, and the open
drawer's rule outranked it too, so the drawer still slid and the scrim
still faded. The override now follows those rules and covers the open
state.
2026-10-23 14:17:14 -07:00
Nariman Jelveh ba06512ac4 fix(dashboard): draw Files select-mode accents in the selection color
The checked checkbox, the active Select button and the Done button were
filled with --primary-color, the desktop's text color rather than an
accent: charcoal by default, and white (on white text and ticks) for
anyone whose desktop theme uses light text. They use --select-color, the
accent the rest of the selection already uses.
2026-10-23 14:16:11 -07:00
Nariman Jelveh 4c29f7268f fix(dashboard): don't show a failed usage request as zero usage
getMonthlyUsage() resolves with the error body when the request fails, and
Usage and Home read it as a month with nothing used: $0.00 of $0.00, 0%,
and on Usage an empty table replacing the one already on screen. A body
without a usage report is treated as the failure it is, so the last good
numbers stay and a first load shows the "unavailable" note.
2026-10-23 14:15:35 -07:00
Nariman Jelveh d364509b91 fix(dashboard): keep the Files spinner under the mobile drawer
The loading overlay sat at the maximum z-index, so on phones it drew over
the open drawer and its scrim and took their taps while a folder loaded.
It only needs to sit above the rows.
2026-10-23 14:14:54 -07:00
Nariman Jelveh 222d7eb744 fix(dashboard): show items added elsewhere while New › Web Link prompts
The New menu's create wrapper suppressed item.added for as long as it ran,
which for Web Link includes its URL prompt, so files added to the folder
meanwhile never appeared. It now counts only from the actual create. A
create that fails now says so instead of failing silently.
2026-10-23 14:13:06 -07:00
Nariman Jelveh e4dfb51ea3 fix(dashboard): select mode toggles rows with any pointer
In select mode, a stylus or mouse tap on a phone or tablet toggled the row
in pointerdown and again in click, leaving it as it was; in a narrow
desktop window a click replaced the selection and the selection bar never
showed. Select mode now toggles in click for every pointer and shows its
bar whenever it is on.
2026-10-23 14:13:06 -07:00
Nariman Jelveh 5851671cd6 fix(dashboard): translate the shortcut badge's tooltip 2026-10-23 14:13:06 -07:00
Nariman Jelveh 7561bb0011 fix(dashboard): list failed uploads one per line
The failed-upload list was joined with newlines, which the alert collapses
onto a single line.
2026-10-23 14:13:05 -07:00
Nariman Jelveh 62b1223d5f fix(dashboard): show names as typed in conflict and move-failure alerts
These alerts html-encoded the file name before UIAlert encoded the
message again, so "R&D.txt" read "R&D.txt". "already exists." is
translatable now too.
2026-10-23 14:13:05 -07:00
Nariman Jelveh eb9fd60ade fix(dashboard): offer Restore only for items Restore can handle
Selecting files inside a trashed folder offered Restore in the
multi-select menu and the selection bar, which then failed once per item:
only direct children of Trash carry restore metadata. The trashed
multi-select menu also drew two separators in a row.
2026-10-23 14:13:05 -07:00
Nariman Jelveh cfa1dd58c8 fix(dashboard): listing drops keep working after a drop on a folder row
Dropping files from the computer onto a folder row stopped the native
event before the listing's dragster saw it, leaving its enter state stuck:
later drags didn't highlight the listing, and drops on its background
uploaded nothing.
2026-10-23 14:13:04 -07:00
Nariman Jelveh 3bd73a4b3f fix(dashboard): clear a drop target's highlight after the drop
jQuery UI fires no `out` on drop, so the folder row a selection was
dropped on stayed selected (and went to the Trash with the next Delete),
a sidebar folder stayed highlighted as the current one, and a breadcrumb
kept its drop outline.
2026-10-23 14:13:04 -07:00
Nariman Jelveh ac0cffe5d9 fix(dashboard): refresh Files on return after a cancelled rename
Escape, or keeping a name unchanged, hid the rename editor but left its
-active class, and the refresh on returning to the browser tab takes that
class for an open editor: the listing stopped refreshing until the next
navigation.
2026-10-23 14:13:03 -07:00
Nariman Jelveh 5718f0f3dc fix(dashboard): Delete Permanently works in every language
The confirmation compared the clicked button's label with 'Delete', so in
any other locale confirming did nothing. The buttons carry values now.
2026-10-23 14:13:03 -07:00
Nariman Jelveh 4be5a8d2c6 fix(dashboard): don't cut or copy trashed items out of the Trash
The single-item menu still offered Cut on trashed items, and Ctrl+C
copied them; pasted elsewhere, they kept their raw name in the Trash, a
uid. Trashed items leave through Restore, which puts the original name
back.
2026-10-23 14:13:03 -07:00
Nariman Jelveh b052916bf9 fix(dashboard): make Paste Into Folder work after a cut
The row menu's Paste Into Folder handed a cut to the desktop's
move_clipboard_items, which finds items by their on-screen elements and
plain-string paths. The Files tab's cut stores {path, uid} objects, so
nothing moved and the clipboard was emptied. The menu now takes a paste
handler, and Paste, Ctrl+V and Paste Into Folder share one.
2026-10-23 14:13:02 -07:00
Nariman Jelveh f8cdcdb8fc fix(dashboard): no New, Upload or Paste where nothing can be created
New Folder, Upload, the New/Paste/Upload menu items and file drops were
only refused in the Trash itself and the Shared view. Inside a trashed
folder they created items without the metadata Restore needs, and at /
every create failed (an upload there threw before its progress window
existed and showed nothing). One check now covers the Trash, folders in
it, the Shared view and /.
2026-10-23 14:13:02 -07:00
Nariman Jelveh c2f2ed8156 fix(dashboard): upload from a folder's menu into that folder
Upload in a sidebar or breadcrumb folder's menu opened the shared file
picker, whose handler always uploaded into the folder on screen: files
picked for Pictures while viewing Documents landed in Documents. The menu
now hands its folder to the picker.
2026-10-23 14:12:47 -07:00
Nariman Jelveh 639d400b31 fix(dashboard): keep focus inside the Apps modals and return it on close
The uninstall and add-app modals are aria-modal but had no Tab trap, so
Tab walked into the search box and tiles behind the scrim, where typing
filtered the grid under the modal. Closing the add-app modal, and
confirming an uninstall, dropped focus to the page body.

Tab now cycles inside both cards; closing the add-app modal returns focus
to the add tile, and an uninstall leaves focus on the tile that takes the
removed app's slot.
2026-10-23 14:05:27 -07:00
Nariman Jelveh 0c76865197 fix(dashboard): say so when an app tile fails to launch
A tile click whose launch rejected (for example the app lookup failing)
only logged to the console: the icon flourish played, settled, and nothing
opened. It now shows the same alert the add-app modal shows for that
failure.
2026-10-23 14:05:27 -07:00
Nariman Jelveh 3e2ba20384 fix(dashboard): don't double-encode the add-app launch failure alert
UIAlert encodes its message, so passing it the already-encoded i18n string
showed entities on screen in languages with an apostrophe (French read
"s'est mal passé").
2026-10-23 14:05:27 -07:00
Nariman Jelveh 7db4d99fab fix(dashboard): put a re-installed app back in its saved slot
Uninstall keeps the app's name in the saved order so a re-install returns
it to its place, but a deep-link landing appended the tile at the end of
the grid. The install animation played on the last page and the tile then
jumped back to its saved slot on the next refresh. The landing now places
the tile through reconcileAppOrder like every other load.
2026-10-23 14:05:27 -07:00
Nariman Jelveh fde558d14a fix(dashboard): drop the Apps tile a failed deep-link launch drew
Landing on /app/<name> (or choosing an option in the add-app modal) adds
the app's tile before the launch runs, because the launch is what installs
it. When the launch failed — no access, no app token, a thrown error — the
tile stayed for the rest of the session, survived refreshes, and every
click on it failed again.

The launch outcome is now passed to settleDeepLinkLaunch, which takes a
tile it drew back out (and restores a previous uninstall record) when
nothing was launched.
2026-10-23 14:05:26 -07:00
Nariman Jelveh 33b7f60bd6 fix(dashboard): keep Apps folders and order when a settings read fails
The Apps tab read the saved order, folders and uninstalled-apps list with
`.catch(() => null)`, so a failed read looked like a user who had never
saved any. One flaky request emptied the folders and reset the grid to
the default order, and the next drag or folder edit wrote that loss back
to kv for good.

A failed read now keeps what the session already has (the last
uninstalled-apps list included). Until a read of the order or folders has
succeeded, saves stay in memory instead of overwriting the stored value.
2026-10-23 14:05:16 -07:00
Nariman Jelveh d7e88e2121 fix(dashboard): make the touch context menu reachable by assistive tech and keyboard
The touch action sheet had no roles and never took focus: it was appended
at the end of the page, so a screen reader announced nothing on open and
focus stayed on the page behind it. It's now a menu of menuitems (with
separators and submenu popups marked), takes focus on open, gives it back
on close, moves between enabled items with the arrow keys and Home/End,
and shows an inset focus ring for keyboard use. Taps draw no ring.
2026-10-23 14:04:55 -07:00
Nariman Jelveh 1163baee4a fix(dashboard): don't double-encode the "anyone" and withheld-invite share rows
The share dialog encodes row names when it renders them, but these two
labels came from i18n() already HTML-encoded, so a translation containing
an apostrophe or ampersand would show its entity text. They're now taken
unencoded like every other row name.
2026-10-23 14:04:45 -07:00
Nariman Jelveh b73fd456cb fix(dashboard): handle the Properties stat failure instead of leaving it unhandled
puter.fs.stat both calls the error callback and rejects. The properties
dialog rendered the error from the callback but dropped the promise, so
opening it on a deleted item or offline logged an unhandled rejection.
2026-10-23 14:04:42 -07:00
Nariman Jelveh 589a411f53 fix(dashboard): keep focus in Properties after disassociating one of several websites
With more than one website on an item, disassociating one removed the
focused button and returned early before refocusing the dialog, so focus
fell to the page and the next Tab landed in the dashboard behind the modal.
The dialog takes focus back as soon as the entry is removed.
2026-10-23 14:04:39 -07:00
Nariman Jelveh 93359218bb fix(dashboard): don't close Properties when a text selection ends on the backdrop
Drag-selecting the path or UID in the properties dialog and releasing over
the dimmed backdrop closed the dialog: the click lands on the overlay when
press and release are on different elements. The backdrop now closes it
only when the press started there, as the share dialog already does.
2026-10-23 14:04:33 -07:00
Nariman Jelveh 0a291e936b fix(dashboard): keep Escape working when two share or properties dialogs are open
Each share and properties dialog bound its document keydown under one fixed
namespace, so closing either instance unbound every instance's Escape.
Double-clicking Share… or Properties in the context menu opens two; after
the top one closed, Escape no longer closed the one left behind. Each dialog
now binds under its own namespace.
2026-10-23 14:04:26 -07:00
Nariman Jelveh 9c90c7afde fix(dashboard): third adversarial review — bugs, UX, a11y, perf (#4310)
Notify HeyPuter / notify (push) Canceled after 0s
release-please / release-please (push) Canceled after 0s
Backend Tests / changes (push) Canceled after 0s
Backend Tests / typecheck (push) Canceled after 0s
Backend Tests / test shard 1/4 (push) Canceled after 0s
Backend Tests / test shard 2/4 (push) Canceled after 0s
Backend Tests / test shard 3/4 (push) Canceled after 0s
Backend Tests / test shard 4/4 (push) Canceled after 0s
Backend Tests / test (main) (push) Canceled after 0s
Backend Tests / coverage (push) Canceled after 0s
Maintain Release Merge PR / update-release-pr (push) Canceled after 0s
* chore(dashboard): add the standard file header where it was missing

* fix(dashboard): rename editor keeps entity-like names; rows follow remote renames

The name editor decoded its already-decoded value a second time, so opening
it on a file such as "R&amp;D.txt" and clicking away renamed it to "R&D.txt".

A rename or update from another tab only patched a row's attributes, while
its open/copy/share handlers kept using the entry they were rendered with;
the row now keeps that entry current and refits its name.

* fix(dashboard): Files selection, preview and Trash/Shared edge cases

- A marquee drag without modifiers now replaces a selection made by click,
  Ctrl+A or the arrow keys instead of adding to it.
- With the image preview open, clicking another image switches to it, and
  moving onto a non-image closes it instead of keeping the old image up.
- Cut (Ctrl+X, multi-select menu) skips trashed items, which leave the Trash
  through Restore; Ctrl+V refuses the Trash and the Shared view like the
  Paste menu item does.
- Drops on the Shared sidebar entry or breadcrumb are refused (the drag
  snaps back) instead of sending writes to a path that isn't a folder.
- The Trash selection bar shows Delete permanently again after a selection
  elsewhere had hidden it.

* fix(dashboard): keep an open rename across refreshes; re-sort renamed rows

A same-folder refresh (an upload or paste finishing, a sort change) rebuilt
every row and silently dropped a rename in progress; the editor now comes
back on the same item with the text and caret the user left.

A renamed row whose new name sorts last stayed where its old name was.

* fix(dashboard): Files columns follow the room the listing has

- Resizing a column past the listing's width clamps it instead of resetting
  every column to the defaults; a window too narrow for the saved widths
  lays out at the defaults but keeps the saved widths for when it widens.
- Columns and grid names re-fit when the window or sidebar resizes the
  listing, not only on the next navigation, and grid names hidden behind
  another tab are fitted when the Files tab is shown.
- Names are measured in the font they render in (the compact grid's is
  smaller), and a column drag relayouts at most once a frame.

* fix(dashboard): Files keyboard and touch edge cases

- The marquee selects file rows only, not the Shared/Trash place rows Home
  shows on narrow screens.
- Row shortcuts stand aside while the touch action sheet is open.
- Breadcrumb long-press opens its menu on iPadOS too.
- A folder rendered before the saved view preferences load uses the
  defaults instead of throwing and blocking navigation.

* fix(dashboard): share and properties modals — focus, Escape, link state

Share modal:
- Escape pressed in a window opened over the modal (a verification or
  upgrade gate) no longer closes the modal underneath.
- Turning the link on or off for a selection too large to list now shows
  the result instead of leaving the control on its old state.
- Opening the link up starts at view access; it no longer reuses a hidden
  mode left over from earlier, which could hand out edit access.
- Focus returns to the select the user changed.

Properties modal:
- Takes focus when it opens, keeps Tab inside, gives focus back on close,
  and leaves Escape to a window opened over it.
- Shows a loading state, and opening Versions on a folder before its
  details load no longer leaves an empty body.
- Disassociate is a real button, ignores repeat clicks while pending,
  reports a failure, and keeps the website badge while other sites remain.
- Tabs carry tab/tabpanel roles; transitions respect reduced motion.

* fix(dashboard): account dialogs, avatar saves and usage figures

- A form dialog ignores Escape and backdrop clicks while its request runs,
  so the outcome isn't lost behind a closed dialog; the close button still
  works.
- A new API token, shown only once, survives a stray click outside the card.
- Copy token works on origins without navigator.clipboard (plain-http
  self-hosts) instead of throwing, falling back to a selected field.
- Saving one profile picture and then another before the first finished
  can no longer leave the first one's picture or failure on screen.
- The storage host bar is clamped to the room left beside Puter's share and
  hides its label when there is no host figure.
- Sub-cent dollar costs read "<$0.01" rather than "$0.00", and the usage
  meter reads 99% until the allowance is actually spent.

* fix(dashboard): Apps folder drag, search, keys and loading

- A drag inside an open folder that is cancelled (Escape, blur) or dropped
  back in place puts the tiles back in their saved order; the cached panel
  markup used to skip the rebuild, and the next drag then saved the
  cancelled move too.
- Search no longer matches substrings of generated app ids, so "app" or a
  single hex letter stops returning every website shortcut.
- Arrow keys and Enter stay with the notifications panel, an account dialog
  or the touch action sheet while one is open over the grid.
- The grid shows after 1.5s even if an icon host never answers.
- Refreshing a grid already on screen keeps the page and skips the fade.
- Rename from a folder's menu focuses the name on touch devices too, and
  the folder dialog's label follows renames and counts the apps shown.
- i18n inserts %% values literally, so a name containing $& or $' no longer
  comes out mangled.

* fix(dashboard): shell navigation, a11y and notification sync

- Missed notifications replayed on load toast as one burst (a few, then a
  summary) instead of one toast each.
- A notification read in another tab while this tab's first listing is in
  flight is no longer shown as unread when that listing lands.
- Focus stays in the notifications panel when Mark all read or Retry hides
  the button that had it.
- The active sidebar tab carries aria-current, and the account button is
  named by the username even while the collapsed sidebar hides it.
- Landing with ?ref= replaces the history entry, so one Back leaves.
- Ctrl/Cmd/Shift-click on a sidebar tab opens it in a new browser tab.
- Recently used keeps the newest list when refreshes overlap, and app names
  are URL-encoded in the links it opens.

* fix(dashboard): focus rings, dark-mode contrast and reduced motion

- App tiles show a focus ring, not only the hover enlargement; Home card
  headers get an inset ring the card's rounded clip can't cut off; the
  Delete account button gets the settings cards' ring.
- Pager arrows are mouse-only (the dots page by keyboard), so invisible
  arrows are no longer Tab stops, and an arrow with no page leaves the
  accessibility tree.
- Dark mode: the Files toolbar's action icons match the nav arrows and stay
  readable on the hover chip, hovered breadcrumbs keep their contrast, and
  the shared-item dot's ring follows the row background.
- The row '⋯' button is visible at rest on touch screens.
- A long username or email wraps inside the profile card.
- The touch action sheet, the Files selection bar and the app feedback
  modal stop scaling/sliding under reduced motion.

* fix(gui): desktop rows store remote renames raw; column resize stays in bounds

- The desktop's item.renamed/item.updated handlers wrote HTML-escaped names
  into data-name, the title and the name editor (and titled windows by an
  undefined uid). They store the raw name now, as rename_file does, so the
  editor shows the real name now that it no longer decodes a second time.
- Resizing a Files column while saved widths are too wide for the listing
  starts from the widths on screen, and a width is held at its column's
  minimum, so a drag or auto-fit can't save a negative width.
- Double-clicking a row closes the image preview, which would otherwise
  float above the app window it opens.
2026-10-23 12:32:33 -07:00
Rasad RegmiandDaniel Salazar acd3df8c1b fix(puter-js): replay the request after a successful token_auth_failed reauth (#3954)
release-please / release-please (push) Canceled after 0s
Notify HeyPuter / notify (push) Canceled after 0s
Maintain Release Merge PR / update-release-pr (push) Canceled after 0s
Backend Tests / changes (push) Canceled after 0s
Backend Tests / typecheck (push) Canceled after 0s
Backend Tests / test shard 1/4 (push) Canceled after 0s
Backend Tests / test shard 2/4 (push) Canceled after 0s
Backend Tests / test shard 3/4 (push) Canceled after 0s
Backend Tests / test shard 4/4 (push) Canceled after 0s
Backend Tests / test (main) (push) Canceled after 0s
Backend Tests / coverage (push) Canceled after 0s
* fix(puter-js): replay the request after a token_auth_failed reauth

A 401 carrying the legacy `token_auth_failed` code opened the sign-in
prompt and then dropped the re-authenticated token on the floor:
`resolveReauth()` fell through to `return null` instead of returning
`{ action: 'replay' }`, so the original call was never re-issued and
rejected with `Unauthorized` even though the new session was valid.

Return the replay verdict the `reauth_required` branch already returns.
Both replay paths stay one-shot (`ctx.done.add('reauth')`,
`spec._replayed`), and the auth gate rejects before the route handler
runs, so a replay has no side effects.

Closes #3953

* fix(puter-js): sign in once when a replayed XHR is refused again

handle_resp ran the reauth flow on the replay's own 401, so a
token_auth_failed that survived the replay reset the fresh token and
opened a second sign-in before rejecting. Treat a replay's 401 as final,
as the 403 verification-gate branch already does.

---------

Co-authored-by: Daniel Salazar <daniel.salazar@puter.com>
2026-10-23 00:07:56 -07:00
Daniel Salazar 4729d733bb feat(aws): DynamoDB, Polly and Textract can use the default credential chain (#4307)
`useCredentialChain: true` in `dynamo.aws`, `providers['aws-polly']` or
`providers['aws-textract']` takes credentials from the default AWS chain
instead of static keys, as `s3.s3Config` already does. One provider is shared
and refreshes temporary credentials itself.
2026-10-22 21:31:23 -07:00
Nariman Jelveh 26d843778e feat(dashboard): account dialogs as dashboard modals instead of windows (#4305)
Maintain Release Merge PR / update-release-pr (push) Canceled after 0s
Backend Tests / changes (push) Canceled after 0s
Backend Tests / typecheck (push) Canceled after 0s
Backend Tests / test shard 1/4 (push) Canceled after 0s
Backend Tests / test shard 2/4 (push) Canceled after 0s
Backend Tests / test shard 3/4 (push) Canceled after 0s
Backend Tests / test shard 4/4 (push) Canceled after 0s
Backend Tests / test (main) (push) Canceled after 0s
Backend Tests / coverage (push) Canceled after 0s
Notify HeyPuter / notify (push) Canceled after 0s
release-please / release-please (push) Canceled after 0s
* feat(dashboard): account dialogs as dashboard modals instead of windows

Edit profile, change username, change password, change email, create API
token, and delete account in the Account tab (and change password in the
Security tab) now open as dashboard overlay cards, like the share,
properties, and confirm dialogs, instead of desktop UIWindows. They are
centered cards on desktop and tablet and bottom sheets on phones.

- dashboardOverlay.js: the overlay shell UIDashboardDialog already had
  (reveal, Esc/backdrop/close dismissal, focus trap, focus return), pulled
  out so the new form dialog shares it. It also pins the overlay to the
  visual viewport so iOS's keyboard can't cover a sheet's fields, and
  leaves Esc to a modal opened on top of it.
- UIDashboardFormDialog.js: labelled fields, password show/hide, an
  aria-live status line that marks and focuses the offending field, a busy
  submit button, and a done state.
- postUserProtected.js: the cookie-retry / provider re-sign-in / reauth
  flow the four account windows each carried, in one place.
- Deleting an account is one dialog now (warning plus confirmation) rather
  than two stacked windows.
- Touch: 44px controls, 16px inputs (no iOS focus zoom), no autofocus
  that pops the keyboard mid-animation, form buttons side by side on
  phones, safe-area padding dropped while the keyboard is up.
- The replaced windows had no other callers and are removed with their
  tests, which are ported to the new modules.

* fix(dashboard): a double-click that opens a dialog no longer dismisses it

The second press of the double-click lands on the freshly mounted backdrop
and closed the dialog straight away. Backdrop presses with a click count
above one no longer count toward dismissal.

* fix(dashboard): a failed form submit keeps focus in the dialog

Locking the fields disabled the focused control, which drops focus to the
page, so after an error Enter no longer retried and screen readers lost
their place. The control that had focus gets it back once the fields
unlock, unless the handler moved focus elsewhere in the dialog.

* fix(dashboard): a form error keeps the field it names in view

The status line scrolled the dialog body to the bottom, which on a short
screen (a phone with its keyboard up) left the field being focused and
marked invalid scrolled off the top. The body now scrolls back up just
far enough to show that field.

* fix(gui): a blocked re-sign-in popup fails instead of waiting forever

openRevalidatePopup polled a popup that was never opened, so when the
browser blocked it the account dialog stayed busy indefinitely. It now
rejects straight away and the dialog says the sign-in didn't finish.

* fix(dashboard): password show/hide reads as one action, not a pressed toggle

The button flipped its label between Show and Hide password and also set
aria-pressed, so assistive tech announced "Hide password, pressed" while
the password was showing. It keeps the action label and drops aria-pressed.

* fix(dashboard): screen readers hear a form dialog's success message

The done state arrives as a new status region that already holds its text,
which screen readers don't announce, so after a change succeeded they only
heard "Done, button". The Done button that takes focus is now described by
the message.

* fix(dashboard): requesting an email change no longer sets the cached email

The server only stages the new address until the emailed link is
followed, but the dialog wrote it into window.user.email straight away.
That cached a wrong address for the session and kept refresh_user_data from
updating the Account tab once the change was confirmed, since the two
already matched.

* fix(dashboard): form dialog labels drop the global label shadow

style.css's bare `label` rule gave the field labels a white text-shadow,
which ghosted them on the dark theme, and an extra 3px under each label.

* fix(dashboard): dialog inputs keep a 1px border when focused

style.css's global input :focus rule still set a 2px border width, so a
dialog field's text shifted by a pixel each time it took focus. The focus
ring is the box-shadow; the border stays 1px.

* fix(dashboard): phone dialog inputs stay 16px instead of jumping on focus

On phones style.css's .device-phone input rule outranked the dialog's
16px size at rest, so fields drew at 17px and shrank to 16px the moment
they took focus.

* fix(dashboard): temporary accounts can delete themselves again

The server reports oidc_only for every passwordless account, temporary
ones included, so the shared user-protected helper sent a temporary
account into the linked-provider sign-in, which has no URL for it, and the
deletion never went out. Temporary accounts post directly, as the route
admits them without credentials.
2026-10-22 17:13:50 -07:00