Skip to content

[ENHANCEMENT] Refactor Frontend Modal Architecture for Notification Channels #2342

@jcscottiii

Description

@jcscottiii

Problem

Currently, the frontend manages state using independent boolean flags and loose ID properties. This makes it difficult to track valid UI states and forces unsafe as casting.

Proposed Strategy:

1. Unified Modal State (State Machine)

Bind the Mode and Data into a single discriminated union property.

type UIState = 
  | { mode: 'idle' }
  | { mode: 'delete'; channel: NotificationChannelResponse }
  | { mode: 'edit';   channel: NotificationChannelResponse }
  | { mode: 'create' };

@state() private _uiState: UIState = { mode: 'idle' };

// Transitioning is atomic and type-safe!
private _handleDelete(channel: NotificationChannelResponse) {
  this._uiState = { mode: 'delete', channel };
}

2. Registry Inversion (Direct Injection)

Move type-narrowing to the Registry. This allows forms to be "Dumb UI" components that simply receive the data they need.

// channel-config-registry.ts
case 'webhook': {
  // Narrowing happens ONCE here
  const config = channel?.config?.type === 'webhook' ? channel.config : undefined;
  return html`
    <webhook-config-form
      .channelName=${channel?.name ?? ''}
      .config=${config}
    ></webhook-config-form>`;
}

3. Clean Switch-based Rendering

Use a helper method to map state to templates. TypeScript automatically narrows this._uiState in each case.

render() {
  return html`${this.renderModals()}`;
}

private renderModals() {
  switch (this._uiState.mode) {
    case 'delete':
      // Narrowed: this._uiState.channel is guaranteed to exist
      return html`
        <sl-dialog open label="Delete ${this._uiState.channel.type} Channel">
          Are you sure? This cannot be undone.
          <sl-button slot="footer" @click=${this._confirmDelete}>Delete</sl-button>
        </sl-dialog>`;
    case 'edit':
      return html`<edit-form .channel=${this._uiState.channel}></edit-form>`;
    default:
      return nothing;
  }
}

Expected Outcomes

  • Zero Casting: Eliminates as unknown as WebhookConfig.
  • Illegal State Prevention: You can't be in 'delete' mode without a channel.
  • Improved Testability: Deterministic mapping from _uiState value to DOM state.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions