Skip to content

feat(Selector): let an option say why it is disabled - #107

Merged
nowgnuesLee merged 2 commits into
mainfrom
feat/gh-106-option-disabled-reason
Oct 29, 2026
Merged

nowgnuesLee merged 2 commits into
mainfrom
feat/gh-106-option-disabled-reason

Conversation

@agatha197

@agatha197 agatha197 commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Resolves #106

Summary

  • Selector / MultiSelector (the Form.Item wrappers): option data take disabled: boolean | { reason: string }. The wrapper hands Astryx a boolean and, when any option carries a reason, wraps the row (the caller's renderOption, else Astryx's default row) with a glyph at its end. SelectorOptionData, SelectorSection, SelectorOptionType and the MultiSelector* equivalents are widened and exported from the wrappers; renderOption / renderValue still receive a boolean disabled.
  • PagedSelector: PagedSelectorOption.isDisabled takes the same union; the glyph goes before the row's endContent.
  • The glyph is ui-common's IconWithTooltip (not focusable, hover tooltip) with lucide's CircleAlert; the reason is its tooltip and its accessible name. It sets pointer-events: auto, since a disabled Astryx Selector item turns pointer events off. Shared internal piece: src/formControls/optionDisabledReason.tsx, not exported.
  • A bare true still disables silently. A reason on an enabled option cannot be expressed.
  • Stories (Disabled Option Reason on Selector and MultiSelector; PagedSelector's sample list), CLI docs (PagedSelector.doc.mjs, wrapper docs regenerated), src/index.ts regenerated, CHANGELOG under [Unreleased] → Added.

Why

backend.ai-webui disabled options in about ten pickers without saying why, and the few that did wrapped each row in a Tooltip per call site (which a disabled Selector item never shows) with a parallel disabledReason field. backend.ai-webui#10496 built the glyph BUI-side as BAIDisabledOptionReason; it is product-neutral, so it moves here and webui keeps only the mapping. The row-end glyph was chosen over a reason line under the label because many options often share one reason (folders without mount permission), and a line per row lengthens the list with the same sentence.

Test plan

  • pnpm run verify (typecheck, lint, format, boundary, tests: 2170 passed), theme:check, build, check:pack, check:integration all pass locally.
  • New tests: src/formControls/optionDisabledReason.test.tsx (Selector and MultiSelector: the option is aria-disabled, the glyph is named by the reason, a bare true has no glyph, clicking does not select, the caller's renderOption is kept; the split helper on sections and dividers) and a PagedSelector case.
  • Storybook: Form Controls/Selector → Disabled Option Reason, Form Controls/MultiSelector → Disabled Option Reason, Components/PagedSelector (every other 17th item): hover the glyph on a dimmed row.

`Selector` and `MultiSelector` option data take `disabled: boolean |
{ reason: string }`, and `PagedSelectorOption` takes the same union in
`isDisabled`. The object form disables the option and draws a glyph at the
end of its row whose tooltip, and accessible name, is the reason; the row
keeps its height. The wrappers hand Astryx a boolean and add the glyph after
the caller's `renderOption` or the default row.

Resolves #106

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR

GitHub Pages may take up to a minute to hydrate after the deploy.

🧩 Changed Components

Component Changed Stories Open
PagedSelector source + stories 7 Storybook ↗
9 other changed file(s) in src/
  • src/formControls/MultiSelector/MultiSelector.stories.tsx
  • src/formControls/MultiSelector/MultiSelector.tsx
  • src/formControls/MultiSelector/index.ts
  • src/formControls/Selector/Selector.stories.tsx
  • src/formControls/Selector/Selector.tsx
  • src/formControls/Selector/index.ts
  • src/formControls/optionDisabledReason.css
  • src/formControls/optionDisabledReason.tsx
  • src/index.ts

📦 Bundle Size

Group Gzip Δ Gzip vs base
assets 15.4 kB +0.3 kB
formControls 15.3 kB +1.0 kB
components/PagedSelector 4.8 kB +0.1 kB

Total gzip (JS + CSS): 198.4 kB (+1.3 kB vs origin/main)


Generated by the PR Preview workflow for da89221 · Storybook · CI run

github-actions Bot added a commit that referenced this pull request Oct 27, 2026
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Preview published under the pr-107 dist-tag (npmjs): 0.2.0-alpha.20.pr-107-20261027131406-da8922143

pnpm add @lablup/ui-common@0.2.0-alpha.20.pr-107-20261027131406-da8922143
pnpm add -D @lablup/ui-common-cli@0.2.0-alpha.20.pr-107-20261027131406-da8922143

In backend.ai-webui: pnpm run ui-common:pin pr-107. A consumer PR pinned to a preview cannot merge; repin to canary after this PR merges.

@agatha197
agatha197 marked this pull request as draft October 27, 2026 08:45
agatha197 added a commit to lablup/backend.ai-webui that referenced this pull request Oct 27, 2026
ui-common now takes `disabled: { reason }` on Selector / MultiSelector
options and `isDisabled: { reason }` on PagedSelector options, and draws the
row-end glyph itself (lablup/ui-common#107). BAISelect and BAIComplexSelect
pass the union through, the folder mount-permission picker and
ResourcePresetSelect set it on their options, and BUI's
BAIDisabledOptionReason is removed. Pinned to the ui-common#107 preview.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@agatha197

Copy link
Copy Markdown
Contributor Author

Consumer: lablup/backend.ai-webui#10496 (pinned to this PR's preview), with lablup/backend.ai-webui#10279 stacked on it.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@agatha197

Copy link
Copy Markdown
Contributor Author

Ready-gate agent review (Opus) - blocking issues only

No blocking issues found at a4aebecb8.

Copilot: unavailable (insufficient remaining quota) - this review gated the PR alone.

@agatha197
agatha197 marked this pull request as ready for review October 27, 2026 09:12
@agatha197
agatha197 requested a review from nowgnuesLee October 27, 2026 09:12
…edReason

It takes options, renderOption and renderDefault and returns the options and
renderOption Astryx gets, so Selector and MultiSelector each make one call
instead of splitting the reasons and wrapping renderOption themselves.
github-actions Bot added a commit that referenced this pull request Oct 27, 2026
agatha197 added a commit to lablup/backend.ai-webui that referenced this pull request Oct 27, 2026

@nowgnuesLee nowgnuesLee left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nowgnuesLee
nowgnuesLee merged commit 1feb007 into main Oct 29, 2026
10 checks passed
agatha197 added a commit to lablup/backend.ai-webui that referenced this pull request Oct 30, 2026
Moves @lablup/ui-common and @lablup/ui-common-cli to
0.2.0-alpha.20.canary-20261029050354-1feb007cd, which carries
lablup/ui-common#107 (needed by #10496). No codemods run between the two
canaries; the AGENTS.md ui-common blocks are regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was previously deployed

1 inactive deployment
release — da892214 Deployed Oct 27, 2026 by agatha197 via npmjs #92
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Options can say why they are disabled

3 participants