Merge branch 'master' into ft/to-wachter

This commit is contained in:
Rinat Arsaev 2022-08-29 12:00:25 +03:00
commit 4a469a0751
356 changed files with 3021 additions and 4880 deletions

View File

@ -43,7 +43,7 @@ module.exports = {
{ {
...baseTsRules, ...baseTsRules,
// TODO: add fixed directories // TODO: add fixed directories
files: ['**/src/app/core/**/*.ts'], files: ['**/src/app/core/**/*.ts', '**/projects/**/*.ts'],
}, },
{ {
...baseTsRules, ...baseTsRules,

2
.github/settings.yml vendored Normal file
View File

@ -0,0 +1,2 @@
# These settings are synced to GitHub by https://probot.github.io/apps/settings/
_extends: .github

10
.github/workflows/basic-linters.yml vendored Normal file
View File

@ -0,0 +1,10 @@
name: Vality basic linters
on:
pull_request:
branches:
- "*"
jobs:
lint:
uses: valitydev/base-workflows/.github/workflows/basic-linters.yml@v1

View File

@ -9,6 +9,8 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: ./.github/actions/init - uses: ./.github/actions/init
- name: Building libraries
run: npm run build-libs
- name: Cache all - name: Cache all
uses: actions/cache@v3 uses: actions/cache@v3
id: cache id: cache
@ -16,7 +18,7 @@ jobs:
path: ./* path: ./*
key: ${{ github.sha }} key: ${{ github.sha }}
eslint: eslint:
name: ESLint name: ESLint App
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [init] needs: [init]
steps: steps:
@ -27,7 +29,20 @@ jobs:
path: ./* path: ./*
key: ${{ github.sha }} key: ${{ github.sha }}
- name: Check - name: Check
run: npm run lint-cmd run: npm run lint
eslint-libs:
name: ESLint Libs
runs-on: ubuntu-latest
needs: [init]
steps:
- name: Cache all
uses: actions/cache@v3
id: cache
with:
path: ./*
key: ${{ github.sha }}
- name: Check
run: npm run lint-libs
prettier: prettier:
name: Prettier name: Prettier
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -53,4 +68,4 @@ jobs:
path: ./* path: ./*
key: ${{ github.sha }} key: ${{ github.sha }}
- name: Build - name: Build
run: npm run build run: npm run build-app

View File

@ -3,4 +3,7 @@ package-lock.json
node_modules node_modules
dist dist
src/assets/icons/ src/assets/icons/
.angular .angular
.github/settings.*
.github/workflows/basic-*

View File

@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="App Dev Server" type="js.build_tools.npm" activateToolWindowBeforeRun="false">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="dev" />
</scripts>
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
</component>

5
.run/Debug.run.xml Normal file
View File

@ -0,0 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Debug" type="JavascriptDebugType" uri="http://localhost:4200">
<method v="2" />
</configuration>
</component>

View File

@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Libs Dev Server" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="dev-libs" />
</scripts>
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
</component>

7
.run/Start.run.xml Normal file
View File

@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Start" type="CompoundRunConfigurationType">
<toRun name="App Dev Server" type="js.build_tools.npm" />
<toRun name="Libs Dev Server" type="js.build_tools.npm" />
<method v="2" />
</configuration>
</component>

View File

@ -1,3 +1,3 @@
FROM nginx:1.21 FROM nginx:1.21
COPY dist /usr/share/nginx/html COPY dist/control-center /usr/share/nginx/html
COPY nginx.conf /etc/nginx/vhosts.d/control-center.conf COPY nginx.conf /etc/nginx/vhosts.d/control-center.conf

View File

@ -173,4 +173,4 @@
incurred by, or claims asserted against, such Contributor by reason incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability. of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS

View File

@ -40,3 +40,10 @@
npm start npm start
``` ```
2. Open [localhost:4200](http://localhost:4200/) 2. Open [localhost:4200](http://localhost:4200/)
If you want to develop a library, then it's better to start building library separately:
```sh
npm run dev
npm run dev-libs
```

View File

@ -37,9 +37,10 @@
"@vality/payout-manager-proto", "@vality/payout-manager-proto",
"@vality/repairer-proto", "@vality/repairer-proto",
"@vality/fistful-proto", "@vality/fistful-proto",
"@vality/file-storage-proto" "@vality/file-storage-proto",
"@vality/thrift-ts"
], ],
"outputPath": "dist", "outputPath": "dist/control-center",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
@ -143,6 +144,37 @@
} }
} }
} }
},
"ng-core": {
"projectType": "library",
"root": "projects/ng-core",
"sourceRoot": "projects/ng-core/src",
"prefix": "v",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "projects/ng-core/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/ng-core/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "projects/ng-core/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/ng-core/src/test.ts",
"tsConfig": "projects/ng-core/tsconfig.spec.json",
"karmaConfig": "projects/ng-core/karma.conf.js"
}
}
}
} }
}, },
"cli": { "cli": {

1131
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,17 +4,22 @@
"private": true, "private": true,
"scripts": { "scripts": {
"postinstall": "ngcc", "postinstall": "ngcc",
"start": "ng serve --proxy-config proxy.conf.js --port 4200", "start": "concurrently -n LIB,APP -c magenta,cyan npm:dev-libs \"sleep 0.5 && npm run dev\"",
"build": "ng build --extra-webpack-config webpack.extra.js", "dev": "ng serve --proxy-config proxy.conf.js --port 4200",
"dev-libs": "ng build ng-core --watch",
"build-app": "ng build --extra-webpack-config webpack.extra.js",
"build-libs": "ng build ng-core",
"build": "npm run build-libs && npm run build-app",
"test": "ng test", "test": "ng test",
"lint-cmd": "eslint \"src/**/*.{ts,js,html}\" --max-warnings 1115", "lint": "eslint \"src/**/*.{ts,js,html}\" --max-warnings 1033",
"lint": "npm run lint-cmd -- --cache",
"lint-fix": "npm run lint -- --fix", "lint-fix": "npm run lint -- --fix",
"lint-errors": "npm run lint -- --quiet", "lint-errors": "npm run lint -- --quiet",
"lint-libs": "eslint \"projects/**/*.{ts,js,html}\" --max-warnings 0",
"lint-libs-fix": "npm run lint -- --fix",
"prettier-preset": "prettier \"**/*.{html,js,ts,css,scss,md,json,prettierrc,svg,huskyrc,yml,yaml}\"", "prettier-preset": "prettier \"**/*.{html,js,ts,css,scss,md,json,prettierrc,svg,huskyrc,yml,yaml}\"",
"prettier": "npm run prettier-preset -- --list-different", "prettier": "npm run prettier-preset -- --list-different",
"prettier:fix": "npm run prettier-preset -- --write", "prettier-fix": "npm run prettier-preset -- --write",
"fix": "npm run lint-fix; npm run prettier:fix" "fix": "concurrently -n LIB,APP -c magenta,cyan npm:lint-libs-fix npm:lint-fix && npm run prettier-fix"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "14.0.4", "@angular/animations": "14.0.4",
@ -37,7 +42,7 @@
"@s-libs/ng-core": "14.0.0", "@s-libs/ng-core": "14.0.0",
"@s-libs/rxjs-core": "14.0.0", "@s-libs/rxjs-core": "14.0.0",
"@vality/deanonimus-proto": "1.0.1-c9a6cae.0", "@vality/deanonimus-proto": "1.0.1-c9a6cae.0",
"@vality/domain-proto": "1.0.1-9362c08.0", "@vality/domain-proto": "1.0.1-09e7a75.0",
"@vality/dominant-cache-proto": "1.0.1-5b29d81.0", "@vality/dominant-cache-proto": "1.0.1-5b29d81.0",
"@vality/file-storage-proto": "1.0.1-447212b.0", "@vality/file-storage-proto": "1.0.1-447212b.0",
"@vality/fistful-proto": "1.0.1-ea0fe7a.0", "@vality/fistful-proto": "1.0.1-ea0fe7a.0",
@ -86,6 +91,7 @@
"@types/uuid": "3.4.3", "@types/uuid": "3.4.3",
"@typescript-eslint/eslint-plugin": "^5.29.0", "@typescript-eslint/eslint-plugin": "^5.29.0",
"@typescript-eslint/parser": "^5.29.0", "@typescript-eslint/parser": "^5.29.0",
"concurrently": "7.3.0",
"dotenv": "16.0.0", "dotenv": "16.0.0",
"eslint": "8.20.0", "eslint": "8.20.0",
"eslint-config-prettier": "8.5.0", "eslint-config-prettier": "8.5.0",
@ -103,11 +109,12 @@
"karma-coverage-istanbul-reporter": "3.0.3", "karma-coverage-istanbul-reporter": "3.0.3",
"karma-jasmine": "5.1.0", "karma-jasmine": "5.1.0",
"karma-jasmine-html-reporter": "2.0.0", "karma-jasmine-html-reporter": "2.0.0",
"ng-packagr": "14.1.0",
"ngx-build-plus": "14.0.0", "ngx-build-plus": "14.0.0",
"prettier": "2.7.1", "prettier": "2.7.1",
"prettier-plugin-organize-attributes": "0.0.5", "prettier-plugin-organize-attributes": "0.0.5",
"ts-mockito": "2.6.1", "ts-mockito": "2.6.1",
"ts-node": "8.8.2", "ts-node": "10.9.1",
"typescript": "4.7.4" "typescript": "4.7.4"
} }
} }

