qwen-code/packages/web-shell/client/components/dialogs/AddWorkspaceDialog.module.css
Shaojin Wen 732d85df39
fix(web-shell): correct Add Workspace dialog theming and multi-workspace session rows (#6705)
* fix(web-shell): theme and lay out the Add Workspace dialog correctly

The dialog's stylesheet referenced CSS variables that are defined nowhere
(--text-secondary, --input-bg, --border-color, --accent-color, --hover-bg), so
they fell back to hardcoded dark values — in light mode the input rendered
dark-on-light with a purple focus ring, inconsistent with every other dialog. It
also reused a two-column form-row grid meant for label/value pairs, which cramped
the path input into a narrow column.

Rebuild the dialog on the shared dialog primitives (themed .dialog-form input,
dialog-inline-button, dialog-primary-button) so it tracks the active theme in
both light and dark and gives the path a full-width input. Add a proactive
absolute-path hint, an accessible inline error (role="alert", aria-describedby,
aria-invalid) that clears as you type, and a localized "Adding…" state. Keep the
hint and error as siblings of the input rather than nested in the label, so their
text stays out of the input's accessible name.

* fix(web-shell): render full session rows for every workspace in the sidebar

Registering a second workspace switched the sidebar to the multi-workspace view,
which rendered each workspace's sessions with a bespoke minimal row: a smaller
font (12px vs 14px) and no per-session actions. The rich single-workspace row
(hover actions, current-session highlight, inline rename, running/unread state)
was hidden entirely, so even the primary workspace's list degraded.

Render sessions through the sidebar's shared renderSessionRow so every workspace
matches the single-workspace list. Gate the mutation actions to the primary
(daemon-bound) workspace: the daemon can't resolve another workspace's session
for pin/archive/export/delete (they 404 or silently no-op), so non-primary rows
are read-only — they keep click-to-load and the font/highlight but drop the
action buttons. Session mutations now also bump the per-workspace poll token so
those lists refresh promptly.

* refactor(web-shell): move Add Workspace footer padding into a CSS class

The footer sits inside .dialog-form (which already pads its sides) and reuses the
shared dialog-footer-actions primitive, doubling the horizontal padding; the
override lived as an inline style, hiding the deviation from the stylesheet. Move
it to a local .footer class applied alongside the shared class. A doubled
selector keeps it winning over the primitive regardless of stylesheet order.

* test(web-shell): cover workspace read-only gating and Add Workspace dialog

Add tests for the behaviors introduced by the sidebar and dialog fixes:
- non-primary workspace rows render the session but expose no action buttons
  (the daemon, bound to the primary workspace, can't service their mutations),
  while the primary workspace keeps its full actions;
- a session mutation re-polls the per-workspace list instead of waiting for the
  10s interval;
- the Add Workspace dialog's absolute-path validation, accessible error wiring
  (role="alert", aria-describedby/aria-invalid), error-clear-on-edit, trimmed
  submit, and onAdd-failure handling.

* refactor(web-shell): centralize the workspace reload-token bump in a helper

Per review: the setWorkspaceSessionsReloadToken bump was repeated verbatim across
the session-mutation handlers. Extract a stable bumpWorkspaceReload() helper and
route every site through it, including assignSessionGroup and assignSessionColor
— the two organization mutations that were missing the bump — so assigning a
group or color now also re-polls the per-workspace session lists instead of
waiting for the 10s interval.

* test(web-shell): cover Windows paths and non-Error rejections in Add Workspace dialog

Per review: add the two untested handleSubmit branches — a Windows-style absolute
path accepted by the drive-letter regex, and a non-Error onAdd rejection falling
back to the generic error message.

* fix(web-shell): gate inline rename on readOnly and refresh on group-create assign

Per review: the readOnly option hid the hover action buttons but not the inline
rename — onDoubleClick and the isEditing branch still fired on read-only rows, so
a session shown in multiple workspaces could render an editable rename input on
its non-primary (read-only) copy. Gate both on !readOnly. Also add the missing
bumpWorkspaceReload() to saveGroupEditor's create-with-target-session path so
that organization mutation refreshes the per-workspace lists like the others.

* test(web-shell): cover readOnly rename gating and dialog submitting state

Per review: assert the read-only (non-primary) row does not open the inline
rename form when the shared session is renamed from the primary row, and that the
Add Workspace dialog shows the localized "Adding…" label with disabled controls
while onAdd is pending.
2026-07-11 11:19:32 +00:00

37 lines
1.2 KiB
CSS

/* Field styling (label + input + buttons) comes from the shared dialog
primitives (`.dialog-form`, `.dialog-inline-button`, `.dialog-primary-button`)
so the dialog tracks the active theme. Only the field grouping and the helper
text / error line are local. */
/* Group the label, input, hint, and error tightly. They are siblings (not a
label wrapping the input) so the hint/error text stays out of the input's
accessible name — they're associated as descriptions via aria-describedby.
The shared `.dialog-form` gap is larger and meant for separating whole
fields. */
.field {
display: flex;
flex-direction: column;
gap: 4px;
}
.hint {
color: var(--muted-foreground);
font-size: 12px;
line-height: 1.4;
}
/* Applied alongside the shared `dialog-footer-actions`. That primitive adds side
padding for standalone (picker) footers; here the footer lives inside
`.dialog-form`, which already pads its sides, so drop the horizontal padding to
line the buttons up with the input. The selector is doubled so it outranks the
primitive regardless of stylesheet order. */
.footer.footer {
padding-left: 0;
padding-right: 0;
}
.error {
color: var(--error-color);
font-size: 12px;
line-height: 1.4;
}