TD-693: Update Prettier, ESLint (#141)

This commit is contained in:
Rinat Arsaev 2023-08-14 15:38:33 +04:00 committed by GitHub
parent 125d70bec1
commit eb3c5c6b32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
898 changed files with 9995 additions and 6407 deletions

View File

@ -1,8 +1,8 @@
name: Init
description: Init
runs:
using: composite
steps:
- uses: valitydev/action-frontend/setup@v0.1
- run: npm ci --force # TODO: Remove "--force" after updating Angular in external libraries (@vality)
shell: bash
using: composite
steps:
- uses: valitydev/action-frontend/setup@v0.1
- run: npm ci --force # TODO: Remove "--force" after updating Angular in external libraries (@vality)
shell: bash

View File

@ -1,18 +1,18 @@
name: Main
on:
push:
branches: ['master', 'main']
push:
branches: ['master', 'main']
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/init
- name: Build
run: npm run build
- name: Deploy image
uses: valitydev/action-deploy-docker@v2
with:
registry-username: ${{ github.actor }}
registry-access-token: ${{ secrets.GITHUB_TOKEN }}
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/init
- name: Build
run: npm run build
- name: Deploy image
uses: valitydev/action-deploy-docker@v2
with:
registry-username: ${{ github.actor }}
registry-access-token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,69 +1,69 @@
name: PR
on:
pull_request:
branches: ['*']
pull_request:
branches: ['*']
jobs:
init:
name: Initialization
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/init
- name: Cache all
uses: actions/cache@v3
id: cache
with:
path: ./*
key: ${{ github.sha }}
prettier:
name: Prettier check
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 prettier
eslint:
name: ESLint check
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
i18n:
name: Translation keys check
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 i18n:check
build:
name: Build
runs-on: ubuntu-latest
needs: [init]
steps:
- name: Cache all
uses: actions/cache@v3
id: cache
with:
path: ./*
key: ${{ github.sha }}
- name: Build
run: npm run build
init:
name: Initialization
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/init
- name: Cache all
uses: actions/cache@v3
id: cache
with:
path: ./*
key: ${{ github.sha }}
prettier:
name: Format check
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 format
eslint:
name: ESLint check
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
i18n:
name: Translation keys check
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 i18n:check
build:
name: Build
runs-on: ubuntu-latest
needs: [init]
steps:
- name: Cache all
uses: actions/cache@v3
id: cache
with:
path: ./*
key: ${{ github.sha }}
- name: Build
run: npm run build

View File

@ -1,16 +0,0 @@
{
"printWidth": 120,
"singleQuote": true,
"tabWidth": 4,
"endOfLine": "auto",
"overrides": [
{
"files": "*.svg",
"options": { "parser": "html" }
},
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}

1
.prettierrc.js Normal file
View File

@ -0,0 +1 @@
module.exports = require("@vality/prettier-config");

5836
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
"scripts": {
"start": "ng serve --proxy-config proxy.conf.js --port 8000",
"stage": "cross-env NODE_ENV=stage ng serve --proxy-config proxy.conf.js --port 8001 --configuration=stage",
"fix": "npm run lint:fix && npm run prettier-fix",
"fix": "npm run lint:fix && npm run format:fix",
"build": "ng build && transloco-optimize dist/assets/i18n",
"test": "ng test",
"i18n:extract": "transloco-keys-manager extract",
@ -15,32 +15,31 @@
"lint": "ng lint --max-warnings=0",
"lint:fix": "ng lint --fix",
"lint:errors": "ng lint --quiet",
"prettier-cmd": "prettier \"**/*.{html,js,ts,css,scss,md,json,prettierrc,svg,yaml,yml}\"",
"prettier": "npm run prettier-cmd -- --check",
"prettier-fix": "npm run prettier-cmd -- --write",
"format": "prettier * --list-different",
"format:fix": "prettier * --write --loglevel warn",
"tools-cmd": "ts-node --project tools/tsconfig.json",
"icons-list-gen": "npm run tools-cmd -- tools/gen-icons-list.ts",
"icons-ids-gen": "npm run tools-cmd -- tools/gen-icons-ids.ts",
"ci:test": "npm run test -- --configuration=ci"
},
"dependencies": {
"@angular/animations": "^16.1.2",
"@angular/cdk": "~16.1.2",
"@angular/common": "^16.1.2",
"@angular/compiler": "^16.1.2",
"@angular/core": "^16.1.2",
"@angular/flex-layout": "15.0.0-beta.42",
"@angular/forms": "^16.1.2",
"@angular/material": "~16.1.2",
"@angular/material-moment-adapter": "^16.1.2",
"@angular/platform-browser": "^16.1.2",
"@angular/platform-browser-dynamic": "^16.1.2",
"@angular/router": "^16.1.2",
"@angular/animations": "^16.2.0",
"@angular/cdk": "~16.2.0",
"@angular/common": "^16.2.0",
"@angular/compiler": "^16.2.0",
"@angular/core": "^16.2.0",
"@angular/flex-layout": "^15.0.0-beta.42",
"@angular/forms": "^16.2.0",
"@angular/material": "~16.2.0",
"@angular/material-moment-adapter": "^16.2.0",
"@angular/platform-browser": "^16.2.0",
"@angular/platform-browser-dynamic": "^16.2.0",
"@angular/router": "^16.2.0",
"@ngneat/transloco": "^4.3.0",
"@ngneat/until-destroy": "^9.0.0",
"@sentry/angular": "^7.56.0",
"@sentry/integrations": "^7.56.0",
"@sentry/tracing": "^7.56.0",
"@sentry/angular-ivy": "^7.63.0",
"@sentry/integrations": "^7.63.0",
"@sentry/tracing": "^7.63.0",
"@vality/ng-core": "^16.2.1-pr-33-c999544.0",
"@vality/swag-anapi-v2": "2.0.0",
"@vality/swag-api-keys-v2": "^0.1.2-870c41d.0",
@ -71,12 +70,12 @@
},
"devDependencies": {
"@angular-builders/custom-webpack": "^16.0.0",
"@angular-devkit/build-angular": "16.1.1",
"@angular-eslint/builder": "16.0.3",
"@angular-eslint/schematics": "16.0.3",
"@angular/cli": "16.1.1",
"@angular/compiler-cli": "16.1.2",
"@angular/language-service": "16.1.2",
"@angular-devkit/build-angular": "^16.2.0",
"@angular-eslint/builder": "^16.1.0",
"@angular-eslint/schematics": "^16.1.0",
"@angular/cli": "^16.2.0",
"@angular/compiler-cli": "^16.2.0",
"@angular/language-service": "^16.2.0",
"@ngneat/transloco-keys-manager": "^3.7.0",
"@ngneat/transloco-optimize": "^3.0.2",
"@types/d3": "^5.7.0",
@ -86,11 +85,12 @@
"@types/jwt-decode": "^3.1.0",
"@types/lodash-es": "4.17.6",
"@types/moment": "2.13.0",
"@types/prettier": "2.4.3",
"@vality/eslint-config": "0.1.1-2a1b72f.0",
"@types/prettier": "^3.0.0",
"@vality/eslint-config": "^8.0.1-pr-33-52841c7.0",
"@vality/prettier-config": "3.0.1-pr-33-52841c7.0",
"cross-env": "^7.0.3",
"dotenv": "^16.0.3",
"eslint": "^8.39.0",
"eslint": "^8.47.0",
"glob": "^7.1.6",
"jasmine-core": "~3.7.0",
"jasmine-marbles": "0.9.2",
@ -100,7 +100,7 @@
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"karma-spec-reporter": "0.0.32",
"prettier": "^2.8.7",
"prettier": "^3.0.1",
"ts-mockito": "^2.6.1",
"ts-node": "^10.9.1",
"typescript": "~5.1.3"

View File

@ -13,34 +13,94 @@ export class AnapiDictionaryService {
paymentTool$ = this.dictionaryService.create(() => ({
bank_card: this.t.translate('anapi.paymentTool.bank_card', null, 'dictionary'),
digital_wallet: this.t.translate('anapi.paymentTool.digital_wallet', null, 'dictionary'),
payment_terminal: this.t.translate('anapi.paymentTool.payment_terminal', null, 'dictionary'),
payment_terminal: this.t.translate(
'anapi.paymentTool.payment_terminal',
null,
'dictionary',
),
}));
errorCode$ = this.dictionaryService.create(() => ({
account_limit_exceeded: this.t.translate('anapi.errorCode.account_limit_exceeded', null, 'dictionary'),
account_not_found: this.t.translate('anapi.errorCode.account_not_found', null, 'dictionary'),
account_limit_exceeded: this.t.translate(
'anapi.errorCode.account_limit_exceeded',
null,
'dictionary',
),
account_not_found: this.t.translate(
'anapi.errorCode.account_not_found',
null,
'dictionary',
),
amount: this.t.translate('anapi.errorCode.amount', null, 'dictionary'),
authorization_failed: this.t.translate('anapi.errorCode.authorization_failed', null, 'dictionary'),
bank_card_rejected: this.t.translate('anapi.errorCode.bank_card_rejected', null, 'dictionary'),
authorization_failed: this.t.translate(
'anapi.errorCode.authorization_failed',
null,
'dictionary',
),
bank_card_rejected: this.t.translate(
'anapi.errorCode.bank_card_rejected',
null,
'dictionary',
),
card_expired: this.t.translate('anapi.errorCode.card_expired', null, 'dictionary'),
card_number_invalid: this.t.translate('anapi.errorCode.card_number_invalid', null, 'dictionary'),
insufficient_funds: this.t.translate('anapi.errorCode.insufficient_funds', null, 'dictionary'),
card_number_invalid: this.t.translate(
'anapi.errorCode.card_number_invalid',
null,
'dictionary',
),
insufficient_funds: this.t.translate(
'anapi.errorCode.insufficient_funds',
null,
'dictionary',
),
no_route_found: this.t.translate('anapi.errorCode.no_route_found', null, 'dictionary'),
number: this.t.translate('anapi.errorCode.number', null, 'dictionary'),
operation_blocked: this.t.translate('anapi.errorCode.operation_blocked', null, 'dictionary'),
operation_timeout: this.t.translate('anapi.errorCode.operation_timeout', null, 'dictionary'),
payment_tool_rejected: this.t.translate('anapi.errorCode.payment_tool_rejected', null, 'dictionary'),
preauthorization_failed: this.t.translate('anapi.errorCode.preauthorization_failed', null, 'dictionary'),
operation_blocked: this.t.translate(
'anapi.errorCode.operation_blocked',
null,
'dictionary',
),
operation_timeout: this.t.translate(
'anapi.errorCode.operation_timeout',
null,
'dictionary',
),
payment_tool_rejected: this.t.translate(
'anapi.errorCode.payment_tool_rejected',
null,
'dictionary',
),
preauthorization_failed: this.t.translate(
'anapi.errorCode.preauthorization_failed',
null,
'dictionary',
),
processing_deadline_reached: this.t.translate(
'anapi.errorCode.processing_deadline_reached',
null,
'dictionary'
'dictionary',
),
rejected_by_issuer: this.t.translate(
'anapi.errorCode.rejected_by_issuer',
null,
'dictionary',
),
risk_score_is_too_high: this.t.translate(
'anapi.errorCode.risk_score_is_too_high',
null,
'dictionary',
),
security_policy_violated: this.t.translate(
'anapi.errorCode.security_policy_violated',
null,
'dictionary',
),
rejected_by_issuer: this.t.translate('anapi.errorCode.rejected_by_issuer', null, 'dictionary'),
risk_score_is_too_high: this.t.translate('anapi.errorCode.risk_score_is_too_high', null, 'dictionary'),
security_policy_violated: this.t.translate('anapi.errorCode.security_policy_violated', null, 'dictionary'),
three_ds_failed: this.t.translate('anapi.errorCode.three_ds_failed', null, 'dictionary'),
three_ds_not_finished: this.t.translate('anapi.errorCode.three_ds_not_finished', null, 'dictionary'),
three_ds_not_finished: this.t.translate(
'anapi.errorCode.three_ds_not_finished',
null,
'dictionary',
),
other: this.t.translate('anapi.errorCode.other', null, 'dictionary'),
}));
@ -62,9 +122,17 @@ export class AnapiDictionaryService {
}));
reportType$ = this.dictionaryService.create<Report.ReportTypeEnum>(() => ({
provisionOfService: this.t.translate('anapi.reportType.provisionOfService', null, 'dictionary'),
provisionOfService: this.t.translate(
'anapi.reportType.provisionOfService',
null,
'dictionary',
),
paymentRegistry: this.t.translate('anapi.reportType.paymentRegistry', null, 'dictionary'),
paymentRegistryByPayout: this.t.translate('anapi.reportType.paymentRegistryByPayout', null, 'dictionary'),
paymentRegistryByPayout: this.t.translate(
'anapi.reportType.paymentRegistryByPayout',
null,
'dictionary',
),
}));
reportStatus$ = this.dictionaryService.create<Report.StatusEnum>(() => ({
@ -78,14 +146,22 @@ export class AnapiDictionaryService {
dankort: this.t.translate('anapi.bankCardPaymentSystem.dankort', null, 'dictionary'),
dinersclub: this.t.translate('anapi.bankCardPaymentSystem.dinersclub', null, 'dictionary'),
discover: this.t.translate('anapi.bankCardPaymentSystem.discover', null, 'dictionary'),
forbrugsforeningen: this.t.translate('anapi.bankCardPaymentSystem.forbrugsforeningen', null, 'dictionary'),
forbrugsforeningen: this.t.translate(
'anapi.bankCardPaymentSystem.forbrugsforeningen',
null,
'dictionary',
),
jcb: this.t.translate('anapi.bankCardPaymentSystem.jcb', null, 'dictionary'),
maestro: this.t.translate('anapi.bankCardPaymentSystem.maestro', null, 'dictionary'),
mastercard: this.t.translate('anapi.bankCardPaymentSystem.mastercard', null, 'dictionary'),
nspkmir: this.t.translate('anapi.bankCardPaymentSystem.nspkmir', null, 'dictionary'),
unionpay: this.t.translate('anapi.bankCardPaymentSystem.unionpay', null, 'dictionary'),
visa: this.t.translate('anapi.bankCardPaymentSystem.visa', null, 'dictionary'),
visaelectron: this.t.translate('anapi.bankCardPaymentSystem.visaelectron', null, 'dictionary'),
visaelectron: this.t.translate(
'anapi.bankCardPaymentSystem.visaelectron',
null,
'dictionary',
),
elo: this.t.translate('anapi.bankCardPaymentSystem.elo', null, 'dictionary'),
rupay: this.t.translate('anapi.bankCardPaymentSystem.rupay', null, 'dictionary'),
dummy: this.t.translate('anapi.bankCardPaymentSystem.dummy', null, 'dictionary'),
@ -105,5 +181,8 @@ export class AnapiDictionaryService {
failed: this.t.translate('anapi.refundStatus.failed', null, 'dictionary'),
}));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {}
constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
}

View File

@ -13,5 +13,8 @@ export class ApiKeysDictionaryService {
revoked: this.t.translate('api-keys.ApiKeyStatus.revoked', null, 'dictionary'),
}));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {}
constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
}

