Simple Managment webapp [LLM]
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { Router, CanActivateFn } from '@angular/router';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
|
||||
export const authGuard: CanActivateFn = (route, state) => {
|
||||
const authService = inject(AuthService);
|
||||
const router = inject(Router);
|
||||
|
||||
if (authService.isAuthenticated()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
|
||||
return false;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import { HttpInterceptorFn } from '@angular/common/http';
|
||||
import { inject } from '@angular/core';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
|
||||
export const authInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
const authService = inject(AuthService);
|
||||
const authHeader = authService.getAuthHeader();
|
||||
|
||||
if (authHeader) {
|
||||
const clonedReq = req.clone({
|
||||
setHeaders: {
|
||||
Authorization: authHeader
|
||||
}
|
||||
});
|
||||
return next(clonedReq);
|
||||
}
|
||||
|
||||
return next(req);
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
|
||||
import { inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { catchError, throwError } from 'rxjs';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { NotificationService } from '../services/notification.service';
|
||||
import { isApiError } from '../models';
|
||||
|
||||
export const errorInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
const router = inject(Router);
|
||||
const authService = inject(AuthService);
|
||||
const notification = inject(NotificationService);
|
||||
|
||||
return next(req).pipe(
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
if (error.status === 401) {
|
||||
authService.logout();
|
||||
router.navigate(['/login']);
|
||||
notification.error('Session expired. Please login again.');
|
||||
} else if (error.status === 403) {
|
||||
notification.error('Access denied. Insufficient permissions.');
|
||||
} else if (error.status === 404) {
|
||||
notification.error('Resource not found.');
|
||||
} else if (error.status >= 500) {
|
||||
notification.error('Server error. Please try again later.');
|
||||
} else if (error.error && isApiError(error.error)) {
|
||||
notification.error(error.error.message);
|
||||
} else {
|
||||
notification.error('An unexpected error occurred.');
|
||||
}
|
||||
|
||||
return throwError(() => error);
|
||||
})
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
export interface ApiError {
|
||||
success: false;
|
||||
error: number;
|
||||
errhighlight: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export function isApiError(response: unknown): response is ApiError {
|
||||
return (
|
||||
typeof response === 'object' &&
|
||||
response !== null &&
|
||||
'success' in response &&
|
||||
(response as ApiError).success === false
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Subscription } from './subscription.model';
|
||||
|
||||
export interface Channel {
|
||||
channel_id: string;
|
||||
owner_user_id: string;
|
||||
internal_name: string;
|
||||
display_name: string;
|
||||
description_name: string | null;
|
||||
subscribe_key?: string;
|
||||
send_key?: string;
|
||||
timestamp_created: string;
|
||||
timestamp_lastsent: string | null;
|
||||
messages_sent: number;
|
||||
}
|
||||
|
||||
export interface ChannelWithSubscription extends Channel {
|
||||
subscription: Subscription | null;
|
||||
}
|
||||
|
||||
export interface ChannelPreview {
|
||||
channel_id: string;
|
||||
owner_user_id: string;
|
||||
internal_name: string;
|
||||
display_name: string;
|
||||
}
|
||||
|
||||
export type ChannelSelector = 'owned' | 'subscribed' | 'all' | 'subscribed_any' | 'all_any';
|
||||
|
||||
export interface CreateChannelRequest {
|
||||
name: string;
|
||||
subscribe?: boolean;
|
||||
}
|
||||
|
||||
export interface UpdateChannelRequest {
|
||||
display_name?: string;
|
||||
description_name?: string;
|
||||
subscribe_key?: string;
|
||||
send_key?: string;
|
||||
}
|
||||
|
||||
export interface ChannelListResponse {
|
||||
channels: ChannelWithSubscription[];
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
export type ClientType = 'ANDROID' | 'IOS' | 'LINUX' | 'MACOS' | 'WINDOWS';
|
||||
|
||||
export interface Client {
|
||||
client_id: string;
|
||||
user_id: string;
|
||||
type: ClientType;
|
||||
fcm_token: string;
|
||||
timestamp_created: string;
|
||||
agent_model: string;
|
||||
agent_version: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface ClientListResponse {
|
||||
clients: Client[];
|
||||
}
|
||||
|
||||
export function getClientTypeIcon(type: ClientType): string {
|
||||
switch (type) {
|
||||
case 'ANDROID':
|
||||
return 'android';
|
||||
case 'IOS':
|
||||
return 'apple';
|
||||
case 'MACOS':
|
||||
return 'apple';
|
||||
case 'WINDOWS':
|
||||
return 'windows';
|
||||
case 'LINUX':
|
||||
return 'desktop';
|
||||
default:
|
||||
return 'desktop';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export * from './user.model';
|
||||
export * from './message.model';
|
||||
export * from './channel.model';
|
||||
export * from './subscription.model';
|
||||
export * from './key-token.model';
|
||||
export * from './client.model';
|
||||
export * from './sender-name.model';
|
||||
export * from './api-response.model';
|
||||
@@ -0,0 +1,51 @@
|
||||
export interface KeyToken {
|
||||
keytoken_id: string;
|
||||
name: string;
|
||||
timestamp_created: string;
|
||||
timestamp_lastused: string | null;
|
||||
owner_user_id: string;
|
||||
all_channels: boolean;
|
||||
channels: string[];
|
||||
token?: string;
|
||||
permissions: string;
|
||||
messages_sent: number;
|
||||
}
|
||||
|
||||
export interface KeyTokenPreview {
|
||||
keytoken_id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type TokenPermission = 'A' | 'CR' | 'CS' | 'UR';
|
||||
|
||||
export interface CreateKeyRequest {
|
||||
name: string;
|
||||
permissions: string;
|
||||
all_channels?: boolean;
|
||||
channels?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateKeyRequest {
|
||||
name?: string;
|
||||
permissions?: string;
|
||||
all_channels?: boolean;
|
||||
channels?: string[];
|
||||
}
|
||||
|
||||
export interface KeyListResponse {
|
||||
keys: KeyToken[];
|
||||
}
|
||||
|
||||
export function parsePermissions(permissions: string): TokenPermission[] {
|
||||
if (!permissions) return [];
|
||||
return permissions.split(';').filter(p => p) as TokenPermission[];
|
||||
}
|
||||
|
||||
export function hasPermission(permissions: string, required: TokenPermission): boolean {
|
||||
const perms = parsePermissions(permissions);
|
||||
return perms.includes(required) || perms.includes('A');
|
||||
}
|
||||
|
||||
export function isAdminKey(key: KeyToken): boolean {
|
||||
return hasPermission(key.permissions, 'A');
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
export interface Message {
|
||||
message_id: string;
|
||||
sender_user_id: string;
|
||||
channel_internal_name: string;
|
||||
channel_owner_user_id: string;
|
||||
channel_id: string;
|
||||
sender_name: string | null;
|
||||
sender_ip: string;
|
||||
timestamp: string;
|
||||
title: string;
|
||||
content: string | null;
|
||||
priority: number;
|
||||
usr_message_id: string | null;
|
||||
used_key_id: string;
|
||||
trimmed: boolean;
|
||||
}
|
||||
|
||||
export interface MessageListParams {
|
||||
after?: string;
|
||||
before?: string;
|
||||
channel?: string;
|
||||
priority?: number;
|
||||
search?: string;
|
||||
sender?: string;
|
||||
subscription_status?: 'all' | 'confirmed' | 'unconfirmed';
|
||||
trimmed?: boolean;
|
||||
page_size?: number;
|
||||
next_page_token?: string;
|
||||
}
|
||||
|
||||
export interface MessageListResponse {
|
||||
messages: Message[];
|
||||
next_page_token: string;
|
||||
page_size: number;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface SenderNameStatistics {
|
||||
name: string;
|
||||
last_timestamp: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface SenderNameListResponse {
|
||||
senders: SenderNameStatistics[];
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
export interface Subscription {
|
||||
subscription_id: string;
|
||||
subscriber_user_id: string;
|
||||
channel_owner_user_id: string;
|
||||
channel_id: string;
|
||||
channel_internal_name: string;
|
||||
timestamp_created: string;
|
||||
confirmed: boolean;
|
||||
}
|
||||
|
||||
export interface SubscriptionFilter {
|
||||
direction?: 'outgoing' | 'incoming' | 'both';
|
||||
confirmation?: 'all' | 'confirmed' | 'unconfirmed';
|
||||
external?: 'all' | 'true' | 'false';
|
||||
subscriber_user_id?: string;
|
||||
channel_owner_user_id?: string;
|
||||
next_page_token?: string;
|
||||
page_size?: number;
|
||||
}
|
||||
|
||||
export interface CreateSubscriptionRequest {
|
||||
channel_id?: string;
|
||||
channel_owner_user_id?: string;
|
||||
channel_internal_name?: string;
|
||||
}
|
||||
|
||||
export interface ConfirmSubscriptionRequest {
|
||||
confirmed: boolean;
|
||||
}
|
||||
|
||||
export interface SubscriptionListResponse {
|
||||
subscriptions: Subscription[];
|
||||
next_page_token?: string;
|
||||
page_size?: number;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
export interface User {
|
||||
user_id: string;
|
||||
username: string | null;
|
||||
timestamp_created: string;
|
||||
timestamp_lastread: string | null;
|
||||
timestamp_lastsent: string | null;
|
||||
messages_sent: number;
|
||||
is_pro: boolean;
|
||||
quota_used: number;
|
||||
quota_used_day: string | null;
|
||||
}
|
||||
|
||||
export interface UserExtra {
|
||||
quota_remaining: number;
|
||||
quota_max: number;
|
||||
quota_used: number;
|
||||
default_channel: string;
|
||||
max_body_size: number;
|
||||
max_title_length: number;
|
||||
default_priority: number;
|
||||
max_channel_name_length: number;
|
||||
max_channel_description_length: number;
|
||||
max_sender_name_length: number;
|
||||
max_user_message_id_length: number;
|
||||
}
|
||||
|
||||
export interface UserWithExtra extends User, UserExtra {}
|
||||
|
||||
export interface UserPreview {
|
||||
user_id: string;
|
||||
username: string | null;
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import {
|
||||
User,
|
||||
UserWithExtra,
|
||||
Message,
|
||||
MessageListParams,
|
||||
MessageListResponse,
|
||||
Channel,
|
||||
ChannelWithSubscription,
|
||||
ChannelSelector,
|
||||
ChannelListResponse,
|
||||
CreateChannelRequest,
|
||||
UpdateChannelRequest,
|
||||
Subscription,
|
||||
SubscriptionFilter,
|
||||
SubscriptionListResponse,
|
||||
CreateSubscriptionRequest,
|
||||
ConfirmSubscriptionRequest,
|
||||
KeyToken,
|
||||
KeyListResponse,
|
||||
CreateKeyRequest,
|
||||
UpdateKeyRequest,
|
||||
Client,
|
||||
ClientListResponse,
|
||||
SenderNameStatistics,
|
||||
SenderNameListResponse,
|
||||
} from '../models';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ApiService {
|
||||
private http = inject(HttpClient);
|
||||
private baseUrl = environment.apiUrl;
|
||||
|
||||
// User endpoints
|
||||
getUser(userId: string): Observable<UserWithExtra> {
|
||||
return this.http.get<UserWithExtra>(`${this.baseUrl}/users/${userId}`);
|
||||
}
|
||||
|
||||
updateUser(userId: string, data: { username?: string; pro_token?: string }): Observable<User> {
|
||||
return this.http.patch<User>(`${this.baseUrl}/users/${userId}`, data);
|
||||
}
|
||||
|
||||
deleteUser(userId: string): Observable<User> {
|
||||
return this.http.delete<User>(`${this.baseUrl}/users/${userId}`);
|
||||
}
|
||||
|
||||
// Key endpoints
|
||||
getKeys(userId: string): Observable<KeyListResponse> {
|
||||
return this.http.get<KeyListResponse>(`${this.baseUrl}/users/${userId}/keys`);
|
||||
}
|
||||
|
||||
getCurrentKey(userId: string): Observable<KeyToken> {
|
||||
return this.http.get<KeyToken>(`${this.baseUrl}/users/${userId}/keys/current`);
|
||||
}
|
||||
|
||||
getKey(userId: string, keyId: string): Observable<KeyToken> {
|
||||
return this.http.get<KeyToken>(`${this.baseUrl}/users/${userId}/keys/${keyId}`);
|
||||
}
|
||||
|
||||
createKey(userId: string, data: CreateKeyRequest): Observable<KeyToken> {
|
||||
return this.http.post<KeyToken>(`${this.baseUrl}/users/${userId}/keys`, data);
|
||||
}
|
||||
|
||||
updateKey(userId: string, keyId: string, data: UpdateKeyRequest): Observable<KeyToken> {
|
||||
return this.http.patch<KeyToken>(`${this.baseUrl}/users/${userId}/keys/${keyId}`, data);
|
||||
}
|
||||
|
||||
deleteKey(userId: string, keyId: string): Observable<KeyToken> {
|
||||
return this.http.delete<KeyToken>(`${this.baseUrl}/users/${userId}/keys/${keyId}`);
|
||||
}
|
||||
|
||||
// Client endpoints
|
||||
getClients(userId: string): Observable<ClientListResponse> {
|
||||
return this.http.get<ClientListResponse>(`${this.baseUrl}/users/${userId}/clients`);
|
||||
}
|
||||
|
||||
getClient(userId: string, clientId: string): Observable<Client> {
|
||||
return this.http.get<Client>(`${this.baseUrl}/users/${userId}/clients/${clientId}`);
|
||||
}
|
||||
|
||||
deleteClient(userId: string, clientId: string): Observable<Client> {
|
||||
return this.http.delete<Client>(`${this.baseUrl}/users/${userId}/clients/${clientId}`);
|
||||
}
|
||||
|
||||
// Channel endpoints
|
||||
getChannels(userId: string, selector?: ChannelSelector): Observable<ChannelListResponse> {
|
||||
let params = new HttpParams();
|
||||
if (selector) {
|
||||
params = params.set('selector', selector);
|
||||
}
|
||||
return this.http.get<ChannelListResponse>(`${this.baseUrl}/users/${userId}/channels`, { params });
|
||||
}
|
||||
|
||||
getChannel(userId: string, channelId: string): Observable<ChannelWithSubscription> {
|
||||
return this.http.get<ChannelWithSubscription>(`${this.baseUrl}/users/${userId}/channels/${channelId}`);
|
||||
}
|
||||
|
||||
createChannel(userId: string, data: CreateChannelRequest): Observable<ChannelWithSubscription> {
|
||||
return this.http.post<ChannelWithSubscription>(`${this.baseUrl}/users/${userId}/channels`, data);
|
||||
}
|
||||
|
||||
updateChannel(userId: string, channelId: string, data: UpdateChannelRequest): Observable<ChannelWithSubscription> {
|
||||
return this.http.patch<ChannelWithSubscription>(`${this.baseUrl}/users/${userId}/channels/${channelId}`, data);
|
||||
}
|
||||
|
||||
deleteChannel(userId: string, channelId: string): Observable<Channel> {
|
||||
return this.http.delete<Channel>(`${this.baseUrl}/users/${userId}/channels/${channelId}`);
|
||||
}
|
||||
|
||||
getChannelMessages(userId: string, channelId: string, params?: { page_size?: number; next_page_token?: string; trimmed?: boolean }): Observable<MessageListResponse> {
|
||||
let httpParams = new HttpParams();
|
||||
if (params?.page_size) httpParams = httpParams.set('page_size', params.page_size);
|
||||
if (params?.next_page_token) httpParams = httpParams.set('next_page_token', params.next_page_token);
|
||||
if (params?.trimmed !== undefined) httpParams = httpParams.set('trimmed', params.trimmed);
|
||||
return this.http.get<MessageListResponse>(`${this.baseUrl}/users/${userId}/channels/${channelId}/messages`, { params: httpParams });
|
||||
}
|
||||
|
||||
getChannelSubscriptions(userId: string, channelId: string): Observable<SubscriptionListResponse> {
|
||||
return this.http.get<SubscriptionListResponse>(`${this.baseUrl}/users/${userId}/channels/${channelId}/subscriptions`);
|
||||
}
|
||||
|
||||
// Message endpoints
|
||||
getMessages(params?: MessageListParams): Observable<MessageListResponse> {
|
||||
let httpParams = new HttpParams();
|
||||
if (params) {
|
||||
if (params.after) httpParams = httpParams.set('after', params.after);
|
||||
if (params.before) httpParams = httpParams.set('before', params.before);
|
||||
if (params.channel) httpParams = httpParams.set('channel', params.channel);
|
||||
if (params.priority !== undefined) httpParams = httpParams.set('priority', params.priority);
|
||||
if (params.search) httpParams = httpParams.set('search', params.search);
|
||||
if (params.sender) httpParams = httpParams.set('sender', params.sender);
|
||||
if (params.subscription_status) httpParams = httpParams.set('subscription_status', params.subscription_status);
|
||||
if (params.trimmed !== undefined) httpParams = httpParams.set('trimmed', params.trimmed);
|
||||
if (params.page_size) httpParams = httpParams.set('page_size', params.page_size);
|
||||
if (params.next_page_token) httpParams = httpParams.set('next_page_token', params.next_page_token);
|
||||
}
|
||||
return this.http.get<MessageListResponse>(`${this.baseUrl}/messages`, { params: httpParams });
|
||||
}
|
||||
|
||||
getMessage(messageId: string): Observable<Message> {
|
||||
return this.http.get<Message>(`${this.baseUrl}/messages/${messageId}`);
|
||||
}
|
||||
|
||||
deleteMessage(messageId: string): Observable<Message> {
|
||||
return this.http.delete<Message>(`${this.baseUrl}/messages/${messageId}`);
|
||||
}
|
||||
|
||||
// Subscription endpoints
|
||||
getSubscriptions(userId: string, filter?: SubscriptionFilter): Observable<SubscriptionListResponse> {
|
||||
let httpParams = new HttpParams();
|
||||
if (filter) {
|
||||
if (filter.direction) httpParams = httpParams.set('direction', filter.direction);
|
||||
if (filter.confirmation) httpParams = httpParams.set('confirmation', filter.confirmation);
|
||||
if (filter.external) httpParams = httpParams.set('external', filter.external);
|
||||
if (filter.subscriber_user_id) httpParams = httpParams.set('subscriber_user_id', filter.subscriber_user_id);
|
||||
if (filter.channel_owner_user_id) httpParams = httpParams.set('channel_owner_user_id', filter.channel_owner_user_id);
|
||||
if (filter.page_size) httpParams = httpParams.set('page_size', filter.page_size);
|
||||
if (filter.next_page_token) httpParams = httpParams.set('next_page_token', filter.next_page_token);
|
||||
}
|
||||
return this.http.get<SubscriptionListResponse>(`${this.baseUrl}/users/${userId}/subscriptions`, { params: httpParams });
|
||||
}
|
||||
|
||||
getSubscription(userId: string, subscriptionId: string): Observable<Subscription> {
|
||||
return this.http.get<Subscription>(`${this.baseUrl}/users/${userId}/subscriptions/${subscriptionId}`);
|
||||
}
|
||||
|
||||
createSubscription(userId: string, data: CreateSubscriptionRequest): Observable<Subscription> {
|
||||
return this.http.post<Subscription>(`${this.baseUrl}/users/${userId}/subscriptions`, data);
|
||||
}
|
||||
|
||||
confirmSubscription(userId: string, subscriptionId: string, data: ConfirmSubscriptionRequest): Observable<Subscription> {
|
||||
return this.http.patch<Subscription>(`${this.baseUrl}/users/${userId}/subscriptions/${subscriptionId}`, data);
|
||||
}
|
||||
|
||||
deleteSubscription(userId: string, subscriptionId: string): Observable<Subscription> {
|
||||
return this.http.delete<Subscription>(`${this.baseUrl}/users/${userId}/subscriptions/${subscriptionId}`);
|
||||
}
|
||||
|
||||
// Sender names
|
||||
getSenderNames(): Observable<SenderNameListResponse> {
|
||||
return this.http.get<SenderNameListResponse>(`${this.baseUrl}/sender-names`);
|
||||
}
|
||||
|
||||
getUserSenderNames(userId: string): Observable<SenderNameListResponse> {
|
||||
return this.http.get<SenderNameListResponse>(`${this.baseUrl}/users/${userId}/sender-names`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Injectable, signal, computed } from '@angular/core';
|
||||
|
||||
const USER_ID_KEY = 'scn_user_id';
|
||||
const ADMIN_KEY_KEY = 'scn_admin_key';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthService {
|
||||
private userId = signal<string | null>(null);
|
||||
private adminKey = signal<string | null>(null);
|
||||
|
||||
isAuthenticated = computed(() => !!this.userId() && !!this.adminKey());
|
||||
|
||||
constructor() {
|
||||
this.loadFromStorage();
|
||||
}
|
||||
|
||||
private loadFromStorage(): void {
|
||||
const userId = sessionStorage.getItem(USER_ID_KEY);
|
||||
const adminKey = sessionStorage.getItem(ADMIN_KEY_KEY);
|
||||
if (userId && adminKey) {
|
||||
this.userId.set(userId);
|
||||
this.adminKey.set(adminKey);
|
||||
}
|
||||
}
|
||||
|
||||
login(userId: string, adminKey: string): void {
|
||||
sessionStorage.setItem(USER_ID_KEY, userId);
|
||||
sessionStorage.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);
|
||||
this.userId.set(null);
|
||||
this.adminKey.set(null);
|
||||
}
|
||||
|
||||
getUserId(): string | null {
|
||||
return this.userId();
|
||||
}
|
||||
|
||||
getAdminKey(): string | null {
|
||||
return this.adminKey();
|
||||
}
|
||||
|
||||
getAuthHeader(): string | null {
|
||||
const key = this.adminKey();
|
||||
return key ? `SCN ${key}` : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './auth.service';
|
||||
export * from './api.service';
|
||||
export * from './notification.service';
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { NzMessageService } from 'ng-zorro-antd/message';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class NotificationService {
|
||||
private message = inject(NzMessageService);
|
||||
|
||||
success(content: string): void {
|
||||
this.message.success(content);
|
||||
}
|
||||
|
||||
error(content: string): void {
|
||||
this.message.error(content);
|
||||
}
|
||||
|
||||
warning(content: string): void {
|
||||
this.message.warning(content);
|
||||
}
|
||||
|
||||
info(content: string): void {
|
||||
this.message.info(content);
|
||||
}
|
||||
|
||||
loading(content: string): string {
|
||||
return this.message.loading(content, { nzDuration: 0 }).messageId;
|
||||
}
|
||||
|
||||
remove(id: string): void {
|
||||
this.message.remove(id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user