mirror of https://github.com/abpframework/abp.git
committed by
GitHub
107 changed files with 3690 additions and 4412 deletions
@ -1,24 +0,0 @@ |
|||
import { Config } from '../models/config'; |
|||
|
|||
/** |
|||
* @deprecated Use ConfigStateService. To be deleted in v5.0. |
|||
*/ |
|||
export class GetAppConfiguration { |
|||
static readonly type = '[Config] Get App Configuration'; |
|||
} |
|||
|
|||
/** |
|||
* @deprecated Use EnvironmentService instead. To be deleted in v5.0. |
|||
*/ |
|||
export class SetEnvironment { |
|||
static readonly type = '[Config] Set Environment'; |
|||
constructor(public environment: Config.Environment) {} |
|||
} |
|||
|
|||
/** |
|||
* @deprecated Use EnvironmentService instead. To be deleted in v5.0. |
|||
*/ |
|||
export class PatchConfigState { |
|||
static readonly type = '[Config] Set State'; |
|||
constructor(public state: Config.State) {} |
|||
} |
|||
@ -1,4 +0,0 @@ |
|||
export { GetAppConfiguration, SetEnvironment } from './config.actions'; |
|||
export * from './loader.actions'; |
|||
export * from './profile.actions'; |
|||
export * from './rest.actions'; |
|||
@ -1,11 +0,0 @@ |
|||
import { HttpRequest } from '@angular/common/http'; |
|||
|
|||
export class StartLoader { |
|||
static readonly type = '[Loader] Start'; |
|||
constructor(public payload: HttpRequest<any>) {} |
|||
} |
|||
|
|||
export class StopLoader { |
|||
static readonly type = '[Loader] Stop'; |
|||
constructor(public payload: HttpRequest<any>) {} |
|||
} |
|||
@ -1,15 +0,0 @@ |
|||
import { Profile } from '../models'; |
|||
|
|||
export class GetProfile { |
|||
static readonly type = '[Profile] Get'; |
|||
} |
|||
|
|||
export class UpdateProfile { |
|||
static readonly type = '[Profile] Update'; |
|||
constructor(public payload: Profile.Response) {} |
|||
} |
|||
|
|||
export class ChangePassword { |
|||
static readonly type = '[Profile] Change Password'; |
|||
constructor(public payload: Profile.ChangePasswordRequest) {} |
|||
} |
|||
@ -1,6 +0,0 @@ |
|||
import { HttpErrorResponse } from '@angular/common/http'; |
|||
|
|||
export class RestOccurError { |
|||
static readonly type = '[Rest] Error'; |
|||
constructor(public payload: HttpErrorResponse | any) {} |
|||
} |
|||
@ -1,65 +0,0 @@ |
|||
import { ApplicationConfiguration } from './application-configuration'; |
|||
import { ABP } from './common'; |
|||
import { Environment as IEnvironment } from './environment'; |
|||
import { |
|||
LocalizationParam as ILocalizationParam, |
|||
LocalizationWithDefault as ILocalizationWithDefault, |
|||
} from './localization'; |
|||
|
|||
export namespace Config { |
|||
/** |
|||
* @deprecated Use ApplicationConfiguration.Response instead. To be deleted in v5.0. |
|||
*/ |
|||
export type State = ApplicationConfiguration.Response & ABP.Root & { environment: IEnvironment }; |
|||
|
|||
export type Environment = IEnvironment; |
|||
|
|||
/** |
|||
* @deprecated Use ApplicationInfo interface instead. To be deleted in v5.0. |
|||
*/ |
|||
export interface Application { |
|||
name: string; |
|||
baseUrl?: string; |
|||
logoUrl?: string; |
|||
} |
|||
|
|||
/** |
|||
* @deprecated Use ApiConfig interface instead. To be deleted in v5.0. |
|||
*/ |
|||
export type ApiConfig = { |
|||
[key: string]: string; |
|||
url: string; |
|||
} & Partial<{ |
|||
rootNamespace: string; |
|||
}>; |
|||
|
|||
/** |
|||
* @deprecated Use Apis interface instead. To be deleted in v5.0. |
|||
*/ |
|||
export interface Apis { |
|||
[key: string]: ApiConfig; |
|||
default: ApiConfig; |
|||
} |
|||
|
|||
export type LocalizationWithDefault = ILocalizationWithDefault; |
|||
|
|||
export type LocalizationParam = ILocalizationParam; |
|||
|
|||
/** |
|||
* @deprecated Use customMergeFn type instead. To be deleted in v5.0. |
|||
*/ |
|||
export type customMergeFn = ( |
|||
localEnv: Partial<Config.Environment>, |
|||
remoteEnv: any, |
|||
) => Config.Environment; |
|||
|
|||
/** |
|||
* @deprecated Use RemoteEnv interface instead. To be deleted in v5.0. |
|||
*/ |
|||
export interface RemoteEnv { |
|||
url: string; |
|||
mergeStrategy: 'deepmerge' | 'overwrite' | customMergeFn; |
|||
method?: string; |
|||
headers?: ABP.Dictionary<string>; |
|||
} |
|||
} |
|||
@ -1,28 +1,26 @@ |
|||
import { ExtensibleObject } from './dtos'; |
|||
|
|||
export namespace Profile { |
|||
export interface State { |
|||
profile: Response; |
|||
} |
|||
export interface ChangePasswordInput { |
|||
currentPassword: string; |
|||
newPassword: string; |
|||
} |
|||
|
|||
export interface Response extends Partial<ExtensibleObject> { |
|||
userName: string; |
|||
email: string; |
|||
name: string; |
|||
surname: string; |
|||
phoneNumber: string; |
|||
/** |
|||
* Following 4 fields are added as optional (for backward compatibility) on 17.08.2020 |
|||
* Also, this interface extends `ExtensibleObject` as partial for extraProperties field. |
|||
*/ |
|||
isExternal?: boolean; |
|||
hasPassword?: boolean; |
|||
emailConfirmed?: boolean; |
|||
phoneNumberConfirmed?: boolean; |
|||
} |
|||
export interface ProfileDto extends ExtensibleObject { |
|||
userName: string; |
|||
email: string; |
|||
name: string; |
|||
surname: string; |
|||
phoneNumber: string; |
|||
isExternal?: boolean; |
|||
hasPassword?: boolean; |
|||
emailConfirmed?: boolean; |
|||
phoneNumberConfirmed?: boolean; |
|||
} |
|||
|
|||
export interface ChangePasswordRequest { |
|||
currentPassword: string; |
|||
newPassword: string; |
|||
} |
|||
export interface UpdateProfileDto extends ExtensibleObject { |
|||
userName: string; |
|||
email: string; |
|||
name: string; |
|||
surname: string; |
|||
phoneNumber: string; |
|||
} |
|||
|
|||
@ -0,0 +1,26 @@ |
|||
import { HttpErrorResponse } from '@angular/common/http'; |
|||
import { Injectable } from '@angular/core'; |
|||
import { BehaviorSubject, Subject } from 'rxjs'; |
|||
|
|||
@Injectable({ providedIn: 'root' }) |
|||
export class HttpErrorReporterService { |
|||
private _reporter$ = new Subject(); |
|||
private _errors$ = new BehaviorSubject<HttpErrorResponse[]>([]); |
|||
|
|||
get reporter$() { |
|||
return this._reporter$.asObservable(); |
|||
} |
|||
|
|||
get errors$() { |
|||
return this._errors$.asObservable(); |
|||
} |
|||
|
|||
get errors() { |
|||
return this._errors$.value; |
|||
} |
|||
|
|||
reportError = (error: HttpErrorResponse) => { |
|||
this._reporter$.next(error); |
|||
this._errors$.next([...this.errors, error]); |
|||
}; |
|||
} |
|||
@ -1,28 +0,0 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { Store } from '@ngxs/store'; |
|||
import { ProfileState } from '../states'; |
|||
import { Profile } from '../models'; |
|||
import { GetProfile, UpdateProfile, ChangePassword } from '../actions'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root', |
|||
}) |
|||
export class ProfileStateService { |
|||
constructor(private store: Store) {} |
|||
|
|||
getProfile() { |
|||
return this.store.selectSnapshot(ProfileState.getProfile); |
|||
} |
|||
|
|||
dispatchGetProfile() { |
|||
return this.store.dispatch(new GetProfile()); |
|||
} |
|||
|
|||
dispatchUpdateProfile(...args: ConstructorParameters<typeof UpdateProfile>) { |
|||
return this.store.dispatch(new UpdateProfile(...args)); |
|||
} |
|||
|
|||
dispatchChangePassword(...args: ConstructorParameters<typeof ChangePassword>) { |
|||
return this.store.dispatch(new ChangePassword(...args)); |
|||
} |
|||
} |
|||
@ -1,264 +0,0 @@ |
|||
import { HttpErrorResponse } from '@angular/common/http'; |
|||
import { Injectable } from '@angular/core'; |
|||
import { Action, createSelector, Selector, State, StateContext, Store } from '@ngxs/store'; |
|||
import compare from 'just-compare'; |
|||
import { throwError } from 'rxjs'; |
|||
import { catchError, distinctUntilChanged } from 'rxjs/operators'; |
|||
import { GetAppConfiguration, PatchConfigState, SetEnvironment } from '../actions/config.actions'; |
|||
import { RestOccurError } from '../actions/rest.actions'; |
|||
import { Config } from '../models/config'; |
|||
import { ConfigStateService } from '../services/config-state.service'; |
|||
import { EnvironmentService } from '../services/environment.service'; |
|||
import { interpolate } from '../utils/string-utils'; |
|||
|
|||
/** |
|||
* @deprecated Use ConfigStateService instead. To be deleted in v5.0. |
|||
*/ |
|||
@State<Config.State>({ |
|||
name: 'ConfigState', |
|||
defaults: {} as Config.State, |
|||
}) |
|||
@Injectable() |
|||
export class ConfigState { |
|||
@Selector() |
|||
static getAll(state: Config.State) { |
|||
return state; |
|||
} |
|||
|
|||
@Selector() |
|||
static getApplicationInfo(state: Config.State): Config.Application { |
|||
return state.environment.application || ({} as Config.Application); |
|||
} |
|||
|
|||
@Selector() |
|||
static getEnvironment(state: Config.State): Config.Environment { |
|||
return state.environment; |
|||
} |
|||
|
|||
static getOne(key: string) { |
|||
const selector = createSelector([ConfigState], (state: Config.State) => { |
|||
return state[key]; |
|||
}); |
|||
|
|||
return selector; |
|||
} |
|||
|
|||
static getDeep(keys: string[] | string) { |
|||
if (typeof keys === 'string') { |
|||
keys = keys.split('.'); |
|||
} |
|||
|
|||
if (!Array.isArray(keys)) { |
|||
throw new Error('The argument must be a dot string or an string array.'); |
|||
} |
|||
|
|||
const selector = createSelector([ConfigState], (state: Config.State) => { |
|||
return (keys as string[]).reduce((acc, val) => { |
|||
if (acc) { |
|||
return acc[val]; |
|||
} |
|||
|
|||
return undefined; |
|||
}, state); |
|||
}); |
|||
|
|||
return selector; |
|||
} |
|||
|
|||
static getApiUrl(key?: string) { |
|||
const selector = createSelector([ConfigState], (state: Config.State): string => { |
|||
return (state.environment.apis[key || 'default'] || state.environment.apis.default).url; |
|||
}); |
|||
|
|||
return selector; |
|||
} |
|||
|
|||
static getFeature(key: string) { |
|||
const selector = createSelector([ConfigState], (state: Config.State) => { |
|||
return state.features.values?.[key]; |
|||
}); |
|||
|
|||
return selector; |
|||
} |
|||
|
|||
static getSetting(key: string) { |
|||
const selector = createSelector([ConfigState], (state: Config.State) => { |
|||
return state.setting.values?.[key]; |
|||
}); |
|||
|
|||
return selector; |
|||
} |
|||
|
|||
static getSettings(keyword?: string) { |
|||
const selector = createSelector([ConfigState], (state: Config.State) => { |
|||
const settings = state.setting.values || {}; |
|||
|
|||
if (!keyword) return settings; |
|||
|
|||
const keysFound = Object.keys(settings).filter(key => key.indexOf(keyword) > -1); |
|||
|
|||
return keysFound.reduce((acc, key) => { |
|||
acc[key] = settings[key]; |
|||
return acc; |
|||
}, {}); |
|||
}); |
|||
|
|||
return selector; |
|||
} |
|||
|
|||
/** |
|||
* @deprecated use PermissionService's getGrantedPolicyStream or getGrantedPolicy methods. |
|||
*/ |
|||
static getGrantedPolicy(key: string) { |
|||
const selector = createSelector([ConfigState], (state: Config.State): boolean => { |
|||
if (!key) return true; |
|||
const getPolicy = (k: string) => state.auth.grantedPolicies[k] || false; |
|||
|
|||
const orRegexp = /\|\|/g; |
|||
const andRegexp = /&&/g; |
|||
|
|||
// TODO: Allow combination of ANDs & ORs
|
|||
if (orRegexp.test(key)) { |
|||
const keys = key.split('||').filter(Boolean); |
|||
|
|||
if (keys.length < 2) return false; |
|||
|
|||
return keys.some(k => getPolicy(k.trim())); |
|||
} else if (andRegexp.test(key)) { |
|||
const keys = key.split('&&').filter(Boolean); |
|||
|
|||
if (keys.length < 2) return false; |
|||
|
|||
return keys.every(k => getPolicy(k.trim())); |
|||
} |
|||
|
|||
return getPolicy(key); |
|||
}); |
|||
|
|||
return selector; |
|||
} |
|||
|
|||
static getLocalizationResource(resourceName: string) { |
|||
const selector = createSelector( |
|||
[ConfigState], |
|||
( |
|||
state: Config.State, |
|||
): { |
|||
[key: string]: string; |
|||
} => { |
|||
return state.localization.values[resourceName]; |
|||
}, |
|||
); |
|||
|
|||
return selector; |
|||
} |
|||
|
|||
static getLocalization( |
|||
key: string | Config.LocalizationWithDefault, |
|||
...interpolateParams: string[] |
|||
) { |
|||
if (!key) key = ''; |
|||
let defaultValue: string; |
|||
|
|||
if (typeof key !== 'string') { |
|||
defaultValue = key.defaultValue; |
|||
key = key.key; |
|||
} |
|||
|
|||
const keys = key.split('::') as string[]; |
|||
const selector = createSelector([ConfigState], (state: Config.State): string => { |
|||
const warn = (message: string) => { |
|||
if (!state.environment.production) console.warn(message); |
|||
}; |
|||
|
|||
if (keys.length < 2) { |
|||
warn('The localization source separator (::) not found.'); |
|||
return defaultValue || (key as string); |
|||
} |
|||
if (!state.localization) return defaultValue || keys[1]; |
|||
|
|||
const sourceName = |
|||
keys[0] || |
|||
state.environment.localization?.defaultResourceName || |
|||
state.localization.defaultResourceName; |
|||
const sourceKey = keys[1]; |
|||
|
|||
if (sourceName === '_') { |
|||
return defaultValue || sourceKey; |
|||
} |
|||
|
|||
if (!sourceName) { |
|||
warn( |
|||
'Localization source name is not specified and the defaultResourceName was not defined!', |
|||
); |
|||
|
|||
return defaultValue || sourceKey; |
|||
} |
|||
|
|||
const source = state.localization.values[sourceName]; |
|||
if (!source) { |
|||
warn('Could not find localization source: ' + sourceName); |
|||
return defaultValue || sourceKey; |
|||
} |
|||
|
|||
let localization = source[sourceKey]; |
|||
if (typeof localization === 'undefined') { |
|||
return defaultValue || sourceKey; |
|||
} |
|||
|
|||
interpolateParams = interpolateParams.filter(params => params != null); |
|||
if (localization) localization = interpolate(localization, interpolateParams); |
|||
|
|||
if (typeof localization !== 'string') localization = ''; |
|||
|
|||
return localization || defaultValue || (key as string); |
|||
}); |
|||
|
|||
return selector; |
|||
} |
|||
|
|||
constructor( |
|||
private store: Store, |
|||
private environmentService: EnvironmentService, |
|||
private configState: ConfigStateService, |
|||
) { |
|||
this.syncConfigState(); |
|||
this.syncEnvironment(); |
|||
} |
|||
|
|||
private syncConfigState() { |
|||
this.configState |
|||
.createOnUpdateStream(state => state) |
|||
.pipe(distinctUntilChanged(compare)) |
|||
.subscribe(config => this.store.dispatch(new PatchConfigState(config as any))); |
|||
} |
|||
|
|||
private syncEnvironment() { |
|||
this.environmentService |
|||
.createOnUpdateStream(state => state) |
|||
.pipe(distinctUntilChanged(compare)) |
|||
.subscribe(env => this.store.dispatch(new PatchConfigState({ environment: env } as any))); |
|||
} |
|||
|
|||
@Action(GetAppConfiguration) |
|||
addData({ patchState, dispatch }: StateContext<Config.State>) { |
|||
const apiName = 'default'; |
|||
const api = this.store.selectSnapshot(ConfigState.getApiUrl(apiName)); |
|||
return this.configState.refreshAppState().pipe( |
|||
catchError((err: HttpErrorResponse) => { |
|||
dispatch(new RestOccurError(err)); |
|||
return throwError(err); |
|||
}), |
|||
); |
|||
} |
|||
|
|||
@Action(SetEnvironment) |
|||
setEnvironment(_, { environment }: SetEnvironment) { |
|||
return this.environmentService.setState(environment); |
|||
} |
|||
|
|||
@Action(PatchConfigState) |
|||
setConfig({ patchState, getState }: StateContext<Config.State>, { state }: PatchConfigState) { |
|||
patchState({ ...getState(), ...state }); |
|||
} |
|||
} |
|||
@ -1,2 +0,0 @@ |
|||
export * from './config.state'; |
|||
export * from './profile.state'; |
|||
@ -1,47 +0,0 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { Action, Selector, State, StateContext } from '@ngxs/store'; |
|||
import { tap } from 'rxjs/operators'; |
|||
import { ChangePassword, GetProfile, UpdateProfile } from '../actions/profile.actions'; |
|||
import { Profile } from '../models/profile'; |
|||
import { ProfileService } from '../services/profile.service'; |
|||
|
|||
@State<Profile.State>({ |
|||
name: 'ProfileState', |
|||
defaults: {} as Profile.State, |
|||
}) |
|||
@Injectable() |
|||
export class ProfileState { |
|||
@Selector() |
|||
static getProfile({ profile }: Profile.State): Profile.Response { |
|||
return profile; |
|||
} |
|||
|
|||
constructor(private profileService: ProfileService) {} |
|||
|
|||
@Action(GetProfile) |
|||
getProfile({ patchState }: StateContext<Profile.State>) { |
|||
return this.profileService.get().pipe( |
|||
tap(profile => |
|||
patchState({ |
|||
profile, |
|||
}), |
|||
), |
|||
); |
|||
} |
|||
|
|||
@Action(UpdateProfile) |
|||
updateProfile({ patchState }: StateContext<Profile.State>, { payload }: UpdateProfile) { |
|||
return this.profileService.update(payload).pipe( |
|||
tap(profile => |
|||
patchState({ |
|||
profile, |
|||
}), |
|||
), |
|||
); |
|||
} |
|||
|
|||
@Action(ChangePassword) |
|||
changePassword(_, { payload }: ChangePassword) { |
|||
return this.profileService.changePassword(payload, true); |
|||
} |
|||
} |
|||
@ -1,57 +0,0 @@ |
|||
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest'; |
|||
import { ProfileStateService } from '../services/profile-state.service'; |
|||
import { ProfileState } from '../states/profile.state'; |
|||
import { Store } from '@ngxs/store'; |
|||
import * as ProfileActions from '../actions'; |
|||
|
|||
describe('ProfileStateService', () => { |
|||
let service: ProfileStateService; |
|||
let spectator: SpectatorService<ProfileStateService>; |
|||
let store: SpyObject<Store>; |
|||
|
|||
const createService = createServiceFactory({ service: ProfileStateService, mocks: [Store] }); |
|||
beforeEach(() => { |
|||
spectator = createService(); |
|||
service = spectator.service; |
|||
store = spectator.inject(Store); |
|||
}); |
|||
test('should have the all ProfileState static methods', () => { |
|||
const reg = /(?<=static )(.*)(?=\()/gm; |
|||
ProfileState.toString() |
|||
.match(reg) |
|||
.forEach(fnName => { |
|||
expect(service[fnName]).toBeTruthy(); |
|||
|
|||
const spy = jest.spyOn(store, 'selectSnapshot'); |
|||
spy.mockClear(); |
|||
|
|||
const isDynamicSelector = ProfileState[fnName].name !== 'memoized'; |
|||
|
|||
if (isDynamicSelector) { |
|||
ProfileState[fnName] = jest.fn((...args) => args); |
|||
service[fnName]('test', 0, {}); |
|||
expect(ProfileState[fnName]).toHaveBeenCalledWith('test', 0, {}); |
|||
} else { |
|||
service[fnName](); |
|||
expect(spy).toHaveBeenCalledWith(ProfileState[fnName]); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
test('should have a dispatch method for every ProfileState action', () => { |
|||
const reg = /(?<=dispatch)(\w+)(?=\()/gm; |
|||
ProfileStateService.toString() |
|||
.match(reg) |
|||
.forEach(fnName => { |
|||
expect(ProfileActions[fnName]).toBeTruthy(); |
|||
|
|||
const spy = jest.spyOn(store, 'dispatch'); |
|||
spy.mockClear(); |
|||
|
|||
const params = Array.from(new Array(ProfileActions[fnName].length)); |
|||
|
|||
service[`dispatch${fnName}`](...params); |
|||
expect(spy).toHaveBeenCalledWith(new ProfileActions[fnName](...params)); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -1,74 +0,0 @@ |
|||
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest'; |
|||
import { Session } from '../models/session'; |
|||
import { ProfileService } from '../services'; |
|||
import { ProfileState } from '../states'; |
|||
import { GetAppConfiguration } from '../actions/config.actions'; |
|||
import { of } from 'rxjs'; |
|||
import { Profile } from '../models/profile'; |
|||
|
|||
export class DummyClass {} |
|||
|
|||
export const PROFILE_STATE_DATA = { |
|||
profile: { userName: 'admin', email: 'info@abp.io', name: 'Admin' }, |
|||
} as Profile.State; |
|||
|
|||
describe('ProfileState', () => { |
|||
let spectator: SpectatorService<DummyClass>; |
|||
let state: ProfileState; |
|||
let profileService: SpyObject<ProfileService>; |
|||
let patchedData; |
|||
const patchState = jest.fn(data => (patchedData = data)); |
|||
|
|||
const createService = createServiceFactory({ |
|||
service: DummyClass, |
|||
mocks: [ProfileService], |
|||
}); |
|||
|
|||
beforeEach(() => { |
|||
spectator = createService(); |
|||
profileService = spectator.inject(ProfileService); |
|||
state = new ProfileState(profileService); |
|||
}); |
|||
|
|||
describe('#getProfile', () => { |
|||
it('should return the current language', () => { |
|||
expect(ProfileState.getProfile(PROFILE_STATE_DATA)).toEqual(PROFILE_STATE_DATA.profile); |
|||
}); |
|||
}); |
|||
|
|||
describe('#GetProfile', () => { |
|||
it('should call the profile service get method and update the state', () => { |
|||
const mockData = { userName: 'test', email: 'test@abp.io' }; |
|||
const spy = jest.spyOn(profileService, 'get'); |
|||
spy.mockReturnValue(of(mockData as any)); |
|||
|
|||
state.getProfile({ patchState } as any).subscribe(); |
|||
|
|||
expect(patchedData).toEqual({ profile: mockData }); |
|||
}); |
|||
}); |
|||
|
|||
describe('#UpdateProfile', () => { |
|||
it('should call the profile service update method and update the state', () => { |
|||
const mockData = { userName: 'test2', email: 'test@abp.io' }; |
|||
const spy = jest.spyOn(profileService, 'update'); |
|||
spy.mockReturnValue(of(mockData as any)); |
|||
|
|||
state.updateProfile({ patchState } as any, { payload: mockData as any }).subscribe(); |
|||
|
|||
expect(patchedData).toEqual({ profile: mockData }); |
|||
}); |
|||
}); |
|||
|
|||
describe('#ChangePassword', () => { |
|||
it('should call the profile service changePassword method', () => { |
|||
const mockData = { currentPassword: 'test123', newPassword: 'test123' }; |
|||
const spy = jest.spyOn(profileService, 'changePassword'); |
|||
spy.mockReturnValue(of(null)); |
|||
|
|||
state.changePassword(null, { payload: mockData }).subscribe(); |
|||
|
|||
expect(spy).toHaveBeenCalledWith(mockData, true); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -1,64 +0,0 @@ |
|||
import { Identity } from '../models/identity'; |
|||
import { ABP, PagedAndSortedResultRequestDto } from '@abp/ng.core'; |
|||
import { |
|||
GetIdentityUsersInput, |
|||
IdentityRoleCreateDto, |
|||
IdentityRoleUpdateDto, |
|||
IdentityUserCreateDto, |
|||
IdentityUserUpdateDto, |
|||
} from '../proxy/identity/models'; |
|||
|
|||
export class GetRoles { |
|||
static readonly type = '[Identity] Get Roles'; |
|||
constructor(public payload?: PagedAndSortedResultRequestDto) {} |
|||
} |
|||
|
|||
export class GetRoleById { |
|||
static readonly type = '[Identity] Get Role By Id'; |
|||
constructor(public payload: string) {} |
|||
} |
|||
|
|||
export class DeleteRole { |
|||
static readonly type = '[Identity] Delete Role'; |
|||
constructor(public payload: string) {} |
|||
} |
|||
|
|||
export class CreateRole { |
|||
static readonly type = '[Identity] Create Role'; |
|||
constructor(public payload: IdentityRoleCreateDto) {} |
|||
} |
|||
|
|||
export class UpdateRole { |
|||
static readonly type = '[Identity] Update Role'; |
|||
constructor(public payload: IdentityRoleUpdateDto & { id: string }) {} |
|||
} |
|||
|
|||
export class GetUsers { |
|||
static readonly type = '[Identity] Get Users'; |
|||
constructor(public payload?: GetIdentityUsersInput) {} |
|||
} |
|||
|
|||
export class GetUserById { |
|||
static readonly type = '[Identity] Get User By Id'; |
|||
constructor(public payload: string) {} |
|||
} |
|||
|
|||
export class DeleteUser { |
|||
static readonly type = '[Identity] Delete User'; |
|||
constructor(public payload: string) {} |
|||
} |
|||
|
|||
export class CreateUser { |
|||
static readonly type = '[Identity] Create User'; |
|||
constructor(public payload: IdentityUserCreateDto) {} |
|||
} |
|||
|
|||
export class UpdateUser { |
|||
static readonly type = '[Identity] Update User'; |
|||
constructor(public payload: IdentityUserUpdateDto & { id: string }) {} |
|||
} |
|||
|
|||
export class GetUserRoles { |
|||
static readonly type = '[Identity] Get User Roles'; |
|||
constructor(public payload: string) {} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
export * from './identity.actions'; |
|||
@ -1,12 +0,0 @@ |
|||
import { PagedResultDto } from '@abp/ng.core'; |
|||
import { IdentityRoleDto, IdentityUserDto } from '../proxy/identity/models'; |
|||
|
|||
export namespace Identity { |
|||
export interface State { |
|||
roles: PagedResultDto<IdentityRoleDto>; |
|||
users: PagedResultDto<IdentityUserDto>; |
|||
selectedRole: IdentityRoleDto; |
|||
selectedUser: IdentityUserDto; |
|||
selectedUserRoles: IdentityRoleDto[]; |
|||
} |
|||
} |
|||
@ -1,82 +0,0 @@ |
|||
import { ABP } from '@abp/ng.core'; |
|||
import { Injectable } from '@angular/core'; |
|||
import { Store } from '@ngxs/store'; |
|||
import { |
|||
CreateRole, |
|||
CreateUser, |
|||
DeleteRole, |
|||
DeleteUser, |
|||
GetRoleById, |
|||
GetRoles, |
|||
GetUserById, |
|||
GetUsers, |
|||
UpdateRole, |
|||
UpdateUser, |
|||
GetUserRoles, |
|||
} from '../actions/identity.actions'; |
|||
import { Identity } from '../models/identity'; |
|||
import { IdentityState } from '../states/identity.state'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root', |
|||
}) |
|||
export class IdentityStateService { |
|||
constructor(private store: Store) {} |
|||
|
|||
getRoles() { |
|||
return this.store.selectSnapshot(IdentityState.getRoles); |
|||
} |
|||
getRolesTotalCount() { |
|||
return this.store.selectSnapshot(IdentityState.getRolesTotalCount); |
|||
} |
|||
getUsers() { |
|||
return this.store.selectSnapshot(IdentityState.getUsers); |
|||
} |
|||
getUsersTotalCount() { |
|||
return this.store.selectSnapshot(IdentityState.getUsersTotalCount); |
|||
} |
|||
|
|||
dispatchGetRoles(...args: ConstructorParameters<typeof GetRoles>) { |
|||
return this.store.dispatch(new GetRoles(...args)); |
|||
} |
|||
|
|||
dispatchGetRoleById(...args: ConstructorParameters<typeof GetRoleById>) { |
|||
return this.store.dispatch(new GetRoleById(...args)); |
|||
} |
|||
|
|||
dispatchDeleteRole(...args: ConstructorParameters<typeof DeleteRole>) { |
|||
return this.store.dispatch(new DeleteRole(...args)); |
|||
} |
|||
|
|||
dispatchCreateRole(...args: ConstructorParameters<typeof CreateRole>) { |
|||
return this.store.dispatch(new CreateRole(...args)); |
|||
} |
|||
|
|||
dispatchUpdateRole(...args: ConstructorParameters<typeof UpdateRole>) { |
|||
return this.store.dispatch(new UpdateRole(...args)); |
|||
} |
|||
|
|||
dispatchGetUsers(...args: ConstructorParameters<typeof GetUsers>) { |
|||
return this.store.dispatch(new GetUsers(...args)); |
|||
} |
|||
|
|||
dispatchGetUserById(...args: ConstructorParameters<typeof GetUserById>) { |
|||
return this.store.dispatch(new GetUserById(...args)); |
|||
} |
|||
|
|||
dispatchDeleteUser(...args: ConstructorParameters<typeof DeleteUser>) { |
|||
return this.store.dispatch(new DeleteUser(...args)); |
|||
} |
|||
|
|||
dispatchCreateUser(...args: ConstructorParameters<typeof CreateUser>) { |
|||
return this.store.dispatch(new CreateUser(...args)); |
|||
} |
|||
|
|||
dispatchUpdateUser(...args: ConstructorParameters<typeof UpdateUser>) { |
|||
return this.store.dispatch(new UpdateUser(...args)); |
|||
} |
|||
|
|||
dispatchGetUserRoles(...args: ConstructorParameters<typeof GetUserRoles>) { |
|||
return this.store.dispatch(new GetUserRoles(...args)); |
|||
} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
export * from './identity-state.service'; |
|||
@ -1,138 +0,0 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { Action, Selector, State, StateContext } from '@ngxs/store'; |
|||
import { pluck, tap } from 'rxjs/operators'; |
|||
import { |
|||
CreateRole, |
|||
CreateUser, |
|||
DeleteRole, |
|||
DeleteUser, |
|||
GetRoleById, |
|||
GetRoles, |
|||
GetUserById, |
|||
GetUserRoles, |
|||
GetUsers, |
|||
UpdateRole, |
|||
UpdateUser, |
|||
} from '../actions/identity.actions'; |
|||
import { Identity } from '../models/identity'; |
|||
import { IdentityRoleService } from '../proxy/identity/identity-role.service'; |
|||
import { IdentityUserService } from '../proxy/identity/identity-user.service'; |
|||
import { IdentityRoleDto, IdentityUserDto } from '../proxy/identity/models'; |
|||
|
|||
@State<Identity.State>({ |
|||
name: 'IdentityState', |
|||
defaults: { roles: {}, selectedRole: {}, users: {}, selectedUser: {} } as Identity.State, |
|||
}) |
|||
@Injectable() |
|||
export class IdentityState { |
|||
@Selector() |
|||
static getRoles({ roles }: Identity.State): IdentityRoleDto[] { |
|||
return roles.items || []; |
|||
} |
|||
|
|||
@Selector() |
|||
static getRolesTotalCount({ roles }: Identity.State): number { |
|||
return roles.totalCount || 0; |
|||
} |
|||
|
|||
@Selector() |
|||
static getUsers({ users }: Identity.State): IdentityUserDto[] { |
|||
return users.items || []; |
|||
} |
|||
|
|||
@Selector() |
|||
static getUsersTotalCount({ users }: Identity.State): number { |
|||
return users.totalCount || 0; |
|||
} |
|||
|
|||
constructor( |
|||
private identityUserService: IdentityUserService, |
|||
private identityRoleService: IdentityRoleService, |
|||
) {} |
|||
|
|||
@Action(GetRoles) |
|||
getRoles({ patchState }: StateContext<Identity.State>, { payload }: GetRoles) { |
|||
return this.identityRoleService.getList(payload).pipe( |
|||
tap(roles => |
|||
patchState({ |
|||
roles, |
|||
}), |
|||
), |
|||
); |
|||
} |
|||
|
|||
@Action(GetRoleById) |
|||
getRole({ patchState }: StateContext<Identity.State>, { payload }: GetRoleById) { |
|||
return this.identityRoleService.get(payload).pipe( |
|||
tap(selectedRole => |
|||
patchState({ |
|||
selectedRole, |
|||
}), |
|||
), |
|||
); |
|||
} |
|||
|
|||
@Action(DeleteRole) |
|||
deleteRole(_, { payload }: GetRoleById) { |
|||
return this.identityRoleService.delete(payload); |
|||
} |
|||
|
|||
@Action(CreateRole) |
|||
addRole(_, { payload }: CreateRole) { |
|||
return this.identityRoleService.create(payload); |
|||
} |
|||
|
|||
@Action(UpdateRole) |
|||
updateRole({ getState }: StateContext<Identity.State>, { payload }: UpdateRole) { |
|||
return this.identityRoleService.update(payload.id, { ...getState().selectedRole, ...payload }); |
|||
} |
|||
|
|||
@Action(GetUsers) |
|||
getUsers({ patchState }: StateContext<Identity.State>, { payload }: GetUsers) { |
|||
return this.identityUserService.getList(payload).pipe( |
|||
tap(users => |
|||
patchState({ |
|||
users, |
|||
}), |
|||
), |
|||
); |
|||
} |
|||
|
|||
@Action(GetUserById) |
|||
getUser({ patchState }: StateContext<Identity.State>, { payload }: GetUserById) { |
|||
return this.identityUserService.get(payload).pipe( |
|||
tap(selectedUser => |
|||
patchState({ |
|||
selectedUser, |
|||
}), |
|||
), |
|||
); |
|||
} |
|||
|
|||
@Action(DeleteUser) |
|||
deleteUser(_, { payload }: GetUserById) { |
|||
return this.identityUserService.delete(payload); |
|||
} |
|||
|
|||
@Action(CreateUser) |
|||
addUser(_, { payload }: CreateUser) { |
|||
return this.identityUserService.create(payload); |
|||
} |
|||
|
|||
@Action(UpdateUser) |
|||
updateUser({ getState }: StateContext<Identity.State>, { payload }: UpdateUser) { |
|||
return this.identityUserService.update(payload.id, { ...getState().selectedUser, ...payload }); |
|||
} |
|||
|
|||
@Action(GetUserRoles) |
|||
getUserRoles({ patchState }: StateContext<Identity.State>, { payload }: GetUserRoles) { |
|||
return this.identityUserService.getRoles(payload).pipe( |
|||
pluck('items'), |
|||
tap(selectedUserRoles => |
|||
patchState({ |
|||
selectedUserRoles, |
|||
}), |
|||
), |
|||
); |
|||
} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
export * from './identity.state'; |
|||
@ -1,58 +0,0 @@ |
|||
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest'; |
|||
import { IdentityStateService } from '../services/identity-state.service'; |
|||
import { IdentityState } from '../states/identity.state'; |
|||
import { Store } from '@ngxs/store'; |
|||
import * as IdentityActions from '../actions/identity.actions'; |
|||
|
|||
describe('IdentityStateService', () => { |
|||
let service: IdentityStateService; |
|||
let spectator: SpectatorService<IdentityStateService>; |
|||
let store: SpyObject<Store>; |
|||
|
|||
const createService = createServiceFactory({ service: IdentityStateService, mocks: [Store] }); |
|||
beforeEach(() => { |
|||
spectator = createService(); |
|||
service = spectator.service; |
|||
store = spectator.inject(Store); |
|||
}); |
|||
|
|||
test('should have the all IdentityState static methods', () => { |
|||
const reg = /(?<=static )(.*)(?=\()/gm; |
|||
IdentityState.toString() |
|||
.match(reg) |
|||
.forEach(fnName => { |
|||
expect(service[fnName]).toBeTruthy(); |
|||
|
|||
const spy = jest.spyOn(store, 'selectSnapshot'); |
|||
spy.mockClear(); |
|||
|
|||
const isDynamicSelector = IdentityState[fnName].name !== 'memoized'; |
|||
|
|||
if (isDynamicSelector) { |
|||
IdentityState[fnName] = jest.fn((...args) => args); |
|||
service[fnName]('test', 0, {}); |
|||
expect(IdentityState[fnName]).toHaveBeenCalledWith('test', 0, {}); |
|||
} else { |
|||
service[fnName](); |
|||
expect(spy).toHaveBeenCalledWith(IdentityState[fnName]); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
test('should have a dispatch method for every IdentityState action', () => { |
|||
const reg = /(?<=dispatch)(\w+)(?=\()/gm; |
|||
IdentityStateService.toString() |
|||
.match(reg) |
|||
.forEach(fnName => { |
|||
expect(IdentityActions[fnName]).toBeTruthy(); |
|||
|
|||
const spy = jest.spyOn(store, 'dispatch'); |
|||
spy.mockClear(); |
|||
|
|||
const params = Array.from(new Array(IdentityActions[fnName].length)); |
|||
|
|||
service[`dispatch${fnName}`](...params); |
|||
expect(spy).toHaveBeenCalledWith(new IdentityActions[fnName](...params)); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -1 +0,0 @@ |
|||
export * from './permission-management.actions'; |
|||
@ -1,11 +0,0 @@ |
|||
import { ProviderInfoDto, UpdatePermissionsDto } from '../proxy/models'; |
|||
|
|||
export class GetPermissions { |
|||
static readonly type = '[PermissionManagement] Get Permissions'; |
|||
constructor(public payload: ProviderInfoDto) {} |
|||
} |
|||
|
|||
export class UpdatePermissions { |
|||
static readonly type = '[PermissionManagement] Update Permissions'; |
|||
constructor(public payload: ProviderInfoDto & UpdatePermissionsDto) {} |
|||
} |
|||
@ -1,13 +1,11 @@ |
|||
import { CoreModule } from '@abp/ng.core'; |
|||
import { ThemeSharedModule } from '@abp/ng.theme.shared'; |
|||
import { NgModule } from '@angular/core'; |
|||
import { NgxsModule } from '@ngxs/store'; |
|||
import { PermissionManagementComponent } from './components/permission-management.component'; |
|||
import { PermissionManagementState } from './states/permission-management.state'; |
|||
|
|||
@NgModule({ |
|||
declarations: [PermissionManagementComponent], |
|||
imports: [CoreModule, ThemeSharedModule, NgxsModule.forFeature([PermissionManagementState])], |
|||
imports: [CoreModule, ThemeSharedModule], |
|||
exports: [PermissionManagementComponent], |
|||
}) |
|||
export class PermissionManagementModule {} |
|||
|
|||
@ -1 +0,0 @@ |
|||
export * from './permission-management-state.service'; |
|||
@ -1,27 +0,0 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { Store } from '@ngxs/store'; |
|||
import { PermissionManagementState } from '../states/permission-management.state'; |
|||
import { PermissionManagement } from '../models'; |
|||
import { GetPermissions, UpdatePermissions } from '../actions'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root', |
|||
}) |
|||
export class PermissionManagementStateService { |
|||
constructor(private store: Store) {} |
|||
|
|||
getPermissionGroups() { |
|||
return this.store.selectSnapshot(PermissionManagementState.getPermissionGroups); |
|||
} |
|||
getEntityDisplayName() { |
|||
return this.store.selectSnapshot(PermissionManagementState.getEntityDisplayName); |
|||
} |
|||
|
|||
dispatchGetPermissions(...args: ConstructorParameters<typeof GetPermissions>) { |
|||
return this.store.dispatch(new GetPermissions(...args)); |
|||
} |
|||
|
|||
dispatchUpdatePermissions(...args: ConstructorParameters<typeof UpdatePermissions>) { |
|||
return this.store.dispatch(new UpdatePermissions(...args)); |
|||
} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
export * from './permission-management.state'; |
|||
@ -1,47 +0,0 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { Action, Selector, State, StateContext } from '@ngxs/store'; |
|||
import { tap } from 'rxjs/operators'; |
|||
import { GetPermissions, UpdatePermissions } from '../actions/permission-management.actions'; |
|||
import { PermissionManagement } from '../models/permission-management'; |
|||
import { ProviderInfoDto } from '../proxy/models'; |
|||
import { PermissionsService } from '../proxy/permissions.service'; |
|||
|
|||
@State<PermissionManagement.State>({ |
|||
name: 'PermissionManagementState', |
|||
defaults: { permissionRes: {} } as PermissionManagement.State, |
|||
}) |
|||
@Injectable() |
|||
export class PermissionManagementState { |
|||
@Selector() |
|||
static getPermissionGroups({ permissionRes }: PermissionManagement.State) { |
|||
return permissionRes.groups || []; |
|||
} |
|||
|
|||
@Selector() |
|||
static getEntityDisplayName({ permissionRes }: PermissionManagement.State): string { |
|||
return permissionRes.entityDisplayName; |
|||
} |
|||
|
|||
constructor(private service: PermissionsService) {} |
|||
|
|||
@Action(GetPermissions) |
|||
permissionManagementGet( |
|||
{ patchState }: StateContext<PermissionManagement.State>, |
|||
{ payload: { providerKey, providerName } = {} as ProviderInfoDto }: GetPermissions, |
|||
) { |
|||
return this.service.get(providerName, providerKey).pipe( |
|||
tap(permissionResponse => |
|||
patchState({ |
|||
permissionRes: permissionResponse, |
|||
}), |
|||
), |
|||
); |
|||
} |
|||
|
|||
@Action(UpdatePermissions) |
|||
permissionManagementUpdate(_, { payload }: UpdatePermissions) { |
|||
return this.service.update(payload.providerName, payload.providerKey, { |
|||
permissions: payload.permissions, |
|||
}); |
|||
} |
|||
} |
|||
@ -1,60 +0,0 @@ |
|||
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest'; |
|||
import { PermissionManagementStateService } from '../services/permission-management-state.service'; |
|||
import { PermissionManagementState } from '../states/permission-management.state'; |
|||
import { Store } from '@ngxs/store'; |
|||
import * as PermissionManagementActions from '../actions'; |
|||
|
|||
describe('PermissionManagementStateService', () => { |
|||
let service: PermissionManagementStateService; |
|||
let spectator: SpectatorService<PermissionManagementStateService>; |
|||
let store: SpyObject<Store>; |
|||
|
|||
const createService = createServiceFactory({ |
|||
service: PermissionManagementStateService, |
|||
mocks: [Store], |
|||
}); |
|||
beforeEach(() => { |
|||
spectator = createService(); |
|||
service = spectator.service; |
|||
store = spectator.inject(Store); |
|||
}); |
|||
test('should have the all PermissionManagementState static methods', () => { |
|||
const reg = /(?<=static )(.*)(?=\()/gm; |
|||
PermissionManagementState.toString() |
|||
.match(reg) |
|||
.forEach(fnName => { |
|||
expect(service[fnName]).toBeTruthy(); |
|||
|
|||
const spy = jest.spyOn(store, 'selectSnapshot'); |
|||
spy.mockClear(); |
|||
|
|||
const isDynamicSelector = PermissionManagementState[fnName].name !== 'memoized'; |
|||
|
|||
if (isDynamicSelector) { |
|||
PermissionManagementState[fnName] = jest.fn((...args) => args); |
|||
service[fnName]('test', 0, {}); |
|||
expect(PermissionManagementState[fnName]).toHaveBeenCalledWith('test', 0, {}); |
|||
} else { |
|||
service[fnName](); |
|||
expect(spy).toHaveBeenCalledWith(PermissionManagementState[fnName]); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
test('should have a dispatch method for every PermissionManagementState action', () => { |
|||
const reg = /(?<=dispatch)(\w+)(?=\()/gm; |
|||
PermissionManagementStateService.toString() |
|||
.match(reg) |
|||
.forEach(fnName => { |
|||
expect(PermissionManagementActions[fnName]).toBeTruthy(); |
|||
|
|||
const spy = jest.spyOn(store, 'dispatch'); |
|||
spy.mockClear(); |
|||
|
|||
const params = Array.from(new Array(PermissionManagementActions[fnName].length)); |
|||
|
|||
service[`dispatch${fnName}`](...params); |
|||
expect(spy).toHaveBeenCalledWith(new PermissionManagementActions[fnName](...params)); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -1,12 +1,5 @@ |
|||
/* |
|||
* Public API Surface of permission-management |
|||
*/ |
|||
|
|||
export * from './lib/permission-management.module'; |
|||
export * from './lib/actions'; |
|||
export * from './lib/components'; |
|||
export * from './lib/enums/components'; |
|||
export * from './lib/models'; |
|||
export * from './lib/services'; |
|||
export * from './lib/states'; |
|||
export * from './lib/permission-management.module'; |
|||
export * from './lib/proxy'; |
|||
|
|||
@ -1 +0,0 @@ |
|||
export * from './setting-management.actions'; |
|||
@ -1,6 +0,0 @@ |
|||
import { ABP } from '@abp/ng.core'; |
|||
|
|||
export class SetSelectedSettingTab { |
|||
static readonly type = '[SettingManagement] Set Selected Tab'; |
|||
constructor(public payload: ABP.Tab) {} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
export * from './setting-management'; |
|||
@ -1,7 +0,0 @@ |
|||
import { ABP } from '@abp/ng.core'; |
|||
|
|||
export namespace SettingManagement { |
|||
export interface State { |
|||
selectedTab?: ABP.Tab; |
|||
} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
export * from './setting-management.state'; |
|||
@ -1,26 +0,0 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { Action, Selector, State, StateContext } from '@ngxs/store'; |
|||
import { SetSelectedSettingTab } from '../actions/setting-management.actions'; |
|||
import { SettingManagement } from '../models/setting-management'; |
|||
|
|||
@State<SettingManagement.State>({ |
|||
name: 'SettingManagementState', |
|||
defaults: {}, |
|||
}) |
|||
@Injectable() |
|||
export class SettingManagementState { |
|||
@Selector() |
|||
static getSelectedTab({ selectedTab }: SettingManagement.State) { |
|||
return selectedTab; |
|||
} |
|||
|
|||
@Action(SetSelectedSettingTab) |
|||
settingManagementAction( |
|||
{ patchState }: StateContext<SettingManagement.State>, |
|||
{ payload }: SetSelectedSettingTab, |
|||
) { |
|||
patchState({ |
|||
selectedTab: payload, |
|||
}); |
|||
} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
export * from './tenant-management.actions'; |
|||
@ -1,26 +0,0 @@ |
|||
import { GetTenantsInput, TenantCreateDto, TenantUpdateDto } from '../proxy/models'; |
|||
|
|||
export class GetTenants { |
|||
static readonly type = '[TenantManagement] Get Tenant'; |
|||
constructor(public payload?: GetTenantsInput) {} |
|||
} |
|||
|
|||
export class GetTenantById { |
|||
static readonly type = '[TenantManagement] Get Tenant By Id'; |
|||
constructor(public payload: string) {} |
|||
} |
|||
|
|||
export class CreateTenant { |
|||
static readonly type = '[TenantManagement] Create Tenant'; |
|||
constructor(public payload: TenantCreateDto) {} |
|||
} |
|||
|
|||
export class UpdateTenant { |
|||
static readonly type = '[TenantManagement] Update Tenant'; |
|||
constructor(public payload: TenantUpdateDto & { id: string }) {} |
|||
} |
|||
|
|||
export class DeleteTenant { |
|||
static readonly type = '[TenantManagement] Delete Tenant'; |
|||
constructor(public payload: string) {} |
|||
} |
|||
File diff suppressed because it is too large
@ -1 +0,0 @@ |
|||
export * from './tenant-management-state.service'; |
|||
@ -1,41 +0,0 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { Store } from '@ngxs/store'; |
|||
import { TenantManagementState } from '../states/tenant-management.state'; |
|||
import { ABP } from '@abp/ng.core'; |
|||
import { GetTenants, GetTenantById, CreateTenant, UpdateTenant, DeleteTenant } from '../actions'; |
|||
import { TenantManagement } from '../models'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root', |
|||
}) |
|||
export class TenantManagementStateService { |
|||
constructor(private store: Store) {} |
|||
|
|||
get() { |
|||
return this.store.selectSnapshot(TenantManagementState.get); |
|||
} |
|||
|
|||
getTenantsTotalCount() { |
|||
return this.store.selectSnapshot(TenantManagementState.getTenantsTotalCount); |
|||
} |
|||
|
|||
dispatchGetTenants(...args: ConstructorParameters<typeof GetTenants>) { |
|||
return this.store.dispatch(new GetTenants(...args)); |
|||
} |
|||
|
|||
dispatchGetTenantById(...args: ConstructorParameters<typeof GetTenantById>) { |
|||
return this.store.dispatch(new GetTenantById(...args)); |
|||
} |
|||
|
|||
dispatchCreateTenant(...args: ConstructorParameters<typeof CreateTenant>) { |
|||
return this.store.dispatch(new CreateTenant(...args)); |
|||
} |
|||
|
|||
dispatchUpdateTenant(...args: ConstructorParameters<typeof UpdateTenant>) { |
|||
return this.store.dispatch(new UpdateTenant(...args)); |
|||
} |
|||
|
|||
dispatchDeleteTenant(...args: ConstructorParameters<typeof DeleteTenant>) { |
|||
return this.store.dispatch(new DeleteTenant(...args)); |
|||
} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
export * from './tenant-management.state'; |
|||
@ -1,70 +0,0 @@ |
|||
import { ABP, PagedResultDto } from '@abp/ng.core'; |
|||
import { Action, Selector, State, StateContext } from '@ngxs/store'; |
|||
import { tap } from 'rxjs/operators'; |
|||
import { |
|||
CreateTenant, |
|||
DeleteTenant, |
|||
GetTenantById, |
|||
GetTenants, |
|||
UpdateTenant, |
|||
} from '../actions/tenant-management.actions'; |
|||
import { TenantManagement } from '../models/tenant-management'; |
|||
import { Injectable } from '@angular/core'; |
|||
import { TenantService } from '../proxy/tenant.service'; |
|||
import { TenantDto } from '../proxy/models'; |
|||
|
|||
@State<TenantManagement.State>({ |
|||
name: 'TenantManagementState', |
|||
defaults: { result: {}, selectedItem: {} } as TenantManagement.State, |
|||
}) |
|||
@Injectable() |
|||
export class TenantManagementState { |
|||
@Selector() |
|||
static get({ result }: TenantManagement.State): TenantDto[] { |
|||
return result.items || []; |
|||
} |
|||
|
|||
@Selector() |
|||
static getTenantsTotalCount({ result }: TenantManagement.State): number { |
|||
return result.totalCount; |
|||
} |
|||
|
|||
constructor(private service: TenantService) {} |
|||
|
|||
@Action(GetTenants) |
|||
get({ patchState }: StateContext<TenantManagement.State>, { payload }: GetTenants) { |
|||
return this.service.getList(payload).pipe( |
|||
tap(result => |
|||
patchState({ |
|||
result, |
|||
}), |
|||
), |
|||
); |
|||
} |
|||
|
|||
@Action(GetTenantById) |
|||
getById({ patchState }: StateContext<TenantManagement.State>, { payload }: GetTenantById) { |
|||
return this.service.get(payload).pipe( |
|||
tap(selectedItem => |
|||
patchState({ |
|||
selectedItem, |
|||
}), |
|||
), |
|||
); |
|||
} |
|||
|
|||
@Action(DeleteTenant) |
|||
delete(_, { payload }: DeleteTenant) { |
|||
return this.service.delete(payload); |
|||
} |
|||
|
|||
@Action(CreateTenant) |
|||
add(_, { payload }: CreateTenant) { |
|||
return this.service.create(payload); |
|||
} |
|||
|
|||
@Action(UpdateTenant) |
|||
update({ getState }: StateContext<TenantManagement.State>, { payload }: UpdateTenant) { |
|||
return this.service.update(payload.id, { ...getState().selectedItem, ...payload }); |
|||
} |
|||
} |
|||
@ -1,61 +0,0 @@ |
|||
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest'; |
|||
import { TenantManagementStateService } from '../services/tenant-management-state.service'; |
|||
import { TenantManagementState } from '../states/tenant-management.state'; |
|||
import { Store } from '@ngxs/store'; |
|||
import * as TenantManagementActions from '../actions'; |
|||
|
|||
describe('TenantManagementStateService', () => { |
|||
let service: TenantManagementStateService; |
|||
let spectator: SpectatorService<TenantManagementStateService>; |
|||
let store: SpyObject<Store>; |
|||
|
|||
const createService = createServiceFactory({ |
|||
service: TenantManagementStateService, |
|||
mocks: [Store], |
|||
}); |
|||
beforeEach(() => { |
|||
spectator = createService(); |
|||
service = spectator.service; |
|||
store = spectator.inject(Store); |
|||
}); |
|||
|
|||
test('should have the all TenantManagementState static methods', () => { |
|||
const reg = /(?<=static )(.*)(?=\()/gm; |
|||
TenantManagementState.toString() |
|||
.match(reg) |
|||
.forEach(fnName => { |
|||
expect(service[fnName]).toBeTruthy(); |
|||
|
|||
const spy = jest.spyOn(store, 'selectSnapshot'); |
|||
spy.mockClear(); |
|||
|
|||
const isDynamicSelector = TenantManagementState[fnName].name !== 'memoized'; |
|||
|
|||
if (isDynamicSelector) { |
|||
TenantManagementState[fnName] = jest.fn((...args) => args); |
|||
service[fnName]('test', 0, {}); |
|||
expect(TenantManagementState[fnName]).toHaveBeenCalledWith('test', 0, {}); |
|||
} else { |
|||
service[fnName](); |
|||
expect(spy).toHaveBeenCalledWith(TenantManagementState[fnName]); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
test('should have a dispatch method for every TenantManagementState action', () => { |
|||
const reg = /(?<=dispatch)(\w+)(?=\()/gm; |
|||
TenantManagementStateService.toString() |
|||
.match(reg) |
|||
.forEach(fnName => { |
|||
expect(TenantManagementActions[fnName]).toBeTruthy(); |
|||
|
|||
const spy = jest.spyOn(store, 'dispatch'); |
|||
spy.mockClear(); |
|||
|
|||
const params = Array.from(new Array(TenantManagementActions[fnName].length)); |
|||
|
|||
service[`dispatch${fnName}`](...params); |
|||
expect(spy).toHaveBeenCalledWith(new TenantManagementActions[fnName](...params)); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -1,10 +1,7 @@ |
|||
export * from './lib/actions'; |
|||
export * from './lib/components'; |
|||
export * from './lib/enums'; |
|||
export * from './lib/guards'; |
|||
export * from './lib/models'; |
|||
export * from './lib/proxy'; |
|||
export * from './lib/services'; |
|||
export * from './lib/states'; |
|||
export * from './lib/tenant-management.module'; |
|||
export * from './lib/tokens'; |
|||
|
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue