Revert claim-mgt (#99)

This commit is contained in:
Alexandra Usacheva 2019-12-24 16:54:27 +03:00 committed by GitHub
parent a1ee82a491
commit a84912a68f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
101 changed files with 154 additions and 1115 deletions

2
Jenkinsfile vendored
View File

@ -16,7 +16,7 @@ build('control-center', 'docker-host') {
runStage('init') {
withGithubSshCredentials {
withGithubToken {
sh 'make wc_init'
sh 'make wc_init'
}
}
}

View File

@ -22,6 +22,7 @@ BUILD_IMAGE_TAG := f3732d29a5e622aabf80542b5138b3631a726adb
GIT_SSH_COMMAND :=
DOCKER_RUN_OPTS = -e GIT_SSH_COMMAND='$(GIT_SSH_COMMAND)' -e NG_CLI_ANALYTICS=ci -e NPM_TOKEN='$(GITHUB_TOKEN)'
CALL_W_CONTAINER := init build clean submodules
.PHONY: $(CALL_W_CONTAINER)
@ -53,7 +54,7 @@ clean:
compile-damsel: damsel-client damsel-model damsel-meta
damsel-client:
@$(foreach file,domain_config payment_processing merch_stat claim_management,echo $(file); thrift -r -gen js:node,runtime_package=woody_js/dist/thrift -o ./src/app/thrift ./node_modules/damsel/proto/$(file).thrift;)
@$(foreach file,domain_config payment_processing merch_stat,echo $(file); thrift -r -gen js:node,runtime_package=woody_js/dist/thrift -o ./src/app/thrift ./node_modules/damsel/proto/$(file).thrift;)
damsel-meta:
npm run damsel-meta

38
package-lock.json generated
View File

@ -2470,12 +2470,6 @@
"@types/node": "*"
}
},
"@types/humanize-duration": {
"version": "3.18.0",
"resolved": "https://registry.npmjs.org/@types/humanize-duration/-/humanize-duration-3.18.0.tgz",
"integrity": "sha512-11QHl+GvEQ5TlCjA9xqQKNv4S0P8XFq5uHeZe2UPjngESBl7tA1tai/60eEYwWMFWIyQOl7ybarYF0B33K3Qtg==",
"dev": true
},
"@types/jasmine": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.8.tgz",
@ -2491,12 +2485,6 @@
"@types/jasmine": "*"
}
},
"@types/jwt-decode": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@types/jwt-decode/-/jwt-decode-2.2.1.tgz",
"integrity": "sha512-aWw2YTtAdT7CskFyxEX2K21/zSDStuf/ikI3yBqmwpwJF0pS+/IX5DWv+1UFffZIbruP6cnT9/LAJV1gFwAT1A==",
"dev": true
},
"@types/lodash": {
"version": "4.14.116",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.116.tgz",
@ -2977,10 +2965,6 @@
"tslib": "^1.7.1"
}
},
"ank-proto": {
"version": "git+ssh://git@github.com/rbkmoney/ank-proto.git#6535945971838d7dfc021aeff3248a9dac4ba28b",
"from": "git+ssh://git@github.com/rbkmoney/ank-proto.git#6535945971838d7dfc021aeff3248a9dac4ba28b"
},
"ansi-colors": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
@ -5246,8 +5230,8 @@
"integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk="
},
"damsel": {
"version": "git+ssh://git@github.com/rbkmoney/damsel.git#5a78a602632a1dbbc5f294361d1538cff4a27040",
"from": "git+ssh://git@github.com/rbkmoney/damsel.git#5a78a602632a1dbbc5f294361d1538cff4a27040"
"version": "git+ssh://git@github.com/rbkmoney/damsel.git#b563890354447a5e175a9a318b33233a926a5e9c",
"from": "git+ssh://git@github.com/rbkmoney/damsel.git#b563890354447a5e175a9a318b33233a926a5e9c"
},
"dashdash": {
"version": "1.14.1",
@ -6321,10 +6305,6 @@
}
}
},
"file-storage-proto": {
"version": "git+ssh://git@github.com/rbkmoney/file-storage-proto.git#281e1ca4cea9bf32229a6c389f0dcf5d49c05a0b",
"from": "git+ssh://git@github.com/rbkmoney/file-storage-proto.git#281e1ca4cea9bf32229a6c389f0dcf5d49c05a0b"
},
"fileset": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz",
@ -7046,11 +7026,6 @@
}
}
},
"humanize-duration": {
"version": "3.21.0",
"resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.21.0.tgz",
"integrity": "sha512-7BLsrQZ2nMGeakmGDUl1pDne6/7iAdvwf1RtDLCOPHNFIHjkOVW7lcu7xHkIM9HhZAlSSO5crhC1dHvtl4dIQw=="
},
"humanize-ms": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
@ -7920,7 +7895,8 @@
"jwt-decode": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz",
"integrity": "sha1-fYa9VmefWM5qhHBKZX3TkruoGnk="
"integrity": "sha1-fYa9VmefWM5qhHBKZX3TkruoGnk=",
"dev": true
},
"karma": {
"version": "4.3.0",
@ -8337,10 +8313,6 @@
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
"dev": true
},
"messages-proto": {
"version": "git+ssh://git@github.com/rbkmoney/messages-proto.git#e873358674882447bc3a2a0554db6ac08b316bec",
"from": "git+ssh://git@github.com/rbkmoney/messages-proto.git#e873358674882447bc3a2a0554db6ac08b316bec"
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
@ -14306,7 +14278,7 @@
},
"stream-http": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.3.1.tgz",
"resolved": "http://registry.npmjs.org/stream-http/-/stream-http-2.3.1.tgz",
"integrity": "sha1-fh3IcQLD4xsy5mDwTKMfI929HVI=",
"requires": {
"builtin-status-codes": "^2.0.0",

View File

@ -12,7 +12,6 @@
"damsel-meta": "thrift-ts node_modules/damsel/proto -o src/assets/meta-damsel.json --json --pack --prettify",
"machinegun-model": "thrift-ts node_modules/machinegun_proto/proto -o src/app/machinegun/gen-model -d false",
"fistful-model": "thrift-ts node_modules/fistful-proto/proto -o src/app/fistful/gen-model -d false",
"codegen": "npm run damsel-model; npm run damsel-meta; npm run machinegun-model; npm run fistful-model",
"prettier": "prettier \"**/*.{html,js,ts,css,md,json,prettierrc,svg}\" --write",
"check": "prettier \"**/*.{html,js,ts,css,md,json,prettierrc,svg}\" --list-different"
},
@ -34,19 +33,14 @@
"@rbkmoney/partial-fetcher": "^1.0.4",
"angular2-prettyjson": "3.0.1",
"core-js": "^2.5.4",
"damsel": "git+ssh://git@github.com/rbkmoney/damsel.git#5a78a602632a1dbbc5f294361d1538cff4a27040",
"machinegun_proto": "git+ssh://git@github.com/rbkmoney/machinegun_proto.git#ebae56fe2b3e79e4eb34afc8cb55c9012ae989f8",
"messages-proto": "git+ssh://git@github.com:rbkmoney/messages-proto.git#e873358674882447bc3a2a0554db6ac08b316bec",
"file-storage-proto": "git+ssh://git@github.com:rbkmoney/file-storage-proto.git#281e1ca4cea9bf32229a6c389f0dcf5d49c05a0b",
"ank-proto": "git+ssh://git@github.com:rbkmoney/ank-proto.git#6535945971838d7dfc021aeff3248a9dac4ba28b",
"damsel": "git+ssh://git@github.com/rbkmoney/damsel.git#b563890354447a5e175a9a318b33233a926a5e9c",
"fistful-proto": "git+ssh://git@github.com/rbkmoney/fistful-proto.git#6e653a244e7b2106908604c4692ee5ab4496af09",
"hammerjs": "^2.0.8",
"humanize-duration": "^3.21.0",
"jsonc-parser": "^2.0.2",
"jwt-decode": "^2.2.0",
"keycloak-angular": "6.0.0",
"keycloak-js": "4.5.0",
"lodash-es": "^4.17.10",
"machinegun_proto": "git+ssh://git@github.com/rbkmoney/machinegun_proto.git#ebae56fe2b3e79e4eb34afc8cb55c9012ae989f8",
"moment": "^2.22.2",
"monaco-editor": "^0.15.6",
"rxjs": "^6.5.3",
@ -59,16 +53,15 @@
"@angular-devkit/build-angular": "^0.803.6",
"@angular/cli": "^8.3.6",
"@angular/compiler-cli": "^8.2.8",
"@types/humanize-duration": "^3.18.0",
"@types/jasmine": "~2.8.6",
"@types/jasminewd2": "~2.0.3",
"@types/jwt-decode": "^2.2.1",
"@types/lodash-es": "^4.17.1",
"@types/node": "~8.9.4",
"@types/uuid": "^3.4.3",
"codelyzer": "~4.2.1",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"jwt-decode": "^2.2.0",
"karma": "^4.3.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.0",

