-
Notifications
You must be signed in to change notification settings - Fork 14
feat(alert-subsystem-counter): add alert subsystem counter component #1045
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ludvigovrevik
wants to merge
1
commit into
develop
Choose a base branch
from
feat/alert-subsystem-counter
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file added
BIN
+7.03 KB
...lert-subsystem-counter/alert-subsystem-counter.stories.ts/abbreviation-auto.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+7.11 KB
...ystem-counter/alert-subsystem-counter.stories.ts/abbreviation-vertical-auto.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+7 KB
...nts/alert-subsystem-counter/alert-subsystem-counter.stories.ts/default-auto.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+6.4 KB
...s/alert-subsystem-counter/alert-subsystem-counter.stories.ts/no-alerts-auto.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+6.97 KB
...ts/alert-subsystem-counter/alert-subsystem-counter.stories.ts/vertical-auto.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+6.36 KB
...ubsystem-counter/alert-subsystem-counter.stories.ts/vertical-no-alerts-auto.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+6.4 KB
...lert-subsystem-counter/alert-subsystem-counter.stories.ts/without-icon-auto.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions
73
...enbridge-webcomponents/src/components/alert-subsystem-counter/alert-subsystem-counter.css
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| :host { | ||
| display: block; | ||
| } | ||
|
|
||
| .frame { | ||
| box-sizing: border-box; | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 8px; | ||
| padding: 8px; | ||
| border-radius: 6px; | ||
| background: var(--container-section-color); | ||
| border: 1px solid var(--border-outline-color); | ||
| } | ||
|
|
||
| .frame.orientation-vertical { | ||
| flex-direction: column; | ||
| align-items: stretch; | ||
| } | ||
|
|
||
| .leading-container { | ||
| display: flex; | ||
| flex: 1 0 0; | ||
| align-items: center; | ||
| gap: 4px; | ||
| min-width: 0; | ||
| } | ||
|
|
||
| .icon { | ||
| flex-shrink: 0; | ||
| width: 24px; | ||
| height: 24px; | ||
| color: var(--on-indent-neutral-color); | ||
| } | ||
|
|
||
| .icon.no-icon { | ||
| display: none; | ||
| } | ||
|
|
||
| .label { | ||
| @mixin font-body; | ||
| flex: 1 0 0; | ||
| min-width: 0; | ||
| padding-left: 4px; | ||
| color: var(--element-inactive-color); | ||
| font-feature-settings: "ss04" 1; | ||
| overflow: hidden; | ||
| white-space: nowrap; | ||
| text-overflow: ellipsis; | ||
| } | ||
|
|
||
| .frame.has-alert .label { | ||
| @mixin font-body-active; | ||
| color: var(--on-indent-active-color); | ||
| } | ||
|
|
||
| .trailing-container { | ||
| display: flex; | ||
| flex-shrink: 0; | ||
| align-items: center; | ||
| gap: 4px; | ||
| } | ||
|
|
||
| .frame.orientation-horizontal .trailing-container { | ||
| justify-content: flex-end; | ||
| } | ||
|
|
||
| .empty { | ||
| @mixin font-label; | ||
| color: var(--element-inactive-color); | ||
| white-space: nowrap; | ||
| font-feature-settings: "ss04" 1; | ||
| } | ||
105 changes: 105 additions & 0 deletions
105
...e-webcomponents/src/components/alert-subsystem-counter/alert-subsystem-counter.stories.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| import type {Meta, StoryObj} from '@storybook/web-components-vite'; | ||
| import {html} from 'lit'; | ||
| import { | ||
| ObcAlertSubsystemCounter, | ||
| ObcAlertSubsystemCounterOrientation, | ||
| } from './alert-subsystem-counter.js'; | ||
| import './alert-subsystem-counter.js'; | ||
| import '../badge/badge.js'; | ||
| import '../../icons/icon-placeholder.js'; | ||
|
|
||
| const badges = html` | ||
| <obc-badge slot="badges" size="large" type="alarm" .number=${9}></obc-badge> | ||
| <obc-badge slot="badges" size="large" type="warning" .number=${4}></obc-badge> | ||
| <obc-badge slot="badges" size="large" type="caution" .number=${2}></obc-badge> | ||
| `; | ||
|
|
||
| const meta: Meta<typeof ObcAlertSubsystemCounter> = { | ||
| title: 'Application Components/Alerts/Alert Subsystem Counter', | ||
| tags: ['autodocs', '6.0'], | ||
| component: 'obc-alert-subsystem-counter', | ||
| args: { | ||
| label: 'Label', | ||
| orientation: ObcAlertSubsystemCounterOrientation.Horizontal, | ||
| hasAlert: true, | ||
| emptyText: 'No alerts', | ||
| }, | ||
| argTypes: { | ||
| orientation: { | ||
| control: {type: 'inline-radio'}, | ||
| options: Object.values(ObcAlertSubsystemCounterOrientation), | ||
| }, | ||
| hasAlert: {control: {type: 'boolean'}}, | ||
| label: {control: {type: 'text'}}, | ||
| emptyText: {control: {type: 'text'}}, | ||
| }, | ||
| render: (args) => | ||
| html`<div style="width:191px"> | ||
| <obc-alert-subsystem-counter | ||
| .label=${args.label} | ||
| .orientation=${args.orientation} | ||
| .hasAlert=${args.hasAlert} | ||
| .emptyText=${args.emptyText} | ||
| > | ||
| <obi-placeholder slot="icon"></obi-placeholder> | ||
| ${badges} | ||
| </obc-alert-subsystem-counter> | ||
| </div>`, | ||
| } satisfies Meta<ObcAlertSubsystemCounter>; | ||
|
|
||
| export default meta; | ||
| type Story = StoryObj<ObcAlertSubsystemCounter>; | ||
|
|
||
| export const Default: Story = {}; | ||
|
|
||
| export const Abbreviation: Story = { | ||
| args: {label: 'ABC'}, | ||
| }; | ||
|
|
||
| export const NoAlerts: Story = { | ||
| args: {hasAlert: false}, | ||
| }; | ||
|
|
||
| export const Vertical: Story = { | ||
| args: {orientation: ObcAlertSubsystemCounterOrientation.Vertical}, | ||
| }; | ||
|
|
||
| export const VerticalNoAlerts: Story = { | ||
| args: { | ||
| orientation: ObcAlertSubsystemCounterOrientation.Vertical, | ||
| hasAlert: false, | ||
| }, | ||
| }; | ||
|
|
||
| export const AbbreviationVertical: Story = { | ||
| args: { | ||
| label: 'ABC', | ||
| orientation: ObcAlertSubsystemCounterOrientation.Vertical, | ||
| }, | ||
| render: (args) => | ||
| html`<div style="width:fit-content"> | ||
| <obc-alert-subsystem-counter | ||
| .label=${args.label} | ||
| .orientation=${args.orientation} | ||
| .hasAlert=${args.hasAlert} | ||
| .emptyText=${args.emptyText} | ||
| > | ||
| <obi-placeholder slot="icon"></obi-placeholder> | ||
| ${badges} | ||
| </obc-alert-subsystem-counter> | ||
| </div>`, | ||
| }; | ||
|
|
||
| export const WithoutIcon: Story = { | ||
| render: (args) => | ||
| html`<div style="width:191px"> | ||
| <obc-alert-subsystem-counter | ||
| .label=${args.label} | ||
| .orientation=${args.orientation} | ||
| .hasAlert=${args.hasAlert} | ||
| .emptyText=${args.emptyText} | ||
| > | ||
| ${badges} | ||
| </obc-alert-subsystem-counter> | ||
| </div>`, | ||
| }; |
146 changes: 146 additions & 0 deletions
146
...penbridge-webcomponents/src/components/alert-subsystem-counter/alert-subsystem-counter.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| import {LitElement, html, unsafeCSS} from 'lit'; | ||
| import {property, state} from 'lit/decorators.js'; | ||
| import {classMap} from 'lit/directives/class-map.js'; | ||
| import componentStyle from './alert-subsystem-counter.css?inline'; | ||
| import {customElement} from '../../decorator.js'; | ||
|
|
||
| /** | ||
| * `ObcAlertSubsystemCounterOrientation` – Layout direction for the counter. | ||
| * | ||
| * - `horizontal`: Icon, label, and badges sit in a single row. | ||
| * - `vertical`: Badges (or empty text) sit on their own line below the label. | ||
| */ | ||
| export enum ObcAlertSubsystemCounterOrientation { | ||
| Horizontal = 'horizontal', | ||
| Vertical = 'vertical', | ||
| } | ||
|
|
||
| /** | ||
| * `<obc-alert-subsystem-counter>` – A framed summary of a subsystem's alert | ||
| * counts: a leading icon, a label, and a trailing set of slotted count badges. | ||
| * | ||
| * When there are no active alerts it shows a muted label and an empty-state | ||
| * message instead of the badges. The count badges themselves are supplied by | ||
| * the consumer as slotted `obc-badge` elements; this component provides only | ||
| * the frame, layout, label, and empty state. | ||
| * | ||
| * --- | ||
| * | ||
| * ### Features | ||
| * - **Orientation:** `horizontal` (single row) or `vertical` (badges on a line | ||
| * below the label). | ||
| * - **Alert state:** `hasAlert` toggles between an active (bold label, badges) | ||
| * and an inactive (muted label, empty text) presentation. | ||
| * - **Freeform label:** Pass a full title or an abbreviation — the label is | ||
| * plain text decided by the caller. | ||
| * - **Configurable empty text:** Customize the message shown when there are no | ||
| * alerts via `emptyText`. | ||
| * - **Optional leading icon:** Provide an icon through the `icon` slot; omit it | ||
| * and the leading box collapses with no empty gap. | ||
| * | ||
| * --- | ||
| * | ||
| * ### Usage Guidelines | ||
| * - Use this component to give an at-a-glance count of outstanding alerts for a | ||
| * single subsystem, grouped by severity. | ||
| * - Provide one slotted badge per severity in the `badges` slot, typically | ||
| * `<obc-badge size="large">` with a severity `type` and a `number`. | ||
| * - Set `hasAlert` to `false` to present the resolved/clear state; the badges | ||
| * are then hidden and `emptyText` is shown. | ||
| * - Choose `vertical` orientation in narrow containers where the badges do not | ||
| * fit beside the label. | ||
| * | ||
| * --- | ||
| * | ||
| * ### Slots | ||
| * | ||
| * | Slot Name | Renders When... | Purpose | | ||
| * |-----------|------------------------|----------------------------------------------------| | ||
| * | `icon` | The slot has content | Leading 24px icon (e.g. `<obi-placeholder>`). | | ||
| * | `badges` | `hasAlert` is true | Count badges, one per severity (`<obc-badge>`). | | ||
| * | ||
| * --- | ||
| * | ||
| * ### Example | ||
| * | ||
| * ```html | ||
| * <obc-alert-subsystem-counter label="Label" hasAlert> | ||
| * <obi-placeholder slot="icon"></obi-placeholder> | ||
| * <obc-badge slot="badges" size="large" type="alarm" .number=${9}></obc-badge> | ||
| * <obc-badge slot="badges" size="large" type="warning" .number=${4}></obc-badge> | ||
| * <obc-badge slot="badges" size="large" type="caution" .number=${2}></obc-badge> | ||
| * </obc-alert-subsystem-counter> | ||
| * ``` | ||
| * | ||
| * @slot icon - Optional leading 24px icon. | ||
| * @slot badges - Count badges shown when `hasAlert` is true. | ||
| */ | ||
| @customElement('obc-alert-subsystem-counter') | ||
| export class ObcAlertSubsystemCounter extends LitElement { | ||
| /** | ||
| * The subsystem label. Pass a full title or an abbreviation as plain text. | ||
| */ | ||
| @property({type: String}) label = ''; | ||
|
|
||
| /** | ||
| * Layout direction. | ||
| * | ||
| * - `horizontal` (default): icon, label, and badges in one row. | ||
| * - `vertical`: badges (or empty text) on a line below the label. | ||
| */ | ||
| @property({type: String}) orientation: ObcAlertSubsystemCounterOrientation = | ||
| ObcAlertSubsystemCounterOrientation.Horizontal; | ||
|
|
||
| /** | ||
| * Whether the subsystem has active alerts. | ||
| * | ||
| * When `true`, the label is shown active (bold) and the `badges` slot is | ||
| * rendered. When `false`, the label is muted and `emptyText` is shown | ||
| * instead of the badges. | ||
| */ | ||
| @property({type: Boolean}) hasAlert = false; | ||
|
|
||
| /** | ||
| * Text shown in the trailing area when `hasAlert` is `false`. | ||
| */ | ||
| @property({type: String}) emptyText = 'No alerts'; | ||
|
|
||
| @state() private hasIcon = false; | ||
|
|
||
| private handleIconSlotChange(e: Event) { | ||
| const slot = e.target as HTMLSlotElement; | ||
| this.hasIcon = slot.assignedNodes({flatten: true}).length > 0; | ||
| } | ||
|
|
||
| override render() { | ||
| return html` | ||
| <div | ||
| class=${classMap({ | ||
| frame: true, | ||
| ['orientation-' + this.orientation]: true, | ||
| 'has-alert': this.hasAlert, | ||
| })} | ||
| > | ||
| <div class="leading-container"> | ||
| <div class=${classMap({icon: true, 'no-icon': !this.hasIcon})}> | ||
| <slot name="icon" @slotchange=${this.handleIconSlotChange}></slot> | ||
| </div> | ||
| <div class="label">${this.label}</div> | ||
| </div> | ||
| <div class="trailing-container"> | ||
| ${this.hasAlert | ||
| ? html`<slot name="badges" class="badges"></slot>` | ||
| : html`<span class="empty">${this.emptyText}</span>`} | ||
| </div> | ||
| </div> | ||
| `; | ||
| } | ||
|
|
||
| static override styles = unsafeCSS(componentStyle); | ||
| } | ||
|
|
||
| declare global { | ||
| interface HTMLElementTagNameMap { | ||
| 'obc-alert-subsystem-counter': ObcAlertSubsystemCounter; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix Stylelint
declaration-empty-line-beforeviolations.Static analysis flags missing blank lines after
@mixincalls at lines 42, 54, and 70.🎨 Proposed fix
.label { `@mixin` font-body; + flex: 1 0 0; min-width: 0; padding-left: 4px; color: var(--element-inactive-color); font-feature-settings: "ss04" 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .frame.has-alert .label { `@mixin` font-body-active; + color: var(--on-indent-active-color); } .empty { `@mixin` font-label; + color: var(--element-inactive-color); white-space: nowrap; font-feature-settings: "ss04" 1; }Also applies to: 52-55, 68-73
🧰 Tools
🪛 Stylelint (17.14.0)
[error] 42-42: Expected empty line before declaration (declaration-empty-line-before)
(declaration-empty-line-before)
🤖 Prompt for AI Agents
Source: Linters/SAST tools