mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
feat: add core-config and shared-product-image libraries; implement initial structure and configuration
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
||||
import { ErrorHandler, Injector, LOCALE_ID, NgModule, inject, provideAppInitializer } from '@angular/core';
|
||||
import {
|
||||
ErrorHandler,
|
||||
Injector,
|
||||
LOCALE_ID,
|
||||
NgModule,
|
||||
inject,
|
||||
provideAppInitializer,
|
||||
} from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { PlatformModule } from '@angular/cdk/platform';
|
||||
|
||||
import { Config, ConfigModule, JsonConfigLoader } from '@core/config';
|
||||
import { Config } from '@core/config';
|
||||
import { AuthModule, AuthService, LoginStrategy } from '@core/auth';
|
||||
import { CoreCommandModule } from '@core/command';
|
||||
|
||||
@@ -66,7 +73,6 @@ export function _appInitializerFactory(config: Config, injector: Injector) {
|
||||
}
|
||||
|
||||
statusElement.innerHTML = 'Konfigurationen werden geladen...';
|
||||
await config.init();
|
||||
|
||||
statusElement.innerHTML = 'Scanner wird initialisiert...';
|
||||
const scanAdapter = injector.get(ScanAdapterService);
|
||||
@@ -120,7 +126,10 @@ export function _appInitializerFactory(config: Config, injector: Injector) {
|
||||
};
|
||||
}
|
||||
|
||||
export function _notificationsHubOptionsFactory(config: Config, auth: AuthService): SignalRHubOptions {
|
||||
export function _notificationsHubOptionsFactory(
|
||||
config: Config,
|
||||
auth: AuthService,
|
||||
): SignalRHubOptions {
|
||||
const options = { ...config.get('hubs').notifications };
|
||||
options.httpOptions.accessTokenFactory = () => auth.getToken();
|
||||
return options;
|
||||
@@ -137,10 +146,6 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
|
||||
AppSwaggerModule,
|
||||
AppDomainModule,
|
||||
CoreBreadcrumbModule.forRoot(),
|
||||
ConfigModule.forRoot({
|
||||
useConfigLoader: JsonConfigLoader,
|
||||
jsonConfigLoaderUrl: '/config/config.json',
|
||||
}),
|
||||
CoreCommandModule.forRoot(Object.values(Commands)),
|
||||
CoreLoggerModule.forRoot(),
|
||||
AppStoreModule,
|
||||
@@ -186,7 +191,11 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
|
||||
},
|
||||
{ provide: LOCALE_ID, useValue: 'de-DE' },
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
provideMatomo({ trackerUrl: 'https://matomo.paragon-data.net', siteId: '1' }, withRouter(), withRouteData()),
|
||||
provideMatomo(
|
||||
{ trackerUrl: 'https://matomo.paragon-data.net', siteId: '1' },
|
||||
withRouter(),
|
||||
withRouteData(),
|
||||
),
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
/**
|
||||
* Config loader interface for loading configurations
|
||||
*/
|
||||
export interface ConfigLoader {
|
||||
load(): Promise<any>;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './config-loader';
|
||||
export * from './json.config-loader';
|
||||
// end:ng42.barrel
|
||||
@@ -1,36 +0,0 @@
|
||||
// // unit test JsonConfigLoader
|
||||
// import { HttpTestingController } from '@angular/common/http/testing';
|
||||
// import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
|
||||
// import { CORE_JSON_CONFIG_LOADER_URL } from '../tokens';
|
||||
// import { JsonConfigLoader } from './json.config-loader';
|
||||
|
||||
// describe('JsonConfigLoader', () => {
|
||||
// let spectator: SpectatorService<JsonConfigLoader>;
|
||||
// const createService = createServiceFactory({
|
||||
// imports: [HttpClientTestingModule],
|
||||
// service: JsonConfigLoader,
|
||||
// mocks: [],
|
||||
// providers: [{ provide: CORE_JSON_CONFIG_LOADER_URL, useValue: '/assets/config.json' }],
|
||||
// });
|
||||
// let httpTestingController: HttpTestingController;
|
||||
|
||||
// beforeEach(() => {
|
||||
// spectator = createService();
|
||||
// httpTestingController = spectator.inject(HttpTestingController);
|
||||
// });
|
||||
|
||||
// it('should create', () => {
|
||||
// expect(spectator.service).toBeTruthy();
|
||||
// });
|
||||
|
||||
// describe('load', () => {
|
||||
// it('should call the provided url', async () => {
|
||||
// const reqPromise = spectator.service.load();
|
||||
// const req = httpTestingController.expectOne('/assets/config.json');
|
||||
// req.flush({ unit: 'test' });
|
||||
// const result = await reqPromise;
|
||||
// httpTestingController.verify();
|
||||
// expect(result).toEqual({ unit: 'test' });
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
@@ -1,16 +0,0 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { ConfigLoader } from './config-loader';
|
||||
import { CORE_JSON_CONFIG_LOADER_URL } from '../tokens';
|
||||
|
||||
@Injectable()
|
||||
export class JsonConfigLoader implements ConfigLoader {
|
||||
constructor(
|
||||
@Inject(CORE_JSON_CONFIG_LOADER_URL) private url: string,
|
||||
private http: HttpClient,
|
||||
) {}
|
||||
|
||||
load(): Promise<any> {
|
||||
return this.http.get(this.url).toPromise();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { Type } from '@angular/core';
|
||||
import { ConfigLoader } from './config-loaders';
|
||||
|
||||
export interface ConfigModuleOptions {
|
||||
useConfigLoader: Type<ConfigLoader>;
|
||||
jsonConfigLoaderUrl?: string;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { CORE_CONFIG_LOADER } from '@core/config';
|
||||
import { Config } from './config';
|
||||
import { ConfigModuleOptions } from './config-module-options';
|
||||
import { CORE_JSON_CONFIG_LOADER_URL } from './tokens';
|
||||
|
||||
export function _initializeConfigFactory(config: Config) {
|
||||
return () => config.init();
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class ConfigModule {
|
||||
static forRoot(options: ConfigModuleOptions): ModuleWithProviders<ConfigModule> {
|
||||
const configLoaderProvider = {
|
||||
provide: CORE_CONFIG_LOADER,
|
||||
useClass: options.useConfigLoader,
|
||||
};
|
||||
|
||||
return {
|
||||
ngModule: ConfigModule,
|
||||
providers: [
|
||||
Config,
|
||||
configLoaderProvider,
|
||||
options.jsonConfigLoaderUrl
|
||||
? { provide: CORE_JSON_CONFIG_LOADER_URL, useValue: options.jsonConfigLoaderUrl }
|
||||
: null,
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
|
||||
import { Config } from './config';
|
||||
import { ConfigLoader } from './config-loaders';
|
||||
import { CORE_CONFIG_LOADER } from './tokens';
|
||||
|
||||
class TestConfigLoader implements ConfigLoader {
|
||||
load() {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
}
|
||||
|
||||
// Unit test Config
|
||||
describe('Config', () => {
|
||||
let spectator: SpectatorService<Config>;
|
||||
const createService = createServiceFactory({
|
||||
service: Config,
|
||||
providers: [{ provide: CORE_CONFIG_LOADER, useClass: TestConfigLoader }],
|
||||
});
|
||||
let configLoader: ConfigLoader;
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createService();
|
||||
configLoader = spectator.inject(CORE_CONFIG_LOADER);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.service).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('init()', () => {
|
||||
it('should load config and assigns it to _config', async () => {
|
||||
const config = { unit: 'test' };
|
||||
spyOn(configLoader, 'load').and.returnValue(Promise.resolve(config));
|
||||
await spectator.service.init();
|
||||
expect(spectator.service['_config']).toEqual(config);
|
||||
});
|
||||
});
|
||||
|
||||
describe('get()', () => {
|
||||
it('should return config value', () => {
|
||||
spectator.service['_config'] = { test: 'test' };
|
||||
expect(spectator.service.get('test')).toEqual('test');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import { ConfigLoader } from './config-loaders';
|
||||
import { CORE_CONFIG_LOADER } from './tokens';
|
||||
import { pick } from './utils';
|
||||
|
||||
@Injectable()
|
||||
export class Config {
|
||||
private _config: any;
|
||||
|
||||
private readonly _initilized = new ReplaySubject<void>(1);
|
||||
get initialized() {
|
||||
return this._initilized.asObservable();
|
||||
}
|
||||
|
||||
constructor(@Inject(CORE_CONFIG_LOADER) private readonly _configLoader: ConfigLoader) {}
|
||||
|
||||
// load config and assign it to this._config
|
||||
async init() {
|
||||
this._config = await this._configLoader.load();
|
||||
this._initilized.next();
|
||||
}
|
||||
|
||||
get(path: string) {
|
||||
return pick(path, this._config);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export * from './config-loaders';
|
||||
export * from './config-module-options';
|
||||
export * from './config.module';
|
||||
export * from './config';
|
||||
export * from './tokens';
|
||||
export * from './utils';
|
||||
@@ -1,6 +0,0 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import { ConfigLoader } from './config-loaders';
|
||||
|
||||
export const CORE_CONFIG_LOADER = new InjectionToken<ConfigLoader>('core.config.loader');
|
||||
|
||||
export const CORE_JSON_CONFIG_LOADER_URL = new InjectionToken<ConfigLoader>('core.json.config.loader.url');
|
||||
@@ -1,3 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './pick';
|
||||
// end:ng42.barrel
|
||||
@@ -1,41 +0,0 @@
|
||||
import { pick } from './pick';
|
||||
|
||||
describe('pick', () => {
|
||||
it('should pick properties from the 1st level from the object', () => {
|
||||
const obj = {
|
||||
foo: 'bar',
|
||||
};
|
||||
expect(pick('foo', obj)).toEqual('bar');
|
||||
});
|
||||
|
||||
it('should pick properties from the 2nd level from the object', () => {
|
||||
const obj = {
|
||||
foo: {
|
||||
bar: 'baz',
|
||||
},
|
||||
};
|
||||
expect(pick('foo.bar', obj)).toEqual('baz');
|
||||
});
|
||||
|
||||
it('should pick properties from the 3rd level from the object', () => {
|
||||
const obj = {
|
||||
foo: {
|
||||
bar: {
|
||||
baz: 'qux',
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(pick('foo.bar.baz', obj)).toEqual('qux');
|
||||
});
|
||||
|
||||
it('should throw an error of obj is not an object', () => {
|
||||
expect(() => pick('foo', 'bar')).toThrowError(`bar is not an object`);
|
||||
});
|
||||
|
||||
it('should return undefined if the property is not found', () => {
|
||||
const obj = {
|
||||
foo: 'bar',
|
||||
};
|
||||
expect(pick('bar', obj)).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Pick a value from an object at a given path.
|
||||
* @param path path of the value to pick
|
||||
* @param obj object to pick from
|
||||
* @returns the value at the path or undefined
|
||||
* @throws if obj is not an object
|
||||
*/
|
||||
export function pick<T = any>(path: string, obj: object): T {
|
||||
const paths = path.split('.');
|
||||
|
||||
// check if obj is null or undefined
|
||||
if (obj == null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// check if obj is of type object and not an array
|
||||
// and throw an error if not
|
||||
if (typeof obj !== 'object' || Array.isArray(obj)) {
|
||||
throw new Error(`${obj} is not an object`);
|
||||
}
|
||||
|
||||
let result = obj;
|
||||
|
||||
// loop through the path and pick the value
|
||||
// early exit if the path is empty
|
||||
for (const path of paths) {
|
||||
result = result[path];
|
||||
if (result == null) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return result as T;
|
||||
}
|
||||
@@ -1,42 +1,27 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { enableProdMode, isDevMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { CONFIG_DATA } from '@isa/core/config';
|
||||
import * as moment from 'moment';
|
||||
|
||||
moment.locale('de');
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { DebugService } from './app/debug/debug.service';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
if (!isDevMode()) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
const debugService = new DebugService();
|
||||
async function bootstrap() {
|
||||
const configRes = await fetch('/config/config.json');
|
||||
|
||||
if (environment.debug) {
|
||||
const consoleLog = console.log;
|
||||
const config = await configRes.json();
|
||||
|
||||
console.log = (...args) => {
|
||||
debugService.add({ type: 'log', args });
|
||||
consoleLog(...args);
|
||||
};
|
||||
|
||||
const consoleWarn = console.warn;
|
||||
|
||||
console.warn = (...args) => {
|
||||
debugService.add({ type: 'warn', args });
|
||||
consoleWarn(...args);
|
||||
};
|
||||
|
||||
const consoleError = console.error;
|
||||
|
||||
console.error = (...args) => {
|
||||
debugService.add({ type: 'error', args });
|
||||
consoleError(...args);
|
||||
};
|
||||
platformBrowserDynamic([{ provide: CONFIG_DATA, useValue: config }]).bootstrapModule(AppModule);
|
||||
}
|
||||
|
||||
try {
|
||||
bootstrap();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
platformBrowserDynamic([{ provide: DebugService, useValue: debugService }])
|
||||
.bootstrapModule(AppModule)
|
||||
.catch((err) => console.error(err));
|
||||
|
||||
7
libs/core/config/README.md
Normal file
7
libs/core/config/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# core-config
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test core-config` to execute the unit tests.
|
||||
34
libs/core/config/eslint.config.mjs
Normal file
34
libs/core/config/eslint.config.mjs
Normal file
@@ -0,0 +1,34 @@
|
||||
import nx from '@nx/eslint-plugin';
|
||||
import baseConfig from '../../../eslint.config.mjs';
|
||||
|
||||
export default [
|
||||
...baseConfig,
|
||||
...nx.configs['flat/angular'],
|
||||
...nx.configs['flat/angular-template'],
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
'@angular-eslint/directive-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'attribute',
|
||||
prefix: 'lib',
|
||||
style: 'camelCase',
|
||||
},
|
||||
],
|
||||
'@angular-eslint/component-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'element',
|
||||
prefix: 'lib',
|
||||
style: 'kebab-case',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.html'],
|
||||
// Override or add rules here
|
||||
rules: {},
|
||||
},
|
||||
];
|
||||
21
libs/core/config/jest.config.ts
Normal file
21
libs/core/config/jest.config.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export default {
|
||||
displayName: 'core-config',
|
||||
preset: '../../../jest.preset.js',
|
||||
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
||||
coverageDirectory: '../../../coverage/libs/core/config',
|
||||
transform: {
|
||||
'^.+\\.(ts|mjs|js|html)$': [
|
||||
'jest-preset-angular',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\.(html|svg)$',
|
||||
},
|
||||
],
|
||||
},
|
||||
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
|
||||
snapshotSerializers: [
|
||||
'jest-preset-angular/build/serializers/no-ng-attributes',
|
||||
'jest-preset-angular/build/serializers/ng-snapshot',
|
||||
'jest-preset-angular/build/serializers/html-comment',
|
||||
],
|
||||
};
|
||||
20
libs/core/config/project.json
Normal file
20
libs/core/config/project.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "core-config",
|
||||
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/core/config/src",
|
||||
"prefix": "lib",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "libs/core/config/jest.config.ts"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint"
|
||||
}
|
||||
}
|
||||
}
|
||||
1
libs/core/config/src/index.ts
Normal file
1
libs/core/config/src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './lib/config';
|
||||
33
libs/core/config/src/lib/config.ts
Normal file
33
libs/core/config/src/lib/config.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { inject, Injectable, InjectionToken } from '@angular/core';
|
||||
import { z } from 'zod';
|
||||
import { coerceArray } from '@angular/cdk/coercion';
|
||||
|
||||
type JsonPrimitive = string | number | boolean | null | undefined;
|
||||
|
||||
export type JsonValue = Array<JsonPrimitive> | Record<string, JsonPrimitive> | JsonPrimitive;
|
||||
|
||||
export const CONFIG_DATA = new InjectionToken<JsonValue>('ConfigData');
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class Config {
|
||||
#config = inject(CONFIG_DATA);
|
||||
|
||||
get(path: string | string[]): any;
|
||||
get<TOut>(path: string | string[], zSchema: z.ZodSchema<TOut>): TOut;
|
||||
get<TOut>(path: string | string[], zSchema?: z.ZodSchema<TOut>): TOut | any {
|
||||
let result: JsonValue = this.#config;
|
||||
|
||||
for (const p of coerceArray(path)) {
|
||||
if (typeof result === 'object' && result !== null && !Array.isArray(result)) {
|
||||
result = (result as Record<string, JsonPrimitive>)[p];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
if (result === null || result === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return zSchema ? zSchema.parse(result) : result;
|
||||
}
|
||||
}
|
||||
6
libs/core/config/src/test-setup.ts
Normal file
6
libs/core/config/src/test-setup.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
|
||||
|
||||
setupZoneTestEnv({
|
||||
errorOnUnknownElements: true,
|
||||
errorOnUnknownProperties: true,
|
||||
});
|
||||
28
libs/core/config/tsconfig.json
Normal file
28
libs/core/config/tsconfig.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
17
libs/core/config/tsconfig.lib.json
Normal file
17
libs/core/config/tsconfig.lib.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/test-setup.ts",
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts"
|
||||
],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
16
libs/core/config/tsconfig.spec.json
Normal file
16
libs/core/config/tsconfig.spec.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"target": "es2016",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"files": ["src/test-setup.ts"],
|
||||
"include": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
7
libs/shared/product-image/README.md
Normal file
7
libs/shared/product-image/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# shared-product-image
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test shared-product-image` to execute the unit tests.
|
||||
34
libs/shared/product-image/eslint.config.mjs
Normal file
34
libs/shared/product-image/eslint.config.mjs
Normal file
@@ -0,0 +1,34 @@
|
||||
import nx from '@nx/eslint-plugin';
|
||||
import baseConfig from '../../../eslint.config.mjs';
|
||||
|
||||
export default [
|
||||
...baseConfig,
|
||||
...nx.configs['flat/angular'],
|
||||
...nx.configs['flat/angular-template'],
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
'@angular-eslint/directive-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'attribute',
|
||||
prefix: 'shared',
|
||||
style: 'camelCase',
|
||||
},
|
||||
],
|
||||
'@angular-eslint/component-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'element',
|
||||
prefix: 'shared',
|
||||
style: 'kebab-case',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.html'],
|
||||
// Override or add rules here
|
||||
rules: {},
|
||||
},
|
||||
];
|
||||
21
libs/shared/product-image/jest.config.ts
Normal file
21
libs/shared/product-image/jest.config.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export default {
|
||||
displayName: 'shared-product-image',
|
||||
preset: '../../../jest.preset.js',
|
||||
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
||||
coverageDirectory: '../../../coverage/libs/shared/product-image',
|
||||
transform: {
|
||||
'^.+\\.(ts|mjs|js|html)$': [
|
||||
'jest-preset-angular',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\.(html|svg)$',
|
||||
},
|
||||
],
|
||||
},
|
||||
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
|
||||
snapshotSerializers: [
|
||||
'jest-preset-angular/build/serializers/no-ng-attributes',
|
||||
'jest-preset-angular/build/serializers/ng-snapshot',
|
||||
'jest-preset-angular/build/serializers/html-comment',
|
||||
],
|
||||
};
|
||||
20
libs/shared/product-image/project.json
Normal file
20
libs/shared/product-image/project.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "shared-product-image",
|
||||
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/shared/product-image/src",
|
||||
"prefix": "lib",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "libs/shared/product-image/jest.config.ts"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint"
|
||||
}
|
||||
}
|
||||
}
|
||||
1
libs/shared/product-image/src/index.ts
Normal file
1
libs/shared/product-image/src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './lib/product-image.service';
|
||||
26
libs/shared/product-image/src/lib/product-image.service.ts
Normal file
26
libs/shared/product-image/src/lib/product-image.service.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { inject, Injectable, InjectionToken } from '@angular/core';
|
||||
import { Config } from '@isa/core/config';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const PRODUCT_IMAGE_URL = new InjectionToken<string>('PRODUCT_IMAGE_URL', {
|
||||
factory: () => inject(Config).get('@cdn/product-image.url', z.string().url()),
|
||||
});
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ProductImageService {
|
||||
readonly imageUrl = inject(PRODUCT_IMAGE_URL);
|
||||
|
||||
getImageUrl({
|
||||
imageId,
|
||||
width = 150,
|
||||
height = 150,
|
||||
showDummy = true,
|
||||
}: {
|
||||
imageId: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
showDummy?: boolean;
|
||||
}): string {
|
||||
return `${this.imageUrl}/${imageId}_${width}x${height}.jpg?showDummy=${showDummy}`;
|
||||
}
|
||||
}
|
||||
6
libs/shared/product-image/src/test-setup.ts
Normal file
6
libs/shared/product-image/src/test-setup.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
|
||||
|
||||
setupZoneTestEnv({
|
||||
errorOnUnknownElements: true,
|
||||
errorOnUnknownProperties: true,
|
||||
});
|
||||
28
libs/shared/product-image/tsconfig.json
Normal file
28
libs/shared/product-image/tsconfig.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
17
libs/shared/product-image/tsconfig.lib.json
Normal file
17
libs/shared/product-image/tsconfig.lib.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/test-setup.ts",
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts"
|
||||
],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
16
libs/shared/product-image/tsconfig.spec.json
Normal file
16
libs/shared/product-image/tsconfig.spec.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"target": "es2016",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"files": ["src/test-setup.ts"],
|
||||
"include": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -43,9 +43,12 @@
|
||||
],
|
||||
"@generated/swagger/wws-api": ["generated/swagger/wws-api/src/index.ts"],
|
||||
"@hub/*": ["apps/isa-app/src/hub/*/index.ts"],
|
||||
"@isa/core/config": ["libs/core/config/src/index.ts"],
|
||||
"@core/config": ["libs/core/config/src/index.ts"], // fallback for old imports
|
||||
"@isa/core/process": ["libs/core/process/src/index.ts"],
|
||||
"@isa/icons": ["libs/icons/src/index.ts"],
|
||||
"@isa/shared/filter": ["libs/shared/filter/src/index.ts"],
|
||||
"@isa/shared/product-image": ["libs/shared/product-image/src/index.ts"],
|
||||
"@isa/ui/buttons": ["libs/ui/buttons/src/index.ts"],
|
||||
"@isa/ui/input-controls": ["libs/ui/input-controls/src/index.ts"],
|
||||
"@isa/ui/search-bar": ["libs/ui/search-bar/src/index.ts"],
|
||||
|
||||
Reference in New Issue
Block a user