View File

@ -20,6 +20,7 @@ import {
import { AppComponent } from './app.component';
import { CoreModule } from './core/core.module';
import { ClaimsModule } from './claims/claims.module';
import { AppRoutingModule } from './app-routing.module';
import { ClaimModule } from './claim/claim.module';
import { PayoutsModule } from './payouts/payouts.module';
@ -29,7 +30,6 @@ import { PartyModule } from './party/party.module';
import { DomainModule } from './domain';
import { RepairingModule } from './repairing/repairing.module';
import { DepositsModule } from './deposits/deposits.module';
import { ClaimMgtModule } from './claim-mgt/claim-mgt.module';
@NgModule({
declarations: [AppComponent],
@ -44,8 +44,8 @@ import { ClaimMgtModule } from './claim-mgt/claim-mgt.module';
MatMenuModule,
MatSidenavModule,
MatListModule,
ClaimsModule,
ClaimModule,
ClaimMgtModule,
PayoutsModule,
PaymentAdjustmentModule,
PartiesModule,

View File

@ -1,28 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { AppAuthGuardService } from '../app-auth-guard.service';
@NgModule({
imports: [
RouterModule.forChild([
{
path: 'claims',
loadChildren: () => import('./claims').then(m => m.ClaimsModule),
canActivate: [AppAuthGuardService],
data: {
roles: ['claim:get']
}
},
{
path: 'party',
loadChildren: () => import('./claim').then(m => m.ClaimModule),
canActivate: [AppAuthGuardService],
data: {
roles: ['claim:get']
}
}
])
],
exports: [RouterModule]
})
export class ClaimMgtRouting {}

View File

@ -1,7 +0,0 @@
import { NgModule } from '@angular/core';
import { ClaimMgtRouting } from './claim-mgt-routing.module';
@NgModule({
imports: [ClaimMgtRouting]
})
export class ClaimMgtModule {}

View File

@ -1,21 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { AppAuthGuardService } from '../../app-auth-guard.service';
import { ClaimComponent } from './claim.component';
@NgModule({
imports: [
RouterModule.forChild([
{
path: ':party_id/claim/:claim_id',
component: ClaimComponent,
canActivate: [AppAuthGuardService],
data: {
roles: ['claim:get']
}
}
])
],
exports: [RouterModule]
})
export class ClaimRoutingModule {}

View File

@ -1,4 +0,0 @@
<cc-card-container *ngIf="(claim$ | async) as claim">
<cc-claim-details [claim]="claim"></cc-claim-details>
<cc-claim-conversation [claim]="claim"></cc-claim-conversation>
</cc-card-container>

View File

@ -1,19 +0,0 @@
import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ClaimService } from './claim.service';
@Component({
templateUrl: 'claim.component.html',
providers: [ClaimService]
})
export class ClaimComponent {
claim$ = this.claimService.claim$;
constructor(private route: ActivatedRoute, private claimService: ClaimService) {
this.route.params.subscribe(params => {
const { party_id, claim_id } = params;
this.claimService.getClaim(party_id, Number(claim_id));
});
}
}

View File

@ -1,25 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material';
import { FlexModule } from '@angular/flex-layout';
import { ClaimComponent } from './claim.component';
import { ClaimRoutingModule } from './claim-routing.module';
import { SharedModule } from '../../shared/shared.module';
import { ClaimManagementService } from '../../thrift/claim-management.service';
import { DetailsComponent } from './details/details.component';
import { ConversationModule } from './conversation/conversation.module';
@NgModule({
imports: [
ClaimRoutingModule,
SharedModule,
CommonModule,
MatCardModule,
FlexModule,
ConversationModule
],
declarations: [ClaimComponent, DetailsComponent],
providers: [ClaimManagementService]
})
export class ClaimModule {}

View File

@ -1,26 +0,0 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { MatSnackBar } from '@angular/material';
import { ClaimManagementService } from '../../thrift/claim-management.service';
import { Claim } from '../../gen-damsel/claim_management';
@Injectable()
export class ClaimService {
claim$: Subject<Claim> = new Subject();
constructor(
private claimManagementService: ClaimManagementService,
private snackBar: MatSnackBar
) {}
getClaim(partyID: string, claimID: number) {
this.claimManagementService.getClaim(partyID, claimID).subscribe(
claim => this.claim$.next(claim),
e => {
console.error(e);
this.snackBar.open('An error occurred while claim accepting', 'OK');
}
);
}
}

View File

@ -1,21 +0,0 @@
import { Pipe, PipeTransform } from '@angular/core';
import { TimelineAction } from './to-timeline-info/model';
@Pipe({
name: 'actionIcon'
})
export class ActionIconPipe implements PipeTransform {
transform(action: TimelineAction): string {
return ({
[TimelineAction.statusPending]: 'visibility',
[TimelineAction.statusReview]: 'forward',
[TimelineAction.statusRevoked]: 'close',
[TimelineAction.statusDenied]: 'close',
[TimelineAction.statusAccepted]: 'done',
[TimelineAction.filesAdded]: 'attach_file',
[TimelineAction.commentAdded]: 'mode_comment',
[TimelineAction.changesAdded]: 'add'
} as const)[action];
}
}

View File

@ -1,21 +0,0 @@
import { Pipe, PipeTransform } from '@angular/core';
import { TimelineAction } from './to-timeline-info/model';
@Pipe({
name: 'actionName'
})
export class ActionNamePipe implements PipeTransform {
transform(action: TimelineAction): string {
return ({
[TimelineAction.statusPending]: 'Changed status to Pending',
[TimelineAction.statusReview]: 'Changed status to Review',
[TimelineAction.statusRevoked]: 'Changed status to Revoked',
[TimelineAction.statusDenied]: 'Changed status to Denied',
[TimelineAction.statusAccepted]: 'Changed status to Accepted',
[TimelineAction.filesAdded]: 'Files added',
[TimelineAction.commentAdded]: 'Comment added',
[TimelineAction.changesAdded]: 'Changes added'
} as const)[action];
}
}

View File

@ -1,34 +0,0 @@
<cc-timeline>
<cc-timeline-item *ngFor="let item of timelineInfo">
<cc-timeline-item-title>
<span>
{{ item.action | actionName }} by {{ item.user_info.username }} at
{{ item.created_at | date: 'dd.MM.yyyy HH:mm:ss' }} ({{
item.created_at | humanizedDuration: { largest: 1, hasAgoEnding: true }
}})
</span>
</cc-timeline-item-title>
<cc-timeline-item-badge>
<mat-icon>{{ item.action | actionIcon }}</mat-icon>
</cc-timeline-item-badge>
<cc-timeline-item-content
*ngIf="item.modifications.length !== 0"
fxLayout="column"
fxLayoutGap="20px"
>
<mat-expansion-panel *ngFor="let modification of item.modifications">
<mat-expansion-panel-header>
<mat-panel-title> {{ getKey(modification) }} </mat-panel-title>
<mat-panel-description>
{{
modification.claim_modification
? getKey(modification.claim_modification)
: getKey(modification.party_modification)
}}
</mat-panel-description>
</mat-expansion-panel-header>
<cc-pretty-json [object]="modification"></cc-pretty-json>
</mat-expansion-panel>
</cc-timeline-item-content>
</cc-timeline-item>
</cc-timeline>

View File

@ -1,27 +0,0 @@
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { Claim } from '../../../gen-damsel/claim_management';
import { toTimelineInfo } from './to-timeline-info';
import { TimelineItemInfo } from './to-timeline-info/model';
import { getUnionKey } from '../../../shared/get-union-key';
@Component({
selector: 'cc-claim-conversation',
templateUrl: 'conversation.component.html'
})
export class ConversationComponent implements OnChanges {
@Input() claim: Claim;
timelineInfo: TimelineItemInfo[] = [];
ngOnChanges(changes: SimpleChanges) {
const { currentValue } = changes.claim;
if (currentValue) {
this.timelineInfo = toTimelineInfo(currentValue.changeset);
}
}
getKey(u: any): string {
return getUnionKey(u);
}
}

View File

@ -1,42 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FlexLayoutModule } from '@angular/flex-layout';
import {
MatFormFieldModule,
MatInputModule,
MatIconModule,
MatButtonModule,
MatExpansionModule
} from '@angular/material';
import { ReactiveFormsModule } from '@angular/forms';
import { LayoutModule } from '@angular/cdk/layout';
import { ConversationComponent } from './conversation.component';
import { ActionIconPipe } from './action-icon.pipe';
import { TimelineModule } from '../../../shared/components/timeline';
import { SharedModule } from '../../../shared/shared.module';
import { ActionNamePipe } from './action-name.pipe';
import { MonacoEditorModule } from '../../../monaco-editor';
import { HumanizeDurationModule } from '../../../shared/humanize-duration';
@NgModule({
imports: [
LayoutModule,
MatButtonModule,
FlexLayoutModule,
MatFormFieldModule,
MatInputModule,
TimelineModule,
MatIconModule,
SharedModule,
CommonModule,
ReactiveFormsModule,
SharedModule,
MatExpansionModule,
MonacoEditorModule,
HumanizeDurationModule
],
declarations: [ConversationComponent, ActionIconPipe, ActionNamePipe],
exports: [ConversationComponent]
})
export class ConversationModule {}

View File

@ -1,38 +0,0 @@
import { TimelineAction } from './model';
import { ClaimModification, StatusModificationUnit } from '../../../../gen-damsel/claim_management';
import { getUnionKey } from '../../../../shared/get-union-key';
import { ClaimStatus } from '../../../../papi/model/claim-statuses';
function getStatusModificationTimelineAction(unit: StatusModificationUnit): TimelineAction | null {
const Status = ClaimStatus;
switch (getUnionKey(unit.status)) {
case Status.accepted:
return TimelineAction.statusAccepted;
case Status.denied:
return TimelineAction.statusDenied;
case Status.pending:
return TimelineAction.statusPending;
case Status.review:
return TimelineAction.statusReview;
case Status.revoked:
return TimelineAction.statusRevoked;
case Status.pending_acceptance:
return null;
}
}
export function getClaimModificationTimelineAction(m: ClaimModification): TimelineAction | null {
switch (getUnionKey(m)) {
case 'document_modification':
return TimelineAction.changesAdded;
case 'status_modification':
return getStatusModificationTimelineAction(
m.status_modification as StatusModificationUnit
);
case 'file_modification':
return TimelineAction.filesAdded;
case 'comment_modification':
return TimelineAction.commentAdded;
}
throw new Error(`Unknown claimModification: ${m}`);
}

View File

@ -1 +0,0 @@
export * from './to-timeline-info';

View File

@ -1,2 +0,0 @@
export * from './timeline-item-info';
export * from './timeline-action';

View File

@ -1,10 +0,0 @@
export enum TimelineAction {
changesAdded = 'changesAdded',
filesAdded = 'filesAdded',
commentAdded = 'commentAdded',
statusReview = 'statusReview',
statusPending = 'statusPending',
statusDenied = 'statusDenied',
statusRevoked = 'statusRevoked',
statusAccepted = 'statusAccepted'
}

View File

@ -1,9 +0,0 @@
import { TimelineAction } from './timeline-action';
import { Modification, UserInfo } from '../../../../../gen-damsel/claim_management';
export interface TimelineItemInfo {
action: TimelineAction;
user_info: UserInfo;
created_at: string;
modifications: Modification[];
}

View File

@ -1,82 +0,0 @@
import {
ClaimModification,
Modification,
ModificationUnit
} from '../../../../gen-damsel/claim_management';
import { TimelineAction, TimelineItemInfo } from './model';
import { sortUnitsByCreatedAtAsc } from '../../../../shared/utils';
import { getUnionKey } from '../../../../shared/get-union-key';
import { getClaimModificationTimelineAction } from './get-claim-modification-timeline-action';
const isSame = (x: TimelineItemInfo, y: TimelineItemInfo): boolean =>
x.action === y.action && x.user_info.type === y.user_info.type;
const getUnitTimelineAction = (modification: Modification): TimelineAction | null => {
switch (getUnionKey(modification)) {
case 'claim_modification':
return getClaimModificationTimelineAction(
modification.claim_modification as ClaimModification
);
case 'party_modification':
return TimelineAction.changesAdded;
}
};
const toTimelineInfoModifications = (
action: TimelineAction,
modification: Modification
): Modification[] => {
switch (action) {
case 'changesAdded':
case 'filesAdded':
case 'commentAdded':
return [modification];
default:
return [];
}
};
const concatLastItem = (
acc: TimelineItemInfo[],
updateItem: TimelineItemInfo
): TimelineItemInfo[] =>
acc.map((accItem, accItemIndex) =>
accItemIndex === acc.length - 1
? {
...updateItem,
modifications: accItem.modifications.concat(updateItem.modifications)
}
: accItem
);
const acceptTimelineItem = (
acc: TimelineItemInfo[],
{ created_at, modification, user_info }: ModificationUnit
): TimelineItemInfo[] => {
const action = getUnitTimelineAction(modification);
if (action === null) {
return acc;
}
const modifications = toTimelineInfoModifications(action, modification);
const result = {
action,
user_info,
created_at: created_at as string,
modifications
};
if (acc.length !== 0 && modifications.length !== 0) {
const lastItem = acc[acc.length - 1];
if (isSame(result, lastItem)) {
return concatLastItem(acc, result);
}
}
return acc.concat(result);
};
export const toTimelineInfo = (units: ModificationUnit[]): TimelineItemInfo[] => {
if (!units || units.length === 0) {
return [];
}
const sortedUnits = sortUnitsByCreatedAtAsc(units);
return sortedUnits.reduce(acceptTimelineItem, []);
};

View File

@ -1,33 +0,0 @@
<mat-card *ngIf="claim">
<mat-card-subtitle>Claim details</mat-card-subtitle>
<mat-card-content>
<div fxFlex="50" fxLayout="column" fxLayoutGap="10px">
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Claim ID:</label>
<div>{{ claim.id }}</div>
</div>
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Status:</label>
<div>{{ extractClaimStatus(claim.status) }}</div>
</div>
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Revision:</label>
<div>{{ claim.revision }}</div>
</div>
</div>
<div fxFlex="50" fxLayout="column" fxLayoutGap="10px">
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Party ID:</label>
<div>{{ claim.party_id }}</div>
</div>
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Created At:</label>
<div>{{ claim.created_at | date: 'dd.MM.yyyy HH:mm:ss' }}</div>
</div>
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Updated At:</label>
<div>{{ claim.updated_at | date: 'dd.MM.yyyy HH:mm:ss' }}</div>
</div>
</div>
</mat-card-content>
</mat-card>

View File

@ -1,16 +0,0 @@
import { Component, Input } from '@angular/core';
import { Claim, ClaimStatus } from '../../../gen-damsel/claim_management';
import { extractClaimStatus } from '../../../shared/extract-claim-status';
@Component({
selector: 'cc-claim-details',
templateUrl: 'details.component.html'
})
export class DetailsComponent {
@Input() claim: Claim;
extractClaimStatus(status: ClaimStatus) {
return extractClaimStatus(status);
}
}

View File

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

View File

@ -1,29 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { ClaimsService } from './claims.service';
import { SearchFormValue } from './search-form/search-form-value';
import { ClaimStatus } from '../../papi/model/claim-statuses';
@Component({
templateUrl: 'claims.component.html',
styleUrls: []
})
export class ClaimsComponent implements OnInit {
isLoading$ = this.claimService.isLoading$;
claims$ = this.claimService.claims$;
hasMore$ = this.claimService.hasMore$;
constructor(private claimService: ClaimsService) {}
ngOnInit(): void {
this.search({ statuses: [ClaimStatus.pending] });
}
search(searchFormValue: SearchFormValue) {
this.claimService.search(searchFormValue);
}
fetchMore() {
this.claimService.fetchMore();
}
}

View File

@ -1,53 +0,0 @@
import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material';
import { Observable } from 'rxjs';
import { catchError, map, shareReplay } from 'rxjs/operators';
import { FetchResult, PartialFetcher } from '@rbkmoney/partial-fetcher';
import { ClaimManagementService } from '../../thrift/claim-management.service';
import { SearchFormValue } from './search-form/search-form-value';
import { booleanDebounceTime } from '../../shared/operators';
import { convertFormValueToParams } from './convert-form-value-to-params';
import { Claim } from '../../gen-damsel/claim_management';
@Injectable()
export class ClaimsService extends PartialFetcher<Claim, SearchFormValue> {
private readonly searchLimit = 20;
claims$: Observable<Claim> = this.searchResult$.pipe(
catchError(() => {
this.snackBar.open('An error occurred while processing your search', 'OK');
return [];
})
);
isLoading$: Observable<boolean> = this.doAction$.pipe(
booleanDebounceTime(),
shareReplay(1)
);
constructor(
private claimManagementService: ClaimManagementService,
private snackBar: MatSnackBar
) {
super();
}
protected fetch(
searchFormValue: SearchFormValue,
continuationToken: string
): Observable<FetchResult<Claim>> {
return this.claimManagementService
.searchClaims({
...convertFormValueToParams(searchFormValue),
continuation_token: continuationToken,
limit: this.searchLimit
})
.pipe(
map(r => ({
result: r.result,
continuationToken: r.continuation_token
}))
);
}
}

View File

@ -1,19 +0,0 @@
import { SearchFormValue } from './search-form/search-form-value';
export const convertFormValueToParams = (params: SearchFormValue) => {
const result = {};
for (const k in params) {
if (params.hasOwnProperty(k)) {
if (k === 'statuses') {
result[k] = (params[k] as string[]).reduce((acc, cv) => [...acc, { [cv]: {} }], []);
} else {
const v = params[k].trim();
if (v === '') {
break;
}
result[k] = v;
}
}
}
return result;
};

View File

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

View File

@ -1,7 +0,0 @@
import * as domain from '../../../gen-damsel/domain';
import { ClaimStatus } from '../../../papi/model/claim-statuses';
export interface SearchFormValue {
party_id?: domain.PartyID;
statuses?: ClaimStatus[];
}

View File

@ -1,24 +0,0 @@
import { Injectable } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import values from 'lodash-es/values';
import { ClaimStatus } from '../../../papi/model/claim-statuses';
@Injectable()
export class SearchFormService {
form: FormGroup;
claimStatuses: string[];
constructor(private fb: FormBuilder) {
this.form = this.prepareForm();
this.claimStatuses = values(ClaimStatus);
this.form.patchValue({ statuses: [ClaimStatus.pending] });
}
private prepareForm(): FormGroup {
return this.fb.group({
statuses: '',
party_id: ''
});
}
}

View File

@ -1,13 +1,14 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { ClaimsComponent } from './claims.component';
import { AppAuthGuardService } from '../../app-auth-guard.service';
import { AppAuthGuardService } from '../app-auth-guard.service';
@NgModule({
imports: [
RouterModule.forChild([
{
path: '',
path: 'claims',
component: ClaimsComponent,
canActivate: [AppAuthGuardService],
data: {

View File

@ -1,15 +1,15 @@
<table mat-table [dataSource]="claims">
<ng-container matColumnDef="partyID">
<th mat-header-cell *matHeaderCellDef>Party ID</th>
<td mat-cell *matCellDef="let claim">{{ claim.party_id }}</td>
<td mat-cell *matCellDef="let claim">{{ claim.partyId }}</td>
</ng-container>
<ng-container matColumnDef="claimID">
<th fxHide.sm fxHide.xs mat-header-cell *matHeaderCellDef>Claim ID</th>
<td fxHide.sm fxHide.xs mat-cell *matCellDef="let claim">{{ claim.id }}</td>
<td fxHide.sm fxHide.xs mat-cell *matCellDef="let claim">{{ claim.claimId }}</td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef>Status</th>
<td mat-cell *matCellDef="let claim">{{ getClaimStatus(claim.status) }}</td>
<td mat-cell *matCellDef="let claim">{{ claim.status }}</td>
</ng-container>
<ng-container matColumnDef="revision">
<th fxHide.sm fxHide.xs mat-header-cell *matHeaderCellDef>Revision</th>
@ -18,19 +18,19 @@
<ng-container matColumnDef="createdAt">
<th fxHide.xs mat-header-cell *matHeaderCellDef>Created at</th>
<td fxHide.xs mat-cell *matCellDef="let claim">
{{ claim.created_at | date: 'dd.MM.yyyy HH:mm:ss' }}
{{ claim.createdAt | date: 'dd.MM.yyyy HH:mm:ss' }}
</td>
</ng-container>
<ng-container matColumnDef="updatedAt">
<th fxHide.sm fxHide.xs mat-header-cell *matHeaderCellDef>Updated at</th>
<td fxHide.sm fxHide.xs mat-cell *matCellDef="let claim">
{{ claim.updated_at | date: 'dd.MM.yyyy HH:mm:ss' }}
{{ claim.updatedAt | date: 'dd.MM.yyyy HH:mm:ss' }}
</td>
</ng-container>
<ng-container matColumnDef="claimDetailButton">
<th mat-header-cell *matHeaderCellDef class="action-cell"></th>
<td mat-cell *matCellDef="let claim" class="action-cell">
<button mat-icon-button (click)="navigateToClaim(claim.party_id, claim.id)">
<button mat-icon-button (click)="navigateToClaim(claim)">
<mat-icon>more_vert</mat-icon>
</button>
</td>

View File

@ -1,8 +1,8 @@
import { Component, Input } from '@angular/core';
import { Router } from '@angular/router';
import { Claim, ClaimStatus } from '../../../gen-damsel/claim_management';
import { extractClaimStatus } from '../../../shared/extract-claim-status';
import { ClaimInfo } from '../../papi/model';
import { ClaimActionType } from '../../claim/claim-action-type';
@Component({
selector: 'cc-claims-table',
@ -11,9 +11,10 @@ import { extractClaimStatus } from '../../../shared/extract-claim-status';
})
export class ClaimsTableComponent {
@Input()
claims: Claim[];
claims: ClaimInfo[];
displayedColumns = [
'partyID',
'claimID',
'status',
'revision',
@ -24,11 +25,8 @@ export class ClaimsTableComponent {
constructor(private router: Router) {}
navigateToClaim(partyID: string, claimID: number) {
this.router.navigate([`party/${partyID}/claim/${claimID}`]);
}
getClaimStatus(status: ClaimStatus) {
return extractClaimStatus(status);
navigateToClaim(claim: ClaimInfo) {
const c = claim as any;
this.router.navigate([`/claims/${c.partyId}/${ClaimActionType.edit}/${c.claimId}`]);
}
}

View File

@ -4,7 +4,7 @@
<mat-card-content>
<cc-search-form (valueChanges)="search($event)"></cc-search-form>
</mat-card-content>
<mat-card-footer *ngIf="(isLoading$ | async)">
<mat-card-footer *ngIf="isLoading">
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</mat-card-footer>
</mat-card>
@ -14,15 +14,5 @@
<cc-claim-actions></cc-claim-actions>
</mat-card-content>
</mat-card>
<div class="mat-elevation-z2" fxLayout="column">
<cc-claims-table [claims]="claims$ | async"></cc-claims-table>
<button
mat-raised-button
*ngIf="(hasMore$ | async)"
(click)="fetchMore()"
[disabled]="isLoading$ | async"
>
Load more...
</button>
</div>
<div class="mat-elevation-z2"><cc-claims-table [claims]="claims"></cc-claims-table></div>
</cc-card-container>

View File

@ -0,0 +1,39 @@
import { Component, OnInit } from '@angular/core';
import { MatSnackBar } from '@angular/material';
import { HttpErrorResponse } from '@angular/common/http';
import { ClaimService } from '../papi/claim.service';
import { ClaimSearchParams } from '../papi/params';
import { ClaimInfo } from '../papi/model';
@Component({
templateUrl: 'claims.component.html',
styleUrls: []
})
export class ClaimsComponent implements OnInit {
isLoading = false;
claims: ClaimInfo[];
constructor(private claimService: ClaimService, private snackBar: MatSnackBar) {}
ngOnInit() {
this.search({ claimStatus: 'pending' });
}
search(params: ClaimSearchParams) {
this.isLoading = true;
this.claimService.getClaims(params).subscribe(
claims => {
this.isLoading = false;
this.claims = claims.reverse();
},
(error: HttpErrorResponse) => {
this.isLoading = false;
this.snackBar.open(`${error.status}: ${error.message}`, 'OK', {
duration: 1500
});
}
);
}
}

View File

@ -18,20 +18,18 @@ import { ReactiveFormsModule } from '@angular/forms';
import { CdkTableModule } from '@angular/cdk/table';
import { ClaimsComponent } from './claims.component';
import { PapiModule } from '../../papi/papi.module';
import { ClaimsRoutingModule } from './claims-routing.module';
import { PapiModule } from '../papi/papi.module';
import { SearchFormComponent } from './search-form/search-form.component';
import { ClaimsTableComponent } from './claims-table/claims-table.component';
import { ClaimActionsComponent } from './claim-actions/claim-actions.component';
import { CreateClaimComponent } from './create-claim/create-claim.component';
import { SharedModule } from '../../shared/shared.module';
import { ClaimsService } from './claims.service';
import { ClaimManagementService } from '../../thrift/claim-management.service';
import { ClaimsRoutingModule } from './claims-routing.module';
import { SharedModule } from '../shared/shared.module';
@NgModule({
imports: [
ClaimsRoutingModule,
CommonModule,
ClaimsRoutingModule,
FlexLayoutModule,
PapiModule,
ReactiveFormsModule,
@ -56,7 +54,6 @@ import { ClaimsRoutingModule } from './claims-routing.module';
ClaimActionsComponent,
CreateClaimComponent
],
entryComponents: [CreateClaimComponent],
providers: [ClaimsService, ClaimManagementService]
entryComponents: [CreateClaimComponent]
})
export class ClaimsModule {}

View File

@ -3,7 +3,7 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatDialogRef } from '@angular/material';
import { Router } from '@angular/router';
import { ClaimActionType } from '../../../claim/claim-action-type';
import { ClaimActionType } from '../../claim/claim-action-type';
@Component({
templateUrl: 'create-claim.component.html'

View File

@ -1,12 +1,13 @@
<form fxLayout="row" fxLayout.xs="column" fxLayoutGap="20px" [formGroup]="form">
<mat-form-field fxFlex="15" fxFlex.sm="30">
<mat-select placeholder="Claim status" formControlName="statuses" multiple>
<mat-select placeholder="Claim status" formControlName="claimStatus">
<mat-option [value]="null">any</mat-option>
<mat-option *ngFor="let status of claimStatuses" [value]="status">{{
status
}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="30" fxFlex.sm="70">
<input matInput placeholder="Party ID" formControlName="party_id" />
<input matInput placeholder="Party ID" formControlName="partyId" />
</mat-form-field>
</form>

View File

@ -2,8 +2,8 @@ import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { SearchFormService } from './search-form.service';
import { ClaimSearchParams } from '../../papi/params';
import { debounceTime } from 'rxjs/internal/operators';
import { SearchFormValue } from './search-form-value';
@Component({
selector: 'cc-search-form',
@ -12,7 +12,7 @@ import { SearchFormValue } from './search-form-value';
})
export class SearchFormComponent implements OnInit {
@Output()
valueChanges: EventEmitter<SearchFormValue> = new EventEmitter();
valueChanges: EventEmitter<ClaimSearchParams> = new EventEmitter();
form: FormGroup;
@ -21,11 +21,11 @@ export class SearchFormComponent implements OnInit {
constructor(private searchFormService: SearchFormService) {}
ngOnInit() {
const { form, claimStatuses } = this.searchFormService;
const { claimStatuses, form, formValueToSearchParams } = this.searchFormService;
this.claimStatuses = claimStatuses;
this.form = form;
this.form.valueChanges.pipe(debounceTime(300)).subscribe(value => {
this.valueChanges.emit(value);
});
this.form.valueChanges
.pipe(debounceTime(300))
.subscribe(value => this.valueChanges.emit(formValueToSearchParams(value)));
}
}

View File

@ -0,0 +1,39 @@
import { Injectable } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import values from 'lodash-es/values';
import mapValues from 'lodash-es/mapValues';
import isString from 'lodash-es/isString';
import { ClaimStatus } from '../../papi/model/claim-statuses';
import { ClaimSearchParams } from '../../papi/params';
@Injectable()
export class SearchFormService {
form: FormGroup;
claimStatuses: string[];
constructor(private fb: FormBuilder) {
this.form = this.prepareForm();
this.claimStatuses = values(ClaimStatus);
}
formValueToSearchParams(formValue): ClaimSearchParams {
return mapValues(formValue, value => {
let result = value;
if (value === '') {
result = null;
} else if (isString(value)) {
result = value.trim();
}
return result;
});
}
private prepareForm(): FormGroup {
return this.fb.group({
claimStatus: 'pending',
partyId: ''
});
}
}

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { DomainPair } from './domain-group';
import { DomainPair } from './domain-group/domain-group';
@Injectable()
export class DomainDetailsService {

View File

@ -2,12 +2,12 @@ import { Component, OnInit, Input, OnChanges, SimpleChanges, ViewChild } from '@
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
import { DomainGroup } from '../domain-group';
import { DomainDetailsService } from '../../domain-details.service';
import { DomainDetailsService } from '../../../domain-info/domain-details.service';
import { toTableGroup, toDataSource } from './table-group';
import { sortData } from './sort-table-data';
import { filterPredicate } from './filter-predicate';
import { TableDataSource, TableGroup } from './model';
import { DetailsContainerService } from '../../details-container.service';
import { DetailsContainerService } from '../../../domain-info/details-container.service';
@Component({
selector: 'cc-group-table',

View File

@ -1,10 +1,11 @@
import { parse } from '../../jsonc/json-parser';
import {
CodeLensProvider,
ITextModel,
CancellationToken,
ICodeLensSymbol,
ProviderResult
} from '../../monaco-editor';
} from '../../monaco-editor/model';
export class DomainObjCodeLensProvider implements CodeLensProvider {
get language() {

View File

@ -3,7 +3,7 @@ import { MatSnackBar, MatDialog } from '@angular/material';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { MonacoFile, CodeLensProvider, CompletionProvider } from '../../monaco-editor';
import { MonacoFile, CodeLensProvider, CompletionProvider } from '../../monaco-editor/model';
import { DomainObjModificationService } from './domain-obj-modification.service';
import { DomainObjCodeLensProvider } from './domain-obj-code-lens-provider';
import { DomainObjCompletionProvider } from './domain-obj-completion-provider';

View File

@ -11,7 +11,7 @@ import { MatIconModule } from '@angular/material/icon';
import { RouterModule } from '@angular/router';
import { DomainObjModificationComponent } from './domain-obj-modification.component';
import { MonacoEditorModule } from '../../monaco-editor';
import { MonacoEditorModule } from '../../monaco-editor/monaco-editor.module';
import { SharedModule } from '../../shared/shared.module';
import { ResetConfirmDialogComponent } from './reset-confirm-dialog/reset-confirm-dialog.component';

View File

@ -3,7 +3,7 @@ import { Router } from '@angular/router';
import { MatCheckboxChange, MatSnackBar } from '@angular/material';
import { Subscription } from 'rxjs';
import { MonacoFile, IDiffEditorOptions } from '../../monaco-editor';
import { MonacoFile, IDiffEditorOptions } from '../../monaco-editor/model';
import { toMonacoFile } from '../utils';
import { DomainModificationModel } from '../domain-modification-model';
import { DomainObjReviewService } from './domain-obj-review.service';

View File

@ -10,7 +10,7 @@ import {
} from '@angular/material';
import { DomainObjReviewComponent } from './domain-obj-review.component';
import { MonacoEditorModule } from '../../monaco-editor';
import { MonacoEditorModule } from '../../monaco-editor/monaco-editor.module';
import { SharedModule } from '../../shared/shared.module';
@NgModule({

View File

@ -4,7 +4,7 @@ import { DomainRoutingModule } from './domain-routing.module';
import { DomainService } from './domain.service';
import { MetadataService } from './metadata.service';
import { DomainObjModificationModule } from './domain-obj-modification';
import { DomainInfoModule } from './domain-info';
import { DomainInfoModule } from './domain-info/domain-info.module';
import { DamselMetaModule } from '../damsel-meta/damsel-meta.module';
import { DomainObjReviewModule } from './domain-obj-review';
import { DomainReviewService } from './domain-review.service';

View File

@ -1,11 +1,11 @@
import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs';
import { KeycloakService } from 'keycloak-angular';
import { DepositParams } from './gen-model/fistful_admin';
import { DepositParams as DepositParamsObject } from './gen-nodejs/fistful_admin_types';
import { ThriftService } from '../thrift';
import * as FistfulAdmin from './gen-nodejs/FistfulAdmin';
import { KeycloakService } from 'keycloak-angular';
@Injectable()
export class FistfulAdminService extends ThriftService {

View File

@ -1,11 +1,11 @@
import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs';
import { KeycloakService } from 'keycloak-angular';
import { ThriftService } from '../thrift';
import { RepairScenario, SessionID } from './gen-model/withdrawal_session';
import { RepairScenario as RepairScenarioObject } from './gen-nodejs/withdrawal_session_types';
import * as Repairer from './gen-nodejs/Repairer';
import { KeycloakService } from 'keycloak-angular';
@Injectable()
export class RepairerService extends ThriftService {

View File

@ -1,5 +1,6 @@
import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs';
import { KeycloakService } from 'keycloak-angular';
import * as Automaton from './gen-nodejs/Automaton';
import {
@ -9,7 +10,6 @@ import {
import { ThriftService } from '../thrift';
import { Namespace } from './gen-model/base';
import { Reference, MachineDescriptor, Machine } from './gen-model/state_processing';
import { KeycloakService } from 'keycloak-angular';
@Injectable()
export class AutomatonService extends ThriftService {

View File

@ -6,8 +6,7 @@ import { map } from 'rxjs/operators';
import { ClaimCreated, ClaimInfo, PartyModificationUnit } from './model';
import { ConfigService } from '../core/config.service';
import { decode, encode } from '../shared/java-thrift-formatter';
import { ClaimAcceptParams, ClaimDenyParams } from './params';
import { ClaimSearchQuery } from '../gen-damsel/claim_management';
import { ClaimAcceptParams, ClaimDenyParams, ClaimSearchParams } from './params';
@Injectable()
export class ClaimService {
@ -17,7 +16,7 @@ export class ClaimService {
this.papiEndpoint = configService.config.papiEndpoint;
}
getClaims(params: ClaimSearchQuery): Observable<ClaimInfo[]> {
getClaims(params: ClaimSearchParams): Observable<ClaimInfo[]> {
return this.http.post<ClaimInfo[]>(`${this.papiEndpoint}/walk/claim/search`, params);
}

View File

@ -2,7 +2,5 @@ export enum ClaimStatus {
accepted = 'accepted',
denied = 'denied',
revoked = 'revoked',
pending = 'pending',
review = 'review',
pending_acceptance = 'pending_acceptance'
pending = 'pending'
}

View File

@ -1,17 +0,0 @@
export enum StatusColor {
neutral = 'neutral',
success = 'success',
pending = 'pending',
warn = 'warn'
}
export enum PaletteColor {
primary = 'primary',
accent = 'accent',
warn = 'warn'
}
export type Status = keyof typeof StatusColor;
export type Palette = keyof typeof PaletteColor;
export const slateblue400 = '#695BFF';

View File

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

View File

@ -1 +0,0 @@
export * from './timeline-item.component';

View File

@ -1 +0,0 @@
export * from './timeline-item-badge.component';

View File

@ -1,10 +0,0 @@
<div
[ngClass]="{
'cc-timeline-item-badge': true,
'cc-timeline-item-badge-success': color === 'success',
'cc-timeline-item-badge-warn': color === 'warn',
'cc-timeline-item-badge-pending': color === 'pending'
}"
>
<ng-content></ng-content>
</div>

View File

@ -1,31 +0,0 @@
@import '../timeline-item.scss';
@import '../../../../styles/light';
$size: 36px;
$line-size: 2px;
$neutral: map-get($theme, neutral);
$line-color: mat-color($neutral, 200);
.cc-timeline-item-badge {
position: absolute;
left: 0;
top: 0;
display: flex;
height: $size;
width: $size;
justify-content: center;
align-items: center;
border-radius: 50%;
z-index: 10;
::ng-deep > *,
::ng-deep > * mat-icon {
height: $icons-size;
width: $icons-size;
font-size: $icons-size;
}
}
.cc-timeline-item-badge {
background-color: $line-color;
}

View File

@ -1,11 +0,0 @@
import { Component, Input } from '@angular/core';
import { StatusColor } from '../../../../color';
@Component({
selector: 'cc-timeline-item-badge',
templateUrl: 'timeline-item-badge.component.html',
styleUrls: ['timeline-item-badge.component.scss']
})
export class TimelineItemBadgeComponent {
@Input() color: StatusColor;
}

View File

@ -1 +0,0 @@
export * from './timeline-item-content.component';

View File

@ -1,5 +0,0 @@
@import '../timeline-item.scss';
.cc-timeline-item-content {
padding-top: $content-padding;
}

View File

@ -1,11 +0,0 @@
import { Component, ViewEncapsulation, HostBinding } from '@angular/core';
@Component({
selector: 'cc-timeline-item-content, [cc-timeline-item-content]',
template: '<ng-content></ng-content>',
styleUrls: ['timeline-item-content.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class TimelineItemContentComponent {
@HostBinding('class.cc-timeline-item-content') rootClass = true;
}

View File

@ -1 +0,0 @@
export * from './timeline-item-title.component';

View File

@ -1,3 +0,0 @@
<div class="cc-timeline-item-title">
<div><ng-content></ng-content></div>
</div>

View File

@ -1,7 +0,0 @@
@import '../timeline-item.scss';
.cc-timeline-item-title {
min-height: $size;
display: flex;
align-items: center;
}

View File

@ -1,8 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'cc-timeline-item-title',
templateUrl: 'timeline-item-title.component.html',
styleUrls: ['timeline-item-title.component.scss']
})
export class TimelineItemTitleComponent {}

View File

@ -1 +0,0 @@
<div class="cc-timeline-item"><ng-content></ng-content></div>

View File

@ -1,7 +0,0 @@
@import './timeline-item.scss';
.cc-timeline-item {
padding-bottom: 20px;
padding-left: $size + $content-padding;
position: relative;
}

View File

@ -1,8 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'cc-timeline-item',
templateUrl: 'timeline-item.component.html',
styleUrls: ['timeline-item.component.scss']
})
export class TimelineItemComponent {}

View File

@ -1,4 +0,0 @@
$size: 36px;
$icons-size: 18px;
$line-size: 2px;
$content-padding: 10px;

View File

@ -1 +0,0 @@
<div fxLayout="column" class="cc-timeline"><ng-content></ng-content></div>

View File

@ -1,24 +0,0 @@
@import '../../styles/light';
$size: 36px;
$line-size: 2px;
$neutral: map-get($theme, neutral);
$line-color: mat-color($neutral, 200);
.cc-timeline {
position: relative;
border-bottom: $line-size solid;
border-bottom-color: $line-color;
font-family: Roboto, "Helvetica Neue", sans-serif;
&::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
width: $line-size;
left: $size / 2 - $line-size / 2;
background-color: $line-color;
}
}

View File

@ -1,8 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'cc-timeline',
templateUrl: 'timeline.component.html',
styleUrls: ['timeline.component.scss']
})
export class TimelineComponent {}

View File

@ -1,24 +0,0 @@
import { NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { CommonModule } from '@angular/common';
import { TimelineComponent } from './timeline.component';
import { TimelineItemComponent } from './timeline-item';
import { TimelineItemTitleComponent } from './timeline-item/timeline-item-title';
import { TimelineItemBadgeComponent } from './timeline-item/timeline-item-badge';
import { TimelineItemContentComponent } from './timeline-item/timeline-item-content';
const EXPORTED_DECLARATIONS = [
TimelineComponent,
TimelineItemComponent,
TimelineItemTitleComponent,
TimelineItemBadgeComponent,
TimelineItemContentComponent
];
@NgModule({
imports: [FlexLayoutModule, CommonModule],
declarations: EXPORTED_DECLARATIONS,
exports: EXPORTED_DECLARATIONS
})
export class TimelineModule {}

View File

@ -1,15 +0,0 @@
import { ClaimStatus as UnionClaimStatus } from '../gen-damsel/claim_management';
import { ClaimStatus } from '../papi/model/claim-statuses';
import { getUnionKey } from './get-union-key';
export const claimStatusByUnionClaimStatus: { [name in keyof UnionClaimStatus]-?: ClaimStatus } = {
accepted: ClaimStatus.accepted,
denied: ClaimStatus.denied,
revoked: ClaimStatus.revoked,
pending: ClaimStatus.pending,
review: ClaimStatus.review,
pending_acceptance: ClaimStatus.pending_acceptance
};
export const extractClaimStatus = (status: UnionClaimStatus): ClaimStatus =>
claimStatusByUnionClaimStatus[getUnionKey(status) as keyof UnionClaimStatus];

View File

@ -1 +0,0 @@
export const getUnionKey = (union: any) => Object.entries(union).find(([, v]) => !!v)[0];

View File

@ -1,11 +0,0 @@
import { NgModule } from '@angular/core';
import { HumanizedDurationPipe } from './humanized-duration.pipe';
import { HumanizeDurationService } from './humanize-duration.service';
@NgModule({
declarations: [HumanizedDurationPipe],
providers: [HumanizeDurationService],
exports: [HumanizedDurationPipe]
})
export class HumanizeDurationModule {}

View File

@ -1,70 +0,0 @@
import { Injectable } from '@angular/core';
import * as humanizeDuration from 'humanize-duration';
import * as moment from 'moment';
export type Value = number | string | moment.Moment | Date;
export interface HumanizeConfig extends humanizeDuration.HumanizerOptions {
isShort?: boolean;
hasAgoEnding?: boolean;
}
@Injectable()
export class HumanizeDurationService {
static HOUR_MS = 3600000;
static MIN_HUMANIZE_DURATION_UPDATE_MS = 1000;
static MOMENT_HUMANIZE_ALLOWED_DELAY_BETWEEN_UPDATES_FOR_MINUTE_UPDATES_MS = 20000;
static MOMENT_HUMANIZE_ALLOWED_DELAY_BETWEEN_UPDATES_FOR_HOURLY_AND_LONGER_UPDATES_MS = 600000;
static LESS_THAN_FEW_SECONDS = 3000;
private get duration() {
return humanizeDuration.humanizer({
language: 'en',
round: true,
delimiter: ' '
});
}
get shortEnglishHumanizer(): humanizeDuration.HumanizerOptions {
return {
language: 'short'
};
}
getDiffMs(value: Value): number {
return Math.abs(this.isDiff(value) ? value : moment().diff(moment(value)));
}
getDuration(value: Value, config: HumanizeConfig = {}): string {
const diffMs = this.getDiffMs(value);
let duration = this.duration(diffMs, config);
if (isNaN(diffMs)) {
return null;
} else if (diffMs < HumanizeDurationService.LESS_THAN_FEW_SECONDS) {
return 'just now';
} else if (config.isShort) {
duration = this.duration(diffMs, { ...config, ...this.shortEnglishHumanizer });
} else if (config.largest === 1) {
duration = moment.duration(diffMs).humanize();
}
return config.hasAgoEnding ? `${duration} ago` : duration;
}
getOptimalUpdateInterval(value: Value, { largest }: HumanizeConfig): number {
const diffMs = this.getDiffMs(value);
if (diffMs < HumanizeDurationService.LESS_THAN_FEW_SECONDS) {
return HumanizeDurationService.MIN_HUMANIZE_DURATION_UPDATE_MS;
}
if (largest === 1) {
if (diffMs < HumanizeDurationService.HOUR_MS) {
return HumanizeDurationService.MOMENT_HUMANIZE_ALLOWED_DELAY_BETWEEN_UPDATES_FOR_MINUTE_UPDATES_MS;
}
return HumanizeDurationService.MOMENT_HUMANIZE_ALLOWED_DELAY_BETWEEN_UPDATES_FOR_HOURLY_AND_LONGER_UPDATES_MS;
}
return HumanizeDurationService.MIN_HUMANIZE_DURATION_UPDATE_MS;
}
isDiff(value: Value): value is number {
return typeof value === 'number';
}
}

View File

@ -1,54 +0,0 @@
import { Pipe, PipeTransform, ChangeDetectorRef, OnDestroy } from '@angular/core';
import { Subscription, interval } from 'rxjs';
import { HumanizerOptions } from 'humanize-duration';
import { HumanizeConfig, HumanizeDurationService, Value } from './humanize-duration.service';
export interface HumanizeDurationConfig extends HumanizeConfig {
interval?: number;
}
@Pipe({ name: 'humanizedDuration', pure: false })
export class HumanizedDurationPipe implements OnDestroy, PipeTransform {
private latestValue: string;
private subscription: Subscription;
private inputValue: Value;
constructor(
private humanizeDurationService: HumanizeDurationService,
private ref: ChangeDetectorRef
) {}
transform(value: Value, { interval: inpIntervalMs, ...config }: HumanizeDurationConfig = {}) {
if (value !== this.inputValue) {
this.inputValue = value;
this.latestValue = this.humanizeDurationService.getDuration(value, config);
this.dispose();
if (!this.humanizeDurationService.isDiff(value)) {
this.subscription = interval(
inpIntervalMs ||
this.humanizeDurationService.getOptimalUpdateInterval(value, config)
).subscribe(() => this.updateValue(value, config));
}
}
return this.latestValue;
}
ngOnDestroy(): void {
this.dispose();
}
private dispose(): void {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
private updateValue(value: Value, config: HumanizerOptions): void {
const duration = this.humanizeDurationService.getDuration(value, config);
if (duration !== this.latestValue) {
this.ref.markForCheck();
this.latestValue = duration;
}
}
}

View File

@ -1,2 +0,0 @@
export * from './humanize-duration.module';
export * from './humanize-duration.service';

View File

@ -1,11 +0,0 @@
import { distinctUntilChanged, debounce } from 'rxjs/operators';
import { timer, empty, Observable } from 'rxjs';
export const booleanDebounceTime = (timeoutMs: number = 500) => (
s: Observable<boolean>
): Observable<boolean> =>
s.pipe(
distinctUntilChanged(),
debounce(v => (v ? timer(timeoutMs) : empty())),
distinctUntilChanged()
);

View File

@ -1 +0,0 @@
export * from './boolean-debounce-time';

View File

@ -1,7 +0,0 @@
@mixin fill($color) {
color: $color;
* {
fill: $color;
}
}

View File

@ -1,6 +0,0 @@
@import '../../../../node_modules/@angular/material/theming';
$theme: (
name: 'light',
neutral: mat-palette($mat-grey),
);

View File

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

View File

@ -1,5 +0,0 @@
import * as moment from 'moment';
import { ModificationUnit } from '../../gen-damsel/claim_management';
export const sortUnitsByCreatedAtAsc = <T extends ModificationUnit>(units: T[]): T[] =>
units.slice().sort(({ created_at: a }, { created_at: b }) => moment(a).diff(moment(b)));

View File

@ -1,22 +0,0 @@
import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs';
import { KeycloakService } from 'keycloak-angular';
import { ThriftService } from '../thrift';
import * as ClaimManagement from './gen-nodejs/ClaimManagement';
import { Claim, ClaimSearchQuery, ClaimSearchResponse } from '../gen-damsel/claim_management';
import { ClaimSearchQuery as ClaimSearchQueryType } from './gen-nodejs/claim_management_types';
@Injectable()
export class ClaimManagementService extends ThriftService {
constructor(zone: NgZone, keycloakService: KeycloakService) {
super(zone, keycloakService, '/v1/cm', ClaimManagement);
}
searchClaims = (query: ClaimSearchQuery): Observable<ClaimSearchResponse> =>
this.toObservableAction('SearchClaims')(new ClaimSearchQueryType(query));
getClaim = (partyID: string, claimID: number): Observable<Claim> => {
return this.toObservableAction('GetClaim')(partyID, claimID);
};
}

View File

@ -1,10 +1,10 @@
import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs';
import { KeycloakService } from 'keycloak-angular';
import * as Repository from './gen-nodejs/Repository';
import { ThriftService } from './thrift-service';
import { Reference, Snapshot, Commit, Version, Limit } from '../gen-damsel/domain_config';
import { KeycloakService } from 'keycloak-angular';
@Injectable()
export class DomainService extends ThriftService {

View File

@ -1,11 +1,11 @@
import { Injectable, NgZone } from '@angular/core';
import { Observable } from 'rxjs';
import { KeycloakService } from 'keycloak-angular';
import * as MerchantStatistics from './gen-nodejs/MerchantStatistics';
import { ThriftService } from './thrift-service';
import { StatRequest, StatResponse } from '../gen-damsel/merch_stat';
import { StatRequest as ThriftStatRequest } from './gen-nodejs/merch_stat_types';
import { KeycloakService } from 'keycloak-angular';
@Injectable()
export class MerchantStatisticsService extends ThriftService {

View File

@ -2,7 +2,12 @@ import cloneDeep from 'lodash-es/cloneDeep';
import last from 'lodash-es/last';
import dropRight from 'lodash-es/dropRight';
import { ProviderObject, TerminalDecision, TerminalRef } from '../../gen-damsel/domain';
import {
ProviderObject,
TerminalSelector,
TerminalDecision,
TerminalRef
} from '../../gen-damsel/domain';
import { toGenTerminalDecision } from '../converters';
import { checkSelector } from './utils';

View File

@ -1,5 +1,7 @@
import { Injectable, NgZone } from '@angular/core';
import { Observable, timer } from 'rxjs';
import { share, switchMap, first } from 'rxjs/operators';
import { KeycloakService } from 'keycloak-angular';
import {
InvoicePaymentAdjustmentParams as InvoicePaymentAdjustmentParamsObject,
@ -15,8 +17,6 @@ import {
import { ThriftService } from './thrift-service';
import * as Invoicing from './gen-nodejs/Invoicing';
import { InvoiceID } from '../gen-damsel/domain';
import { share, switchMap, first } from 'rxjs/operators';
import { KeycloakService } from 'keycloak-angular';
@Injectable()
export class PaymentProcessingService extends ThriftService {

View File

@ -11,10 +11,9 @@ type Exception<N = string, T = {}> = {
} & T;
export class ThriftService {
protected realm = 'internal';
protected endpoint: string;
protected service: any;
protected realm = 'internal';
constructor(
private zone: NgZone,
@ -48,7 +47,7 @@ export class ThriftService {
}).pipe(timeout(60000))) as any;
}
private createClient(errorCb: Function): Observable<any> {
private createClient(errorCb: Function) {
return from(this.keycloakService.getToken()).pipe(
map(token => {
const { email, preferred_username, sub } = jwtDecode(token);

View File

@ -5,7 +5,6 @@ import { PaymentProcessingService } from './payment-processing.service';
import { MerchantStatisticsService } from './merchant-statistics.service';
import { DomainTypedManager } from './domain-typed-manager';
import { DomainCacheService } from './domain-cache.service';
import { ClaimManagementService } from './claim-management.service';
@NgModule({
providers: [
@ -13,8 +12,7 @@ import { ClaimManagementService } from './claim-management.service';
DomainTypedManager,
PaymentProcessingService,
MerchantStatisticsService,
DomainCacheService,
ClaimManagementService
DomainCacheService
]
})
export class ThriftModule {}

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