View File

@ -0,0 +1,16 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR

View File

@ -0,0 +1 @@
package.json

View File

@ -0,0 +1,25 @@
# NgCore
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.0.0.
## Code scaffolding
Run `ng generate component component-name --project ng-core` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ng-core`.
> Note: Don't forget to add `--project ng-core` or else it will be added to the default project in your `angular.json` file.
## Build
Run `ng build ng-core` to build the project. The build artifacts will be stored in the `dist/` directory.
## Publishing
After building your library with `ng build ng-core`, go to the dist folder `cd dist/ng-core` and run `npm publish`.
## Running unit tests
Run `ng test ng-core` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

View File

@ -0,0 +1,41 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma'),
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false, // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true, // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, '../../coverage/ng-core'),
subdir: '.',
reporters: [{ type: 'html' }, { type: 'text-summary' }],
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true,
});
};

View File

@ -0,0 +1,7 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/ng-core",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

@ -0,0 +1,11 @@
{
"name": "@vality/ng-core",
"version": "0.0.1",
"peerDependencies": {
"@angular/common": "^14.0.0",
"@angular/core": "^14.0.0"
},
"dependencies": {
"tslib": "^2.3.0"
}
}

View File

@ -0,0 +1,2 @@
export * from './actions.module';
export * from './actions.component';

View File

@ -9,7 +9,7 @@ import { BaseDialogResponseStatus } from './types/base-dialog-response-status';
styleUrls: ['base-dialog.component.scss'], styleUrls: ['base-dialog.component.scss'],
}) })
export class BaseDialogComponent { export class BaseDialogComponent {
@Input() title: string; @Input() title!: string;
@coerceBoolean @Input() disabled = false; @coerceBoolean @Input() disabled = false;
@coerceBoolean @Input() inProgress = false; @coerceBoolean @Input() inProgress = false;

View File

@ -7,8 +7,7 @@ import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatProgressBarModule } from '@angular/material/progress-bar';
import { ActionsModule } from '@cc/components/actions'; import { ActionsModule } from '../actions';
import { BaseDialogComponent } from './base-dialog.component'; import { BaseDialogComponent } from './base-dialog.component';
import { BaseDialogActionsComponent } from './components/base-dialog-actions/base-dialog-actions.component'; import { BaseDialogActionsComponent } from './components/base-dialog-actions/base-dialog-actions.component';
@ -21,7 +20,6 @@ const SHARED_DECLARATIONS = [BaseDialogComponent, BaseDialogActionsComponent];
MatDividerModule, MatDividerModule,
MatButtonModule, MatButtonModule,
ActionsModule, ActionsModule,
ActionsModule,
MatIconModule, MatIconModule,
MatProgressBarModule, MatProgressBarModule,
MatDialogModule, MatDialogModule,

View File

@ -0,0 +1,8 @@
export * from './base-dialog.module';
export * from './types/base-dialog-response-status';
export * from './types/base-dialog-response';
export * from './utils/base-dialog-superclass';
export * from './tokens';
export * from './base-dialog.component';
export * from './components/base-dialog-actions/base-dialog-actions.component';
export * from './services/base-dialog.service';

View File

@ -1,9 +1,10 @@
import { ComponentType } from '@angular/cdk/overlay'; import { ComponentType } from '@angular/cdk/overlay';
import { Inject, Injectable } from '@angular/core'; import { Inject, Injectable, Optional } from '@angular/core';
import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog';
import { DIALOG_CONFIG, DialogConfig } from '@cc/app/tokens'; import { DEFAULT_DIALOG_CONFIG, DIALOG_CONFIG, DialogConfig } from '../tokens';
import { BaseDialogResponse, BaseDialogSuperclass } from '@cc/components/base-dialog'; import { BaseDialogResponse } from '../types/base-dialog-response';
import { BaseDialogSuperclass } from '../utils/base-dialog-superclass';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
@ -11,8 +12,12 @@ import { BaseDialogResponse, BaseDialogSuperclass } from '@cc/components/base-di
export class BaseDialogService { export class BaseDialogService {
constructor( constructor(
private dialog: MatDialog, private dialog: MatDialog,
@Inject(DIALOG_CONFIG) private dialogConfig: DialogConfig @Optional()
) {} @Inject(DIALOG_CONFIG)
private readonly dialogConfig: DialogConfig
) {
if (!dialogConfig) this.dialogConfig = DEFAULT_DIALOG_CONFIG;
}
open<C, D, R, S>( open<C, D, R, S>(
dialogComponent: ComponentType<BaseDialogSuperclass<C, D, R, S>>, dialogComponent: ComponentType<BaseDialogSuperclass<C, D, R, S>>,
@ -25,12 +30,16 @@ export class BaseDialogService {
? [] ? []
: [data: D, configOrConfigName?: Omit<MatDialogConfig<D>, 'data'> | keyof DialogConfig] : [data: D, configOrConfigName?: Omit<MatDialogConfig<D>, 'data'> | keyof DialogConfig]
): MatDialogRef<C, BaseDialogResponse<R, S>> { ): MatDialogRef<C, BaseDialogResponse<R, S>> {
let config: Partial<MatDialogConfig<D>>;
if (!configOrConfigName) config = {};
else if (typeof configOrConfigName === 'string')
config = this.dialogConfig[configOrConfigName];
else config = configOrConfigName;
return this.dialog.open(dialogComponent as never, { return this.dialog.open(dialogComponent as never, {
data, data,
...(dialogComponent as typeof BaseDialogSuperclass).defaultDialogConfig, ...(dialogComponent as typeof BaseDialogSuperclass).defaultDialogConfig,
...(typeof configOrConfigName === 'string' ...config,
? this.dialogConfig[configOrConfigName]
: configOrConfigName),
}); });
} }
} }

View File

@ -0,0 +1,20 @@
import { InjectionToken } from '@angular/core';
import { MatDialogConfig } from '@angular/material/dialog';
import { ValuesType } from 'utility-types';
export type DialogConfig = Record<'small' | 'medium' | 'large', MatDialogConfig<undefined>>;
export const DIALOG_CONFIG = new InjectionToken<DialogConfig>('dialogConfig');
export const BASE_CONFIG: ValuesType<DialogConfig> = {
maxHeight: '90vh',
disableClose: true,
autoFocus: false,
width: '552px',
};
export const DEFAULT_DIALOG_CONFIG: DialogConfig = {
small: { ...BASE_CONFIG, width: '360px' },
medium: BASE_CONFIG,
large: { ...BASE_CONFIG, width: '800px' },
};

View File

@ -1,4 +1,4 @@
import { BaseDialogResponseStatus } from '@cc/components/base-dialog'; import { BaseDialogResponseStatus } from './base-dialog-response-status';
export interface BaseDialogResponse<T = void, S = void> { export interface BaseDialogResponse<T = void, S = void> {
status: S | BaseDialogResponseStatus; status: S | BaseDialogResponseStatus;

View File

@ -1,9 +1,9 @@
import { Directive, Injector } from '@angular/core'; import { Directive, Injector } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { DEFAULT_DIALOG_CONFIG } from '@cc/app/tokens'; import { DEFAULT_DIALOG_CONFIG } from '../tokens';
import { BaseDialogResponse } from '../types/base-dialog-response'; import { BaseDialogResponse } from '../types/base-dialog-response';
import { BaseDialogResponseStatus } from '../types/base-dialog-response-status';
@Directive() @Directive()
export class BaseDialogSuperclass< export class BaseDialogSuperclass<
@ -19,4 +19,25 @@ export class BaseDialogSuperclass<
dialogRef = this.injector.get(MatDialogRef) as MatDialogRef<DialogComponent, DialogResponse>; dialogRef = this.injector.get(MatDialogRef) as MatDialogRef<DialogComponent, DialogResponse>;
constructor(private injector: Injector) {} constructor(private injector: Injector) {}
closeWithCancellation(data?: DialogResponseData) {
this.dialogRef.close({
status: BaseDialogResponseStatus.Cancelled,
data,
} as never);
}
closeWithSuccess(data?: DialogResponseData) {
this.dialogRef.close({
status: BaseDialogResponseStatus.Success,
data,
} as never);
}
closeWithError(data?: DialogResponseData) {
this.dialogRef.close({
status: BaseDialogResponseStatus.Error,
data,
} as never);
}
} }

View File

@ -0,0 +1,2 @@
export * from './actions';
export * from './base-dialog';

View File

@ -0,0 +1,2 @@
export * from './components';
export * from './utils';

View File

@ -0,0 +1,45 @@
import isEmpty from 'lodash-es/isEmpty';
import isNil from 'lodash-es/isNil';
import isObject from 'lodash-es/isObject';
import { ValuesType } from 'utility-types';
function isEmptyPrimitive(value: unknown): boolean {
return isNil(value) || value === '';
}
function isEmptyObjectOrPrimitive(value: unknown): boolean {
return isObject(value) ? isEmpty(value) : isEmptyPrimitive(value);
}
export function clean<T>(
value: T,
allowRootRemoval = false,
isNotDeep = false,
filterPredicate: (v: unknown, k?: PropertyKey) => boolean = (v) => !isEmptyObjectOrPrimitive(v)
): T | null {
if (!isObject(value)) return value;
if (allowRootRemoval && !filterPredicate(value as never)) return null;
let result: unknown;
const cleanChild = (v: unknown) =>
isNotDeep ? v : clean(v as never, allowRootRemoval, isNotDeep, filterPredicate);
if (Array.isArray(value))
result = (value as ValuesType<T>[])
.slice()
.map((v) => cleanChild(v))
.filter((v, idx) => filterPredicate(v, idx));
else
result = Object.fromEntries(
(Object.entries(value) as [keyof T, ValuesType<T>][])
.map(([k, v]) => [k, cleanChild(v)] as const)
.filter(([k, v]) => filterPredicate(v, k))
);
return allowRootRemoval && !filterPredicate(result) ? null : (result as never);
}
export function cleanPrimitiveProps<T extends object>(
obj: T,
allowRootRemoval = false,
isNotDeep = false
) {
return clean(obj, allowRootRemoval, isNotDeep, (v) => !isEmptyPrimitive(v));
}

View File

@ -0,0 +1 @@
export * from './clean';

View File

@ -0,0 +1,5 @@
/*
* Public API Surface of ng-core
*/
export * from './lib';

View File

@ -0,0 +1,29 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting,
} from '@angular/platform-browser-dynamic/testing';
// eslint-disable-next-line @typescript-eslint/naming-convention
declare const require: {
context(
path: string,
deep?: boolean,
filter?: RegExp
): {
<T>(id: string): T;
keys(): string[];
};
};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().forEach(context);

View File

@ -0,0 +1,21 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/lib",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": [],
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitAny": true
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true,
"strictTemplates": true
},
"exclude": ["src/test.ts", "**/*.spec.ts"]
}

View File

@ -0,0 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.lib.json",
"compilerOptions": {
"declarationMap": false
},
"angularCompilerOptions": {
"compilationMode": "partial"
}
}

View File

@ -0,0 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/spec",
"types": ["jasmine"]
},
"files": ["src/test.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts"]
}

View File

@ -1 +1,2 @@
export * from './party-management.service'; export * from './party-management.service';
export * from './invoicing.service';

View File

@ -0,0 +1,22 @@
import { Injectable, Injector } from '@angular/core';
import {
codegenClientConfig,
CodegenClient,
} from '@vality/domain-proto/lib/payment_processing-Invoicing';
import context from '@vality/domain-proto/lib/payment_processing/context';
import * as service from '@vality/domain-proto/lib/payment_processing/gen-nodejs/Invoicing';
import { createThriftApi } from '@cc/app/api/utils';
@Injectable({ providedIn: 'root' })
export class InvoicingService extends createThriftApi<CodegenClient>() {
constructor(injector: Injector) {
super(injector, {
service,
path: '/v1/processing/invoicing',
metadata: () => import('@vality/domain-proto/lib/metadata.json').then((m) => m.default),
context,
...codegenClientConfig,
});
}
}

View File

@ -26,7 +26,6 @@ import { DomainModule } from './domain';
import icons from './icons.json'; import icons from './icons.json';
import { NotFoundModule } from './not-found'; import { NotFoundModule } from './not-found';
import { RepairingModule } from './repairing/repairing.module'; import { RepairingModule } from './repairing/repairing.module';
import { ClaimModule } from './sections/claim';
import { DomainConfigModule } from './sections/domain-config'; import { DomainConfigModule } from './sections/domain-config';
import { OperationsModule } from './sections/operations/operations.module'; import { OperationsModule } from './sections/operations/operations.module';
import { PaymentAdjustmentModule } from './sections/payment-adjustment/payment-adjustment.module'; import { PaymentAdjustmentModule } from './sections/payment-adjustment/payment-adjustment.module';
@ -36,12 +35,10 @@ import { SearchPartiesModule } from './sections/search-parties/search-parties.mo
import { SectionsModule } from './sections/sections.module'; import { SectionsModule } from './sections/sections.module';
import { ThemeManager, ThemeManagerModule, ThemeName } from './theme-manager'; import { ThemeManager, ThemeManagerModule, ThemeName } from './theme-manager';
import { import {
DEFAULT_DIALOG_CONFIG,
DEFAULT_MAT_DATE_FORMATS, DEFAULT_MAT_DATE_FORMATS,
DEFAULT_QUERY_PARAMS_SERIALIZERS, DEFAULT_QUERY_PARAMS_SERIALIZERS,
DEFAULT_SEARCH_LIMIT, DEFAULT_SEARCH_LIMIT,
DEFAULT_SMALL_SEARCH_LIMIT, DEFAULT_SMALL_SEARCH_LIMIT,
DIALOG_CONFIG,
SEARCH_LIMIT, SEARCH_LIMIT,
SMALL_SEARCH_LIMIT, SMALL_SEARCH_LIMIT,
} from './tokens'; } from './tokens';
@ -49,7 +46,7 @@ import {
/** /**
* For use in specific locations (for example, questionary PDF document) * For use in specific locations (for example, questionary PDF document)
*/ */
moment.locale('en'); moment.locale('en-GB');
@NgModule({ @NgModule({
declarations: [AppComponent], declarations: [AppComponent],
@ -74,7 +71,6 @@ moment.locale('en');
DomainConfigModule, DomainConfigModule,
KeycloakTokenInfoModule, KeycloakTokenInfoModule,
PayoutsModule, PayoutsModule,
ClaimModule,
SectionsModule, SectionsModule,
// It is important that NotFoundModule module should be last // It is important that NotFoundModule module should be last
NotFoundModule, NotFoundModule,
@ -83,11 +79,10 @@ moment.locale('en');
{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } }, { provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } },
{ provide: MAT_DATE_FORMATS, useValue: DEFAULT_MAT_DATE_FORMATS }, { provide: MAT_DATE_FORMATS, useValue: DEFAULT_MAT_DATE_FORMATS },
{ provide: DateAdapter, useClass: MomentUtcDateAdapter, deps: [MAT_DATE_LOCALE] }, { provide: DateAdapter, useClass: MomentUtcDateAdapter, deps: [MAT_DATE_LOCALE] },
{ provide: MAT_DATE_LOCALE, useValue: 'en' }, { provide: MAT_DATE_LOCALE, useValue: 'ru' },
{ provide: LOCALE_ID, useValue: 'en' }, { provide: LOCALE_ID, useValue: 'en' },
{ provide: SEARCH_LIMIT, useValue: DEFAULT_SEARCH_LIMIT }, { provide: SEARCH_LIMIT, useValue: DEFAULT_SEARCH_LIMIT },
{ provide: SMALL_SEARCH_LIMIT, useValue: DEFAULT_SMALL_SEARCH_LIMIT }, { provide: SMALL_SEARCH_LIMIT, useValue: DEFAULT_SMALL_SEARCH_LIMIT },
{ provide: DIALOG_CONFIG, useValue: DEFAULT_DIALOG_CONFIG },
{ provide: QUERY_PARAMS_SERIALIZERS, useValue: DEFAULT_QUERY_PARAMS_SERIALIZERS }, { provide: QUERY_PARAMS_SERIALIZERS, useValue: DEFAULT_QUERY_PARAMS_SERIALIZERS },
], ],
bootstrap: [AppComponent], bootstrap: [AppComponent],

View File

@ -9,7 +9,7 @@ import { ClaimComponent } from './claim.component';
imports: [ imports: [
RouterModule.forChild([ RouterModule.forChild([
{ {
path: 'party/:partyID/claim/:claimID/new', path: '',
component: ClaimComponent, component: ClaimComponent,
canActivate: [AppAuthGuardService], canActivate: [AppAuthGuardService],
data: { data: {

View File

@ -1,6 +1,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { BaseDialogResponseStatus, BaseDialogService } from '@vality/ng-core';
import { import {
BehaviorSubject, BehaviorSubject,
combineLatest, combineLatest,
@ -19,8 +20,6 @@ import { ChangeStatusDialogComponent } from '@cc/app/sections/claim/components/c
import { AllowedClaimStatusesService } from '@cc/app/sections/claim/services/allowed-claim-statuses.service'; import { AllowedClaimStatusesService } from '@cc/app/sections/claim/services/allowed-claim-statuses.service';
import { UploadFileService } from '@cc/app/sections/claim/services/upload-file.service'; import { UploadFileService } from '@cc/app/sections/claim/services/upload-file.service';
import { NotificationService } from '@cc/app/shared/services/notification'; import { NotificationService } from '@cc/app/shared/services/notification';
import { BaseDialogResponseStatus } from '@cc/components/base-dialog';
import { BaseDialogService } from '@cc/components/base-dialog/services/base-dialog.service';
import { getUnionKey, inProgressFrom, progressTo } from '@cc/utils'; import { getUnionKey, inProgressFrom, progressTo } from '@cc/utils';
import { AddModificationDialogComponent } from './components/add-modification-dialog/add-modification-dialog.component'; import { AddModificationDialogComponent } from './components/add-modification-dialog/add-modification-dialog.component';

View File

@ -15,16 +15,15 @@ import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { ActionsModule, BaseDialogModule } from '@vality/ng-core';
import { ngfModule } from 'angular-file'; import { ngfModule } from 'angular-file';
import { MetadataFormModule, StatusModule } from '@cc/app/shared/components'; import { MetadataFormModule, StatusModule } from '@cc/app/shared/components';
import { JsonViewerModule } from '@cc/app/shared/components/json-viewer/json-viewer.module'; import { JsonViewerModule } from '@cc/app/shared/components/json-viewer/json-viewer.module';
import { ThriftPipesModule } from '@cc/app/shared/pipes'; import { ThriftPipesModule } from '@cc/app/shared/pipes';
import { ActionsModule } from '@cc/components/actions';
import { BaseDialogModule } from '@cc/components/base-dialog';
import { TimelineModule } from '@cc/components/timeline'; import { TimelineModule } from '@cc/components/timeline';
import { TimelineComponentsModule } from '../party-claim/changeset/timeline-components'; import { HumanizeDurationModule } from '../../shared/pipes/humanize-duration';
import { ClaimRoutingModule } from './claim-routing.module'; import { ClaimRoutingModule } from './claim-routing.module';
import { ClaimComponent } from './claim.component'; import { ClaimComponent } from './claim.component';
import { AddModificationDialogComponent } from './components/add-modification-dialog/add-modification-dialog.component'; import { AddModificationDialogComponent } from './components/add-modification-dialog/add-modification-dialog.component';
@ -34,6 +33,8 @@ import { ModificationFormComponent } from './components/modification-form/modifi
import { ModificationUnitTimelineItemComponent } from './components/modification-unit-timeline-item/modification-unit-timeline-item.component'; import { ModificationUnitTimelineItemComponent } from './components/modification-unit-timeline-item/modification-unit-timeline-item.component';
import { ShopModificationTimelineItemComponent } from './components/shop-modification-timeline-item/shop-modification-timeline-item.component'; import { ShopModificationTimelineItemComponent } from './components/shop-modification-timeline-item/shop-modification-timeline-item.component';
import { StatusModificationTimelineItemComponent } from './components/status-modification-timeline-item/status-modification-timeline-item.component'; import { StatusModificationTimelineItemComponent } from './components/status-modification-timeline-item/status-modification-timeline-item.component';
import { TimelineItemHeaderComponent } from './components/timeline-item-header/timeline-item-header.component';
import { TimelineItemLoadingComponent } from './components/timeline-item-loading/timeline-item-loading.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -45,6 +46,8 @@ import { StatusModificationTimelineItemComponent } from './components/status-mod
AddModificationDialogComponent, AddModificationDialogComponent,
ChangeStatusDialogComponent, ChangeStatusDialogComponent,
ModificationFormComponent, ModificationFormComponent,
TimelineItemHeaderComponent,
TimelineItemLoadingComponent,
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -53,7 +56,6 @@ import { StatusModificationTimelineItemComponent } from './components/status-mod
RouterModule, RouterModule,
TimelineModule, TimelineModule,
MatIconModule, MatIconModule,
TimelineComponentsModule,
ThriftPipesModule, ThriftPipesModule,
MatExpansionModule, MatExpansionModule,
JsonViewerModule, JsonViewerModule,
@ -73,6 +75,7 @@ import { StatusModificationTimelineItemComponent } from './components/status-mod
MatProgressBarModule, MatProgressBarModule,
BaseDialogModule, BaseDialogModule,
ActionsModule, ActionsModule,
HumanizeDurationModule,
], ],
}) })
export class ClaimModule {} export class ClaimModule {}

View File

@ -9,12 +9,15 @@ import {
PartyModificationChange, PartyModificationChange,
} from '@vality/domain-proto/lib/claim_management'; } from '@vality/domain-proto/lib/claim_management';
import { Party } from '@vality/domain-proto/lib/domain'; import { Party } from '@vality/domain-proto/lib/domain';
import {
BaseDialogResponseStatus,
BaseDialogSuperclass,
DEFAULT_DIALOG_CONFIG,
} from '@vality/ng-core';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { ClaimManagementService } from '@cc/app/api/claim-management'; import { ClaimManagementService } from '@cc/app/api/claim-management';
import { NotificationService } from '@cc/app/shared/services/notification'; import { NotificationService } from '@cc/app/shared/services/notification';
import { DEFAULT_DIALOG_CONFIG } from '@cc/app/tokens';
import { BaseDialogResponseStatus, BaseDialogSuperclass } from '@cc/components/base-dialog';
import { inProgressFrom, progressTo } from '@cc/utils'; import { inProgressFrom, progressTo } from '@cc/utils';
@UntilDestroy() @UntilDestroy()

View File

@ -2,12 +2,12 @@ import { Component, Injector } from '@angular/core';
import { Validators, FormBuilder } from '@angular/forms'; import { Validators, FormBuilder } from '@angular/forms';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { Claim, ClaimStatus } from '@vality/domain-proto/lib/claim_management'; import { Claim, ClaimStatus } from '@vality/domain-proto/lib/claim_management';
import { BaseDialogResponseStatus, BaseDialogSuperclass } from '@vality/ng-core';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { ClaimManagementService } from '@cc/app/api/claim-management'; import { ClaimManagementService } from '@cc/app/api/claim-management';
import { AllowedClaimStatusesService } from '@cc/app/sections/claim/services/allowed-claim-statuses.service'; import { AllowedClaimStatusesService } from '@cc/app/sections/claim/services/allowed-claim-statuses.service';
import { NotificationService } from '@cc/app/shared/services/notification'; import { NotificationService } from '@cc/app/shared/services/notification';
import { BaseDialogResponseStatus, BaseDialogSuperclass } from '@cc/components/base-dialog';
import { getUnionKey, inProgressFrom, progressTo } from '@cc/utils'; import { getUnionKey, inProgressFrom, progressTo } from '@cc/utils';
@UntilDestroy() @UntilDestroy()

View File

@ -2,10 +2,10 @@ import { Component, Injector, Input, OnChanges } from '@angular/core';
import { Validator } from '@angular/forms'; import { Validator } from '@angular/forms';
import { Claim } from '@vality/domain-proto/lib/claim_management'; import { Claim } from '@vality/domain-proto/lib/claim_management';
import { Party } from '@vality/domain-proto/lib/domain'; import { Party } from '@vality/domain-proto/lib/domain';
import { from, Observable } from 'rxjs'; import { from, combineLatest, ReplaySubject, defer } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { ComponentChanges, MetadataFormExtension } from '@cc/app/shared'; import { ComponentChanges } from '@cc/app/shared';
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services/domain-metadata-form-extensions'; import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services/domain-metadata-form-extensions';
import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils'; import { createControlProviders, ValidatedFormControlSuperclass } from '@cc/utils';
@ -25,7 +25,14 @@ export class ModificationFormComponent
@Input() type: string; @Input() type: string;
metadata$ = from(import('@vality/domain-proto/lib/metadata.json').then((m) => m.default)); metadata$ = from(import('@vality/domain-proto/lib/metadata.json').then((m) => m.default));
extensions$: Observable<MetadataFormExtension[]>; extensions$ = combineLatest([
defer(() => this.claimOrPartyChanged$).pipe(
map(() => createPartyClaimMetadataFormExtensions(this.party, this.claim))
),
this.domainMetadataFormExtensionsService.extensions$,
]).pipe(map((extensionGroups) => extensionGroups.flat()));
private claimOrPartyChanged$ = new ReplaySubject<void>(1);
constructor( constructor(
injector: Injector, injector: Injector,
@ -37,12 +44,7 @@ export class ModificationFormComponent
ngOnChanges(changes: ComponentChanges<ModificationFormComponent>) { ngOnChanges(changes: ComponentChanges<ModificationFormComponent>) {
super.ngOnChanges(changes); super.ngOnChanges(changes);
if (changes.party || changes.claim) { if (changes.party || changes.claim) {
this.extensions$ = this.domainMetadataFormExtensionsService.extensions$.pipe( this.claimOrPartyChanged$.next();
map((e) => [
...createPartyClaimMetadataFormExtensions(this.party, this.claim),
...e,
])
);
} }
} }
} }

View File

@ -109,9 +109,5 @@ export function createPartyClaimMetadataFormExtensions(
isIdentifier: true, isIdentifier: true,
}), }),
}, },
{
determinant: (data) => of(isTypeWithAliases(data, 'ID', 'base')),
extension: () => of({ generate, isIdentifier: true }),
},
]; ];
} }

View File

@ -1,6 +1,7 @@
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { Claim, ModificationUnit } from '@vality/domain-proto/lib/claim_management'; import { Claim, ModificationUnit } from '@vality/domain-proto/lib/claim_management';
import { BaseDialogResponseStatus, BaseDialogService } from '@vality/ng-core';
import { coerceBoolean } from 'coerce-property'; import { coerceBoolean } from 'coerce-property';
import isEmpty from 'lodash-es/isEmpty'; import isEmpty from 'lodash-es/isEmpty';
import { BehaviorSubject, switchMap } from 'rxjs'; import { BehaviorSubject, switchMap } from 'rxjs';
@ -12,8 +13,6 @@ import { getModificationName } from '@cc/app/sections/claim/utils/get-modificati
import { Patch } from '@cc/app/shared/components/json-viewer'; import { Patch } from '@cc/app/shared/components/json-viewer';
import { NotificationService } from '@cc/app/shared/services/notification'; import { NotificationService } from '@cc/app/shared/services/notification';
import { Color, StatusColor } from '@cc/app/styles'; import { Color, StatusColor } from '@cc/app/styles';
import { BaseDialogResponseStatus } from '@cc/components/base-dialog';
import { BaseDialogService } from '@cc/components/base-dialog/services/base-dialog.service';
import { ConfirmActionDialogComponent } from '@cc/components/confirm-action-dialog'; import { ConfirmActionDialogComponent } from '@cc/components/confirm-action-dialog';
import { inProgressFrom, progressTo } from '@cc/utils'; import { inProgressFrom, progressTo } from '@cc/utils';
import { getUnionValue } from '@cc/utils/get-union-key'; import { getUnionValue } from '@cc/utils/get-union-key';

View File

@ -1,5 +1,6 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BaseDialogResponseStatus, BaseDialogService } from '@vality/ng-core';
import moment from 'moment'; import moment from 'moment';
import { switchMap } from 'rxjs'; import { switchMap } from 'rxjs';
import { filter, map } from 'rxjs/operators'; import { filter, map } from 'rxjs/operators';
@ -7,8 +8,6 @@ import { filter, map } from 'rxjs/operators';
import { ClaimManagementService } from '@cc/app/api/claim-management'; import { ClaimManagementService } from '@cc/app/api/claim-management';
import { FileStorageService } from '@cc/app/api/file-storage'; import { FileStorageService } from '@cc/app/api/file-storage';
import { NotificationService } from '@cc/app/shared/services/notification'; import { NotificationService } from '@cc/app/shared/services/notification';
import { BaseDialogResponseStatus } from '@cc/components/base-dialog';
import { BaseDialogService } from '@cc/components/base-dialog/services/base-dialog.service';
import { ConfirmActionDialogComponent } from '@cc/components/confirm-action-dialog'; import { ConfirmActionDialogComponent } from '@cc/components/confirm-action-dialog';
@Injectable() @Injectable()

View File

@ -1,7 +0,0 @@
@import './changeset/timeline-components/timeline-item-loading/timeline-item-loading-theme';
@import './party-claim-title/party-claim-title-theme';
@mixin cc-party-claim-theme($theme) {
@include cc-party-claim-title-theme($theme);
@include cc-timeline-item-loading-theme($theme);
}

View File

@ -1,27 +0,0 @@
import { Modification, UserInfo } from '@vality/domain-proto/lib/claim_management';
/* eslint-disable @typescript-eslint/naming-convention */
export enum ChangesetInfoType {
partyModification = 'partyModification',
commentModification = 'commentModification',
fileModification = 'fileModification',
documentModification = 'documentModification',
statusModification = 'statusModification',
}
export enum ChangesetInfoModificationType {
creation = 'creation',
deletion = 'deletion',
}
/* eslint-enable @typescript-eslint/naming-convention */
export interface ChangesetInfo {
createdAt: string;
modification: Modification;
userInfo: UserInfo;
type: ChangesetInfoType;
modificationType: ChangesetInfoModificationType;
hash: string;
outdated?: boolean;
removed?: boolean;
}

View File

@ -1,2 +0,0 @@
export * from './to-changeset-infos';
export * from './changeset-info';

View File

@ -1,9 +0,0 @@
import { ChangesetInfo } from './changeset-info';
export const markOutdated = (infos: ChangesetInfo[], hash: string): ChangesetInfo[] =>
infos.map((info) => {
if (info.hash === hash) {
info.outdated = true;
}
return info;
});

View File

@ -1,9 +0,0 @@
import { ChangesetInfo } from './changeset-info';
export const markRemoved = (infos: ChangesetInfo[], hash: string): ChangesetInfo[] =>
infos.map((info) => {
if (info.hash === hash) {
info.removed = true;
}
return info;
});

View File

@ -1,43 +0,0 @@
import { ModificationUnit } from '@vality/domain-proto/lib/claim_management';
import { ChangesetInfo, ChangesetInfoType } from './changeset-info';
import { toCommentModificationChangesetInfo } from './to-comment-modification-changeset-info';
import { toDocumentModificationChangesetInfo } from './to-document-modification-changeset-info';
import { toFileModificationChangesetInfo } from './to-file-modification-changeset-info';
import { toPartyModificationChangesetInfo } from './to-party-modification-changeset-info';
import { toStatusModificationChangesetInfo } from './to-status-modification-changeset-info';
const getModificationType = (unit: ModificationUnit): ChangesetInfoType | null => {
if (unit.modification.party_modification) {
return ChangesetInfoType.partyModification;
} else if (unit.modification.claim_modification.comment_modification) {
return ChangesetInfoType.commentModification;
} else if (unit.modification.claim_modification.file_modification) {
return ChangesetInfoType.fileModification;
} else if (unit.modification.claim_modification.document_modification) {
return ChangesetInfoType.documentModification;
} else if (unit.modification.claim_modification.status_modification) {
return ChangesetInfoType.statusModification;
} else {
return null;
}
};
export const toChangesetInfos = (units: ModificationUnit[]): ChangesetInfo[] =>
units.reduce((acc, cur) => {
switch (getModificationType(cur)) {
case ChangesetInfoType.partyModification:
return toPartyModificationChangesetInfo(acc, cur);
case ChangesetInfoType.commentModification:
return toCommentModificationChangesetInfo(acc, cur);
case ChangesetInfoType.fileModification:
return toFileModificationChangesetInfo(acc, cur);
case ChangesetInfoType.documentModification:
return toDocumentModificationChangesetInfo(acc, cur);
case ChangesetInfoType.statusModification:
return toStatusModificationChangesetInfo(acc, cur);
default:
console.error('Changeset infos: Unknown type', cur);
return acc;
}
}, []);

View File

@ -1,38 +0,0 @@
import { CommentModification, ModificationUnit } from '@vality/domain-proto/lib/claim_management';
import { getUnionKey } from '@cc/utils/get-union-key';
import { ChangesetInfo, ChangesetInfoModificationType, ChangesetInfoType } from './changeset-info';
import { markRemoved } from './mark-removed';
const getCommentChangesetInfoHash = (unit: ModificationUnit): string =>
`${ChangesetInfoType.commentModification}.${unit.modification.claim_modification.comment_modification.id}`;
const commentModificationType = (mod: CommentModification): ChangesetInfoModificationType => {
switch (getUnionKey(mod)) {
case 'creation':
return ChangesetInfoModificationType.creation;
case 'deletion':
return ChangesetInfoModificationType.deletion;
}
};
const makeCommentChangesetInfo = (unit: ModificationUnit): ChangesetInfo =>
({
createdAt: unit.created_at,
modification: unit.modification,
userInfo: unit.user_info,
type: ChangesetInfoType.commentModification,
hash: getCommentChangesetInfoHash(unit),
modificationType: commentModificationType(
unit.modification.claim_modification.comment_modification.modification
),
} as ChangesetInfo);
export const toCommentModificationChangesetInfo = (
infos: ChangesetInfo[],
unit: ModificationUnit
): ChangesetInfo[] => {
const commentChangesetInfo = makeCommentChangesetInfo(unit);
return [...markRemoved(infos, commentChangesetInfo.hash), commentChangesetInfo];
};

View File

@ -1,23 +0,0 @@
import { ModificationUnit } from '@vality/domain-proto/lib/claim_management';
import { ChangesetInfo, ChangesetInfoType } from './changeset-info';
import { markOutdated } from './mark-outdated';
const getDocumentChangesetInfoHash = (): string => `${ChangesetInfoType.documentModification}`;
const makeDocumentChangesetInfo = (unit: ModificationUnit): ChangesetInfo =>
({
createdAt: unit.created_at,
modification: unit.modification,
userInfo: unit.user_info,
type: ChangesetInfoType.documentModification,
hash: getDocumentChangesetInfoHash(),
} as ChangesetInfo);
export const toDocumentModificationChangesetInfo = (
infos: ChangesetInfo[],
unit: ModificationUnit
): ChangesetInfo[] => {
const documentChangesetInfo = makeDocumentChangesetInfo(unit);
return [...markOutdated(infos, documentChangesetInfo.hash), documentChangesetInfo];
};

View File

@ -1,38 +0,0 @@
import { FileModification, ModificationUnit } from '@vality/domain-proto/lib/claim_management';
import { getUnionKey } from '@cc/utils/get-union-key';
import { ChangesetInfo, ChangesetInfoModificationType, ChangesetInfoType } from './changeset-info';
import { markRemoved } from './mark-removed';
const getFileChangesetInfoHash = (unit: ModificationUnit): string =>
`${ChangesetInfoType.fileModification}.${unit.modification.claim_modification.file_modification.id}`;
const fileModificationType = (mod: FileModification): ChangesetInfoModificationType => {
switch (getUnionKey(mod)) {
case 'creation':
return ChangesetInfoModificationType.creation;
case 'deletion':
return ChangesetInfoModificationType.deletion;
}
};
const makeFileChangesetInfo = (unit: ModificationUnit): ChangesetInfo =>
({
createdAt: unit.created_at,
modification: unit.modification,
userInfo: unit.user_info,
type: ChangesetInfoType.fileModification,
hash: getFileChangesetInfoHash(unit),
modificationType: fileModificationType(
unit.modification.claim_modification.file_modification.modification
),
} as ChangesetInfo);
export const toFileModificationChangesetInfo = (
infos: ChangesetInfo[],
unit: ModificationUnit
): ChangesetInfo[] => {
const fileChangesetInfo = makeFileChangesetInfo(unit);
return [...markRemoved(infos, fileChangesetInfo.hash), fileChangesetInfo];
};

View File

@ -1,31 +0,0 @@
import { ModificationUnit } from '@vality/domain-proto/lib/claim_management';
import { getUnionKey } from '@cc/utils/get-union-key';
import { ChangesetInfo, ChangesetInfoType } from './changeset-info';
import { markOutdated } from './mark-outdated';
const getHash = (m: any, acc: string = ''): string => {
if (m.id && m.modification) {
return `${acc}.${getUnionKey(m.modification) as string}`;
}
const unionKey = getUnionKey(m) as string;
return getHash(m[unionKey], `${acc}.${unionKey}`);
};
const makePartyChangesetInfo = (unit: ModificationUnit): ChangesetInfo =>
({
createdAt: unit.created_at,
modification: unit.modification,
userInfo: unit.user_info,
type: ChangesetInfoType.partyModification,
hash: getHash(unit.modification),
} as ChangesetInfo);
export const toPartyModificationChangesetInfo = (
infos: ChangesetInfo[],
unit: ModificationUnit
): ChangesetInfo[] => {
const partyChangesetInfo = makePartyChangesetInfo(unit);
return [...markOutdated(infos, partyChangesetInfo.hash), partyChangesetInfo];
};

View File

@ -1,17 +0,0 @@
import { ModificationUnit } from '@vality/domain-proto/lib/claim_management';
import { ChangesetInfo, ChangesetInfoType } from './changeset-info';
const makeStatusChangesetInfo = (unit: ModificationUnit): ChangesetInfo =>
({
createdAt: unit.created_at,
modification: unit.modification,
userInfo: unit.user_info,
type: ChangesetInfoType.statusModification,
hash: ChangesetInfoType.statusModification,
} as ChangesetInfo);
export const toStatusModificationChangesetInfo = (
infos: ChangesetInfo[],
unit: ModificationUnit
): ChangesetInfo[] => [...infos, makeStatusChangesetInfo(unit)];

View File

@ -1,35 +0,0 @@
<form [formGroup]="changesetsFilterForm">
<mat-form-field fxFlex>
<mat-label>Changeset filters</mat-label>
<mat-select formControlName="filters" multiple>
<mat-option class="changeset-filter-option" value="outdated"
>Hide outdated changes</mat-option
>
<mat-option class="changeset-filter-option" value="removed"
>Hide removed changes</mat-option
>
<mat-optgroup label="Modification filters">
<mat-option
[value]="changesetInfoType.partyModification"
class="changeset-filter-option"
>Party mods</mat-option
>
<mat-option
[value]="changesetInfoType.fileModification"
class="changeset-filter-option"
>Files</mat-option
>
<mat-option
[value]="changesetInfoType.commentModification"
class="changeset-filter-option"
>Comments</mat-option
>
<mat-option
[value]="changesetInfoType.documentModification"
class="changeset-filter-option"
>Documents</mat-option
>
</mat-optgroup>
</mat-select>
</mat-form-field>
</form>

View File

@ -1,3 +0,0 @@
::ng-deep .mat-select-panel {
max-height: 300px !important;
}

View File

@ -1,31 +0,0 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { ChangesetInfo, ChangesetInfoType } from '../changeset-infos';
import { ChangesetsFilterService } from './changesets-filter.service';
@Component({
selector: 'cc-changesets-filter',
templateUrl: 'changesets-filter.component.html',
styleUrls: ['changesets-filter.component.scss'],
providers: [ChangesetsFilterService],
})
export class ChangesetsFilterComponent implements OnInit {
@Input()
set changesetInfos(v: ChangesetInfo[]) {
this.changesetsFilterService.setChangesetInfos(v);
}
@Output()
filterChange: EventEmitter<ChangesetInfo[]> = new EventEmitter();
changesetsFilterForm = this.changesetsFilterService.changesetsFilterForm;
changesetInfoType = ChangesetInfoType;
constructor(private changesetsFilterService: ChangesetsFilterService) {}
ngOnInit(): void {
this.changesetsFilterService.filteredChangesetInfos$.subscribe((infos) => {
this.filterChange.emit(infos);
});
}
}

View File

@ -1,14 +0,0 @@
import { NgModule } from '@angular/core';
import { FlexModule } from '@angular/flex-layout';
import { ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
import { ChangesetsFilterComponent } from './changesets-filter.component';
@NgModule({
declarations: [ChangesetsFilterComponent],
imports: [ReactiveFormsModule, MatFormFieldModule, MatSelectModule, FlexModule],
exports: [ChangesetsFilterComponent],
})
export class ChangesetsFilterModule {}

View File

@ -1,42 +0,0 @@
import { Injectable } from '@angular/core';
import { UntypedFormBuilder } from '@angular/forms';
import { combineLatest, Subject } from 'rxjs';
import { map, shareReplay, startWith } from 'rxjs/operators';
import { ChangesetInfo, ChangesetInfoType } from '../changeset-infos';
import { infosFilter } from './infos-filter';
@Injectable()
export class ChangesetsFilterService {
private changesetInfos$ = new Subject<ChangesetInfo[]>();
// eslint-disable-next-line @typescript-eslint/member-ordering
changesetsFilterForm = this.fb.group({
filters: [
[
ChangesetInfoType.documentModification,
ChangesetInfoType.commentModification,
ChangesetInfoType.fileModification,
ChangesetInfoType.partyModification,
ChangesetInfoType.statusModification,
],
],
});
// eslint-disable-next-line @typescript-eslint/member-ordering
filteredChangesetInfos$ = combineLatest([
this.changesetInfos$,
this.changesetsFilterForm.valueChanges.pipe(startWith(this.changesetsFilterForm.value)),
]).pipe(
map(([infos, { filters }]) => infos.filter((info) => infosFilter(info, filters))),
shareReplay(1)
);
constructor(private fb: UntypedFormBuilder) {
this.filteredChangesetInfos$.subscribe();
}
setChangesetInfos(changesetInfos: ChangesetInfo[]) {
this.changesetInfos$.next(changesetInfos);
}
}

View File

@ -1 +0,0 @@
export * from './changesets-filter.module';

View File

@ -1,13 +0,0 @@
import { ChangesetInfo } from '../changeset-infos';
export const infosFilter = (info: ChangesetInfo, filters: string[]) => {
if (
filters.length === 0 ||
(info.outdated && filters.includes('outdated')) ||
(info.removed && filters.includes('removed'))
) {
return false;
} else {
return filters.includes(info.type);
}
};

View File

@ -1,39 +0,0 @@
<div fxLayout="column" fxLayoutGap="24px">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="16px">
<h3 class="cc-title">Changeset</h3>
<cc-changesets-filter
[changesetInfos]="changesetInfos$ | async"
fxFlex="0 1 266px"
(filterChange)="filterChange($event)"
></cc-changesets-filter>
</div>
<cc-timeline>
<cc-created-timeline-item [createdAt]="createdAt"></cc-created-timeline-item>
<ng-container
*ngFor="let info of filteredChangesetInfos; let i = index; trackBy: simpleTrackBy"
>
<cc-file-timeline-item
*ngIf="info.type === changesetInfoType.fileModification"
[changesetInfo]="info"
[menuConfig]="fileMenuConfig"
(menuItemSelected)="menuItemSelected($event, i)"
></cc-file-timeline-item>
<cc-comment-timeline-item
*ngIf="info.type === changesetInfoType.commentModification"
[changesetInfo]="info"
[menuConfig]="commentMenuConfig"
(menuItemSelected)="menuItemSelected($event, i)"
></cc-comment-timeline-item>
<cc-party-modification-timeline-item
*ngIf="info.type === changesetInfoType.partyModification"
[changesetInfo]="info"
[menuConfig]="partyModMenuConfig"
(menuItemSelected)="menuItemSelected($event, i)"
></cc-party-modification-timeline-item>
<cc-status-timeline-item
*ngIf="info.type === changesetInfoType.statusModification"
[changesetInfo]="info"
></cc-status-timeline-item>
</ng-container>
</cc-timeline>
</div>

View File

@ -1,53 +0,0 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { PartyID } from '@vality/domain-proto';
import { ClaimChangeset } from '@vality/domain-proto/lib/claim_management';
import { BehaviorSubject } from 'rxjs';
import { ChangesetInfo, ChangesetInfoType, toChangesetInfos } from '../changeset-infos';
import { MenuConfigAction, MenuConfigItem } from '../timeline-items/menu-config';
import { ClaimChangesetService } from './claim-changeset.service';
@Component({
selector: 'cc-claim-changeset',
templateUrl: 'claim-changeset.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [ClaimChangesetService],
})
export class ClaimChangesetComponent {
@Input()
createdAt: string;
@Input()
set changeset(v: ClaimChangeset) {
this.changesetInfos$.next(toChangesetInfos(v));
}
@Input()
partyID: PartyID;
fileMenuConfig: MenuConfigItem[] = [
{ action: MenuConfigAction.deleteFile, label: 'Delete file' },
];
commentMenuConfig: MenuConfigItem[] = [
{ action: MenuConfigAction.deleteComment, label: 'Delete comment' },
];
partyModMenuConfig: MenuConfigItem[] = [];
changesetInfoType = ChangesetInfoType;
changesetInfos$ = new BehaviorSubject<ChangesetInfo[]>([]);
filteredChangesetInfos: ChangesetInfo[] = [];
constructor(private claimChangesetService: ClaimChangesetService) {}
simpleTrackBy(index: number): number {
return index;
}
filterChange($event: ChangesetInfo[]) {
this.filteredChangesetInfos = $event;
}
menuItemSelected($event: MenuConfigItem, i: number) {
this.claimChangesetService.menuItemSelected($event, this.changesetInfos$.getValue(), i);
}
}

View File

@ -1,38 +0,0 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FlexModule } from '@angular/flex-layout';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { PartyModificationFormsModule } from '@cc/app/shared/components';
import { TimelineModule } from '@cc/components/timeline';
import { ChangesetsFilterModule } from '../changesets-filter';
import { CommentTimelineItemModule } from '../timeline-items/comment-timeline-item/comment-timeline-item.module';
import { CreatedTimelineItemModule } from '../timeline-items/created-timeline-item';
import { FileTimelineItemModule } from '../timeline-items/file-timeline-item/file-timeline-item.module';
import { PartyModificationTimelineItemModule } from '../timeline-items/party-modification-timeline-item/party-modification-timeline-item.module';
import { StatusTimelineItemModule } from '../timeline-items/status-timeline-item/status-timeline-item.module';
import { SaveClaimChangesetService } from '../unsaved-changeset/save-claim-changeset.service';
import { ClaimChangesetComponent } from './claim-changeset.component';
@NgModule({
imports: [
FlexModule,
CommonModule,
ChangesetsFilterModule,
TimelineModule,
MatDialogModule,
MatButtonModule,
PartyModificationFormsModule,
CreatedTimelineItemModule,
FileTimelineItemModule,
CommentTimelineItemModule,
PartyModificationTimelineItemModule,
StatusTimelineItemModule,
],
declarations: [ClaimChangesetComponent],
providers: [SaveClaimChangesetService],
exports: [ClaimChangesetComponent],
})
export class ClaimChangesetModule {}

View File

@ -1,30 +0,0 @@
import { Injectable } from '@angular/core';
import { ChangesetInfo } from '../changeset-infos';
import { MenuConfigAction, MenuConfigItem } from '../timeline-items/menu-config';
import { UnsavedClaimChangesetService } from '../unsaved-changeset/unsaved-claim-changeset.service';
import { createDeleteCommentModification } from './create-delete-comment-modification';
import { createDeleteFileModification } from './create-delete-file-modification';
@Injectable()
export class ClaimChangesetService {
constructor(private unsavedClaimChangesetService: UnsavedClaimChangesetService) {}
menuItemSelected($event: MenuConfigItem, changesetInfos: ChangesetInfo[], index: number) {
const changesetInfo = changesetInfos[index];
switch ($event.action) {
case MenuConfigAction.deleteComment:
this.unsavedClaimChangesetService.addModification(
createDeleteCommentModification(changesetInfo)
);
break;
case MenuConfigAction.deleteFile:
this.unsavedClaimChangesetService.addModification(
createDeleteFileModification(changesetInfo)
);
break;
default:
console.warn('Unsupported method', $event);
}
}
}

View File

@ -1,14 +0,0 @@
import { Modification } from '@vality/domain-proto/lib/claim_management';
import { ChangesetInfo } from '../changeset-infos';
export const createDeleteCommentModification = (info: ChangesetInfo): Modification => ({
claim_modification: {
comment_modification: {
id: info.modification.claim_modification.comment_modification.id,
modification: {
deletion: {},
},
},
},
});

View File

@ -1,14 +0,0 @@
import { Modification } from '@vality/domain-proto/lib/claim_management';
import { ChangesetInfo } from '../changeset-infos';
export const createDeleteFileModification = (info: ChangesetInfo): Modification => ({
claim_modification: {
file_modification: {
id: info.modification.claim_modification.file_modification.id,
modification: {
deletion: {},
},
},
},
});

View File

@ -1,2 +0,0 @@
export * from './claim-changeset/claim-changeset.module';
export * from './unsaved-changeset/unsaved-claim-changeset.module';

View File

@ -1 +0,0 @@
export * from './timeline-components.module';

View File

@ -1,23 +0,0 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { HumanizeDurationModule } from '@cc/app/shared/pipes/humanize-duration';
import { TimelineItemErrorComponent } from './timeline-item-error/timeline-item-error.component';
import { TimelineItemHeaderComponent } from './timeline-item-header/timeline-item-header.component';
import { TimelineItemLoadingComponent } from './timeline-item-loading/timeline-item-loading.component';
@NgModule({
declarations: [
TimelineItemLoadingComponent,
TimelineItemErrorComponent,
TimelineItemHeaderComponent,
],
imports: [CommonModule, HumanizeDurationModule],
exports: [
TimelineItemLoadingComponent,
TimelineItemErrorComponent,
TimelineItemHeaderComponent,
],
})
export class TimelineComponentsModule {}

View File

@ -1,11 +0,0 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
@Component({
selector: 'cc-timeline-item-error',
templateUrl: 'timeline-item-error.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TimelineItemErrorComponent {
@Input()
text: string;
}

View File

@ -1,17 +0,0 @@
import { Pipe, PipeTransform } from '@angular/core';
import { ChangesetInfoModificationType } from '../../changeset-infos';
@Pipe({
name: 'ccCommentActionIcon',
})
export class CommentActionIconPipe implements PipeTransform {
transform(type: ChangesetInfoModificationType): string {
return (
{
[ChangesetInfoModificationType.creation]: 'add_comment',
[ChangesetInfoModificationType.deletion]: 'clear',
} as const
)[type];
}
}

View File

@ -1,17 +0,0 @@
import { Pipe, PipeTransform } from '@angular/core';
import { ChangesetInfoModificationType } from '../../changeset-infos';
@Pipe({
name: 'ccCommentBadgeColor',
})
export class CommentBadgeColorPipe implements PipeTransform {
transform(type: ChangesetInfoModificationType): 'primary' | 'warn' | 'error' | 'success' {
return (
{
[ChangesetInfoModificationType.creation]: 'primary',
[ChangesetInfoModificationType.deletion]: null,
} as const
)[type];
}
}

View File

@ -1,5 +0,0 @@
<mat-card>
<mat-card-content>
{{ text }}
</mat-card-content>
</mat-card>

View File

@ -1,10 +0,0 @@
import { Component, Input } from '@angular/core';
@Component({
selector: 'cc-comment-content',
templateUrl: 'comment-content.component.html',
})
export class CommentContentComponent {
@Input()
text: string;
}

View File

@ -1,17 +0,0 @@
import { Pipe, PipeTransform } from '@angular/core';
import { ChangesetInfoModificationType } from '../../changeset-infos';
@Pipe({
name: 'ccCommentHeader',
})
export class CommentHeaderPipe implements PipeTransform {
transform(type: ChangesetInfoModificationType): string {
return (
{
[ChangesetInfoModificationType.creation]: 'added message',
[ChangesetInfoModificationType.deletion]: 'removed message',
} as const
)[type];
}
}

View File

@ -1,39 +0,0 @@
<cc-timeline-item>
<cc-timeline-item-title>
<cc-timeline-item-header
[createdAt]="changesetInfo.createdAt"
[removed]="changesetInfo.removed"
[text]="changesetInfo.modificationType | ccCommentHeader"
[username]="changesetInfo.userInfo.username"
></cc-timeline-item-header>
<div *ngIf="menuConfig.length > 0">
<button [matMenuTriggerFor]="menu" mat-icon-button>
<mat-icon>more_horiz</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button *ngFor="let item of menuConfig" mat-menu-item (click)="action(item)">
{{ item.label }}
</button>
</mat-menu>
</div>
</cc-timeline-item-title>
<cc-timeline-item-badge
[color]="
changesetInfo.removed ? (changesetInfo.modificationType | ccCommentBadgeColor) : null
"
>
<mat-icon>{{ changesetInfo.modificationType | ccCommentActionIcon }}</mat-icon>
</cc-timeline-item-badge>
<cc-timeline-item-content fxLayout="column" fxLayoutGap="24px">
<cc-comment-content
*ngIf="message$ | async as message"
[text]="message.text"
></cc-comment-content>
<cc-timeline-item-loading *ngIf="isLoading$ | async"></cc-timeline-item-loading>
<cc-timeline-item-error
*ngIf="error$ | async as error"
[text]="error"
></cc-timeline-item-error>
</cc-timeline-item-content>
</cc-timeline-item>

Some files were not shown because too many files have changed in this diff Show More