From 4860e4ccad11970d7d439176b3e0411fa71a3f0e Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Mon, 18 Nov 2024 16:30:22 +0100 Subject: [PATCH 1/6] fix post dropdown&reaction bar issues on exercise view --- .../answer-post/answer-post.component.html | 2 +- .../answer-post/answer-post.component.ts | 1 + .../app/shared/metis/post/post.component.html | 10 +- .../app/shared/metis/post/post.component.ts | 9 +- .../post-footer/post-footer.component.html | 2 +- .../post-footer/post-footer.component.ts | 10 +- .../answer-post-reactions-bar.component.html | 9 -- .../answer-post-reactions-bar.component.ts | 6 +- .../post-reactions-bar.component.html | 14 +- .../post-reactions-bar.component.ts | 17 +- .../posting-reactions-bar.component.scss | 1 + .../app/shared/metis/posting.directive.ts | 4 +- .../shared/metis/post/post.component.spec.ts | 9 ++ .../post-footer/post-footer.component.spec.ts | 9 ++ ...nswer-post-reactions-bar.component.spec.ts | 9 -- .../post-reactions-bar.component.spec.ts | 149 +++++++++++++----- 16 files changed, 174 insertions(+), 87 deletions(-) diff --git a/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html b/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html index 073e4e907593..85a61e59eb89 100644 --- a/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html +++ b/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html @@ -5,7 +5,6 @@ [isReadOnlyMode]="isReadOnlyMode" [isCommunicationPage]="isCommunicationPage" [lastReadDate]="lastReadDate" - [hasChannelModerationRights]="hasChannelModerationRights" [isDeleted]="isDeleted" /> } @@ -34,6 +33,7 @@ (reactionsUpdated)="onReactionsUpdated($event)" (mayEditOrDeleteOutput)="onMayEditOrDelete($event)" (isDeleteEvent)="onDeleteEvent(true)" + [hasChannelModerationRights]="hasChannelModerationRights()" /> diff --git a/src/main/webapp/app/shared/metis/answer-post/answer-post.component.ts b/src/main/webapp/app/shared/metis/answer-post/answer-post.component.ts index 3b3c5e7ffdf1..798e8d81ae76 100644 --- a/src/main/webapp/app/shared/metis/answer-post/answer-post.component.ts +++ b/src/main/webapp/app/shared/metis/answer-post/answer-post.component.ts @@ -54,6 +54,7 @@ export class AnswerPostComponent extends PostingDirective { static activeDropdownPost: AnswerPostComponent | null = null; mayEditOrDelete: boolean = false; @ViewChild(AnswerPostReactionsBarComponent) private reactionsBarComponent!: AnswerPostReactionsBarComponent; + hasChannelModerationRights = input(false); constructor( public changeDetector: ChangeDetectorRef, diff --git a/src/main/webapp/app/shared/metis/post/post.component.html b/src/main/webapp/app/shared/metis/post/post.component.html index 1fcad5a5987f..80ec95f76f61 100644 --- a/src/main/webapp/app/shared/metis/post/post.component.html +++ b/src/main/webapp/app/shared/metis/post/post.component.html @@ -6,7 +6,6 @@ [posting]="posting" [isDeleted]="isDeleted" [isCommunicationPage]="isCommunicationPage" - [hasChannelModerationRights]="hasChannelModerationRights" (isModalOpen)="displayInlineInput = true" [lastReadDate]="lastReadDate" /> @@ -68,6 +67,7 @@ >
@if (!previewMode) { + }
@@ -98,7 +99,7 @@ } @if (!isDeleted) {
- + @if (!previewMode) { @@ -158,7 +160,7 @@ } - diff --git a/src/main/webapp/app/shared/metis/post/post.component.ts b/src/main/webapp/app/shared/metis/post/post.component.ts index d70c13abae68..bd502fbea1ac 100644 --- a/src/main/webapp/app/shared/metis/post/post.component.ts +++ b/src/main/webapp/app/shared/metis/post/post.component.ts @@ -90,7 +90,7 @@ export class PostComponent extends PostingDirective implements OnInit, OnC isConsecutive = input(false); dropdownPosition = { x: 0, y: 0 }; - @ViewChild(PostReactionsBarComponent) private reactionsBarComponent!: PostReactionsBarComponent; + @ViewChild(PostReactionsBarComponent) protected reactionsBarComponent!: PostReactionsBarComponent; constructor( public metisService: MetisService, @@ -218,6 +218,13 @@ export class PostComponent extends PostingDirective implements OnInit, OnC this.postFooterComponent.openCreateAnswerPostModal(); } + /** + * Close create answer modal + */ + closeCreateAnswerPostModal() { + this.postFooterComponent.closeCreateAnswerPostModal(); + } + /** * sorts answerPosts by two criteria * 1. criterion: resolvesPost -> true comes first diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html index 6a980a907348..e462e5bd12f2 100644 --- a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html +++ b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html @@ -25,7 +25,7 @@ (openPostingCreateEditModal)="createAnswerPostModal.open()" (userReferenceClicked)="userReferenceClicked.emit($event)" (channelReferenceClicked)="channelReferenceClicked.emit($event)" - [hasChannelModerationRights]="hasChannelModerationRights" + [hasChannelModerationRights]="hasChannelModerationRights()" /> } } diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts index 7f6d3b0531a5..e00c1a250209 100644 --- a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts +++ b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts @@ -11,6 +11,7 @@ import { SimpleChanges, ViewChild, ViewContainerRef, + input, } from '@angular/core'; import { PostingFooterDirective } from 'app/shared/metis/posting-footer/posting-footer.directive'; import { Post } from 'app/entities/metis/post.model'; @@ -36,7 +37,6 @@ export class PostFooterComponent extends PostingFooterDirective implements @Input() readOnlyMode = false; @Input() previewMode = false; @Input() modalRef?: NgbModalRef; - @Input() hasChannelModerationRights = false; @Input() showAnswers = false; @Input() isCommunicationPage = false; @Input() sortedAnswerPosts: AnswerPost[] = []; @@ -48,6 +48,7 @@ export class PostFooterComponent extends PostingFooterDirective implements @ViewChild(AnswerPostCreateEditModalComponent) answerPostCreateEditModal?: AnswerPostCreateEditModalComponent; @ViewChild('createEditAnswerPostContainer', { read: ViewContainerRef }) containerRef!: ViewContainerRef; @ViewChild('createAnswerPostModal') createAnswerPostModalComponent!: AnswerPostCreateEditModalComponent; + hasChannelModerationRights = input(false); createdAnswerPost: AnswerPost; isAtLeastTutorInCourse = false; @@ -173,6 +174,13 @@ export class PostFooterComponent extends PostingFooterDirective implements this.createAnswerPostModalComponent.open(); } + /** + * Close create answer modal + */ + closeCreateAnswerPostModal() { + this.createAnswerPostModalComponent.close(); + } + protected postsTrackByFn(index: number, post: Post): number { return post.id!; } diff --git a/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.html b/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.html index 86a4a499a599..e0ed87168dc9 100644 --- a/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.html +++ b/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.html @@ -89,13 +89,4 @@ } }
- - @if (isLastAnswer && !isThreadSidebar) { -
- -
- } diff --git a/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.ts b/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.ts index 9023089670d5..09af48ab9cab 100644 --- a/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.ts +++ b/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnInit, Output, input } from '@angular/core'; import { Reaction } from 'app/entities/metis/reaction.model'; import { PostingsReactionsBarDirective } from 'app/shared/metis/posting-reactions-bar/posting-reactions-bar.directive'; import { AnswerPost } from 'app/entities/metis/answer-post.model'; @@ -27,6 +27,7 @@ export class AnswerPostReactionsBarComponent extends PostingsReactionsBarDirecti readonly faPencilAlt = faPencilAlt; @Input() isEmojiCount: boolean = false; @Output() postingUpdated = new EventEmitter(); + hasChannelModerationRights = input(false); constructor(metisService: MetisService) { super(metisService); @@ -70,8 +71,7 @@ export class AnswerPostReactionsBarComponent extends PostingsReactionsBarDirecti this.isAnswerOfAnnouncement = getAsChannelDTO(this.posting.post?.conversation)?.isAnnouncementChannel ?? false; const isCourseWideChannel = getAsChannelDTO(this.posting.post?.conversation)?.isCourseWide ?? false; const isAtLeastInstructorInCourse = this.metisService.metisUserIsAtLeastInstructorInCourse(); - const mayEditOrDeleteOtherUsersAnswer = - (isCourseWideChannel && isAtLeastInstructorInCourse) || (getAsChannelDTO(this.metisService.getCurrentConversation())?.hasChannelModerationRights ?? false); + const mayEditOrDeleteOtherUsersAnswer = (isCourseWideChannel && isAtLeastInstructorInCourse) || (this.hasChannelModerationRights() ?? false); this.mayEditOrDelete = !this.isReadOnlyMode && (this.isAuthorOfPosting || mayEditOrDeleteOtherUsersAnswer); this.mayEditOrDeleteOutput.emit(this.mayEditOrDelete); } diff --git a/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.html b/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.html index 5ba32fbe573e..48f0f6a35ef5 100644 --- a/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.html +++ b/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.html @@ -4,7 +4,7 @@ @if (showAnswers) {
- @@ -12,8 +12,8 @@ } @else {
-
} - } @else { - -
- -
} } @else { @if (!isThreadSidebar) { diff --git a/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.ts b/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.ts index 1d039326b20b..ed55094bdd14 100644 --- a/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.ts +++ b/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild, input } from '@angular/core'; import { Reaction } from 'app/entities/metis/reaction.model'; import { Post } from 'app/entities/metis/post.model'; import { PostingsReactionsBarDirective } from 'app/shared/metis/posting-reactions-bar/posting-reactions-bar.directive'; @@ -41,6 +41,7 @@ export class PostReactionsBarComponent extends PostingsReactionsBarDirective(); @Output() openPostingCreateEditModal = new EventEmitter(); + @Output() closePostingCreateEditModal = new EventEmitter(); @Output() openThread = new EventEmitter(); @Input() previewMode: boolean; isAtLeastInstructorInCourse: boolean; @@ -51,6 +52,7 @@ export class PostReactionsBarComponent extends PostingsReactionsBarDirective(false); constructor( metisService: MetisService, @@ -63,6 +65,16 @@ export class PostReactionsBarComponent extends PostingsReactionsBarDirective reaction.count >= 1); } + openAnswerView() { + this.showAnswersChange.emit(true); + this.openPostingCreateEditModal.emit(); + } + + closeAnswerView() { + this.showAnswersChange.emit(false); + this.closePostingCreateEditModal.emit(); + } + /** * on initialization: call resetTooltipsAndPriority */ @@ -188,8 +200,7 @@ export class PostReactionsBarComponent extends PostingsReactionsBarDirective implements OnInit, OnD @Input() isCommunicationPage: boolean; @Input() showChannelReference?: boolean; - @Input() hasChannelModerationRights = false; + hasChannelModerationRights = input(false); @Input() isThreadSidebar: boolean; abstract get reactionsBar(): any; showDropdown = false; diff --git a/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts b/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts index cdcc598b7988..c7c9cf4f24db 100644 --- a/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts @@ -170,6 +170,15 @@ describe('PostComponent', () => { expect(postFooterOpenCreateAnswerPostModal).toHaveBeenCalledOnce(); }); + it('should close create answer post modal', () => { + component.posting = metisPostExerciseUser1; + component.ngOnInit(); + fixture.detectChanges(); + const postFooterOpenCreateAnswerPostModal = jest.spyOn(component.postFooterComponent, 'closeCreateAnswerPostModal'); + component.closeCreateAnswerPostModal(); + expect(postFooterOpenCreateAnswerPostModal).toHaveBeenCalledOnce(); + }); + it('should create or navigate to oneToOneChat when not on messaging page', () => { const navigateSpy = jest.spyOn(router, 'navigate'); const oneToOneChatService = TestBed.inject(OneToOneChatService); diff --git a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts index 45c38925db52..8071b5a84a95 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts @@ -151,4 +151,13 @@ describe('PostFooterComponent', () => { component.openCreateAnswerPostModal(); expect(createAnswerPostModalOpen).toHaveBeenCalledOnce(); }); + + it('should close create answer post modal', () => { + component.posting = metisPostExerciseUser1; + component.ngOnInit(); + fixture.detectChanges(); + const createAnswerPostModalClose = jest.spyOn(component.createAnswerPostModalComponent, 'close'); + component.closeCreateAnswerPostModal(); + expect(createAnswerPostModalClose).toHaveBeenCalledOnce(); + }); }); diff --git a/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.spec.ts index 8e5b51590166..a3b889e8d146 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.spec.ts @@ -193,15 +193,6 @@ describe('AnswerPostReactionsBarComponent', () => { expect(answerNowButton).toBeNull(); }); - it('answer now button should be visible if answer is the last one', () => { - component.posting = post; - component.isLastAnswer = true; - component.ngOnInit(); - fixture.detectChanges(); - const answerNowButton = fixture.debugElement.query(By.css('.reply-btn')).nativeElement; - expect(answerNowButton.innerHTML).toContain('reply'); - }); - it('should invoke metis service when toggle resolve is clicked', () => { metisServiceUserPostingAuthorMock.mockReturnValue(true); fixture.detectChanges(); diff --git a/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/post-reactions-bar/post-reactions-bar.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/post-reactions-bar/post-reactions-bar.component.spec.ts index f5ccda3ada15..a7dd96e750f3 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/post-reactions-bar/post-reactions-bar.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/post-reactions-bar/post-reactions-bar.component.spec.ts @@ -3,7 +3,7 @@ import { MetisService } from 'app/shared/metis/metis.service'; import { DebugElement } from '@angular/core'; import { Post } from 'app/entities/metis/post.model'; import { MockComponent, MockDirective, MockModule, MockPipe, MockProvider } from 'ng-mocks'; -import { getElement, getElements } from '../../../../../helpers/utils/general.utils'; +import { getElement } from '../../../../../helpers/utils/general.utils'; import { PostReactionsBarComponent } from 'app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component'; import { OverlayModule } from '@angular/cdk/overlay'; import { Reaction } from 'app/entities/metis/reaction.model'; @@ -23,15 +23,14 @@ import { MockRouter } from '../../../../../helpers/mocks/mock-router'; import { MockLocalStorageService } from '../../../../../helpers/mocks/service/mock-local-storage.service'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { By } from '@angular/platform-browser'; -import { PLACEHOLDER_USER_REACTED, ReactingUsersOnPostingPipe } from 'app/shared/pipes/reacting-users-on-posting.pipe'; +import { ReactingUsersOnPostingPipe } from 'app/shared/pipes/reacting-users-on-posting.pipe'; import { metisAnnouncement, metisCourse, metisPostExerciseUser1, metisPostInChannel, metisUser1, sortedAnswerArray } from '../../../../../helpers/sample/metis-sample-data'; import { EmojiComponent } from 'app/shared/metis/emoji/emoji.component'; import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; import { NotificationService } from 'app/shared/notification/notification.service'; import { MockNotificationService } from '../../../../../helpers/mocks/service/mock-notification.service'; -import { ConversationDTO, ConversationType } from 'app/entities/metis/conversation/conversation.model'; +import { ConversationType } from 'app/entities/metis/conversation/conversation.model'; import { ChannelDTO } from 'app/entities/metis/conversation/channel.model'; -import { User } from 'app/core/user/user.model'; import { provideHttpClient } from '@angular/common/http'; import { PostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; import { ConfirmIconComponent } from 'app/shared/confirm-icon/confirm-icon.component'; @@ -41,7 +40,6 @@ describe('PostReactionsBarComponent', () => { let fixture: ComponentFixture; let debugElement: DebugElement; let metisService: MetisService; - let accountService: AccountService; let metisServiceUpdateDisplayPriorityMock: jest.SpyInstance; let metisServiceUserIsAtLeastTutorStub: jest.SpyInstance; let metisServiceUserIsAtLeastInstructorStub: jest.SpyInstance; @@ -84,7 +82,6 @@ describe('PostReactionsBarComponent', () => { .then(() => { fixture = TestBed.createComponent(PostReactionsBarComponent); metisService = TestBed.inject(MetisService); - accountService = TestBed.inject(AccountService); debugElement = fixture.debugElement; component = fixture.componentInstance; metisServiceUpdateDisplayPriorityMock = jest.spyOn(metisService, 'updatePostDisplayPriority'); @@ -154,14 +151,9 @@ describe('PostReactionsBarComponent', () => { component.previewMode = false; component.isEmojiCount = false; - const channelConversation = { - type: ConversationType.CHANNEL, - hasChannelModerationRights: true, - } as ChannelDTO; - jest.spyOn(metisService, 'metisUserIsAuthorOfPosting').mockReturnValue(false); jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(false); - jest.spyOn(metisService, 'getCurrentConversation').mockReturnValue(channelConversation); + jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(true); component.ngOnInit(); fixture.detectChanges(); @@ -225,31 +217,92 @@ describe('PostReactionsBarComponent', () => { expect(getDeleteButton()).not.toBeNull(); }); - it.each([ - { type: ConversationType.CHANNEL, hasChannelModerationRights: true } as ChannelDTO, - { type: ConversationType.GROUP_CHAT, creator: { id: 99 } }, - { type: ConversationType.ONE_TO_ONE }, - ])('should initialize user authority and reactions correctly with same user', (dto: ConversationDTO) => { - component.posting!.author!.id = 99; - jest.spyOn(metisService, 'getCurrentConversation').mockReturnValue(dto); - jest.spyOn(accountService, 'userIdentity', 'get').mockReturnValue({ id: 99 } as User); + describe('setMayEditOrDelete', () => { + beforeEach(() => { + // Reset spies and component state before each test + jest.clearAllMocks(); + component.readOnlyMode = false; + component.previewMode = false; + component.isAuthorOfPosting = false; + component.posting = { + conversation: {}, + } as Post; + + // Mock EventEmitter + jest.spyOn(component.mayEditOrDeleteOutput, 'emit'); + }); - reactionToDelete.user = { id: 99 } as User; - post.reactions = [reactionToDelete]; - component.posting = post; + it('should allow edit/delete when user is the author and not in read-only or preview mode', () => { + // Arrange + component.isAuthorOfPosting = true; + jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(false); + jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(false); - component.ngOnInit(); - fixture.detectChanges(); - const reactions = getElements(debugElement, 'jhi-emoji'); - expect(reactions).toHaveLength(2); - expect(component.reactionMetaDataMap).toEqual({ - smile: { - count: 1, - hasReacted: true, - reactingUsers: [PLACEHOLDER_USER_REACTED], - }, + // Act + component.setMayEditOrDelete(); + + // Assert + expect(component.mayEditOrDelete).toBeTrue(); + expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(true); + }); + + it('should allow edit/delete when user has channel moderation rights', () => { + // Arrange + component.isAuthorOfPosting = false; + jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(false); + jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(true); + + // Act + component.setMayEditOrDelete(); + + // Assert + expect(component.mayEditOrDelete).toBeTrue(); + expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(true); + }); + + it('should not allow edit/delete when in read-only mode', () => { + // Arrange + component.readOnlyMode = true; + component.isAuthorOfPosting = true; + jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(true); + jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(true); + + // Act + component.setMayEditOrDelete(); + + // Assert + expect(component.mayEditOrDelete).toBeFalse(); + expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(false); + }); + + it('should not allow edit/delete when in preview mode', () => { + // Arrange + component.previewMode = true; + component.isAuthorOfPosting = true; + jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(true); + jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(true); + + // Act + component.setMayEditOrDelete(); + + // Assert + expect(component.mayEditOrDelete).toBeFalse(); + expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(false); + }); + + it('should not allow edit/delete when user is not author and lacks permissions', () => { + // Arrange + component.isAuthorOfPosting = false; + jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(false); + jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(false); + + // Act + component.setMayEditOrDelete(); + + // Assert + expect(component.mayEditOrDelete).toBeFalse(); + expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(false); }); - expect(component.pinTooltip).toBe('artemisApp.metis.pinPostTooltip'); }); it.each` @@ -311,14 +364,6 @@ describe('PostReactionsBarComponent', () => { expect(component.pinTooltip).toBe('artemisApp.metis.pinnedPostTooltip'); }); - it('start discussion button should be visible if post does not yet have any answers', () => { - component.posting = post; - component.sortedAnswerPosts = []; - fixture.detectChanges(); - const startDiscussion = fixture.debugElement.query(By.css('.reply-btn')).nativeElement; - expect(startDiscussion.innerHTML).toContain('reply'); - }); - it('should display button to show single answer', () => { component.posting = post; component.sortedAnswerPosts = [metisPostExerciseUser1]; @@ -343,4 +388,24 @@ describe('PostReactionsBarComponent', () => { const answerNowButton = fixture.debugElement.query(By.css('.collapse-answers-btn')).nativeElement; expect(answerNowButton.innerHTML).toContain('collapseAnswers'); }); + + it('should emit showAnswersChange and openPostingCreateEditModal when openAnswerView is called', () => { + const showAnswersChangeSpy = jest.spyOn(component.showAnswersChange, 'emit'); + const openPostingCreateEditModalSpy = jest.spyOn(component.openPostingCreateEditModal, 'emit'); + + component.openAnswerView(); + + expect(showAnswersChangeSpy).toHaveBeenCalledWith(true); + expect(openPostingCreateEditModalSpy).toHaveBeenCalled(); + }); + + it('should emit showAnswersChange and closePostingCreateEditModal when closeAnswerView is called', () => { + const showAnswersChangeSpy = jest.spyOn(component.showAnswersChange, 'emit'); + const closePostingCreateEditModalSpy = jest.spyOn(component.closePostingCreateEditModal, 'emit'); + + component.closeAnswerView(); + + expect(showAnswersChangeSpy).toHaveBeenCalledWith(false); + expect(closePostingCreateEditModalSpy).toHaveBeenCalled(); + }); }); From 0b609dcabfcd5d72f8447ba636c1659aff22605e Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Mon, 18 Nov 2024 16:35:22 +0100 Subject: [PATCH 2/6] refactor --- .../post-reactions-bar.component.spec.ts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/post-reactions-bar/post-reactions-bar.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/post-reactions-bar/post-reactions-bar.component.spec.ts index a7dd96e750f3..c6f8b6c1b081 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/post-reactions-bar/post-reactions-bar.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-reactions-bar/post-reactions-bar/post-reactions-bar.component.spec.ts @@ -219,7 +219,6 @@ describe('PostReactionsBarComponent', () => { describe('setMayEditOrDelete', () => { beforeEach(() => { - // Reset spies and component state before each test jest.clearAllMocks(); component.readOnlyMode = false; component.previewMode = false; @@ -228,78 +227,62 @@ describe('PostReactionsBarComponent', () => { conversation: {}, } as Post; - // Mock EventEmitter jest.spyOn(component.mayEditOrDeleteOutput, 'emit'); }); it('should allow edit/delete when user is the author and not in read-only or preview mode', () => { - // Arrange component.isAuthorOfPosting = true; jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(false); jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(false); - // Act component.setMayEditOrDelete(); - // Assert expect(component.mayEditOrDelete).toBeTrue(); expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(true); }); it('should allow edit/delete when user has channel moderation rights', () => { - // Arrange component.isAuthorOfPosting = false; jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(false); jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(true); - // Act component.setMayEditOrDelete(); - // Assert expect(component.mayEditOrDelete).toBeTrue(); expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(true); }); it('should not allow edit/delete when in read-only mode', () => { - // Arrange component.readOnlyMode = true; component.isAuthorOfPosting = true; jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(true); jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(true); - // Act component.setMayEditOrDelete(); - // Assert expect(component.mayEditOrDelete).toBeFalse(); expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(false); }); it('should not allow edit/delete when in preview mode', () => { - // Arrange component.previewMode = true; component.isAuthorOfPosting = true; jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(true); jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(true); - // Act component.setMayEditOrDelete(); - // Assert expect(component.mayEditOrDelete).toBeFalse(); expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(false); }); it('should not allow edit/delete when user is not author and lacks permissions', () => { - // Arrange component.isAuthorOfPosting = false; jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(false); jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(false); - // Act component.setMayEditOrDelete(); - // Assert expect(component.mayEditOrDelete).toBeFalse(); expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(false); }); From 485e0486c1c580125c12010298b0718b823411f9 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Mon, 18 Nov 2024 17:19:58 +0100 Subject: [PATCH 3/6] fix styling --- src/main/webapp/app/shared/metis/post/post.component.scss | 1 + .../posting-reactions-bar/posting-reactions-bar.component.scss | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/webapp/app/shared/metis/post/post.component.scss b/src/main/webapp/app/shared/metis/post/post.component.scss index 1a6cf4b3ace2..10cb7ef83132 100644 --- a/src/main/webapp/app/shared/metis/post/post.component.scss +++ b/src/main/webapp/app/shared/metis/post/post.component.scss @@ -20,6 +20,7 @@ top: -1.8rem; right: 1%; display: flex; + max-height: 2.2rem; gap: 10px; visibility: hidden; transition: diff --git a/src/main/webapp/app/shared/metis/posting-reactions-bar/posting-reactions-bar.component.scss b/src/main/webapp/app/shared/metis/posting-reactions-bar/posting-reactions-bar.component.scss index 641abc0076e7..bc7fbfc61165 100644 --- a/src/main/webapp/app/shared/metis/posting-reactions-bar/posting-reactions-bar.component.scss +++ b/src/main/webapp/app/shared/metis/posting-reactions-bar/posting-reactions-bar.component.scss @@ -13,7 +13,7 @@ border-radius: 1rem; align-items: center; height: 1.2rem; - display: flex; + display: inline-flex; &.open-selector { box-shadow: inset 0 0 0 1px var(--metis-gray); From 9f255f2ee2d6116d7020a2d8b5e93fca43e34363 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Tue, 19 Nov 2024 01:06:55 +0100 Subject: [PATCH 4/6] fix reply button in post bar --- .../post-reactions-bar.component.html | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.html b/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.html index 48f0f6a35ef5..500954b38df8 100644 --- a/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.html +++ b/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.html @@ -1,4 +1,12 @@ -
+
+ @if (hoverBar && sortedAnswerPosts.length === 0) { +
+ +
+ } @if (!isCommunicationPage) { @if (sortedAnswerPosts.length) { @@ -25,15 +33,6 @@ } } @else { @if (!isThreadSidebar) { - - @if (hoverBar && sortedAnswerPosts.length === 0) { -
- -
- } @if (!showAnswers && sortedAnswerPosts.length) {
@@ -134,7 +133,7 @@ }
- @if (getShowNewMessageIcon()) { + @if (isEmojiCount && getShowNewMessageIcon()) {
}
From b4a0e9fdebcd20ee14055b933e5d115fb7661ca8 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Tue, 19 Nov 2024 01:54:08 +0100 Subject: [PATCH 5/6] revert some changes --- .../answer-post/answer-post.component.html | 1 - .../app/shared/metis/post/post.component.html | 1 - .../post-footer/post-footer.component.html | 1 - .../post-footer/post-footer.component.ts | 3 +- .../answer-post-reactions-bar.component.ts | 6 +- .../post-reactions-bar.component.ts | 6 +- .../post-reactions-bar.component.spec.ts | 101 ++++++------------ 7 files changed, 39 insertions(+), 80 deletions(-) diff --git a/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html b/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html index 85a61e59eb89..6682f5c146c0 100644 --- a/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html +++ b/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html @@ -33,7 +33,6 @@ (reactionsUpdated)="onReactionsUpdated($event)" (mayEditOrDeleteOutput)="onMayEditOrDelete($event)" (isDeleteEvent)="onDeleteEvent(true)" - [hasChannelModerationRights]="hasChannelModerationRights()" />
diff --git a/src/main/webapp/app/shared/metis/post/post.component.html b/src/main/webapp/app/shared/metis/post/post.component.html index 80ec95f76f61..539aba3d1676 100644 --- a/src/main/webapp/app/shared/metis/post/post.component.html +++ b/src/main/webapp/app/shared/metis/post/post.component.html @@ -83,7 +83,6 @@ (mayEditOrDeleteOutput)="onMayEditOrDelete($event)" (canPinOutput)="onCanPin($event)" (isDeleteEvent)="onDeleteEvent(true)" - [hasChannelModerationRights]="hasChannelModerationRights()" /> }
diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html index e462e5bd12f2..f402a94fea76 100644 --- a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html +++ b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html @@ -25,7 +25,6 @@ (openPostingCreateEditModal)="createAnswerPostModal.open()" (userReferenceClicked)="userReferenceClicked.emit($event)" (channelReferenceClicked)="channelReferenceClicked.emit($event)" - [hasChannelModerationRights]="hasChannelModerationRights()" /> } } diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts index e00c1a250209..5808a9b342ba 100644 --- a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts +++ b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts @@ -11,7 +11,6 @@ import { SimpleChanges, ViewChild, ViewContainerRef, - input, } from '@angular/core'; import { PostingFooterDirective } from 'app/shared/metis/posting-footer/posting-footer.directive'; import { Post } from 'app/entities/metis/post.model'; @@ -37,6 +36,7 @@ export class PostFooterComponent extends PostingFooterDirective implements @Input() readOnlyMode = false; @Input() previewMode = false; @Input() modalRef?: NgbModalRef; + @Input() hasChannelModerationRights = false; @Input() showAnswers = false; @Input() isCommunicationPage = false; @Input() sortedAnswerPosts: AnswerPost[] = []; @@ -48,7 +48,6 @@ export class PostFooterComponent extends PostingFooterDirective implements @ViewChild(AnswerPostCreateEditModalComponent) answerPostCreateEditModal?: AnswerPostCreateEditModalComponent; @ViewChild('createEditAnswerPostContainer', { read: ViewContainerRef }) containerRef!: ViewContainerRef; @ViewChild('createAnswerPostModal') createAnswerPostModalComponent!: AnswerPostCreateEditModalComponent; - hasChannelModerationRights = input(false); createdAnswerPost: AnswerPost; isAtLeastTutorInCourse = false; diff --git a/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.ts b/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.ts index 09af48ab9cab..9023089670d5 100644 --- a/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.ts +++ b/src/main/webapp/app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, OnChanges, OnInit, Output, input } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; import { Reaction } from 'app/entities/metis/reaction.model'; import { PostingsReactionsBarDirective } from 'app/shared/metis/posting-reactions-bar/posting-reactions-bar.directive'; import { AnswerPost } from 'app/entities/metis/answer-post.model'; @@ -27,7 +27,6 @@ export class AnswerPostReactionsBarComponent extends PostingsReactionsBarDirecti readonly faPencilAlt = faPencilAlt; @Input() isEmojiCount: boolean = false; @Output() postingUpdated = new EventEmitter(); - hasChannelModerationRights = input(false); constructor(metisService: MetisService) { super(metisService); @@ -71,7 +70,8 @@ export class AnswerPostReactionsBarComponent extends PostingsReactionsBarDirecti this.isAnswerOfAnnouncement = getAsChannelDTO(this.posting.post?.conversation)?.isAnnouncementChannel ?? false; const isCourseWideChannel = getAsChannelDTO(this.posting.post?.conversation)?.isCourseWide ?? false; const isAtLeastInstructorInCourse = this.metisService.metisUserIsAtLeastInstructorInCourse(); - const mayEditOrDeleteOtherUsersAnswer = (isCourseWideChannel && isAtLeastInstructorInCourse) || (this.hasChannelModerationRights() ?? false); + const mayEditOrDeleteOtherUsersAnswer = + (isCourseWideChannel && isAtLeastInstructorInCourse) || (getAsChannelDTO(this.metisService.getCurrentConversation())?.hasChannelModerationRights ?? false); this.mayEditOrDelete = !this.isReadOnlyMode && (this.isAuthorOfPosting || mayEditOrDeleteOtherUsersAnswer); this.mayEditOrDeleteOutput.emit(this.mayEditOrDelete); } diff --git a/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.ts b/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.ts index ed55094bdd14..2ff96f282a6b 100644 --- a/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.ts +++ b/src/main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild, input } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { Reaction } from 'app/entities/metis/reaction.model'; import { Post } from 'app/entities/metis/post.model'; import { PostingsReactionsBarDirective } from 'app/shared/metis/posting-reactions-bar/posting-reactions-bar.directive'; @@ -52,7 +52,6 @@ export class PostReactionsBarComponent extends PostingsReactionsBarDirective(false); constructor( metisService: MetisService, @@ -200,7 +199,8 @@ export class PostReactionsBarComponent extends PostingsReactionsBarDirective { let fixture: ComponentFixture; let debugElement: DebugElement; let metisService: MetisService; + let accountService: AccountService; let metisServiceUpdateDisplayPriorityMock: jest.SpyInstance; let metisServiceUserIsAtLeastTutorStub: jest.SpyInstance; let metisServiceUserIsAtLeastInstructorStub: jest.SpyInstance; @@ -82,6 +84,7 @@ describe('PostReactionsBarComponent', () => { .then(() => { fixture = TestBed.createComponent(PostReactionsBarComponent); metisService = TestBed.inject(MetisService); + accountService = TestBed.inject(AccountService); debugElement = fixture.debugElement; component = fixture.componentInstance; metisServiceUpdateDisplayPriorityMock = jest.spyOn(metisService, 'updatePostDisplayPriority'); @@ -151,9 +154,14 @@ describe('PostReactionsBarComponent', () => { component.previewMode = false; component.isEmojiCount = false; + const channelConversation = { + type: ConversationType.CHANNEL, + hasChannelModerationRights: true, + } as ChannelDTO; + jest.spyOn(metisService, 'metisUserIsAuthorOfPosting').mockReturnValue(false); jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(false); - jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(true); + jest.spyOn(metisService, 'getCurrentConversation').mockReturnValue(channelConversation); component.ngOnInit(); fixture.detectChanges(); @@ -217,75 +225,30 @@ describe('PostReactionsBarComponent', () => { expect(getDeleteButton()).not.toBeNull(); }); - describe('setMayEditOrDelete', () => { - beforeEach(() => { - jest.clearAllMocks(); - component.readOnlyMode = false; - component.previewMode = false; - component.isAuthorOfPosting = false; - component.posting = { - conversation: {}, - } as Post; - - jest.spyOn(component.mayEditOrDeleteOutput, 'emit'); - }); - - it('should allow edit/delete when user is the author and not in read-only or preview mode', () => { - component.isAuthorOfPosting = true; - jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(false); - jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(false); - - component.setMayEditOrDelete(); - - expect(component.mayEditOrDelete).toBeTrue(); - expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(true); - }); - - it('should allow edit/delete when user has channel moderation rights', () => { - component.isAuthorOfPosting = false; - jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(false); - jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(true); - - component.setMayEditOrDelete(); - - expect(component.mayEditOrDelete).toBeTrue(); - expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(true); - }); - - it('should not allow edit/delete when in read-only mode', () => { - component.readOnlyMode = true; - component.isAuthorOfPosting = true; - jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(true); - jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(true); - - component.setMayEditOrDelete(); - - expect(component.mayEditOrDelete).toBeFalse(); - expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(false); - }); - - it('should not allow edit/delete when in preview mode', () => { - component.previewMode = true; - component.isAuthorOfPosting = true; - jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(true); - jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(true); - - component.setMayEditOrDelete(); - - expect(component.mayEditOrDelete).toBeFalse(); - expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(false); - }); - - it('should not allow edit/delete when user is not author and lacks permissions', () => { - component.isAuthorOfPosting = false; - jest.spyOn(metisService, 'metisUserIsAtLeastInstructorInCourse').mockReturnValue(false); - jest.spyOn(component, 'hasChannelModerationRights').mockReturnValue(false); + it.each([ + { type: ConversationType.CHANNEL, hasChannelModerationRights: true } as ChannelDTO, + { type: ConversationType.GROUP_CHAT, creator: { id: 99 } }, + { type: ConversationType.ONE_TO_ONE }, + ])('should initialize user authority and reactions correctly with same user', (dto: ConversationDTO) => { + component.posting!.author!.id = 99; + jest.spyOn(metisService, 'getCurrentConversation').mockReturnValue(dto); + jest.spyOn(accountService, 'userIdentity', 'get').mockReturnValue({ id: 99 } as User); - component.setMayEditOrDelete(); + reactionToDelete.user = { id: 99 } as User; + post.reactions = [reactionToDelete]; + component.posting = post; - expect(component.mayEditOrDelete).toBeFalse(); - expect(component.mayEditOrDeleteOutput.emit).toHaveBeenCalledWith(false); + component.ngOnInit(); + component.isEmojiCount = true; + fixture.detectChanges(); + expect(component.reactionMetaDataMap).toEqual({ + smile: { + count: 1, + hasReacted: true, + reactingUsers: [PLACEHOLDER_USER_REACTED], + }, }); + expect(component.pinTooltip).toBe('artemisApp.metis.pinPostTooltip'); }); it.each` From 5d4c4e770bd366ce32e24e408b640920301d233b Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Tue, 19 Nov 2024 02:02:15 +0100 Subject: [PATCH 6/6] removed some unused fields in answer post and post headers --- .../shared/metis/answer-post/answer-post.component.ts | 1 - .../webapp/app/shared/metis/post/post.component.html | 2 +- .../post-footer/post-footer.component.html | 1 + .../answer-post-header/answer-post-header.component.ts | 10 +++------- .../post-header/post-header.component.ts | 7 +++---- src/main/webapp/app/shared/metis/posting.directive.ts | 4 ++-- 6 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/main/webapp/app/shared/metis/answer-post/answer-post.component.ts b/src/main/webapp/app/shared/metis/answer-post/answer-post.component.ts index 798e8d81ae76..3b3c5e7ffdf1 100644 --- a/src/main/webapp/app/shared/metis/answer-post/answer-post.component.ts +++ b/src/main/webapp/app/shared/metis/answer-post/answer-post.component.ts @@ -54,7 +54,6 @@ export class AnswerPostComponent extends PostingDirective { static activeDropdownPost: AnswerPostComponent | null = null; mayEditOrDelete: boolean = false; @ViewChild(AnswerPostReactionsBarComponent) private reactionsBarComponent!: AnswerPostReactionsBarComponent; - hasChannelModerationRights = input(false); constructor( public changeDetector: ChangeDetectorRef, diff --git a/src/main/webapp/app/shared/metis/post/post.component.html b/src/main/webapp/app/shared/metis/post/post.component.html index 539aba3d1676..42352bdfa0d6 100644 --- a/src/main/webapp/app/shared/metis/post/post.component.html +++ b/src/main/webapp/app/shared/metis/post/post.component.html @@ -134,7 +134,7 @@ [lastReadDate]="lastReadDate" (userReferenceClicked)="onUserReferenceClicked($event)" (channelReferenceClicked)="onChannelReferenceClicked($event)" - [hasChannelModerationRights]="hasChannelModerationRights()" + [hasChannelModerationRights]="hasChannelModerationRights" /> diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html index f402a94fea76..6a980a907348 100644 --- a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html +++ b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html @@ -25,6 +25,7 @@ (openPostingCreateEditModal)="createAnswerPostModal.open()" (userReferenceClicked)="userReferenceClicked.emit($event)" (channelReferenceClicked)="channelReferenceClicked.emit($event)" + [hasChannelModerationRights]="hasChannelModerationRights" /> } } diff --git a/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.ts b/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.ts index 9871b3bbee8f..bb1ff3cbbbd2 100644 --- a/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.ts +++ b/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angu import { AnswerPost } from 'app/entities/metis/answer-post.model'; import { PostingHeaderDirective } from 'app/shared/metis/posting-header/posting-header.directive'; import { MetisService } from 'app/shared/metis/metis.service'; -import { faCheck, faCog, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; +import { faCheck, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import dayjs from 'dayjs/esm'; import { AccountService } from 'app/core/auth/account.service'; @@ -18,13 +18,9 @@ export class AnswerPostHeaderComponent extends PostingHeaderDirective(); - isAuthorOfOriginalPost: boolean; - isAnswerOfAnnouncement: boolean; - // Icons - faCheck = faCheck; - faPencilAlt = faPencilAlt; - faCog = faCog; + readonly faCheck = faCheck; + readonly faPencilAlt = faPencilAlt; constructor( protected metisService: MetisService, diff --git a/src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.ts b/src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.ts index 3463b66456fc..fe4bc129addd 100644 --- a/src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.ts +++ b/src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.ts @@ -3,7 +3,7 @@ import { Post } from 'app/entities/metis/post.model'; import { PostingHeaderDirective } from 'app/shared/metis/posting-header/posting-header.directive'; import { MetisService } from 'app/shared/metis/metis.service'; import { PostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; -import { faCheckSquare, faCog, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; +import { faCheckSquare, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import dayjs from 'dayjs/esm'; import { CachingStrategy } from 'app/shared/image/secured-image.component'; import { AccountService } from 'app/core/auth/account.service'; @@ -22,9 +22,8 @@ export class PostHeaderComponent extends PostingHeaderDirective implements isAtLeastInstructorInCourse: boolean; // Icons - faPencilAlt = faPencilAlt; - faCheckSquare = faCheckSquare; - faCog = faCog; + readonly faPencilAlt = faPencilAlt; + readonly faCheckSquare = faCheckSquare; constructor( protected metisService: MetisService, diff --git a/src/main/webapp/app/shared/metis/posting.directive.ts b/src/main/webapp/app/shared/metis/posting.directive.ts index a416dc61ae5e..7e601e30d3ca 100644 --- a/src/main/webapp/app/shared/metis/posting.directive.ts +++ b/src/main/webapp/app/shared/metis/posting.directive.ts @@ -1,5 +1,5 @@ import { Posting } from 'app/entities/metis/posting.model'; -import { ChangeDetectorRef, Directive, Input, OnDestroy, OnInit, inject, input } from '@angular/core'; +import { ChangeDetectorRef, Directive, Input, OnDestroy, OnInit, inject } from '@angular/core'; import { MetisService } from 'app/shared/metis/metis.service'; import { DisplayPriority } from 'app/shared/metis/metis.util'; @@ -9,7 +9,7 @@ export abstract class PostingDirective implements OnInit, OnD @Input() isCommunicationPage: boolean; @Input() showChannelReference?: boolean; - hasChannelModerationRights = input(false); + @Input() hasChannelModerationRights = false; @Input() isThreadSidebar: boolean; abstract get reactionsBar(): any; showDropdown = false;