Skip to content
Snippets Groups Projects
Commit c1b9513d authored by Sebastian Wittek's avatar Sebastian Wittek
Browse files

add missing }

parents 188ff5a7 3af7484f
No related merge requests found
Showing
with 306 additions and 51 deletions
<mat-radio-group (change)="onChange($event)">
<mat-radio-button value="json" #json checked (click)="comma.checked=true">JSON</mat-radio-button>
<mat-divider></mat-divider>
<mat-radio-button #csv value="csv">CSV</mat-radio-button>
</mat-radio-group>
<div id="csvBlock">
<mat-hint>{{'comment-page.delimiter' | translate}}</mat-hint>
<mat-radio-group (change)="onChange($event)" id="csvOptions">
<mat-radio-button value="comma" #comma checked>{{'comment-page.comma' | translate}}</mat-radio-button>
<mat-radio-button value="semicolon" #semicolon>{{'comment-page.semicolon' | translate}}</mat-radio-button>
</mat-radio-group>
</div>
<button mat-raised-button color="primary" (click)="onExport()">{{'comment-page.export' | translate}}</button>
<button mat-raised-button color="warn" (click)="onNoClick()">{{'comment-page.abort' | translate}}</button>
mat-radio-button {
display: block;
}
mat-divider {
margin: 30px 0 30px 0;
}
* {
margin-bottom: 10px;
}
button {
float:right !important;
margin: 0 0 0 10px;
}
#csvBlock {
margin: 10px 0 20px 30px;
visibility: hidden;
transform: scale(0.9);
}
#csvOptions mat-radio-button{
margin-top:10px;
}
\ No newline at end of file
/** import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CommentExportComponent } from './comment-export.component';
describe('CommentExportComponent', () => {
let component: CommentExportComponent;
let fixture: ComponentFixture<CommentExportComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CommentExportComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CommentExportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
}); */
import { Component, OnInit, EventEmitter } from '@angular/core';
import { MatRadioChange, MatDialogRef } from '@angular/material';
import { CommentCreatorPageComponent } from '../../comment-creator-page/comment-creator-page.component';
import { CommentService } from '../../../../services/http/comment.service';
import { Comment } from '../../../../models/comment';
@Component({
selector: 'app-comment-export',
templateUrl: './comment-export.component.html',
styleUrls: ['./comment-export.component.scss']
})
export class CommentExportComponent implements OnInit {
change: EventEmitter<MatRadioChange>;
currentButton: string;
csvSelected: boolean;
comments: Comment[];
roomId: string;
constructor(public dialogRef: MatDialogRef<CommentCreatorPageComponent>,
private commentService: CommentService) { }
ngOnInit() {
this.currentButton = 'json';
this.roomId = localStorage.getItem(`roomId`);
this.getComments();
}
getComments(): void {
this.commentService.getComments(this.roomId)
.subscribe(comments => {
this.comments = comments;
});
}
onChange(change: MatRadioChange): string {
const csv = document.getElementById('csvBlock');
if (change.value === 'json') {
csv.style.visibility = 'hidden';
this.csvSelected = false;
}
if (change.value === 'csv') {
csv.style.visibility = 'visible';
this.csvSelected = true;
}
return this.currentButton = change.value;
}
onNoClick(): void {
this.dialogRef.close();
}
exportJson(date: string): void {
const jsonComments = JSON.parse(JSON.stringify(this.comments));
jsonComments.forEach(element => {
delete element.id;
delete element.roomId;
delete element.creatorId;
element.body = element.body.replace(/[\r\n]/g, ' ').replace(/ +/g, ' ');
});
const myBlob = new Blob([JSON.stringify(jsonComments, null, 2)], { type: 'application/json' });
const link = document.createElement('a');
const fileName = 'comments_' + date + '.json';
link.setAttribute('download', fileName);
link.href = window.URL.createObjectURL(myBlob);
link.click();
}
exportCsv(delimiter: string, date: string): void {
let csv: string;
let keyFields = '';
let valueFields = '';
keyFields = Object.keys(this.comments[0]).slice(3).join(delimiter) + '\r\n';
this.comments.forEach(element => {
element.body = '"' + element.body.replace(/[\r\n]/g, ' ').replace(/ +/g, ' ').replace(/"/g, '""') + '"';
valueFields += Object.values(element).slice(3).join(delimiter) + '\r\n';
});
csv = keyFields + valueFields;
const myBlob = new Blob([csv], { type: 'text/csv' });
const link = document.createElement('a');
const fileName = 'comments_' + date + '.csv';
link.setAttribute('download', fileName);
link.href = window.URL.createObjectURL(myBlob);
link.click();
}
onExport(): void {
const date = new Date();
const dateString = date.getFullYear() + '_' + ('0' + (date.getMonth() + 1)).slice(-2) + '_' + ('0' + date.getDate()).slice(-2);
const timeString = ('0' + date.getHours()).slice(-2) + ('0' + date.getMinutes()).slice(-2) + ('0' + date.getSeconds()).slice(-2);
const timestamp = dateString + '_' + timeString;
if (this.currentButton === 'json') {
this.exportJson(timestamp);
this.onNoClick();
}
if (this.csvSelected) {
if (this.currentButton === 'comma') {
this.exportCsv(',', timestamp);
this.onNoClick();
}
if (this.currentButton === 'semicolon') {
this.exportCsv(';', timestamp);
this.onNoClick();
} else {
this.exportCsv(',', timestamp);
this.onNoClick();
}
}
}
}
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { CommentService } from '../../../services/http/comment.service';
import { MatDialog } from '@angular/material';
import { CommentExportComponent } from '../_dialogs/comment-export/comment-export.component';
@Component({ @Component({
selector: 'app-comment-creator-page', selector: 'app-comment-creator-page',
...@@ -7,9 +10,24 @@ import { Component, OnInit } from '@angular/core'; ...@@ -7,9 +10,24 @@ import { Component, OnInit } from '@angular/core';
}) })
export class CommentCreatorPageComponent implements OnInit { export class CommentCreatorPageComponent implements OnInit {
constructor() { } constructor(private commentService: CommentService,
public dialog: MatDialog,
) { }
ngOnInit() { ngOnInit() {
this.commentService.exportButton.subscribe(s => {
if (s === true) {
this.showExportDialog();
}
});
} }
showExportDialog(): void {
this.commentService.exportButtonClicked(false);
if (this.dialog.openDialogs.length === 0) {
this.dialog.open(CommentExportComponent, {
width: '400px', height: '300px', restoreFocus: false
});
}
}
} }
...@@ -22,6 +22,7 @@ import { ContentListComponent } from './content-list/content-list.component'; ...@@ -22,6 +22,7 @@ import { ContentListComponent } from './content-list/content-list.component';
import { ContentEditComponent } from './_dialogs/content-edit/content-edit.component'; import { ContentEditComponent } from './_dialogs/content-edit/content-edit.component';
import { ContentPresentationComponent } from './content-presentation/content-presentation.component'; import { ContentPresentationComponent } from './content-presentation/content-presentation.component';
import { CommentCreatorPageComponent } from './comment-creator-page/comment-creator-page.component'; import { CommentCreatorPageComponent } from './comment-creator-page/comment-creator-page.component';
import { CommentExportComponent } from './_dialogs/comment-export/comment-export.component';
@NgModule({ @NgModule({
imports: [ imports: [
...@@ -52,7 +53,8 @@ import { CommentCreatorPageComponent } from './comment-creator-page/comment-crea ...@@ -52,7 +53,8 @@ import { CommentCreatorPageComponent } from './comment-creator-page/comment-crea
ContentListComponent, ContentListComponent,
ContentEditComponent, ContentEditComponent,
ContentPresentationComponent, ContentPresentationComponent,
CommentCreatorPageComponent CommentCreatorPageComponent,
CommentExportComponent
], ],
entryComponents: [ entryComponents: [
RoomDeleteComponent, RoomDeleteComponent,
...@@ -63,7 +65,8 @@ import { CommentCreatorPageComponent } from './comment-creator-page/comment-crea ...@@ -63,7 +65,8 @@ import { CommentCreatorPageComponent } from './comment-creator-page/comment-crea
ContentLikertCreatorComponent, ContentLikertCreatorComponent,
ContentTextCreatorComponent, ContentTextCreatorComponent,
ContentYesNoCreatorComponent, ContentYesNoCreatorComponent,
ContentEditComponent ContentEditComponent,
CommentExportComponent
] ]
}) })
export class CreatorModule { export class CreatorModule {
......
...@@ -3,17 +3,21 @@ ...@@ -3,17 +3,21 @@
<mat-icon class="search-icon">search</mat-icon> <mat-icon class="search-icon">search</mat-icon>
</mat-label> </mat-label>
<input #searchBox placeholder="{{ 'comment-list-page.search-box-placeholder-text' | translate }}" <input #searchBox placeholder="{{ 'comment-list-page.search-box-placeholder-text' | translate }}"
(input)="searchComments(searchBox.value)"> (input)="searchComments(searchBox.value)">
<button mat-button *ngIf="searchBox.value" (click)="hideCommentsList=false; searchBox.value=''"> <button mat-button *ngIf="searchBox.value" (click)="hideCommentsList=false; searchBox.value=''">
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
</button> </button>
<button mat-button *ngIf="!searchBox.value && userRole == '1' && comments.length > 0"
[matTooltip]="'Export comments'" (click)="export(true)">
<mat-icon class="add-icon" id="export-icon">cloud_download</mat-icon>
</button>
<button mat-button *ngIf="!searchBox.value" color="accent" (click)="openSubmitDialog()"> <button mat-button *ngIf="!searchBox.value" color="accent" (click)="openSubmitDialog()">
<mat-icon class="add-icon">add_circle</mat-icon> <mat-icon class="add-icon">add_circle</mat-icon>
</button> </button>
</div> </div>
<mat-card class="outer-card" *ngIf="hideCommentsList"> <mat-card class="outer-card" *ngIf="hideCommentsList">
<app-comment *ngFor="let current of filteredComments" [comment]="current"> </app-comment> <app-comment *ngFor="let current of filteredComments" [comment]="current"></app-comment>
</mat-card> </mat-card>
<mat-card class="outer-card" *ngIf="!hideCommentsList"> <mat-card class="outer-card" *ngIf="!hideCommentsList">
<app-comment *ngFor="let current of comments | orderBy: 'score'" [comment]="current"> </app-comment> <app-comment *ngFor="let current of comments | orderBy: 'score'" [comment]="current"></app-comment>
</mat-card> </mat-card>
\ No newline at end of file
...@@ -26,7 +26,6 @@ input { ...@@ -26,7 +26,6 @@ input {
margin-bottom: 10px; margin-bottom: 10px;
} }
.add-button { .add-button {
width: 44px!important; width: 44px!important;
height: 44px!important; height: 44px!important;
...@@ -44,3 +43,6 @@ input { ...@@ -44,3 +43,6 @@ input {
padding: 10px; padding: 10px;
} }
#export-icon {
color: rgba(30,136,229,0.7)
}
...@@ -9,6 +9,8 @@ import { SubmitCommentComponent } from '../_dialogs/submit-comment/submit-commen ...@@ -9,6 +9,8 @@ import { SubmitCommentComponent } from '../_dialogs/submit-comment/submit-commen
import { MatDialog } from '@angular/material'; import { MatDialog } from '@angular/material';
import { WsCommentServiceService } from '../../../services/websockets/ws-comment-service.service'; import { WsCommentServiceService } from '../../../services/websockets/ws-comment-service.service';
import { User } from '../../../models/user'; import { User } from '../../../models/user';
import { UserRole } from '../../../models/user-roles.enum';
import { AuthenticationService } from '../../../services/http/authentication.service';
@Component({ @Component({
selector: 'app-comment-list', selector: 'app-comment-list',
...@@ -22,13 +24,15 @@ export class CommentListComponent implements OnInit { ...@@ -22,13 +24,15 @@ export class CommentListComponent implements OnInit {
isLoading = true; isLoading = true;
hideCommentsList: boolean; hideCommentsList: boolean;
filteredComments: Comment[]; filteredComments: Comment[];
userRole: UserRole;
constructor(private commentService: CommentService, constructor(private commentService: CommentService,
private translateService: TranslateService, private translateService: TranslateService,
public dialog: MatDialog, public dialog: MatDialog,
protected langService: LanguageService, protected langService: LanguageService,
private rxStompService: RxStompService, private rxStompService: RxStompService,
private wsCommentService: WsCommentServiceService) { private wsCommentService: WsCommentServiceService,
private authenticationService: AuthenticationService) {
langService.langEmitter.subscribe(lang => translateService.use(lang)); langService.langEmitter.subscribe(lang => translateService.use(lang));
} }
...@@ -41,6 +45,8 @@ export class CommentListComponent implements OnInit { ...@@ -41,6 +45,8 @@ export class CommentListComponent implements OnInit {
}); });
this.getComments(); this.getComments();
this.translateService.use(localStorage.getItem('currentLang')); this.translateService.use(localStorage.getItem('currentLang'));
this.userRole = this.authenticationService.getRole();
} }
getComments(): void { getComments(): void {
...@@ -80,13 +86,13 @@ export class CommentListComponent implements OnInit { ...@@ -80,13 +86,13 @@ export class CommentListComponent implements OnInit {
case 'read': case 'read':
this.comments[i].read = <boolean>value; this.comments[i].read = <boolean>value;
break; break;
case 'correct' : case 'correct':
this.comments[i].correct = <boolean>value; this.comments[i].correct = <boolean>value;
break; break;
case 'favorite' : case 'favorite':
this.comments[i].favorite = <boolean>value; this.comments[i].favorite = <boolean>value;
break; break;
case 'score' : case 'score':
this.comments[i].score = <number>value; this.comments[i].score = <number>value;
break; break;
} }
...@@ -115,5 +121,8 @@ export class CommentListComponent implements OnInit { ...@@ -115,5 +121,8 @@ export class CommentListComponent implements OnInit {
send(comment: Comment): void { send(comment: Comment): void {
this.wsCommentService.add(comment); this.wsCommentService.add(comment);
} }
}
export(clicked: boolean): void {
this.commentService.exportButtonClicked(clicked);
}
}
<mat-card class="card-container"> <mat-card class="card-container" [@slide]>
<div fxLayout="column"> <div fxLayout="column">
<div fxLayout="row"> <div fxLayout="row">
<span class="fill-remaining-space"></span> <span class="fill-remaining-space"></span>
<div id="date"> <div id="date">
<div *ngIf="language === 'de'; else englishDate"> <div *ngIf="language === 'de'; else englishDate">
{{comment.timestamp | date: ' HH:mm:ss '}}Uhr,{{comment.timestamp | date: ' M.d.yy'}} {{comment.timestamp | date: ' HH:mm:ss '}}Uhr,{{comment.timestamp | date: ' M.d.yy'}}
...@@ -15,24 +15,24 @@ ...@@ -15,24 +15,24 @@
</button> </button>
<button mat-icon-button *ngIf="comment.favorite || !isStudent" [disabled]="isStudent" (click)="setFavorite(comment)" [matTooltip]="comment.favorite ? 'Mark as not favorite' : 'Mark as favorite'"> <button mat-icon-button *ngIf="comment.favorite || !isStudent" [disabled]="isStudent" (click)="setFavorite(comment)" [matTooltip]="comment.favorite ? 'Mark as not favorite' : 'Mark as favorite'">
<mat-icon [ngClass]="{true: 'favorite-icon', false: 'not-favorite-icon'}[comment.favorite]">favorite_border</mat-icon> <mat-icon [ngClass]="{true: 'favorite-icon', false: 'not-favorite-icon'}[comment.favorite]">favorite_border</mat-icon>
</button>
<button mat-icon-button [disabled]="isStudent" (click)="setRead(comment)" [matTooltip]="comment.read ? 'Mark as unread' : 'Mark as read'">
<mat-icon class="icon" [ngClass]="{true: 'read-icon', false: 'unread-icon'}[comment.read]">visibility</mat-icon>
</button>
</div>
<div fxLayout="row">
<div class="body" (click)="openPresentDialog(comment.body)">{{comment.body}}</div>
<span class="fill-remaining-space"></span>
<div fxLayout="column">
<button mat-icon-button [disabled]="!isStudent" (click)="voteUp(comment)">
<mat-icon class="voting-icon" [ngClass]="{'upvoted' : hasVoted === 1}">keyboard_arrow_up</mat-icon>
</button> </button>
<h2>{{comment.score}}</h2> <button mat-icon-button [disabled]="isStudent" (click)="setRead(comment)" [matTooltip]="comment.read ? 'Mark as unread' : 'Mark as read'">
<button mat-icon-button [disabled]="!isStudent" (click)="voteDown(comment)"> <mat-icon class="icon" [ngClass]="{true: 'read-icon', false: 'unread-icon'}[comment.read]">visibility</mat-icon>
<mat-icon class="voting-icon" [ngClass]="{'downvoted' : hasVoted === -1}">keyboard_arrow_down</mat-icon>
</button> </button>
</div> </div>
<div fxLayout="row">
<div class="body" (click)="openPresentDialog(comment.body)">{{comment.body}}</div>
<span class="fill-remaining-space"></span>
<div fxLayout="column" (tap)="startAnimation('rubberBand')" [@rubberBand]="animationState" (@rubberBand.done)="resetAnimationState()">
<button mat-icon-button [disabled]="!isStudent" (click)="voteUp(comment)" >
<mat-icon class="voting-icon" [ngClass]="{'upvoted' : hasVoted === 1}">keyboard_arrow_up</mat-icon>
</button>
<h2>{{comment.score}}</h2>
<button mat-icon-button [disabled]="!isStudent" (click)="voteDown(comment)">
<mat-icon class="voting-icon" [ngClass]="{'downvoted' : hasVoted === -1}">keyboard_arrow_down</mat-icon>
</button>
</div>
</div>
</div> </div>
</div> </mat-card>
</mat-card>
...@@ -73,8 +73,7 @@ h2 { ...@@ -73,8 +73,7 @@ h2 {
text-align: start; text-align: start;
font-size: 140%; font-size: 140%;
max-height: 120px; max-height: 120px;
overflow: hidden; overflow: auto;
text-overflow: ellipsis;
padding-left: 2%; padding-left: 2%;
padding-right: 2%; padding-right: 2%;
} }
......
...@@ -10,28 +10,50 @@ import { LanguageService } from '../../../services/util/language.service'; ...@@ -10,28 +10,50 @@ import { LanguageService } from '../../../services/util/language.service';
import { WsCommentServiceService } from '../../../services/websockets/ws-comment-service.service'; import { WsCommentServiceService } from '../../../services/websockets/ws-comment-service.service';
import { PresentCommentComponent } from '../_dialogs/present-comment/present-comment.component'; import { PresentCommentComponent } from '../_dialogs/present-comment/present-comment.component';
import { MatDialog } from '@angular/material'; import { MatDialog } from '@angular/material';
import { trigger, transition, style, animate, state, keyframes } from '@angular/animations';
export const rubberBand = [
style({ transform: 'scale3d(1, 1, 1)', offset: 0 }),
style({ transform: 'scale3d(1.05, 0.75, 1)', offset: 0.3 }),
style({ transform: 'scale3d(0.75, 1.05, 1)', offset: 0.4 }),
style({ transform: 'scale3d(1.05, 0.95, 1)', offset: 0.5 }),
style({ transform: 'scale3d(0.95, 1.05, 1)', offset: 0.65 }),
style({ transform: 'scale3d(1.05, 0.95, 1)', offset: 0.75 }),
style({ transform: 'scale3d(1, 1, 1)', offset: 1 })
];
@Component({ @Component({
selector: 'app-comment', selector: 'app-comment',
templateUrl: './comment.component.html', templateUrl: './comment.component.html',
styleUrls: ['./comment.component.scss'] styleUrls: ['./comment.component.scss'],
animations: [
trigger('slide', [
state('void', style({ opacity: 0, transform: 'translateY(-10px)' })),
transition('void <=> *', animate(700)),
]),
trigger('rubberBand', [
transition('* => rubberBand', animate(1000, keyframes(rubberBand))),
])
]
}) })
export class CommentComponent implements OnInit { export class CommentComponent implements OnInit {
@Input() comment: Comment; @Input() comment: Comment;
isStudent = false; isStudent = false;
isLoading = true; isLoading = true;
hasVoted = 0; hasVoted = 0;
language: string; language: string;
animationState: string;
constructor(protected authenticationService: AuthenticationService, constructor(protected authenticationService: AuthenticationService,
private route: ActivatedRoute, private route: ActivatedRoute,
private location: Location, private location: Location,
private commentService: CommentService, private commentService: CommentService,
private notification: NotificationService, private notification: NotificationService,
private translateService: TranslateService, private translateService: TranslateService,
public dialog: MatDialog, public dialog: MatDialog,
protected langService: LanguageService, protected langService: LanguageService,
private wsCommentService: WsCommentServiceService) { private wsCommentService: WsCommentServiceService) {
langService.langEmitter.subscribe(lang => { langService.langEmitter.subscribe(lang => {
translateService.use(lang); translateService.use(lang);
this.language = lang; this.language = lang;
...@@ -46,6 +68,16 @@ export class CommentComponent implements OnInit { ...@@ -46,6 +68,16 @@ export class CommentComponent implements OnInit {
this.translateService.use(this.language); this.translateService.use(this.language);
} }
startAnimation(state_: any): void {
if (!this.animationState) {
this.animationState = state_;
}
}
resetAnimationState(): void {
this.animationState = '';
}
setRead(comment: Comment): void { setRead(comment: Comment): void {
this.comment = this.wsCommentService.toggleRead(comment); this.comment = this.wsCommentService.toggleRead(comment);
} }
......
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http'; import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { Comment } from '../../models/comment'; import { Comment } from '../../models/comment';
import { catchError, tap } from 'rxjs/operators'; import { catchError, tap } from 'rxjs/operators';
import { BaseHttpService } from './base-http.service'; import { BaseHttpService } from './base-http.service';
...@@ -17,6 +17,8 @@ export class CommentService extends BaseHttpService { ...@@ -17,6 +17,8 @@ export class CommentService extends BaseHttpService {
find: '/find' find: '/find'
}; };
exportButton = new Subject<boolean>();
constructor(private http: HttpClient) { constructor(private http: HttpClient) {
super(); super();
} }
...@@ -66,4 +68,8 @@ export class CommentService extends BaseHttpService { ...@@ -66,4 +68,8 @@ export class CommentService extends BaseHttpService {
catchError(this.handleError<any>('updateComment')) catchError(this.handleError<any>('updateComment'))
); );
} }
exportButtonClicked(state: boolean): void {
this.exportButton.next(state);
}
} }
...@@ -82,7 +82,11 @@ ...@@ -82,7 +82,11 @@
"abort": "Abbrechen", "abort": "Abbrechen",
"error-comment": "Bitte geben Sie ein Kommentar ein.", "error-comment": "Bitte geben Sie ein Kommentar ein.",
"error-title": "Bitte geben Sie einen Titel ein.", "error-title": "Bitte geben Sie einen Titel ein.",
"error-both-fields": "Bitte füllen Sie alle Felder aus." "error-both-fields": "Bitte füllen Sie alle Felder aus.",
"delimiter": "Bitte wählen Sie ein Trennzeichen:",
"comma": "Komma",
"semicolon": "Semikolon",
"export": "Exportieren"
}, },
"comment-list-page": { "comment-list-page": {
"search-box-placeholder-text": "Kommentare durchsuchen", "search-box-placeholder-text": "Kommentare durchsuchen",
......
...@@ -82,7 +82,11 @@ ...@@ -82,7 +82,11 @@
"abort": "Cancel", "abort": "Cancel",
"error-title": "Please enter a title.", "error-title": "Please enter a title.",
"error-comment": "Please enter a comment.", "error-comment": "Please enter a comment.",
"error-both-fields": "Please fill in all fields." "error-both-fields": "Please fill in all fields.",
"delimiter": "Please select a delimiter:",
"comma": "Comma",
"semicolon": "Semicolon",
"export": "Export"
}, },
"comment-list-page": { "comment-list-page": {
"search-box-placeholder-text": "Search in comments", "search-box-placeholder-text": "Search in comments",
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment