commit
This commit is contained in:
parent
0e94a19d27
commit
cd76913035
|
@ -5,7 +5,11 @@ const routes: Routes = [
|
|||
{
|
||||
path: 'pages',
|
||||
loadChildren: './pages/pages.module#PagesModule'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'auth',
|
||||
loadChildren: './pages/accounts/accounts.module#AccountsModule'
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -82,11 +82,14 @@ $typography: mat-typography-config(
|
|||
@import 'src/app/layout/components/chat-panel/chat-panel.theme';
|
||||
@import 'src/app/layout/components/toolbar/toolbar.theme';
|
||||
|
||||
@import 'src/app/pages/accounts/component/authentication/authentication.theme';
|
||||
|
||||
// Define a mixin for easier access
|
||||
@mixin components-theme($theme) {
|
||||
// Layout components
|
||||
@include chat-panel-theme($theme);
|
||||
@include toolbar-theme($theme);
|
||||
@include login-theme($theme);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
|
37
src/app/pages/accounts/accounts-routing.page.module.ts
Normal file
37
src/app/pages/accounts/accounts-routing.page.module.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
// import { AccountsLayoutComponent } from '../../layout/component/accounts/accounts.layout.component';
|
||||
|
||||
// import { AuthenticationPageComponent } from './component/authentication/authentication.page.component';
|
||||
// import { WelcomePageComponent } from './component/welcome/welcome.page.component';
|
||||
// import { AuthenticationCallbackPageComponent } from './component/authentication/authentication-callback.page.component';
|
||||
|
||||
import { AuthenticationComponent } from './component/authentication/authentication.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'signin',
|
||||
component: AuthenticationComponent,
|
||||
// children: [
|
||||
// {
|
||||
// path: 'authentication',
|
||||
// component: AuthenticationPageComponent
|
||||
// },
|
||||
// {
|
||||
// path: 'authentication/callback',
|
||||
// component: AuthenticationCallbackPageComponent
|
||||
// },
|
||||
// {
|
||||
// path: 'welcome',
|
||||
// component: WelcomePageComponent
|
||||
// }
|
||||
// ]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AccountsRoutingPageModule { }
|
17
src/app/pages/accounts/accounts-store.module.ts
Executable file
17
src/app/pages/accounts/accounts-store.module.ts
Executable file
|
@ -0,0 +1,17 @@
|
|||
import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { EffectsModule } from '@ngrx/effects';
|
||||
|
||||
import {
|
||||
REDUCERS,
|
||||
EFFECTS,
|
||||
} from './store';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
StoreModule.forFeature('accounts', REDUCERS),
|
||||
EffectsModule.forFeature(EFFECTS),
|
||||
],
|
||||
})
|
||||
export class AccountsStoreModule {
|
||||
}
|
62
src/app/pages/accounts/accounts.module.ts
Executable file
62
src/app/pages/accounts/accounts.module.ts
Executable file
|
@ -0,0 +1,62 @@
|
|||
import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { COMPONENTS } from './component';
|
||||
import { AccountsService } from './service/accounts.service';
|
||||
import { AccountsStoreModule } from './accounts-store.module';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
|
||||
import { FuseSharedModule } from 'src/@fuse/shared.module';
|
||||
import { AccountsRoutingPageModule } from './accounts-routing.page.module';
|
||||
|
||||
// import { SharedModule } from '../../../common/shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
TranslateModule,
|
||||
AccountsRoutingPageModule,
|
||||
|
||||
MatButtonModule,
|
||||
MatCheckboxModule,
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
|
||||
FuseSharedModule
|
||||
|
||||
// SharedModule,
|
||||
|
||||
],
|
||||
declarations: [
|
||||
...COMPONENTS,
|
||||
],
|
||||
exports: [
|
||||
...COMPONENTS,
|
||||
],
|
||||
})
|
||||
export class AccountsModule {
|
||||
public static forRoot(): ModuleWithProviders<AccountsRootModule> {
|
||||
return {
|
||||
ngModule: AccountsRootModule,
|
||||
providers: [
|
||||
AccountsService,
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
AccountsStoreModule,
|
||||
],
|
||||
exports: [
|
||||
]
|
||||
})
|
||||
export class AccountsRootModule {
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<div id="login" fxLayout="column">
|
||||
|
||||
<div id="login-form-wrapper" fxLayout="column" fxLayoutAlign="center center">
|
||||
|
||||
<div id="login-form" [@animate]="{value:'*',params:{duration:'300ms',y:'100px'}}">
|
||||
|
||||
<div class="logo">
|
||||
<img src="assets/images/logos/fuse.svg">
|
||||
</div>
|
||||
|
||||
<div class="title">LOGIN TO YOUR ACCOUNT</div>
|
||||
|
||||
<form name="loginForm" [formGroup]="loginForm" (submit)="onSignin()" novalidate>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>username</mat-label>
|
||||
<input matInput formControlName="username">
|
||||
<mat-icon matSuffix class="secondary-text">mail</mat-icon>
|
||||
<mat-error *ngIf="loginForm.get('username').hasError('required')">
|
||||
username is required
|
||||
</mat-error>
|
||||
<mat-error *ngIf="!loginForm.get('username').hasError('required') &&
|
||||
loginForm.get('username').hasError('username')">
|
||||
Please enter a valid username
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Password</mat-label>
|
||||
<input matInput type="password" formControlName="password">
|
||||
<mat-icon matSuffix class="secondary-text">vpn_key</mat-icon>
|
||||
<mat-error>
|
||||
Password is required
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<div class="remember-forgot-password" fxLayout="row" fxLayout.xs="column" fxLayoutAlign="space-between center">
|
||||
<mat-checkbox class="remember-me" aria-label="Remember Me">
|
||||
Remember Me
|
||||
</mat-checkbox>
|
||||
|
||||
<a class="forgot-password" [routerLink]="'/pages/auth/forgot-password'">
|
||||
Forgot Password?
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<button mat-raised-button color="accent" class="submit-button" aria-label="LOG IN"
|
||||
[disabled]="loginForm.invalid">
|
||||
LOGIN
|
||||
</button>
|
||||
|
||||
</form>
|
||||
<!--
|
||||
<div class="separator">
|
||||
<span class="text">OR</span>
|
||||
</div>
|
||||
|
||||
<button mat-raised-button class="google">
|
||||
Log in with Google
|
||||
</button>
|
||||
|
||||
<button mat-raised-button class="facebook">
|
||||
Log in with Facebook
|
||||
</button>
|
||||
|
||||
<div class="register" fxLayout="column" fxLayoutAlign="center center">
|
||||
<span class="text">Don't have an account?</span>
|
||||
<a class="link" [routerLink]="'/pages/auth/register'">Create an account</a>
|
||||
</div> -->
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,147 @@
|
|||
@import "src/@fuse/scss/fuse.scss";
|
||||
|
||||
authentication {
|
||||
|
||||
#login {
|
||||
width: 100%;
|
||||
background: url('/assets/images/backgrounds/dark-material-bg.jpg') no-repeat;
|
||||
background-size: cover;
|
||||
|
||||
#login-form-wrapper {
|
||||
flex: 1 0 auto;
|
||||
padding: 32px;
|
||||
|
||||
@include media-breakpoint('xs') {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
#login-form {
|
||||
width: 384px;
|
||||
max-width: 384px;
|
||||
padding: 32px;
|
||||
text-align: center;
|
||||
@include mat-elevation(16);
|
||||
|
||||
@include media-breakpoint('xs') {
|
||||
padding: 24px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 128px;
|
||||
margin: 32px auto;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
margin: 16px 0 32px 0;
|
||||
}
|
||||
|
||||
form {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
|
||||
mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
mat-checkbox {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.remember-forgot-password {
|
||||
font-size: 13px;
|
||||
margin-top: 8px;
|
||||
|
||||
.remember-me {
|
||||
margin-bottom: 16px
|
||||
}
|
||||
|
||||
.forgot-password {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px
|
||||
}
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
width: 220px;
|
||||
margin: 16px auto;
|
||||
display: block;
|
||||
|
||||
@include media-breakpoint('xs') {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.register {
|
||||
margin: 32px auto 24px auto;
|
||||
font-weight: 600;
|
||||
|
||||
.text {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
margin: 24px auto;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100px;
|
||||
|
||||
.text {
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
padding: 0 8px;
|
||||
z-index: 9999;
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 30px;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
border-top: 1px solid;
|
||||
}
|
||||
|
||||
&:before {
|
||||
right: 100%;
|
||||
}
|
||||
|
||||
&:after {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
|
||||
&.google,
|
||||
&.facebook {
|
||||
width: 192px;
|
||||
text-transform: none;
|
||||
color: #FFFFFF;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
@include media-breakpoint('xs') {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
&.google {
|
||||
background-color: #D73D32;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&.facebook {
|
||||
background-color: rgb(63, 92, 154);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
|
||||
import { FuseConfigService } from 'src/@fuse/services/config.service';
|
||||
import { fuseAnimations } from 'src/@fuse/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'authentication',
|
||||
templateUrl: './authentication.component.html',
|
||||
styleUrls: ['./authentication.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations: fuseAnimations
|
||||
})
|
||||
export class AuthenticationComponent implements OnInit {
|
||||
|
||||
loginForm: FormGroup;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param {FuseConfigService} _fuseConfigService
|
||||
* @param {FormBuilder} _formBuilder
|
||||
*/
|
||||
constructor(
|
||||
private _fuseConfigService: FuseConfigService,
|
||||
private _formBuilder: FormBuilder
|
||||
) {
|
||||
// Configure the layout
|
||||
this._fuseConfigService.config = {
|
||||
layout: {
|
||||
navbar: {
|
||||
hidden: true
|
||||
},
|
||||
toolbar: {
|
||||
hidden: true
|
||||
},
|
||||
footer: {
|
||||
hidden: true
|
||||
},
|
||||
sidepanel: {
|
||||
hidden: true
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Lifecycle hooks
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* On init
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.loginForm = this._formBuilder.group({
|
||||
username: ['', [Validators.required]],
|
||||
password: ['', Validators.required]
|
||||
});
|
||||
}
|
||||
|
||||
onSignin(): void {
|
||||
let userName = this.loginForm.get('username').value;
|
||||
let password = this.loginForm.get('password').value;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
@mixin login-theme($theme) {
|
||||
|
||||
$background: map-get($theme, background);
|
||||
$foreground: map-get($theme, foreground);
|
||||
$is-dark: map-get($theme, is-dark);
|
||||
|
||||
authentication {
|
||||
|
||||
#login {
|
||||
|
||||
#login-form-wrapper {
|
||||
|
||||
#login-form {
|
||||
@if ($is-dark) {
|
||||
background: mat-color($fuse-navy, 600);
|
||||
} @else {
|
||||
background: map-get($background, card);
|
||||
}
|
||||
|
||||
.separator {
|
||||
color: map-get($foreground, divider);
|
||||
|
||||
.text {
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
border-top-color: map-get($foreground, divider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
5
src/app/pages/accounts/component/index.ts
Normal file
5
src/app/pages/accounts/component/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { AuthenticationComponent } from './authentication/authentication.component';
|
||||
|
||||
export const COMPONENTS = [
|
||||
AuthenticationComponent,
|
||||
];
|
68
src/app/pages/accounts/service/accounts.service.ts
Normal file
68
src/app/pages/accounts/service/accounts.service.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { CookieService } from 'ngx-cookie-service';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { User } from '../../../../shared/user/model/user.model';
|
||||
|
||||
@Injectable()
|
||||
export class AccountsService {
|
||||
public constructor(
|
||||
private httpClient: HttpClient,
|
||||
private cookieService: CookieService,
|
||||
) {
|
||||
}
|
||||
|
||||
// public authenticate(oauthType: string, params?: Map<string, string>) {
|
||||
// const query = this.getQueryParams(params);
|
||||
|
||||
// const externalUrl = new URL(`${environment.oauth[oauthType].authenticateURL}?${query}`);
|
||||
|
||||
// window.open(externalUrl.href, '_self');
|
||||
// }
|
||||
|
||||
// public authenticateOneall(oauthType: string, params?: Map<string, string>) {
|
||||
// const callbackUri = `${environment.oauth.oneall.callbackURL}?${this.getQueryParams(params)}`;
|
||||
|
||||
// let query = '';
|
||||
// query += `service=social_login`;
|
||||
// query += `&callback_uri=${callbackUri}`;
|
||||
|
||||
// const externalUrl = new URL(`${environment.oauth.oneall.authenticateURL}/${oauthType}/?${query}`);
|
||||
|
||||
// window.open(externalUrl.href, '_self');
|
||||
// }
|
||||
|
||||
protected getQueryParams(params?: Map<string, string>): string {
|
||||
let query = '';
|
||||
|
||||
if (!params || 0 === params.size) {
|
||||
model
|
||||
return query;
|
||||
}
|
||||
|
||||
params.forEach((value, key) => {
|
||||
if ('' !== query) {
|
||||
query += '&';
|
||||
}
|
||||
query += `${key}=${value}`;
|
||||
});
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
public login(username: string, password: string): Observable<User> {
|
||||
const model = {
|
||||
username,
|
||||
password
|
||||
};
|
||||
|
||||
return this.httpClient.post<User>(
|
||||
`${this.apiEntryPoint}/auth/signin`,
|
||||
model
|
||||
);
|
||||
}
|
||||
}
|
48
src/app/pages/accounts/store/auth/auth.action.ts
Executable file
48
src/app/pages/accounts/store/auth/auth.action.ts
Executable file
|
@ -0,0 +1,48 @@
|
|||
import { Action } from '@ngrx/store';
|
||||
import { User } from '../../../../../shared/user/model/user.model';
|
||||
|
||||
export enum ActionType {
|
||||
LoginProcessing = '[account.auth] LoginProcessing',
|
||||
|
||||
LoginSuccess = '[account.auth] LoginSuccess',
|
||||
LogoutSuccess = '[account.auth] LogoutSuccess',
|
||||
ChangeUser = '[account.auth] ChangeUser',
|
||||
LoginRequired = '[account.auth] LoginRequired',
|
||||
}
|
||||
|
||||
export class LoginProcessing implements Action {
|
||||
readonly type = ActionType.LoginProcessing;
|
||||
|
||||
constructor(public payload: { processing: boolean }) { }
|
||||
}
|
||||
|
||||
export class LoginSuccess implements Action {
|
||||
readonly type = ActionType.LoginSuccess;
|
||||
|
||||
constructor(public payload: { user: User, returnURL: string }) { }
|
||||
}
|
||||
|
||||
export class ChangeUser implements Action {
|
||||
readonly type = ActionType.ChangeUser;
|
||||
|
||||
constructor(public payload: { user: User }) { }
|
||||
}
|
||||
|
||||
export class LogoutSuccess implements Action {
|
||||
readonly type = ActionType.LogoutSuccess;
|
||||
}
|
||||
|
||||
export class LoginRequired implements Action {
|
||||
readonly type = ActionType.LoginRequired;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
|
||||
export type Actions =
|
||||
| LoginProcessing
|
||||
| LoginSuccess
|
||||
| ChangeUser
|
||||
| LogoutSuccess
|
||||
| LoginRequired
|
||||
;
|
43
src/app/pages/accounts/store/auth/auth.reducer.ts
Executable file
43
src/app/pages/accounts/store/auth/auth.reducer.ts
Executable file
|
@ -0,0 +1,43 @@
|
|||
import { Actions, ActionType } from './auth.action';
|
||||
|
||||
import { State, initialState } from './auth.state';
|
||||
|
||||
export function reducer(state: State = initialState, action: Actions): State {
|
||||
switch (action.type) {
|
||||
case ActionType.LoginProcessing: {
|
||||
return {
|
||||
...state,
|
||||
processing: action.payload.processing
|
||||
};
|
||||
}
|
||||
|
||||
case ActionType.LoginSuccess: {
|
||||
return {
|
||||
...state,
|
||||
processing: false,
|
||||
logined: true,
|
||||
user: action.payload.user
|
||||
};
|
||||
}
|
||||
|
||||
case ActionType.ChangeUser: {
|
||||
return {
|
||||
...state,
|
||||
user: action.payload.user
|
||||
};
|
||||
}
|
||||
|
||||
case ActionType.LogoutSuccess: {
|
||||
return {
|
||||
...state,
|
||||
processing: false,
|
||||
logined: false,
|
||||
user: null
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
22
src/app/pages/accounts/store/auth/auth.state.ts
Executable file
22
src/app/pages/accounts/store/auth/auth.state.ts
Executable file
|
@ -0,0 +1,22 @@
|
|||
import { Selector, createSelector } from '@ngrx/store';
|
||||
import { User } from '../../../../../shared/user/model/user.model';
|
||||
|
||||
export interface State {
|
||||
processing: boolean;
|
||||
logined: boolean;
|
||||
user: User | null;
|
||||
}
|
||||
|
||||
export const initialState: State = {
|
||||
processing: false,
|
||||
logined: false,
|
||||
user: null,
|
||||
};
|
||||
|
||||
export function getSelectors<S>(selector: Selector<any, State>) {
|
||||
return {
|
||||
selectProcessing: createSelector(selector, (state: State) => state.processing),
|
||||
selectLogined: createSelector(selector, (state: State) => state.logined),
|
||||
selectUser: createSelector(selector, (state: State) => state.user),
|
||||
};
|
||||
}
|
3
src/app/pages/accounts/store/auth/index.ts
Normal file
3
src/app/pages/accounts/store/auth/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './auth.action';
|
||||
export * from './auth.reducer';
|
||||
export * from './auth.state';
|
24
src/app/pages/accounts/store/index.ts
Normal file
24
src/app/pages/accounts/store/index.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import {
|
||||
createSelector,
|
||||
createFeatureSelector,
|
||||
} from '@ngrx/store';
|
||||
|
||||
import * as AuthStore from './auth';
|
||||
|
||||
export interface State {
|
||||
auth: AuthStore.State;
|
||||
}
|
||||
|
||||
export const REDUCERS = {
|
||||
auth: AuthStore.reducer,
|
||||
};
|
||||
|
||||
export const EFFECTS = [
|
||||
];
|
||||
|
||||
export const selectState = createFeatureSelector<State>('accounts');
|
||||
|
||||
export const AuthSelector = AuthStore.getSelectors(createSelector(
|
||||
selectState,
|
||||
(state: State) => state.auth,
|
||||
));
|
|
@ -4,6 +4,7 @@ import { FuseSharedModule } from 'src/@fuse/shared.module';
|
|||
import { PagesRoutingModule } from './pages-routing.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [FuseSharedModule, PagesRoutingModule]
|
||||
imports: [FuseSharedModule, PagesRoutingModule],
|
||||
declarations: []
|
||||
})
|
||||
export class PagesModule {}
|
||||
export class PagesModule { }
|
||||
|
|
|
@ -48,6 +48,9 @@ export class UserListComponent implements OnInit, OnDestroy {
|
|||
'recentConnectIp'
|
||||
];
|
||||
|
||||
total: number;
|
||||
userList: User[];
|
||||
|
||||
@ViewChild(MatPaginator, { static: true })
|
||||
paginator: MatPaginator;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user