diff --git a/webapp/CLAUDE.md b/webapp/CLAUDE.md index 436d40d..d66654b 100644 --- a/webapp/CLAUDE.md +++ b/webapp/CLAUDE.md @@ -26,7 +26,7 @@ The app follows a feature-based module organization with standalone components: ### Key Patterns -**Authentication**: Uses a custom `SCN` token scheme. Credentials (user_id and admin_key) are stored in sessionStorage and attached via `authInterceptor`. The `authGuard` protects all routes except `/login`. +**Authentication**: Uses a custom `SCN` token scheme. Credentials (user_id and admin_key) are stored in localStorage and attached via `authInterceptor`. The `authGuard` protects all routes except `/login`. **API Communication**: All API calls go through `ApiService` (`src/app/core/services/api.service.ts`). The base URL is configured in `src/environments/environment.ts`. diff --git a/webapp/src/app/core/models/channel.model.ts b/webapp/src/app/core/models/channel.model.ts index 5517884..23b00a1 100644 --- a/webapp/src/app/core/models/channel.model.ts +++ b/webapp/src/app/core/models/channel.model.ts @@ -7,7 +7,6 @@ export interface Channel { display_name: string; description_name: string | null; subscribe_key?: string; - send_key?: string; timestamp_created: string; timestamp_lastsent: string | null; messages_sent: number; @@ -34,8 +33,7 @@ export interface CreateChannelRequest { export interface UpdateChannelRequest { display_name?: string; description_name?: string; - subscribe_key?: string; - send_key?: string; + subscribe_key?: boolean; // RefreshSubscribeKey } export interface ChannelListResponse { diff --git a/webapp/src/app/core/services/auth.service.ts b/webapp/src/app/core/services/auth.service.ts index 8b8b362..ea80279 100644 --- a/webapp/src/app/core/services/auth.service.ts +++ b/webapp/src/app/core/services/auth.service.ts @@ -17,8 +17,8 @@ export class AuthService { } private loadFromStorage(): void { - const userId = sessionStorage.getItem(USER_ID_KEY); - const adminKey = sessionStorage.getItem(ADMIN_KEY_KEY); + const userId = localStorage.getItem(USER_ID_KEY); + const adminKey = localStorage.getItem(ADMIN_KEY_KEY); if (userId && adminKey) { this.userId.set(userId); this.adminKey.set(adminKey); @@ -26,15 +26,15 @@ export class AuthService { } login(userId: string, adminKey: string): void { - sessionStorage.setItem(USER_ID_KEY, userId); - sessionStorage.setItem(ADMIN_KEY_KEY, adminKey); + localStorage.setItem(USER_ID_KEY, userId); + localStorage.setItem(ADMIN_KEY_KEY, adminKey); this.userId.set(userId); this.adminKey.set(adminKey); } logout(): void { - sessionStorage.removeItem(USER_ID_KEY); - sessionStorage.removeItem(ADMIN_KEY_KEY); + localStorage.removeItem(USER_ID_KEY); + localStorage.removeItem(ADMIN_KEY_KEY); this.userId.set(null); this.adminKey.set(null); } diff --git a/webapp/src/app/core/services/settings.service.ts b/webapp/src/app/core/services/settings.service.ts index ec53afd..83f92f2 100644 --- a/webapp/src/app/core/services/settings.service.ts +++ b/webapp/src/app/core/services/settings.service.ts @@ -16,9 +16,7 @@ export class SettingsService { private loadFromStorage(): void { const stored = localStorage.getItem(EXPERT_MODE_KEY); - if (stored === 'true') { - this._expertMode.set(true); - } + this._expertMode.set(stored === 'true'); } setExpertMode(enabled: boolean): void { diff --git a/webapp/src/app/features/auth/login/login.component.html b/webapp/src/app/features/auth/login/login.component.html index 6f5a3c0..8e794aa 100644 --- a/webapp/src/app/features/auth/login/login.component.html +++ b/webapp/src/app/features/auth/login/login.component.html @@ -14,59 +14,37 @@ > } -
- - User ID - - - - - - +
+ + - - Admin Key - - - - - - - - - + + +
- - - -
+ @@ -110,42 +109,6 @@ } - @if (isOwner() && channel()!.send_key) { - -
- - - - - - -
- -
-
-
- } @@ -238,18 +201,20 @@ } @else { - + @if (expertMode()) { + + } } diff --git a/webapp/src/app/features/channels/channel-detail/channel-detail.component.scss b/webapp/src/app/features/channels/channel-detail/channel-detail.component.scss index 5b399c3..815c35f 100644 --- a/webapp/src/app/features/channels/channel-detail/channel-detail.component.scss +++ b/webapp/src/app/features/channels/channel-detail/channel-detail.component.scss @@ -12,7 +12,7 @@ .key-field { display: flex; - flex-direction: column; + flex-direction: row; gap: 8px; } diff --git a/webapp/src/app/features/channels/channel-detail/channel-detail.component.ts b/webapp/src/app/features/channels/channel-detail/channel-detail.component.ts index a0a9606..40e9551 100644 --- a/webapp/src/app/features/channels/channel-detail/channel-detail.component.ts +++ b/webapp/src/app/features/channels/channel-detail/channel-detail.component.ts @@ -280,7 +280,7 @@ export class ChannelDetailComponent implements OnInit { if (!channel || !userId) return; this.apiService.updateChannel(userId, channel.channel_id, { - subscribe_key: 'true' + subscribe_key: true }).subscribe({ next: (updated) => { this.channel.set(updated); @@ -289,21 +289,6 @@ export class ChannelDetailComponent implements OnInit { }); } - regenerateSendKey(): void { - const channel = this.channel(); - const userId = this.authService.getUserId(); - if (!channel || !userId) return; - - this.apiService.updateChannel(userId, channel.channel_id, { - send_key: 'true' - }).subscribe({ - next: (updated) => { - this.channel.set(updated); - this.notification.success('Send key regenerated'); - } - }); - } - getSubscriptionStatus(): { label: string; color: string } { const channel = this.channel(); if (!channel) return { label: 'Unknown', color: 'default' }; diff --git a/webapp/src/app/features/subscriptions/subscription-list/subscription-list.component.html b/webapp/src/app/features/subscriptions/subscription-list/subscription-list.component.html index b8dd074..183c1c6 100644 --- a/webapp/src/app/features/subscriptions/subscription-list/subscription-list.component.html +++ b/webapp/src/app/features/subscriptions/subscription-list/subscription-list.component.html @@ -161,18 +161,20 @@ } } - + @if (expertMode()) { + + } } diff --git a/webapp/src/app/features/subscriptions/subscription-list/subscription-list.component.ts b/webapp/src/app/features/subscriptions/subscription-list/subscription-list.component.ts index a49cf8e..f5b483e 100644 --- a/webapp/src/app/features/subscriptions/subscription-list/subscription-list.component.ts +++ b/webapp/src/app/features/subscriptions/subscription-list/subscription-list.component.ts @@ -18,6 +18,7 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination'; import { ApiService } from '../../../core/services/api.service'; import { AuthService } from '../../../core/services/auth.service'; import { NotificationService } from '../../../core/services/notification.service'; +import { SettingsService } from '../../../core/services/settings.service'; import { UserCacheService, ResolvedUser } from '../../../core/services/user-cache.service'; import { Subscription, SubscriptionFilter } from '../../../core/models'; import { RelativeTimePipe } from '../../../shared/pipes/relative-time.pipe'; @@ -67,8 +68,11 @@ export class SubscriptionListComponent implements OnInit { private apiService = inject(ApiService); private authService = inject(AuthService); private notification = inject(NotificationService); + private settingsService = inject(SettingsService); private userCacheService = inject(UserCacheService); + expertMode = this.settingsService.expertMode; + subscriptions = signal([]); userNames = signal>(new Map()); loading = signal(false);