mirror of https://github.com/abpframework/abp.git
8 changed files with 828 additions and 1190 deletions
@ -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,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 +1 @@ |
|||||
export * from './config.state'; |
|
||||
export * from './profile.state'; |
export * from './profile.state'; |
||||
|
|||||
File diff suppressed because it is too large
Loading…
Reference in new issue