View File

@ -12,7 +12,7 @@ export class ApiKeysService extends createApi(ApiService, [PartyIdExtension]) {
super(injector);
this.requestRevokeApiKey = partyIdPatchMethodService.patch(
this.requestRevokeApiKey,
(params, partyId) => (params.partyId = partyId)
(params, partyId) => (params.partyId = partyId),
);
}
}

View File

@ -12,10 +12,17 @@ export class ClaimManagementDictionaryService {
accepted: this.t.translate('claimManagement.claimStatus.accepted', null, 'dictionary'),
denied: this.t.translate('claimManagement.claimStatus.denied', null, 'dictionary'),
pending: this.t.translate('claimManagement.claimStatus.pending', null, 'dictionary'),
pendingAcceptance: this.t.translate('claimManagement.claimStatus.pendingAcceptance', null, 'dictionary'),
pendingAcceptance: this.t.translate(
'claimManagement.claimStatus.pendingAcceptance',
null,
'dictionary',
),
review: this.t.translate('claimManagement.claimStatus.review', null, 'dictionary'),
revoked: this.t.translate('claimManagement.claimStatus.revoked', null, 'dictionary'),
}));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {}
constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
}

View File

@ -12,7 +12,10 @@ import { PartyIdExtension } from '../utils/extensions';
})
export class ClaimsService extends createApi(ApiClaimsService, [PartyIdExtension]) {
requestReviewClaimByIDWithRevisionCheck = (
params: ApiMethodParams<ApiClaimsService['requestReviewClaimByID'], 'xRequestID' | 'partyID'>
params: ApiMethodParams<
ApiClaimsService['requestReviewClaimByID'],
'xRequestID' | 'partyID'
>,
) => {
return this.requestReviewClaimByID(params).pipe(
catchError((err) => {
@ -22,11 +25,11 @@ export class ClaimsService extends createApi(ApiClaimsService, [PartyIdExtension
this.requestReviewClaimByID({
...params,
claimRevision: claim.revision,
})
)
}),
),
);
return throwError(err);
})
}),
);
};
}

View File

