import * as appstate from '../../appstate.js'; import { viewHostCss } from '../shared/css.js'; import { DeesElement, css, cssManager, customElement, html, state, type TemplateResult, } from '@design.estate/dees-element'; @customElement('ops-view-users') export class OpsViewUsers extends DeesElement { @state() accessor usersState: appstate.IUsersState = { users: [], isLoading: false, error: null, lastUpdated: 0, }; @state() accessor loginState: appstate.ILoginState = { identity: null, isLoggedIn: false, }; constructor() { super(); const usersSub = appstate.usersStatePart .select((s) => s) .subscribe((usersState) => { this.usersState = usersState; }); this.rxSubscriptions.push(usersSub); const loginSub = appstate.loginStatePart .select((s) => s) .subscribe((loginState) => { this.loginState = loginState; // Re-fetch users when user logs in (fixes race condition where // the view is created before authentication completes) if (loginState.isLoggedIn) { appstate.usersStatePart.dispatchAction(appstate.fetchUsersAction, null); } }); this.rxSubscriptions.push(loginSub); } public static styles = [ cssManager.defaultStyles, viewHostCss, css` .usersContainer { display: flex; flex-direction: column; gap: 24px; } .roleBadge { display: inline-flex; align-items: center; padding: 3px 10px; border-radius: 12px; font-size: 12px; font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase; } .roleBadge.admin { background: ${cssManager.bdTheme('#fef3c7', '#451a03')}; color: ${cssManager.bdTheme('#92400e', '#fbbf24')}; } .roleBadge.user { background: ${cssManager.bdTheme('#e0f2fe', '#0c4a6e')}; color: ${cssManager.bdTheme('#075985', '#7dd3fc')}; } .sessionBadge { display: inline-flex; align-items: center; padding: 3px 10px; border-radius: 12px; font-size: 12px; font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase; background: ${cssManager.bdTheme('#dcfce7', '#14532d')}; color: ${cssManager.bdTheme('#166534', '#4ade80')}; } .userIdCell { font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace; font-size: 11px; color: ${cssManager.bdTheme('#6b7280', '#9ca3af')}; } `, ]; public render(): TemplateResult { const { users } = this.usersState; const currentUserId = this.loginState.identity?.userId; return html` Users
({ ID: html`${user.id}`, Username: user.username, Role: this.renderRoleBadge(user.role), Session: user.id === currentUserId ? html`current` : '', })} >
`; } private renderRoleBadge(role: string): TemplateResult { const cls = role === 'admin' ? 'admin' : 'user'; return html`${role}`; } async firstUpdated() { if (this.loginState.isLoggedIn) { await appstate.usersStatePart.dispatchAction(appstate.fetchUsersAction, null); } } }