@ -1,12 +1,16 @@
import { ContractModificationUnit, PartyModification, PartyModificationType } from '@vality/swag-claim-management';
import {
ContractModificationUnit,
PartyModification,
PartyModificationType,
} from '@vality/swag-claim-management';
import { PARTY_MODIFICATION } from '../consts';
import PartyModificationTypeEnum = PartyModificationType.PartyModificationTypeEnum;
export function createBaseContractModification<M extends Omit<ContractModificationUnit, 'partyModificationType'>>(
modification: M
): PartyModification {
export function createBaseContractModification<
M extends Omit<ContractModificationUnit, 'partyModificationType'>,
>(modification: M): PartyModification {
return {
...PARTY_MODIFICATION,
partyModificationType: {

View File

@ -1,10 +1,14 @@
import { ContractCreationModification, ContractModification, PartyModification } from '@vality/swag-claim-management';
import {
ContractCreationModification,
ContractModification,
PartyModification,
} from '@vality/swag-claim-management';
import { createBaseContractModification } from './create-base-contract-modification';
export function createContractCreationModification(
id: string,
params: Omit<ContractCreationModification, 'contractModificationType'>
params: Omit<ContractCreationModification, 'contractModificationType'>,
): PartyModification {
return {
...createBaseContractModification({
@ -18,7 +22,10 @@ export function createContractCreationModification(
};
}
export function createTestContractCreationModification(id: string, contractorID: string): PartyModification {
export function createTestContractCreationModification(
id: string,
contractorID: string,
): PartyModification {
return createContractCreationModification(id, {
contractorID,
});

View File

@ -6,12 +6,16 @@ import {
import { createBaseContractModification } from './create-base-contract-modification';
export const createContractLegalAgreementBindingModification = (id: string, legalAgreement: LegalAgreement) =>
export const createContractLegalAgreementBindingModification = (
id: string,
legalAgreement: LegalAgreement,
) =>
createBaseContractModification({
id,
modification: {
contractModificationType:
ContractModification.ContractModificationTypeEnum.ContractLegalAgreementBindingModification,
ContractModification.ContractModificationTypeEnum
.ContractLegalAgreementBindingModification,
legalAgreement,
} as ContractLegalAgreementBindingModification,
});

View File

@ -1,18 +1,23 @@
import { ContractModification, ContractPayoutToolModification, PartyModification } from '@vality/swag-claim-management';
import {
ContractModification,
ContractPayoutToolModification,
PartyModification,
} from '@vality/swag-claim-management';
import { createBaseContractModification } from './create-base-contract-modification';
export function createContractPayoutToolCreationModification(
id: string,
payoutToolID: string,
params: Omit<ContractPayoutToolModification, 'payoutToolModificationType'>
params: Omit<ContractPayoutToolModification, 'payoutToolModificationType'>,
): PartyModification {
return {
...createBaseContractModification({
id,
modification: {
contractModificationType:
ContractModification.ContractModificationTypeEnum.ContractPayoutToolModificationUnit,
ContractModification.ContractModificationTypeEnum
.ContractPayoutToolModificationUnit,
payoutToolID,
modification: {
payoutToolModificationType:

View File

@ -1,18 +1,23 @@
import { ContractModification, ContractPayoutToolModification, PartyModification } from '@vality/swag-claim-management';
import {
ContractModification,
ContractPayoutToolModification,
PartyModification,
} from '@vality/swag-claim-management';
import { createBaseContractModification } from './create-base-contract-modification';
export function createContractPayoutToolInfoModification(
id: string,
payoutToolID: string,
params: Omit<ContractPayoutToolModification, 'payoutToolModificationType'>
params: Omit<ContractPayoutToolModification, 'payoutToolModificationType'>,
): PartyModification {
return {
...createBaseContractModification({
id,
modification: {
contractModificationType:
ContractModification.ContractModificationTypeEnum.ContractPayoutToolModificationUnit,
ContractModification.ContractModificationTypeEnum
.ContractPayoutToolModificationUnit,
payoutToolID,
modification: {
payoutToolModificationType:

View File

@ -25,7 +25,7 @@ export function createInternationalContractPayoutToolModification(
{ accountHolder?: CorrespondentAccount['accountHolder'] }
>;
}
>
>,
): PartyModification {
return createContractPayoutToolCreationModification(id, payoutToolID, {
currency: {

View File

@ -1,4 +1,8 @@
import { PartyModification, PayoutToolInfo, RussianBankAccount } from '@vality/swag-claim-management';
import {
PartyModification,
PayoutToolInfo,
RussianBankAccount,
} from '@vality/swag-claim-management';
import { createContractPayoutToolCreationModification } from './create-contract-payout-tool-creation-modification';
@ -6,7 +10,7 @@ export function createRussianContractPayoutToolCreationModification(
id: string,
payoutToolID: string,
params: Omit<RussianBankAccount, 'payoutToolType'>,
currency?: string
currency?: string,
): PartyModification {
return createContractPayoutToolCreationModification(id, payoutToolID, {
currency: {

View File

@ -1,11 +1,15 @@
import { PartyModification, PayoutToolInfo, RussianBankAccount } from '@vality/swag-claim-management';
import {
PartyModification,
PayoutToolInfo,
RussianBankAccount,
} from '@vality/swag-claim-management';
import { createContractPayoutToolInfoModification } from './create-contract-payout-tool-info-modification';
export function createRussianContractPayoutToolInfoModification(
id: string,
payoutToolID: string,
params: Omit<RussianBankAccount, 'payoutToolType'>
params: Omit<RussianBankAccount, 'payoutToolType'>,
): PartyModification {
return createContractPayoutToolInfoModification(id, payoutToolID, {
payoutToolInfo: {

View File

@ -1,12 +1,16 @@
import { ContractorModification, PartyModification, PartyModificationType } from '@vality/swag-claim-management';
import {
ContractorModification,
PartyModification,
PartyModificationType,
} from '@vality/swag-claim-management';
import { PARTY_MODIFICATION } from '../consts';
import PartyModificationTypeEnum = PartyModificationType.PartyModificationTypeEnum;
export function createBaseContractorModification<M extends Omit<ContractorModification, 'contractorModificationType'>>(
modification: M
): PartyModification {
export function createBaseContractorModification<
M extends Omit<ContractorModification, 'contractorModificationType'>,
>(modification: M): PartyModification {
return {
...PARTY_MODIFICATION,
partyModificationType: {

View File

@ -7,12 +7,16 @@ import {
import { createBaseContractorModification } from './create-base-contractor-modification';
export function createContractorLegalEntityModification(id: string, entity: LegalEntityType): PartyModification {
export function createContractorLegalEntityModification(
id: string,
entity: LegalEntityType,
): PartyModification {
return {
...createBaseContractorModification({
id,
modification: {
contractorModificationType: ContractorModification.ContractorModificationTypeEnum.Contractor,
contractorModificationType:
ContractorModification.ContractorModificationTypeEnum.Contractor,
contractorType: {
contractorType: ContractorType.ContractorTypeEnum.LegalEntity,
legalEntityType: {

View File

@ -4,7 +4,7 @@ import { createContractorLegalEntityModification } from './create-contractor-leg
export function createInternationalLegalEntityModification(
id: string,
params: Omit<InternationalLegalEntity, 'legalEntityType'>
params: Omit<InternationalLegalEntity, 'legalEntityType'>,
): PartyModification {
return createContractorLegalEntityModification(id, {
legalEntityType: 'InternationalLegalEntity',

View File

@ -1,7 +1,7 @@
import { PayoutToolInfo, RussianBankAccount } from '@vality/swag-claim-management';
export function createRussianBankAccountModification(
params: Omit<RussianBankAccount, 'payoutToolType'>
params: Omit<RussianBankAccount, 'payoutToolType'>,
): RussianBankAccount {
return {
payoutToolType: PayoutToolInfo.PayoutToolTypeEnum.RussianBankAccount,

View File

@ -1,10 +1,14 @@
import { LegalEntityType, PartyModification, RussianLegalEntity } from '@vality/swag-claim-management';
import {
LegalEntityType,
PartyModification,
RussianLegalEntity,
} from '@vality/swag-claim-management';
import { createContractorLegalEntityModification } from './create-contractor-legal-entity-modification';
export function createRussianLegalEntityModification(
id: string,
params: Omit<RussianLegalEntity, 'legalEntityType'>
params: Omit<RussianLegalEntity, 'legalEntityType'>,
): PartyModification {
return createContractorLegalEntityModification(id, {
legalEntityType: LegalEntityType.LegalEntityTypeEnum.RussianLegalEntity,

View File

@ -1,11 +1,15 @@
import { PartyModification, PartyModificationType, ShopModificationUnit } from '@vality/swag-claim-management';
import {
PartyModification,
PartyModificationType,
ShopModificationUnit,
} from '@vality/swag-claim-management';
import { PARTY_MODIFICATION } from '../consts';
import PartyModificationTypeEnum = PartyModificationType.PartyModificationTypeEnum;
export function createBaseShopModification(
modification: Omit<ShopModificationUnit, 'partyModificationType'>
modification: Omit<ShopModificationUnit, 'partyModificationType'>,
): PartyModification {
return {
...PARTY_MODIFICATION,

View File

@ -4,7 +4,7 @@ import { createBaseShopModification } from './create-base-shop-modification';
export function createShopCreationModification(
id: string,
params: Omit<ShopCreationModification, 'shopModificationType'>
params: Omit<ShopCreationModification, 'shopModificationType'>,
): PartyModification {
return {
...createBaseShopModification({

View File

@ -42,7 +42,10 @@ const createTestLegalAgreement = (): LegalAgreement => ({
legalAgreementID: '000000/00',
});
const TEST_SHOP_CREATION: Omit<ShopCreationModification, 'shopModificationType' | 'contractID' | 'payoutToolID'> = {
const TEST_SHOP_CREATION: Omit<
ShopCreationModification,
'shopModificationType' | 'contractID' | 'payoutToolID'
> = {
category: {
categoryID: 1,
},
@ -67,6 +70,10 @@ export const createTestShopModifications = ({
createRussianLegalEntityModification(contractorID, TEST_RUSSIAN_LEGAL_ENTITY),
createContractCreationModification(contractID, { contractorID }),
createContractLegalAgreementBindingModification(contractID, createTestLegalAgreement()),
createRussianContractPayoutToolCreationModification(contractID, payoutToolID, TEST_RUSSIAN_BANK_ACCOUNT),
createRussianContractPayoutToolCreationModification(
contractID,
payoutToolID,
TEST_RUSSIAN_BANK_ACCOUNT,
),
createShopCreationModification(shopID, { ...TEST_SHOP_CREATION, contractID, payoutToolID }),
];

View File

@ -3,7 +3,7 @@ import { CommentModificationUnit } from '@vality/swag-claim-management';
import { SpecificClaimModificationUnit } from './specific-claim-modification-unit';
export const createCommentModificationUnit = (
commentId: string
commentId: string,
): SpecificClaimModificationUnit<CommentModificationUnit> => ({
modificationType: 'ClaimModification',
claimModificationType: {

View File

@ -3,7 +3,7 @@ import { DocumentModificationUnit } from '@vality/swag-claim-management';
import { SpecificClaimModificationUnit } from './specific-claim-modification-unit';
export const createDocumentModificationUnit = (
documentId: string
documentId: string,
): SpecificClaimModificationUnit<DocumentModificationUnit> => ({
modificationType: 'ClaimModification',
claimModificationType: {

View File

@ -8,7 +8,7 @@ type FileModificationType = FileModification.FileModificationTypeEnum;
export const createFileModificationUnit = (
fileId: string,
fileModificationType: FileModificationType = FileModificationType.FileCreated
fileModificationType: FileModificationType = FileModificationType.FileCreated,
): SpecificClaimModificationUnit<FileModificationUnit> => ({
modificationType: 'ClaimModification',
claimModificationType: {

View File

@ -25,7 +25,7 @@ export const createTestShopClaimChangeset = (
testShopID: string,
testContractID: string,
testPayoutToolID: string,
testContractorID: string
testContractorID: string,
): Modification[] => {
return [
createInternationalLegalEntityModification(testContractorID, {

View File

@ -3,5 +3,5 @@ import * as moment from 'moment';
export const sortUnitsByCreatedAtAsc = (
{ createdAt: a }: ModificationUnit,
{ createdAt: b }: ModificationUnit
{ createdAt: b }: ModificationUnit,
): number => moment(a).diff(moment(b));

View File

@ -1,7 +1,15 @@
import { ClaimModification, ClaimModificationType, Modification } from '@vality/swag-claim-management';
import {
ClaimModification,
ClaimModificationType,
Modification,
} from '@vality/swag-claim-management';
import { Overwrite } from 'utility-types';
export type SpecificClaimModificationUnit<M extends ClaimModificationType = ClaimModificationType> = Overwrite<
ClaimModification,
{ modificationType: typeof Modification.ModificationTypeEnum.ClaimModification; claimModificationType: M }
>;
export type SpecificClaimModificationUnit<M extends ClaimModificationType = ClaimModificationType> =
Overwrite<
ClaimModification,
{
modificationType: typeof Modification.ModificationTypeEnum.ClaimModification;
claimModificationType: M;
}
>;

View File

@ -2,11 +2,14 @@ import { ModificationUnit, DocumentModificationUnit } from '@vality/swag-claim-m
import { isClaimModification, isDocumentModificationUnit } from './type-guards';
export const takeDocumentModificationUnits = (changeset: ModificationUnit[]): DocumentModificationUnit[] =>
export const takeDocumentModificationUnits = (
changeset: ModificationUnit[],
): DocumentModificationUnit[] =>
changeset.reduce(
(acc, { modification }) =>
isClaimModification(modification) && isDocumentModificationUnit(modification.claimModificationType)
isClaimModification(modification) &&
isDocumentModificationUnit(modification.claimModificationType)
? acc.concat(modification.claimModificationType)
: acc,
[] as DocumentModificationUnit[]
[] as DocumentModificationUnit[],
);

View File

@ -1,16 +1,27 @@
import { ModificationUnit, FileModification, FileModificationUnit } from '@vality/swag-claim-management';
import {
ModificationUnit,
FileModification,
FileModificationUnit,
} from '@vality/swag-claim-management';
import { sortUnitsByCreatedAtAsc } from './sort-units';
import { isClaimModification, isFileModificationUnit } from './type-guards';
export const takeFileModificationUnits = (changeset: ModificationUnit[]): FileModificationUnit[] =>
changeset.sort(sortUnitsByCreatedAtAsc).reduce((acc, { modification }) => {
if (isClaimModification(modification) && isFileModificationUnit(modification.claimModificationType)) {
if (
isClaimModification(modification) &&
isFileModificationUnit(modification.claimModificationType)
) {
const m = modification.claimModificationType;
if (m.fileModification.fileModificationType === FileModification.FileModificationTypeEnum.FileCreated) {
if (
m.fileModification.fileModificationType ===
FileModification.FileModificationTypeEnum.FileCreated
) {
return acc.concat(m);
} else if (
m.fileModification.fileModificationType === FileModification.FileModificationTypeEnum.FileDeleted
m.fileModification.fileModificationType ===
FileModification.FileModificationTypeEnum.FileDeleted
) {
return acc.filter(({ fileId }) => fileId !== m.fileId);
}

View File

@ -14,17 +14,17 @@ import ClaimModificationTypeEnum = ClaimModificationType.ClaimModificationTypeEn
const createTypeGuard = createUnionTypeGuardCreator<ClaimModificationType>('claimModificationType');
export const isFileModificationUnit = createTypeGuard<FileModificationUnit>(
ClaimModificationTypeEnum.FileModificationUnit
ClaimModificationTypeEnum.FileModificationUnit,
);
export const isCommentModificationUnit = createTypeGuard<CommentModificationUnit>(
ClaimModificationTypeEnum.CommentModificationUnit
ClaimModificationTypeEnum.CommentModificationUnit,
);
export const isStatusModificationUnit = createTypeGuard<StatusModificationUnit>(
ClaimModificationTypeEnum.StatusModificationUnit
ClaimModificationTypeEnum.StatusModificationUnit,
);
export const isDocumentModificationUnit = createTypeGuard<DocumentModificationUnit>(
ClaimModificationTypeEnum.DocumentModificationUnit
ClaimModificationTypeEnum.DocumentModificationUnit,
);
export const isExternalInfoModificationUnit = createTypeGuard<ExternalInfoModificationUnit>(
ClaimModificationTypeEnum.ExternalInfoModificationUnit
ClaimModificationTypeEnum.ExternalInfoModificationUnit,
);

View File

@ -3,6 +3,8 @@ import { DocumentCreated, DocumentModification } from '@vality/swag-claim-manage
import { createUnionTypeGuardCreator } from '../../../utils';
const TYPE = DocumentModification.DocumentModificationTypeEnum;
const createTypeGuard = createUnionTypeGuardCreator<DocumentModification>('documentModificationType');
const createTypeGuard = createUnionTypeGuardCreator<DocumentModification>(
'documentModificationType',
);
export const isDocumentCreated = createTypeGuard<DocumentCreated>(TYPE.DocumentCreated);

View File

@ -23,5 +23,8 @@ export class OrganizationsDictionaryService {
/* eslint-enable @typescript-eslint/naming-convention */
}));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {}
constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
}

View File

@ -1,4 +1,9 @@
import { Invitation, InvitationStatusName, Invitee, InviteeContact } from '@vality/swag-organizations';
import {
Invitation,
InvitationStatusName,
Invitee,
InviteeContact,
} from '@vality/swag-organizations';
import { MOCK_MEMBER_ROLE } from './mock-member-role';

View File

@ -13,7 +13,7 @@ import { createApi } from '../utils';
export class CategoriesService extends createApi(ApiCategoriesService) {
categories$ = defer(() => this.reloadCategories$).pipe(
switchMap(() => this.getCategories()),
shareReplayRefCount()
shareReplayRefCount(),
);
private reloadCategories$ = new BehaviorSubject<void>(undefined);

View File

@ -18,10 +18,13 @@ export class CountriesService extends createApi(ApiCountriesService) {
this.errorService.error(error, false);
return of([]);
}),
shareReplay(SHARE_REPLAY_CONF)
shareReplay(SHARE_REPLAY_CONF),
);
constructor(injector: Injector, private errorService: ErrorService) {
constructor(
injector: Injector,
private errorService: ErrorService,
) {
super(injector);
this.getCountries = () => {
return this.getCountries().pipe(map((countries) => sortBy(countries, 'id')));

View File

@ -9,11 +9,14 @@ import { createApi } from '../utils';
providedIn: 'root',
})
export class InvoiceTemplatesService extends createApi(ApiInvoiceTemplatesService) {
constructor(injector: Injector, private partyIdPatchMethodService: PartyIdPatchMethodService) {
constructor(
injector: Injector,
private partyIdPatchMethodService: PartyIdPatchMethodService,
) {
super(injector);
this.createInvoiceTemplate = this.partyIdPatchMethodService.patch(
this.createInvoiceTemplate,
(params, partyId) => (params.invoiceTemplateCreateParams.partyID = partyId)
(params, partyId) => (params.invoiceTemplateCreateParams.partyID = partyId),
);
}
}

View File

@ -13,7 +13,7 @@ export class InvoicesService extends createApi(ApiInvoicesService) {
super(injector);
this.createInvoice = partyIdPatchMethodService.patch(
this.createInvoice,
(p, id) => (p.invoiceParams.partyID = id)
(p, id) => (p.invoiceParams.partyID = id),
);
}
}

View File

@ -13,7 +13,7 @@ import { createApi } from '../utils';
export class PaymentInstitutionsService extends createApi(ApiPaymentInstitutionsService) {
paymentInstitutions$ = defer(() => this.reload$).pipe(
switchMap(() => this.getPaymentInstitutions()),
shareReplayRefCount()
shareReplayRefCount(),
);
private reload$ = new BehaviorSubject<void>(undefined);

View File

@ -12,53 +12,105 @@ import { DictionaryService } from '../utils';
export class PaymentsDictionaryService {
invoicesTopicEventType$ = this.dictionaryService.create<InvoicesTopic.EventTypesEnum>(() => ({
/* eslint-disable @typescript-eslint/naming-convention */
InvoiceCreated: this.t.translate('payments.invoicesTopicEventType.InvoiceCreated', null, 'dictionary'),
InvoicePaid: this.t.translate('payments.invoicesTopicEventType.InvoicePaid', null, 'dictionary'),
InvoiceCancelled: this.t.translate('payments.invoicesTopicEventType.InvoiceCancelled', null, 'dictionary'),
InvoiceFulfilled: this.t.translate('payments.invoicesTopicEventType.InvoiceFulfilled', null, 'dictionary'),
PaymentStarted: this.t.translate('payments.invoicesTopicEventType.PaymentStarted', null, 'dictionary'),
PaymentProcessed: this.t.translate('payments.invoicesTopicEventType.PaymentProcessed', null, 'dictionary'),
PaymentCaptured: this.t.translate('payments.invoicesTopicEventType.PaymentCaptured', null, 'dictionary'),
PaymentCancelled: this.t.translate('payments.invoicesTopicEventType.PaymentCancelled', null, 'dictionary'),
PaymentRefunded: this.t.translate('payments.invoicesTopicEventType.PaymentRefunded', null, 'dictionary'),
PaymentFailed: this.t.translate('payments.invoicesTopicEventType.PaymentFailed', null, 'dictionary'),
InvoiceCreated: this.t.translate(
'payments.invoicesTopicEventType.InvoiceCreated',
null,
'dictionary',
),
InvoicePaid: this.t.translate(
'payments.invoicesTopicEventType.InvoicePaid',
null,
'dictionary',
),
InvoiceCancelled: this.t.translate(
'payments.invoicesTopicEventType.InvoiceCancelled',
null,
'dictionary',
),
InvoiceFulfilled: this.t.translate(
'payments.invoicesTopicEventType.InvoiceFulfilled',
null,
'dictionary',
),
PaymentStarted: this.t.translate(
'payments.invoicesTopicEventType.PaymentStarted',
null,
'dictionary',
),
PaymentProcessed: this.t.translate(
'payments.invoicesTopicEventType.PaymentProcessed',
null,
'dictionary',
),
PaymentCaptured: this.t.translate(
'payments.invoicesTopicEventType.PaymentCaptured',
null,
'dictionary',
),
PaymentCancelled: this.t.translate(
'payments.invoicesTopicEventType.PaymentCancelled',
null,
'dictionary',
),
PaymentRefunded: this.t.translate(
'payments.invoicesTopicEventType.PaymentRefunded',
null,
'dictionary',
),
PaymentFailed: this.t.translate(
'payments.invoicesTopicEventType.PaymentFailed',
null,
'dictionary',
),
PaymentRefundCreated: this.t.translate(
'payments.invoicesTopicEventType.PaymentRefundCreated',
null,
'dictionary'
'dictionary',
),
PaymentRefundSucceeded: this.t.translate(
'payments.invoicesTopicEventType.PaymentRefundSucceeded',
null,
'dictionary'
'dictionary',
),
PaymentRefundFailed: this.t.translate(
'payments.invoicesTopicEventType.PaymentRefundFailed',
null,
'dictionary'
'dictionary',
),
/* eslint-enable @typescript-eslint/naming-convention */
}));
customersTopicEventType$ = this.dictionaryService.create<CustomersTopic.EventTypesEnum>(() => ({
/* eslint-disable @typescript-eslint/naming-convention */
CustomerCreated: this.t.translate('payments.customersTopicEventType.CustomerCreated', null, 'dictionary'),
CustomerDeleted: this.t.translate('payments.customersTopicEventType.CustomerDeleted', null, 'dictionary'),
CustomerReady: this.t.translate('payments.customersTopicEventType.CustomerReady', null, 'dictionary'),
CustomerCreated: this.t.translate(
'payments.customersTopicEventType.CustomerCreated',
null,
'dictionary',
),
CustomerDeleted: this.t.translate(
'payments.customersTopicEventType.CustomerDeleted',
null,
'dictionary',
),
CustomerReady: this.t.translate(
'payments.customersTopicEventType.CustomerReady',
null,
'dictionary',
),
CustomerBindingStarted: this.t.translate(
'payments.customersTopicEventType.CustomerBindingStarted',
null,
'dictionary'
'dictionary',
),
CustomerBindingSucceeded: this.t.translate(
'payments.customersTopicEventType.CustomerBindingSucceeded',
null,
'dictionary'
'dictionary',
),
CustomerBindingFailed: this.t.translate(
'payments.customersTopicEventType.CustomerBindingFailed',
null,
'dictionary'
'dictionary',
),
/* eslint-enable @typescript-eslint/naming-convention */
}));
@ -72,5 +124,8 @@ export class PaymentsDictionaryService {
failed: this.t.translate('payments.paymentStatus.failed', null, 'dictionary'),
}));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {}
constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
}

View File

@ -9,11 +9,14 @@ import { createApi } from '../utils';
providedIn: 'root',
})
export class PayoutsService extends createApi(ApiPayoutsService, [PartyIdExtension]) {
constructor(injector: Injector, private partyIdPatchMethodService: PartyIdPatchMethodService) {
constructor(
injector: Injector,
private partyIdPatchMethodService: PartyIdPatchMethodService,
) {
super(injector);
this.createPayout = partyIdPatchMethodService.patch(
this.createPayout,
(params, partyId) => (params.payoutParams.partyID = partyId)
(params, partyId) => (params.payoutParams.partyID = partyId),
);
}
}

View File

@ -1,3 +1,4 @@
import { Shop } from '@vality/swag-payments';
export const findShopById = (s: Shop[], shopID: string): Shop | null => s.find(({ id }) => id === shopID);
export const findShopById = (s: Shop[], shopID: string): Shop | null =>
s.find(({ id }) => id === shopID);

View File

@ -3,4 +3,5 @@ import { Shop } from '@vality/swag-payments';
import { findShopById } from './find-shop-by-id';
import { getShopName } from './get-shop-name';
export const getShopNameById = (s: Shop[], shopID: string): string | null => getShopName(findShopById(s, shopID));
export const getShopNameById = (s: Shop[], shopID: string): string | null =>
getShopName(findShopById(s, shopID));

View File

@ -13,7 +13,7 @@ export class WebhooksService extends createApi(ApiWebhooksService, [PartyIdExten
super(injector);
this.createWebhook = partyIdPatchMethodService.patch(
this.createWebhook,
(params, partyID) => (params.webhookParams.partyID = partyID)
(params, partyID) => (params.webhookParams.partyID = partyID),
);
}
}

View File

@ -1,11 +1,15 @@
import { Injectable } from '@angular/core';
import { DaDataService as ApiDaDataService, DaDataRequest } from '@vality/swag-questionary-aggr-proxy';
import {
DaDataService as ApiDaDataService,
DaDataRequest,
} from '@vality/swag-questionary-aggr-proxy';
import { Observable } from 'rxjs';
import { pluck } from 'rxjs/operators';
import { ParamsByRequestType, ResponseByRequestType, SuggestionsByRequestType } from './utils';
import { createApi } from '../utils';
import { ParamsByRequestType, ResponseByRequestType, SuggestionsByRequestType } from './utils';
type RequestType = DaDataRequest.DaDataRequestTypeEnum;
@Injectable({
@ -14,10 +18,12 @@ type RequestType = DaDataRequest.DaDataRequestTypeEnum;
export class DaDataService extends createApi(ApiDaDataService) {
suggest<T extends RequestType>(
daDataRequestType: T,
params: ParamsByRequestType[T]
params: ParamsByRequestType[T],
): Observable<SuggestionsByRequestType[T]> {
const requestParams = { request: { daDataRequestType, ...params } };
const request = this.requestDaData({ daDataParams: requestParams }) as Observable<ResponseByRequestType[T]>;
const request = this.requestDaData({ daDataParams: requestParams }) as Observable<
ResponseByRequestType[T]
>;
return request.pipe(pluck('suggestions')) as Observable<SuggestionsByRequestType[T]>;
}
}

View File

@ -52,7 +52,7 @@ export type ResponsesByRequestType = Mapping<
export class KonturFocusService extends createApi(ApiKonturFocusService) {
request<T extends RequestType>(
konturFocusRequestType: T,
requestParams: Partial<Omit<ParamsByRequestType[T], 'konturFocusRequestType'>>
requestParams: Partial<Omit<ParamsByRequestType[T], 'konturFocusRequestType'>>,
): Observable<ResponsesByRequestType[T]['responses']> {
return this.requestKonturFocus({
konturFocusParams: { request: { konturFocusRequestType, ...requestParams } },

View File

@ -1,5 +1,7 @@
import { ReqContractor, ReqIndividualEntity } from '@vality/swag-questionary-aggr-proxy';
export function isReqIndividualEntity(contractor: ReqContractor): contractor is ReqIndividualEntity {
export function isReqIndividualEntity(
contractor: ReqContractor,
): contractor is ReqIndividualEntity {
return contractor.reqContractorType === 'ReqIndividualEntity';
}

View File

@ -20,10 +20,14 @@ type DeepOnlyMutable<T> = T extends object
type ApiArgs = [Injector];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type MethodParams<P extends Record<PropertyKey, any>, K extends PropertyKey> = RequiredKeys<Omit<P, K>> extends never
type MethodParams<P extends Record<PropertyKey, any>, K extends PropertyKey> = RequiredKeys<
Omit<P, K>
> extends never
? void | Overwrite<P, { [N in K]?: P[N] }>
: Overwrite<P, { [N in K]?: P[N] }>;
type Method<M, P extends PropertyKey> = M extends (...args: unknown[]) => Observable<HttpResponse<infer R>>
type Method<M, P extends PropertyKey> = M extends (
...args: unknown[]
) => Observable<HttpResponse<infer R>>
? (params: DeepOnlyMutable<MethodParams<Parameters<M>[0], P>>) => Observable<R>
: never;
@ -33,12 +37,14 @@ type Method<M, P extends PropertyKey> = M extends (...args: unknown[]) => Observ
export function createApi<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends Record<PropertyKey, any> & { defaultHeaders: HttpHeaders },
E extends (new (...args: unknown[]) => ApiExtension)[] = []
E extends (new (...args: unknown[]) => ApiExtension)[] = [],
>(apiClass: new (...args: unknown[]) => T, extensions: E = [] as E) {
@Injectable()
class Api {
private api = this.injector.get<T>(apiClass);
private extensions = [XrequestIdExtension, ...extensions].map((e) => this.injector.get<ApiExtension>(e));
private extensions = [XrequestIdExtension, ...extensions].map((e) =>
this.injector.get<ApiExtension>(e),
);
constructor(private injector: Injector) {
if (this.api.defaultHeaders !== DEFAULT_HEADERS) {
@ -47,17 +53,23 @@ export function createApi<
const methodNames = getMethods(apiClass, this.api);
Object.assign(
this,
Object.fromEntries(methodNames.map((name) => [name, (params) => this.call(name, params)]))
Object.fromEntries(
methodNames.map((name) => [name, (params) => this.call(name, params)]),
),
);
}
private call(name: keyof T, params: Record<PropertyKey, unknown>) {
return this.createExtendedParams().pipe(switchMap((p) => this.api[name](Object.assign({}, params, ...p))));
return this.createExtendedParams().pipe(
switchMap((p) => this.api[name](Object.assign({}, params, ...p))),
);
}
private createExtendedParams() {
return combineLatest(
this.extensions.map((extension) => extension.selector()).map((p) => (isObservable(p) ? p : of(p)))
this.extensions
.map((extension) => extension.selector())
.map((p) => (isObservable(p) ? p : of(p))),
);
}
}
@ -65,8 +77,12 @@ export function createApi<
return Api as unknown as new (...args: ApiArgs) => {
[N in keyof T]: Method<
T[N],
| keyof UnionToIntersection<ObservableValue<ReturnType<InstanceType<E[number]>['selector']>>>
| keyof UnionToIntersection<ObservableValue<ReturnType<XrequestIdExtension['selector']>>>
| keyof UnionToIntersection<
ObservableValue<ReturnType<InstanceType<E[number]>['selector']>>
>
| keyof UnionToIntersection<
ObservableValue<ReturnType<XrequestIdExtension['selector']>>
>
>;
};
}

View File

@ -2,5 +2,5 @@ import { Overwrite } from 'utility-types';
export type ApiMethodParams<
M extends (params: object) => unknown,
P extends keyof Parameters<M>[0] = never
P extends keyof Parameters<M>[0] = never,
> = Overwrite<Parameters<M>[0], { [N in P]?: Parameters<M>[0][N] }>;

View File

@ -1,5 +1,5 @@
export function getMethods(klass: new (...args: unknown[]) => unknown, instance: unknown) {
return Object.getOwnPropertyNames(klass.prototype).filter(
(name) => typeof instance[name] === 'function' && name !== 'constructor'
(name) => typeof instance[name] === 'function' && name !== 'constructor',
);
}

View File

@ -13,10 +13,12 @@ export class DictionaryService {
constructor(private readonly transloco: TranslocoService) {}
create<T extends PropertyKey>(getTranslations: () => Record<T, string>): Observable<Record<T, string>> {
create<T extends PropertyKey>(
getTranslations: () => Record<T, string>,
): Observable<Record<T, string>> {
return this.init$.pipe(
map(() => getTranslations()),
shareReplayRefCount()
shareReplayRefCount(),
);
}
}

View File

@ -14,7 +14,7 @@ export class PartyIdExtension implements ApiExtension {
selector() {
return this.contextOrganizationService.organization$.pipe(
first(),
map(({ party }) => ({ partyID: party, partyId: party }))
map(({ party }) => ({ partyID: party, partyId: party })),
);
}
}

View File

@ -11,7 +11,7 @@ import { PartyIdExtension } from './party-id-extension';
export class PartyIdPatchMethodService extends PartyIdExtension {
patch<P extends object, R, E extends DeepPartial<P> | void>(
method: (params: P) => Observable<R>,
patch: (params: P, partyId: string) => unknown
patch: (params: P, partyId: string) => unknown,
): (params: E) => Observable<R> {
return (params) =>
this.selector().pipe(
@ -19,7 +19,7 @@ export class PartyIdPatchMethodService extends PartyIdExtension {
const newParams = cloneDeep(params);
patch(newParams as unknown as P, partyID);
return method(newParams as unknown as P);
})
}),
);
}
}

View File

@ -15,7 +15,7 @@ export class IdentitiesService extends createApi(ApiIdentitiesService) {
startWith<void>(undefined),
switchMap(() => this.listIdentities()),
map((r) => r.result as Identity[]),
shareReplayRefCount()
shareReplayRefCount(),
);
private reloadIdentities$ = new Subject<void>();

View File

@ -1,6 +1,13 @@
import { Injectable } from '@angular/core';
import { TranslocoService } from '@ngneat/transloco';
import { DepositRevert, WithdrawalsTopic, DestinationsTopic, Deposit, Withdrawal, Report } from '@vality/swag-wallet';
import {
DepositRevert,
WithdrawalsTopic,
DestinationsTopic,
Deposit,
Withdrawal,
Report,
} from '@vality/swag-wallet';
import { DictionaryService } from '../utils';
@ -8,37 +15,49 @@ import { DictionaryService } from '../utils';
providedIn: 'root',
})
export class WalletDictionaryService {
withdrawalsTopicEventType$ = this.dictionaryService.create<WithdrawalsTopic.EventTypesEnum>(() => ({
/* eslint-disable @typescript-eslint/naming-convention */
WithdrawalStarted: this.t.translate('wallet.withdrawalsTopicEventType.WithdrawalStarted', null, 'dictionary'),
WithdrawalSucceeded: this.t.translate(
'wallet.withdrawalsTopicEventType.WithdrawalSucceeded',
null,
'dictionary'
),
WithdrawalFailed: this.t.translate('wallet.withdrawalsTopicEventType.WithdrawalFailed', null, 'dictionary'),
/* eslint-enable @typescript-eslint/naming-convention */
}));
withdrawalsTopicEventType$ = this.dictionaryService.create<WithdrawalsTopic.EventTypesEnum>(
() => ({
/* eslint-disable @typescript-eslint/naming-convention */
WithdrawalStarted: this.t.translate(
'wallet.withdrawalsTopicEventType.WithdrawalStarted',
null,
'dictionary',
),
WithdrawalSucceeded: this.t.translate(
'wallet.withdrawalsTopicEventType.WithdrawalSucceeded',
null,
'dictionary',
),
WithdrawalFailed: this.t.translate(
'wallet.withdrawalsTopicEventType.WithdrawalFailed',
null,
'dictionary',
),
/* eslint-enable @typescript-eslint/naming-convention */
}),
);
destinationsTopicEventType$ = this.dictionaryService.create<DestinationsTopic.EventTypesEnum>(() => ({
/* eslint-disable @typescript-eslint/naming-convention */
DestinationCreated: this.t.translate(
'wallet.destinationsTopicEventType.DestinationCreated',
null,
'dictionary'
),
DestinationUnauthorized: this.t.translate(
'wallet.destinationsTopicEventType.DestinationUnauthorized',
null,
'dictionary'
),
DestinationAuthorized: this.t.translate(
'wallet.destinationsTopicEventType.DestinationAuthorized',
null,
'dictionary'
),
/* eslint-enable @typescript-eslint/naming-convention */
}));
destinationsTopicEventType$ = this.dictionaryService.create<DestinationsTopic.EventTypesEnum>(
() => ({
/* eslint-disable @typescript-eslint/naming-convention */
DestinationCreated: this.t.translate(
'wallet.destinationsTopicEventType.DestinationCreated',
null,
'dictionary',
),
DestinationUnauthorized: this.t.translate(
'wallet.destinationsTopicEventType.DestinationUnauthorized',
null,
'dictionary',
),
DestinationAuthorized: this.t.translate(
'wallet.destinationsTopicEventType.DestinationAuthorized',
null,
'dictionary',
),
/* eslint-enable @typescript-eslint/naming-convention */
}),
);
depositRevertStatus$ = this.dictionaryService.create<DepositRevert.StatusEnum>(() => ({
/* eslint-disable @typescript-eslint/naming-convention */
@ -72,5 +91,8 @@ export class WalletDictionaryService {
/* eslint-enable @typescript-eslint/naming-convention */
}));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {}
constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
}

View File

@ -15,13 +15,13 @@ export class WalletsService extends createApi(ApiWalletsService, [PartyIdExtensi
wallets$ = this.listWallets({ limit: 1000 }).pipe(
catchError(() => of({ result: [] })),
pluck('result'),
shareReplay(SHARE_REPLAY_CONF)
shareReplay(SHARE_REPLAY_CONF),
);
hasWallets$ = this.listWallets({ limit: 1 }).pipe(
catchError(() => of({ result: [] })),
pluck('result', 'length'),
map((l) => l > 0),
shareReplay(SHARE_REPLAY_CONF)
shareReplay(SHARE_REPLAY_CONF),
);
}

View File

@ -1,7 +1,7 @@
<dsh-home>
<dsh-sections *ngIf="bootstrapped$ | async; else spinner"></dsh-sections>
<ng-template #spinner>
<div fxLayout="row" fxFlexAlign="center">
<div fxFlexAlign="center" fxLayout="row">
<dsh-spinner style="margin: auto"></dsh-spinner>
</div>
</ng-template>

View File

@ -1,5 +1,5 @@
import { Component, OnInit } from '@angular/core';
import * as Sentry from '@sentry/angular';
import * as Sentry from '@sentry/angular-ivy';
import { first } from 'rxjs/operators';
import { BootstrapService } from './bootstrap.service';
@ -15,7 +15,7 @@ export class AppComponent implements OnInit {
constructor(
private bootstrapService: BootstrapService,
private contextOrganizationService: ContextOrganizationService
private contextOrganizationService: ContextOrganizationService,
) {}
ngOnInit(): void {

View File

@ -2,7 +2,12 @@ import { CommonModule } from '@angular/common';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { APP_INITIALIZER, ErrorHandler, LOCALE_ID, NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MAT_RIPPLE_GLOBAL_OPTIONS } from '@angular/material/core';
import {
DateAdapter,
MAT_DATE_FORMATS,
MAT_DATE_LOCALE,
MAT_RIPPLE_GLOBAL_OPTIONS,
} from '@angular/material/core';
import { MatDialogModule } from '@angular/material/dialog';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import {
@ -13,8 +18,13 @@ import {
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { Router } from '@angular/router';
import { TRANSLOCO_CONFIG, TRANSLOCO_LOADER, TranslocoModule, translocoConfig } from '@ngneat/transloco';
import * as Sentry from '@sentry/angular';
import {
TRANSLOCO_CONFIG,
TRANSLOCO_LOADER,
TranslocoModule,
translocoConfig,
} from '@ngneat/transloco';
import * as Sentry from '@sentry/angular-ivy';
import { AnapiModule } from '@dsh/app/api/anapi';
import { ClaimManagementModule } from '@dsh/app/api/claim-management';
@ -27,6 +37,8 @@ import { QUERY_PARAMS_SERIALIZERS } from '@dsh/app/shared/services/query-params/
import { createDateRangeWithPresetSerializer } from '@dsh/components/date-range-filter';
import { SpinnerModule } from '@dsh/components/indicators';
import { ENV, environment } from '../environments';
import { ApiKeysModule } from './api/api-keys';
import { OrganizationsModule } from './api/organizations';
import { AppComponent } from './app.component';
@ -41,7 +53,6 @@ import { SentryErrorHandler } from './sentry-error-handler.service';
import { SentryHttpInterceptor } from './sentry-http-interceptor';
import { ThemeManager } from './theme-manager';
import { TranslocoHttpLoaderService } from './transloco-http-loader.service';
import { ENV, environment } from '../environments';
@NgModule({
declarations: [AppComponent],
@ -74,7 +85,14 @@ import { ENV, environment } from '../environments';
{
provide: APP_INITIALIZER,
useFactory: initializer,
deps: [ConfigService, KeycloakService, LanguageService, ThemeManager, IconsService, Sentry.TraceService],
deps: [
ConfigService,
KeycloakService,
LanguageService,
ThemeManager,
IconsService,
Sentry.TraceService,
],
multi: true,
},
{
@ -89,7 +107,11 @@ import { ENV, environment } from '../environments';
},
{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: false } },
{ provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS },
{ provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS] },
{
provide: DateAdapter,
useClass: MomentDateAdapter,
deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS],
},
{ provide: MAT_RIPPLE_GLOBAL_OPTIONS, useValue: { disabled: true } },
{ provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'outline' } },
{

View File

@ -14,14 +14,14 @@ export class AppAuthGuardService extends KeycloakAuthGuard {
protected router: Router,
protected keycloakAngular: KeycloakService,
private errorService: ErrorService,
private roleAccessService: RoleAccessService
private roleAccessService: RoleAccessService,
) {
super(router, keycloakAngular);
}
async isAccessAllowed(route: ActivatedRouteSnapshot): Promise<boolean | UrlTree> {
const isAccessAllowed = await firstValueFrom(
this.roleAccessService.isAccessAllowed(route.data.roles as RoleAccessName[])
this.roleAccessService.isAccessAllowed(route.data.roles as RoleAccessName[]),
);
if (!isAccessAllowed) {
this.errorService.error('Access is denied', false);

View File

@ -11,7 +11,10 @@ import { RoleAccessName } from './types/role-access-name';
export class IsAccessAllowedPipe implements PipeTransform, OnDestroy {
private asyncPipe: AsyncPipe;
constructor(private roleAccessService: RoleAccessService, ref: ChangeDetectorRef) {
constructor(
private roleAccessService: RoleAccessService,
ref: ChangeDetectorRef,
) {
this.asyncPipe = new AsyncPipe(ref);
}
@ -21,13 +24,15 @@ export class IsAccessAllowedPipe implements PipeTransform, OnDestroy {
transform(
roleAccessNames: RoleAccessName[] | keyof typeof RoleAccessName,
type: 'every' | 'some' = 'every'
type: 'every' | 'some' = 'every',
): boolean {
return this.asyncPipe.transform(
this.roleAccessService.isAccessAllowed(
Array.isArray(roleAccessNames) ? roleAccessNames : [RoleAccessName[roleAccessNames]],
type
)
Array.isArray(roleAccessNames)
? roleAccessNames
: [RoleAccessName[roleAccessNames]],
type,
),
);
}
}

View File

@ -13,15 +13,30 @@ export const ROLE_ACCESS_GROUPS: RoleAccessGroup[] = [
},
{
name: RoleAccessName.ViewInvoices,
availableRoles: [RoleId.Administrator, RoleId.Manager, RoleId.Accountant, RoleId.Integrator],
availableRoles: [
RoleId.Administrator,
RoleId.Manager,
RoleId.Accountant,
RoleId.Integrator,
],
},
{
name: RoleAccessName.ViewPayments,
availableRoles: [RoleId.Administrator, RoleId.Manager, RoleId.Accountant, RoleId.Integrator],
availableRoles: [
RoleId.Administrator,
RoleId.Manager,
RoleId.Accountant,
RoleId.Integrator,
],
},
{
name: RoleAccessName.ViewRefunds,
availableRoles: [RoleId.Administrator, RoleId.Manager, RoleId.Accountant, RoleId.Integrator],
availableRoles: [
RoleId.Administrator,
RoleId.Manager,
RoleId.Accountant,
RoleId.Integrator,
],
},
{
name: RoleAccessName.ViewPayouts,

View File

@ -9,7 +9,10 @@ import { RoleAccess } from './types/role-access';
import { RoleAccessName } from './types/role-access-name';
const ROLE_ACCESSES_OBJECT = Object.fromEntries(
ROLE_ACCESS_GROUPS.flatMap((r) => [r, ...(r.children || [])] as RoleAccess[]).map((r) => [r.name, r.availableRoles])
ROLE_ACCESS_GROUPS.flatMap((r) => [r, ...(r.children || [])] as RoleAccess[]).map((r) => [
r.name,
r.availableRoles,
]),
);
@Injectable({
@ -18,15 +21,19 @@ const ROLE_ACCESSES_OBJECT = Object.fromEntries(
export class RoleAccessService {
constructor(private contextOrganizationService: ContextOrganizationService) {}
isAccessAllowed(roleAccessNames: RoleAccessName[], type: 'every' | 'some' = 'every'): Observable<boolean> {
isAccessAllowed(
roleAccessNames: RoleAccessName[],
type: 'every' | 'some' = 'every',
): Observable<boolean> {
if (!roleAccessNames.length) return of(true);
return this.contextOrganizationService.member$.pipe(
map((member) => {
const memberRoles = member.roles.map((r) => r.roleId);
return roleAccessNames[type]((access) =>
ROLE_ACCESSES_OBJECT[access]?.some((role) => memberRoles.includes(role))
return roleAccessNames[type](
(access) =>
ROLE_ACCESSES_OBJECT[access]?.some((role) => memberRoles.includes(role)),
);
})
}),
);
}
}

View File

@ -8,6 +8,7 @@ export interface RoleAccess {
availableRoles: RoleId[];
}
export interface RoleAccessGroup extends Overwrite<RoleAccess, Partial<Pick<RoleAccess, 'availableRoles'>>> {
export interface RoleAccessGroup
extends Overwrite<RoleAccess, Partial<Pick<RoleAccess, 'availableRoles'>>> {
children?: RoleAccess[];
}

View File

@ -9,18 +9,20 @@ import { ShopsDataService, ErrorService, CommonError } from '@dsh/app/shared';
export class BootstrapService {
bootstrapped$: Observable<boolean> = this.shopsDataService.shops$.pipe(
catchError((err) =>
this.transloco.selectTranslate<string>('app.errors.bootstrapAppFailed', null, 'components').pipe(
tap((msg) => this.errorService.error(new CommonError(msg))),
switchMap(() => throwError(err))
)
this.transloco
.selectTranslate<string>('app.errors.bootstrapAppFailed', null, 'components')
.pipe(
tap((msg) => this.errorService.error(new CommonError(msg))),
switchMap(() => throwError(err)),
),
),
map(() => true)
map(() => true),
);
constructor(
private shopsDataService: ShopsDataService,
private transloco: TranslocoService,
private errorService: ErrorService
private errorService: ErrorService,
) {}
}

View File

@ -7,10 +7,10 @@ import { catchError, distinctUntilChanged, map, startWith } from 'rxjs/operators
export const progress = (
start$: Observable<unknown>,
end$: Observable<unknown>,
startValue = false
startValue = false,
): Observable<boolean> =>
merge(start$.pipe(map(() => true)), end$.pipe(map(() => false))).pipe(
catchError(() => of(false)),
startWith(startValue),
distinctUntilChanged()
distinctUntilChanged(),
);

View File

@ -34,10 +34,11 @@ export const replaceError = <T, E>(source: Observable<T>): Observable<T | BasicE
export const filterError = <E, T>(source: Observable<T | BasicError<E>>): Observable<E> =>
source.pipe(
filter<BasicError<E>>((value) => value instanceof BasicError),
pluck('error')
pluck('error'),
);
/**
* @deprecated use toError()
*/
export const filterPayload = <T>(source: Observable<T | BasicError>): Observable<T> => source.pipe(filter(isPayload));
export const filterPayload = <T>(source: Observable<T | BasicError>): Observable<T> =>
source.pipe(filter(isPayload));

View File

@ -8,7 +8,7 @@ import { share } from 'rxjs/operators';
export const SHARE_REPLAY_CONF: ShareReplayConfig = { bufferSize: 1, refCount: true };
export function shareReplayRefCount<T>(
params: Pick<ShareReplayConfig, 'bufferSize'> & { resetOnRefCountZeroTimer?: number } = {}
params: Pick<ShareReplayConfig, 'bufferSize'> & { resetOnRefCountZeroTimer?: number } = {},
): MonoTypeOperatorFunction<T> {
const state = new ReplaySubject<T>(1);
return share({

View File

@ -5,7 +5,8 @@ import { shareReplay } from 'rxjs/operators';
export function shareReplayUntilDestroyed<T>(
instance: unknown,
{ bufferSize = 1, ...rest }: Omit<ShareReplayConfig, 'refCount'> = {}
{ bufferSize = 1, ...rest }: Omit<ShareReplayConfig, 'refCount'> = {},
): MonoTypeOperatorFunction<T> {
return (src$) => src$.pipe(untilDestroyed(instance), shareReplay({ ...rest, bufferSize, refCount: false }));
return (src$) =>
src$.pipe(untilDestroyed(instance), shareReplay({ ...rest, bufferSize, refCount: false }));
}

View File

@ -3,4 +3,5 @@ import { map } from 'rxjs/operators';
import { ResultWithToken } from './result-with-token';
export const mapResult = <T>(s: Observable<ResultWithToken<T>>): Observable<T[]> => s.pipe(map((r) => r.result));
export const mapResult = <T>(s: Observable<ResultWithToken<T>>): Observable<T[]> =>
s.pipe(map((r) => r.result));

View File

@ -3,7 +3,15 @@ import { switchMap } from 'rxjs/operators';
import { ResultWithToken } from './result-with-token';
export const noContinuationToken = <T>(s: Observable<ResultWithToken<T>>): Observable<ResultWithToken<T>> =>
export const noContinuationToken = <T>(
s: Observable<ResultWithToken<T>>,
): Observable<ResultWithToken<T>> =>
s.pipe(
switchMap((r) => iif(() => !!r.continuationToken, throwError('Continuation token is not supported'), of(r)))
switchMap((r) =>
iif(
() => !!r.continuationToken,
throwError('Continuation token is not supported'),
of(r),
),
),
);

View File

@ -7,5 +7,5 @@ import { catchError, filter } from 'rxjs/operators';
export const takeError = <T>(source: Observable<T>) =>
source.pipe(
filter((_) => false),
catchError((err) => of(err))
catchError((err) => of(err)),
);

View File

@ -1,16 +1,20 @@
<mat-form-field class="field">
<mat-label>{{ label }}</mat-label>
<input matInput [required]="required" [formControl]="control" [matAutocomplete]="auto" />
<input [formControl]="control" [matAutocomplete]="auto" [required]="required" matInput />
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="optionSelectedHandler($event)">
<ng-container *ngIf="!(isOptionsLoading$ | async)">
<mat-option *ngFor="let option of options$ | async" [value]="option.label" class="option">
<mat-option
*ngFor="let option of options$ | async"
[value]="option.label"
class="option"
>
<div
[innerHTML]="option.label | highlight: control.value"
class="dsh-dadata-autocomplete-option-header"
[innerHTML]="option.label | highlight : control.value"
></div>
<div
[innerHTML]="option.description | highlight: control.value"
class="dsh-dadata-autocomplete-option-description"
[innerHTML]="option.description | highlight : control.value"
></div>
</mat-option>
</ng-container>

View File

@ -49,7 +49,10 @@ const REQUEST_TYPE_BY_TYPE: RequestTypeByType = {
templateUrl: 'dadata.component.html',
providers: createControlProviders(() => DaDataAutocompleteComponent),
})
export class DaDataAutocompleteComponent<T extends Type = Type, R extends DaDataRequestType = RequestTypeByType[T]>
export class DaDataAutocompleteComponent<
T extends Type = Type,
R extends DaDataRequestType = RequestTypeByType[T],
>
extends FormControlSuperclass<string>
implements OnInit
{
@ -66,15 +69,16 @@ export class DaDataAutocompleteComponent<T extends Type = Type, R extends DaData
filter<string>(Boolean),
debounce(() => interval(300)),
switchMap((v) => this.loadSuggestions(v)),
shareReplayUntilDestroyed(this)
shareReplayUntilDestroyed(this),
);
options$: Observable<Option<ContentByRequestType[R]>[]> = this.suggestions$.pipe(
map((suggestions) => suggestions.map((s) => this.getOption(s))),
shareReplayUntilDestroyed(this)
);
isOptionsLoading$: Observable<boolean> = progress(this.control.valueChanges, this.suggestions$).pipe(
shareReplayUntilDestroyed(this)
shareReplayUntilDestroyed(this),
);
isOptionsLoading$: Observable<boolean> = progress(
this.control.valueChanges,
this.suggestions$,
).pipe(shareReplayUntilDestroyed(this));
constructor(private daDataService: DaDataService) {
super();
@ -82,8 +86,12 @@ export class DaDataAutocompleteComponent<T extends Type = Type, R extends DaData
ngOnInit(): void {
this.isOptionsLoading$.pipe(untilDestroyed(this)).subscribe();
this.suggestions$.pipe(filter(isEmpty), untilDestroyed(this)).subscribe(() => this.suggestionNotFound.emit());
this.suggestions$.pipe(takeError, untilDestroyed(this)).subscribe((error) => this.errorOccurred.next(error));
this.suggestions$
.pipe(filter(isEmpty), untilDestroyed(this))
.subscribe(() => this.suggestionNotFound.emit());
this.suggestions$
.pipe(takeError, untilDestroyed(this))
.subscribe((error) => this.errorOccurred.next(error));
}
optionSelectedHandler(e: MatAutocompleteSelectedEvent): void {
@ -102,7 +110,7 @@ export class DaDataAutocompleteComponent<T extends Type = Type, R extends DaData
const params: ParamsByRequestType[R] = { query } as ParamsByRequestType[R];
return this.daDataService.suggest(
REQUEST_TYPE_BY_TYPE[this.type],
this.withSpecificParams(params)
this.withSpecificParams(params),
) as unknown as Observable<ContentByRequestType[R][]>;
}

View File

@ -20,7 +20,10 @@ export class HighlightSearchPipe implements PipeTransform {
return value;
}
const replacedValue = value.replace(re, '<mark class="dsh-dadata-autocomplete-mark">' + match[0] + '</mark>');
const replacedValue = value.replace(
re,
'<mark class="dsh-dadata-autocomplete-mark">' + match[0] + '</mark>',
);
return this.sanitizer.bypassSecurityTrustHtml(replacedValue);
}
}

View File

@ -3,6 +3,6 @@
[expanded]="(userDropdown.state$ | async) === 'open'"
></dsh-user-dropdown>
<dsh-dropdown width="287px" #userDropdown="dshDropdown" [hasArrow]="false" position="left">
<dsh-dropdown #userDropdown="dshDropdown" [hasArrow]="false" position="left" width="287px">
<ng-template><dsh-user (selected)="userDropdown.close()"></dsh-user></ng-template>
</dsh-dropdown>

View File

@ -1,4 +1,10 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input, ViewEncapsulation } from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
HostBinding,
Input,
ViewEncapsulation,
} from '@angular/core';
import { coerceBoolean } from 'coerce-property';
@Component({

View File

@ -1,16 +1,20 @@
<div
*transloco="let t; scope: 'components'; read: 'components.actionbar.organizations'"
fxLayout="column"
fxLayoutGap="16px"
*transloco="let t; scope: 'components'; read: 'components.actionbar.organizations'"
>
<dsh-menu-item header routerLink="/organization-section/organizations" (click)="selected.emit()">
<dsh-menu-item
header
routerLink="/organization-section/organizations"
(click)="selected.emit()"
>
{{ t('title') }}
</dsh-menu-item>
<dsh-menu-item
*ngFor="let org of orgs$ | async"
[fragment]="org.id"
class="dsh-user-link"
routerLink="/organization-section/organizations"
[fragment]="org.id"
(click)="selected.emit()"
>
{{ org.name }}

View File

@ -4,9 +4,19 @@
(cancel)="close()"
>
<div fxLayout="column" fxLayoutGap="8px">
<dsh-limited-panel (showMore)="showMore()" [hasMore]="(isLoading$ | async) === false && (hasMore$ | async)">
<mat-radio-group [(ngModel)]="selectedOrganization" fxLayout="column" fxLayoutGap="24px">
<mat-radio-button *ngFor="let organization of organizations$ | async" [value]="organization">
<dsh-limited-panel
[hasMore]="(isLoading$ | async) === false && (hasMore$ | async)"
(showMore)="showMore()"
>
<mat-radio-group
[(ngModel)]="selectedOrganization"
fxLayout="column"
fxLayoutGap="24px"
>
<mat-radio-button
*ngFor="let organization of organizations$ | async"
[value]="organization"
>
{{ organization.name }}
</mat-radio-button>
</mat-radio-group>
@ -15,10 +25,13 @@
</div>
<ng-container dshBaseDialogActions>
<button
dsh-button
[disabled]="
!selectedOrganization ||
selectedOrganization.id === (contextOrganization$ | async)?.id
"
color="accent"
dsh-button
(click)="confirm()"
[disabled]="!selectedOrganization || selectedOrganization.id === (contextOrganization$ | async)?.id"
>
{{ t('confirm') }}
</button>

View File

@ -34,7 +34,7 @@ export class SelectActiveOrganizationDialogComponent implements OnInit {
>,
private fetchOrganizationsService: FetchOrganizationsService,
private router: Router,
private contextOrganizationService: ContextOrganizationService
private contextOrganizationService: ContextOrganizationService,
) {}
ngOnInit(): void {
@ -43,7 +43,7 @@ export class SelectActiveOrganizationDialogComponent implements OnInit {
.pipe(
first(),
map(([orgs, activeOrg]) => orgs.find((org) => org.id === activeOrg.id)),
untilDestroyed(this)
untilDestroyed(this),
)
.subscribe((organization) => (this.selectedOrganization = organization));
}

View File

@ -1,7 +1,11 @@
<div class="dsh-user-dropdown" fxLayout="column" fxLayoutGap="4px">
<div fxLayout fxLayoutGap="8px" fxLayoutAlign=" center">
<div fxLayout fxLayoutAlign=" center" fxLayoutGap="8px">
<div class="dsh-body-2 username">{{ username }}</div>
<dsh-bi icon="chevron-down" size="sm" [@rotate]="expanded ? 'expanded' : 'collapsed'"></dsh-bi>
<dsh-bi
[@rotate]="expanded ? 'expanded' : 'collapsed'"
icon="chevron-down"
size="sm"
></dsh-bi>
</div>
<div class="dsh-caption organization" *ngIf="orgName$ | async">{{ orgName$ | async }}</div>
<div *ngIf="orgName$ | async" class="dsh-caption organization">{{ orgName$ | async }}</div>
</div>

View File

@ -4,9 +4,10 @@ import { map } from 'rxjs/operators';
import { ContextOrganizationService } from '@dsh/app/shared/services';
import { ROTATE } from './utils/rotate-animation';
import { KeycloakService } from '../../../../auth';
import { ROTATE } from './utils/rotate-animation';
@Component({
selector: 'dsh-user-dropdown',
templateUrl: 'user-dropdown.component.html',
@ -22,6 +23,6 @@ export class UserDropdownComponent {
constructor(
private contextOrganizationService: ContextOrganizationService,
private keycloakService: KeycloakService
private keycloakService: KeycloakService,
) {}
}

View File

@ -2,5 +2,8 @@ import { trigger, state, style, transition, animate } from '@angular/animations'
export const ROTATE = trigger('rotate', [
state('expanded', style({ transform: 'rotate(180deg)' })),
transition('expanded <=> collapsed, void => collapsed', animate('225ms cubic-bezier(0.4,0.0,0.2,1)')),
transition(
'expanded <=> collapsed, void => collapsed',
animate('225ms cubic-bezier(0.4,0.0,0.2,1)'),
),
]);

View File

@ -4,15 +4,21 @@
fxLayoutGap="24px"
>
<ng-container>
<dsh-menu-item class="dsh-body-2" *ngIf="activeOrg$ | async as activeOrg" (click)="toActiveOrg(activeOrg.id)">{{
activeOrg.name
}}</dsh-menu-item>
<dsh-menu-item
*ngIf="activeOrg$ | async as activeOrg"
class="dsh-body-2"
(click)="toActiveOrg(activeOrg.id)"
>{{ activeOrg.name }}</dsh-menu-item
>
<dsh-menu-item (click)="selectActiveOrg()">{{ t('selectActiveOrg') }}</dsh-menu-item>
<dsh-menu-item (click)="openOrgList()">{{ t('orgList') }}</dsh-menu-item>
</ng-container>
<mat-divider></mat-divider>
<span class="dsh-body-2">{{ username }}</span>
<dsh-menu-item *ngFor="let linkConfig of userLinksConfig$ | async" (click)="openBlank(linkConfig.href)">
<dsh-menu-item
*ngFor="let linkConfig of userLinksConfig$ | async"
(click)="openBlank(linkConfig.href)"
>
{{ linkConfig.title }}
</dsh-menu-item>
<dsh-menu-item (click)="logout()">{{ t('logout') }}</dsh-menu-item>

View File

@ -38,7 +38,7 @@ export class UserComponent {
title: this.transloco.translate('actionbar.user.twoFactorAuth', {}, 'components'),
href: `${this.keycloakAccountEndpoint}/totp`,
},
])
]),
);
constructor(
@ -48,7 +48,7 @@ export class UserComponent {
private router: Router,
private dialog: MatDialog,
private transloco: TranslocoService,
@Inject(DIALOG_CONFIG) private dialogConfig: DialogConfig
@Inject(DIALOG_CONFIG) private dialogConfig: DialogConfig,
) {}
openBlank(href: string): void {
@ -62,12 +62,20 @@ export class UserComponent {
selectActiveOrg(): void {
this.selected.emit();
this.dialog
.open<SelectActiveOrganizationDialogComponent, void, BaseDialogResponseStatus | Organization>(
.open<
SelectActiveOrganizationDialogComponent,
this.dialogConfig.medium
)
void,
BaseDialogResponseStatus | Organization
>(SelectActiveOrganizationDialogComponent, this.dialogConfig.medium)
.afterClosed()
.pipe(filter((res) => !Object.values(BaseDialogResponseStatus).includes(res as BaseDialogResponseStatus)))
.pipe(
filter(
(res) =>
!Object.values(BaseDialogResponseStatus).includes(
res as BaseDialogResponseStatus,
),
),
)
.subscribe((org: Organization) => {
this.contextOrganizationService.switchOrganization(org.id);
});
@ -79,7 +87,9 @@ export class UserComponent {
}
toActiveOrg(activeOrg: string): void {
void this.router.navigate(['organization-section', 'organizations'], { fragment: activeOrg });
void this.router.navigate(['organization-section', 'organizations'], {
fragment: activeOrg,
});
this.selected.emit();
}
}

View File

@ -20,7 +20,7 @@ export class HomeComponent implements OnInit {
private router: Router,
// need to create class when home component was init
private themeManager: ThemeManager,
private breakpointObserver: BreakpointObserver
private breakpointObserver: BreakpointObserver,
) {}
ngOnInit(): void {
@ -28,7 +28,7 @@ export class HomeComponent implements OnInit {
filter((event) => event instanceof NavigationEnd),
map(() => true),
take(1),
untilDestroyed(this)
untilDestroyed(this),
);
this.isXSmallSmall$ = this.breakpointObserver
.observe([Breakpoints.XSmall, Breakpoints.Small])

View File

@ -2,9 +2,10 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { LaptopGridComponent } from './laptop-grid.component';
import { ToolbarModule } from '../toolbar';
import { LaptopGridComponent } from './laptop-grid.component';
@NgModule({
imports: [CommonModule, ToolbarModule, FlexLayoutModule],
declarations: [LaptopGridComponent],

View File

@ -1,16 +1,31 @@
<mat-drawer-container class="dsh-mobile-grid">
<mat-drawer class="dsh-mobile-grid-drawer" mode="over" [autoFocus]="false">
<mat-drawer [autoFocus]="false" class="dsh-mobile-grid-drawer" mode="over">
<div class="dsh-mobile-grid-drawer-wrapper" fxLayout="column">
<div class="dsh-mobile-grid-drawer-actions" fxLayout="row" fxLayoutAlign="end center">
<dsh-bi class="dsh-mobile-grid-toggle-button" (click)="closeSideNav()" icon="x" size="lg"></dsh-bi>
<dsh-bi
class="dsh-mobile-grid-toggle-button"
icon="x"
size="lg"
(click)="closeSideNav()"
></dsh-bi>
</div>
<dsh-mobile-menu fxFlex (menuItemSelected)="closeSideNav()"></dsh-mobile-menu>
</div>
</mat-drawer>
<mat-drawer-content>
<div class="dsh-mobile-grid-content" fxLayout="column" fxLayoutGap="24px">
<div class="dsh-mobile-grid-content-actions" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="24px">
<dsh-bi class="dsh-mobile-grid-toggle-button" (click)="openSideNav()" icon="list" size="lg"></dsh-bi>
<div
class="dsh-mobile-grid-content-actions"
fxLayout="row"
fxLayoutAlign="start center"
fxLayoutGap="24px"
>
<dsh-bi
class="dsh-mobile-grid-toggle-button"
icon="list"
size="lg"
(click)="openSideNav()"
></dsh-bi>
<dsh-brand></dsh-brand>
</div>
<ng-content></ng-content>

View File

@ -5,12 +5,20 @@ import { MatSidenavModule } from '@angular/material/sidenav';
import { BootstrapIconModule } from '@dsh/components/indicators';
import { MobileGridComponent } from './mobile-grid.component';
import { MobileMenuModule } from './mobile-menu';
import { BrandModule } from '../brand';
import { MobileGridComponent } from './mobile-grid.component';
import { MobileMenuModule } from './mobile-menu';
@NgModule({
imports: [CommonModule, MatSidenavModule, BrandModule, FlexLayoutModule, MobileMenuModule, BootstrapIconModule],
imports: [
CommonModule,
MatSidenavModule,
BrandModule,
FlexLayoutModule,
MobileMenuModule,
BootstrapIconModule,
],
declarations: [MobileGridComponent],
exports: [MobileGridComponent],
})

View File

@ -1,3 +1,3 @@
<div class="dsh-mobile-menu-nav-item" [ngClass]="{ 'dsh-mobile-nav-item-active': active }">
<div [ngClass]="{ 'dsh-mobile-nav-item-active': active }" class="dsh-mobile-menu-nav-item">
<ng-content></ng-content>
</div>

View File

@ -1,12 +1,12 @@
<div class="dsh-mobile-menu" fxLayout="column">
<div class="dsh-enu-nav-items" fxFlex fxLayout="column" fxLayoutGap="16px">
<dsh-mobile-menu-nav-item
*ngFor="let link of sectionLinks$ | async"
[routerLink]="link.path"
routerLinkActive
[routerLinkActiveOptions]="{ exact: link?.exact }"
#rla="routerLinkActive"
*ngFor="let link of sectionLinks$ | async"
[active]="rla.isActive"
[routerLink]="link.path"
[routerLinkActiveOptions]="{ exact: link?.exact }"
routerLinkActive
(click)="menuItemSelected.emit()"
>{{ link.label }}</dsh-mobile-menu-nav-item
>

View File

@ -1,15 +1,15 @@
<div class="dsh-toolbar" fxLayout fxLayoutGap="24px" fxLayoutAlign="center center">
<div class="dsh-toolbar" fxLayout fxLayoutAlign="center center" fxLayoutGap="24px">
<dsh-brand fxFlex fxLayoutAlign="start"></dsh-brand>
<div fxFlex fxLayoutAlign="center">
<nav class="dsh-top-tab-nav-bar" mat-tab-nav-bar [tabPanel]="tabPanel">
<nav [tabPanel]="tabPanel" class="dsh-top-tab-nav-bar" mat-tab-nav-bar>
<a
*ngFor="let link of sectionLinks$ | async"
mat-tab-link
[routerLink]="link.path"
routerLinkActive
[routerLinkActiveOptions]="{ exact: link?.exact }"
#rla="routerLinkActive"
*ngFor="let link of sectionLinks$ | async"
[active]="rla.isActive"
[routerLink]="link.path"
[routerLinkActiveOptions]="{ exact: link?.exact }"
mat-tab-link
routerLinkActive
>
{{ link.label }}
</a>

View File

@ -6,10 +6,11 @@ import { RouterModule } from '@angular/router';
import { SectionsLinksModule } from '@dsh/app/shared/services/sections-links';
import { ToolbarComponent } from './toolbar.component';
import { ActionbarModule } from '../actionbar';
import { BrandModule } from '../brand';
import { ToolbarComponent } from './toolbar.component';
@NgModule({
imports: [
CommonModule,

View File

@ -32,8 +32,9 @@ export class HumanizeDurationService {
}
get shortEnglishHumanizer(): humanizeDuration.HumanizerOptions {
const getLocalizedUnitFn = (unit: keyof ReturnType<HumanizeDurationService['getUnitLabels']>) => () =>
this.getUnitLabels()[unit];
const getLocalizedUnitFn =
(unit: keyof ReturnType<HumanizeDurationService['getUnitLabels']>) => () =>
this.getUnitLabels()[unit];
return {
language: 'short',
languages: {
@ -51,7 +52,10 @@ export class HumanizeDurationService {
};
}
constructor(private languageService: LanguageService, private transloco: TranslocoService) {}
constructor(
private languageService: LanguageService,
private transloco: TranslocoService,
) {}
getDiffMs(value: Value): number {
return Math.abs(this.isDiff(value) ? value : moment().diff(moment(value)));
@ -63,7 +67,11 @@ export class HumanizeDurationService {
if (isNaN(diffMs)) {
return null;
} else if (diffMs < HumanizeDurationService.LESS_THAN_FEW_SECONDS) {
return this.transloco.selectTranslate('humanizeDuration.justNow', null, 'core-components');
return this.transloco.selectTranslate(
'humanizeDuration.justNow',
null,
'core-components',
);
} else if (config.isShort) {
duration = this.duration(diffMs, { ...config, ...this.shortEnglishHumanizer });
} else if (config.largest === 1) {
@ -72,8 +80,12 @@ export class HumanizeDurationService {
duration = duration === 'минута' ? 'минуту' : duration;
return of(
config.hasAgoEnding
? `${duration} ${this.transloco.translate('humanizeDuration.ago', null, 'core-components')}`
: duration
? `${duration} ${this.transloco.translate(
'humanizeDuration.ago',
null,
'core-components',
)}`
: duration,
);
}
@ -97,14 +109,46 @@ export class HumanizeDurationService {
private getUnitLabels() {
return {
day: this.transloco.translate('humanizeDuration.shortUnit.day', null, 'core-components'),
hour: this.transloco.translate('humanizeDuration.shortUnit.hour', null, 'core-components'),
millisecond: this.transloco.translate('humanizeDuration.shortUnit.millisecond', null, 'core-components'),
minute: this.transloco.translate('humanizeDuration.shortUnit.minute', null, 'core-components'),
month: this.transloco.translate('humanizeDuration.shortUnit.month', null, 'core-components'),
second: this.transloco.translate('humanizeDuration.shortUnit.second', null, 'core-components'),
week: this.transloco.translate('humanizeDuration.shortUnit.week', null, 'core-components'),
year: this.transloco.translate('humanizeDuration.shortUnit.year', null, 'core-components'),
day: this.transloco.translate(
'humanizeDuration.shortUnit.day',
null,
'core-components',
),
hour: this.transloco.translate(
'humanizeDuration.shortUnit.hour',
null,
'core-components',
),
millisecond: this.transloco.translate(
'humanizeDuration.shortUnit.millisecond',
null,
'core-components',
),
minute: this.transloco.translate(
'humanizeDuration.shortUnit.minute',
null,
'core-components',
),
month: this.transloco.translate(
'humanizeDuration.shortUnit.month',
null,
'core-components',
),
second: this.transloco.translate(
'humanizeDuration.shortUnit.second',
null,
'core-components',
),
week: this.transloco.translate(
'humanizeDuration.shortUnit.week',
null,
'core-components',
),
year: this.transloco.translate(
'humanizeDuration.shortUnit.year',
null,
'core-components',
),
};
}
}

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