diff --git a/src/main/webapp/app/overview/course-conversations/course-conversations.module.ts b/src/main/webapp/app/overview/course-conversations/course-conversations.module.ts
index 172e645e956d..0d593728c9f2 100644
--- a/src/main/webapp/app/overview/course-conversations/course-conversations.module.ts
+++ b/src/main/webapp/app/overview/course-conversations/course-conversations.module.ts
@@ -3,13 +3,11 @@ import { ArtemisSharedModule } from 'app/shared/shared.module';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ArtemisSharedComponentModule } from 'app/shared/components/shared-component.module';
-import { ConversationSelectionSidebarComponent } from 'app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component';
import { CourseConversationsComponent } from 'app/overview/course-conversations/course-conversations.component';
import { ArtemisDataTableModule } from 'app/shared/data-table/data-table.module';
import { ConversationMessagesComponent } from 'app/overview/course-conversations/layout/conversation-messages/conversation-messages.component';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { ConversationThreadSidebarComponent } from 'app/overview/course-conversations/layout/conversation-thread-sidebar/conversation-thread-sidebar.component';
-import { ConversationSidebarSectionComponent } from './layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component';
import { ChannelsOverviewDialogComponent } from './dialogs/channels-overview-dialog/channels-overview-dialog.component';
import { ChannelItemComponent } from './dialogs/channels-overview-dialog/channel-item/channel-item.component';
import { ChannelFormComponent } from './dialogs/channels-create-dialog/channel-form/channel-form.component';
@@ -26,7 +24,6 @@ import { ConversationMemberRowComponent } from './dialogs/conversation-detail-di
import { GenericUpdateTextPropertyDialogComponent } from './dialogs/generic-update-text-property-dialog/generic-update-text-property-dialog.component';
import { GenericConfirmationDialogComponent } from './dialogs/generic-confirmation-dialog/generic-confirmation-dialog.component';
import { ConversationSettingsComponent } from './dialogs/conversation-detail-dialog/tabs/conversation-settings/conversation-settings.component';
-import { ConversationSidebarEntryComponent } from './layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component';
import { OneToOneChatCreateDialogComponent } from './dialogs/one-to-one-chat-create-dialog/one-to-one-chat-create-dialog.component';
import { GroupChatCreateDialogComponent } from './dialogs/group-chat-create-dialog/group-chat-create-dialog.component';
import { GroupChatIconComponent } from './other/group-chat-icon/group-chat-icon.component';
@@ -61,10 +58,8 @@ const routes: Routes = [
declarations: [
CourseConversationsComponent,
CourseConversationsCodeOfConductComponent,
- ConversationSelectionSidebarComponent,
ConversationThreadSidebarComponent,
ConversationMessagesComponent,
- ConversationSidebarSectionComponent,
ChannelsOverviewDialogComponent,
ChannelItemComponent,
ChannelFormComponent,
@@ -80,7 +75,6 @@ const routes: Routes = [
GenericUpdateTextPropertyDialogComponent,
GenericConfirmationDialogComponent,
ConversationSettingsComponent,
- ConversationSidebarEntryComponent,
OneToOneChatCreateDialogComponent,
GroupChatCreateDialogComponent,
GroupChatIconComponent,
diff --git a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.html b/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.html
deleted file mode 100644
index 932aca3ae777..000000000000
--- a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.html
+++ /dev/null
@@ -1,256 +0,0 @@
-@if (course) {
-
-}
diff --git a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.scss b/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.scss
deleted file mode 100644
index 2f4ef688b478..000000000000
--- a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.scss
+++ /dev/null
@@ -1,151 +0,0 @@
-@import 'src/main/webapp/content/scss/artemis-variables';
-
-$draggable-width: 15px;
-$conversation-section-card-min-width: 215px;
-
-@mixin icon {
- fa-icon svg path {
- fill: var(--metis-conversation-sidebar);
- stroke: var(--metis-conversation-sidebar);
- }
-}
-
-@mixin active-icon {
- fa-icon svg path {
- fill: var(--metis-conversation-sidebar-active);
- stroke: var(--metis-conversation-sidebar-active);
- }
-}
-
-.selection-sidebar {
- .filter-active {
- span {
- color: var(--primary);
- }
-
- fa-icon svg path {
- fill: var(--primary);
- stroke: var(--primary);
- }
- }
-
- .sidebar-button {
- border: 0;
- border-radius: var(--bs-btn-border-radius);
-
- @include icon;
-
- &:hover {
- background-color: var(--metis-conversation-sidebar-button-background-hover);
- }
- }
-
- .expand-button {
- color: var(--metis-conversation-sidebar);
- border-radius: var(--bs-btn-border-radius);
-
- @include icon;
-
- &:hover {
- color: var(--metis-conversation-sidebar-active);
- background-color: var(--metis-conversation-sidebar-button-background-hover);
-
- @include active-icon;
- }
- }
-
- .dropdown-toggle::after {
- content: none;
- }
-
- .expanded-conversations {
- display: flex;
- width: calc(#{$draggable-width} + #{$conversation-section-card-min-width});
- margin-left: auto;
-
- .scrollbar {
- position: relative;
- max-height: 700px;
- overflow: auto;
- }
-
- .wrapper-scroll-y {
- display: block;
- }
-
- .draggable-right {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- min-width: $draggable-width;
- }
-
- .card {
- width: inherit;
- min-width: $conversation-section-card-min-width;
-
- .card-header {
- display: inline-flex;
- justify-content: space-between;
- align-items: center;
- cursor: pointer;
-
- .card-title {
- display: flex;
- }
-
- .row > .col-auto:last-child {
- display: flex;
- flex-direction: column;
- justify-content: center;
- }
- }
-
- .card-body {
- padding: 0;
-
- .conversation-empty {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- text-align: center;
- opacity: 0.75;
- padding-top: 30px;
- gap: 10px;
- }
- }
- }
- }
-
- .collapsed-conversations {
- display: flex;
- width: 38px;
- justify-content: space-between;
- flex-flow: column;
- cursor: pointer;
-
- span {
- writing-mode: vertical-lr;
- transform: rotate(180deg);
- margin: auto;
- }
-
- .expand-conversations-icon {
- padding-top: 0.5rem;
- padding-bottom: 0.5rem;
- place-self: center;
- }
- }
-
- @media screen and (max-width: 992px) {
- .expanded-conversations {
- width: 94vw;
-
- .draggable-right {
- display: none;
- }
- }
- }
-}
diff --git a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.ts b/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.ts
deleted file mode 100644
index 0858dccc61b2..000000000000
--- a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.ts
+++ /dev/null
@@ -1,366 +0,0 @@
-import { AfterViewInit, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
-import interact from 'interactjs';
-import { faChevronLeft, faChevronRight, faComments, faFilter, faGripLinesVertical, faPlus } from '@fortawesome/free-solid-svg-icons';
-import { EMPTY, Subject, from, map, takeUntil } from 'rxjs';
-import { UserPublicInfoDTO } from 'app/core/user/user.model';
-import { Course, isMessagingEnabled } from 'app/entities/course.model';
-import { ConversationDTO } from 'app/entities/metis/conversation/conversation.model';
-import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
-import { ChannelsOverviewDialogComponent } from 'app/overview/course-conversations/dialogs/channels-overview-dialog/channels-overview-dialog.component';
-import { ChannelsCreateDialogComponent } from 'app/overview/course-conversations/dialogs/channels-create-dialog/channels-create-dialog.component';
-import { Channel, ChannelDTO, ChannelSubType, isChannelDTO } from 'app/entities/metis/conversation/channel.model';
-import { GroupChatDTO, isGroupChatDTO } from 'app/entities/metis/conversation/group-chat.model';
-import { MetisConversationService } from 'app/shared/metis/metis-conversation.service';
-import { canCreateChannel } from 'app/shared/metis/conversations/conversation-permissions.utils';
-import { AccountService } from 'app/core/auth/account.service';
-import { OneToOneChatCreateDialogComponent } from 'app/overview/course-conversations/dialogs/one-to-one-chat-create-dialog/one-to-one-chat-create-dialog.component';
-import { OneToOneChatDTO, isOneToOneChatDTO } from 'app/entities/metis/conversation/one-to-one-chat.model';
-import { GroupChatCreateDialogComponent } from 'app/overview/course-conversations/dialogs/group-chat-create-dialog/group-chat-create-dialog.component';
-import { catchError, debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
-import { ConversationService } from 'app/shared/metis/conversations/conversation.service';
-import { defaultFirstLayerDialogOptions } from 'app/overview/course-conversations/other/conversation.util';
-
-interface SearchQuery {
- searchTerm: string;
- force: boolean;
-}
-
-@Component({
- selector: 'jhi-conversation-selection-sidebar',
- styleUrls: ['./conversation-selection-sidebar.component.scss'],
- templateUrl: './conversation-selection-sidebar.component.html',
- encapsulation: ViewEncapsulation.None,
-})
-export class ConversationSelectionSidebarComponent implements AfterViewInit, OnInit, OnDestroy {
- private ngUnsubscribe = new Subject();
- private readonly search$ = new Subject();
- searchTerm = '';
- course?: Course;
-
- activeConversation?: ConversationDTO;
- allConversations: ConversationDTO[] = [];
-
- starredConversations: ConversationDTO[] = [];
- displayedStarredConversations: ConversationDTO[] = [];
-
- channelConversations: ChannelDTO[] = [];
- displayedChannelConversations: ChannelDTO[] = [];
-
- oneToOneChats: OneToOneChatDTO[] = [];
- displayedOneToOneChats: OneToOneChatDTO[] = [];
-
- groupChats: GroupChatDTO[] = [];
- displayedGroupChats: GroupChatDTO[] = [];
-
- collapsed: boolean;
- // Icons
- faChevronLeft = faChevronLeft;
- faChevronRight = faChevronRight;
- faGripLinesVertical = faGripLinesVertical;
- faConversation = faComments;
- faPlus = faPlus;
- faFilter = faFilter;
- numberOfConversationsPassingFilter = 0;
-
- canCreateChannel = canCreateChannel;
- channelSubType = ChannelSubType;
-
- displayedGeneralChannels: ChannelDTO[] = [];
- displayedExerciseChannels: ChannelDTO[] = [];
- displayedLectureChannels: ChannelDTO[] = [];
- displayedExamChannels: ChannelDTO[] = [];
-
- isMessagingEnabled = false;
-
- constructor(
- private modalService: NgbModal,
- private cdr: ChangeDetectorRef,
- // instantiated at course-conversation.component.ts
- public metisConversationService: MetisConversationService,
- public accountService: AccountService,
- public conversationService: ConversationService,
- ) {}
-
- ngOnInit(): void {
- this.course = this.metisConversationService.course;
- this.isMessagingEnabled = isMessagingEnabled(this.course);
- this.subscribeToSearch();
- this.subscribeToActiveConversation();
- this.subscribeToConversationsOfUser();
- }
-
- private subscribeToSearch() {
- this.search$
- .pipe(
- debounceTime(300),
- distinctUntilChanged((prev, curr) => {
- if (curr.force === true) {
- return false;
- } else {
- return prev === curr;
- }
- }),
- tap(() => {
- this.displayedStarredConversations = [];
- this.setDisplayedChannels([]);
- this.displayedOneToOneChats = [];
- this.displayedGroupChats = [];
- }),
- map((query: SearchQuery) => {
- const searchTerm = query.searchTerm !== null && query.searchTerm !== undefined ? query.searchTerm : '';
- return searchTerm.trim().toLowerCase();
- }),
- tap((searchTerm: string) => {
- this.searchTerm = searchTerm;
- }),
- takeUntil(this.ngUnsubscribe),
- )
- .subscribe({
- next: (searchTerm: string) => {
- this.displayedStarredConversations = this.starredConversations.filter((conversation) => {
- return this.conversationService.getConversationName(conversation).toLowerCase().includes(searchTerm);
- });
- this.setDisplayedChannels(
- this.channelConversations.filter((conversation) => {
- return this.conversationService.getConversationName(conversation).toLowerCase().includes(searchTerm);
- }),
- );
- this.displayedOneToOneChats = this.oneToOneChats.filter((conversation) => {
- return this.conversationService.getConversationName(conversation).toLowerCase().includes(searchTerm);
- });
- this.displayedGroupChats = this.groupChats.filter((conversation) => {
- return this.conversationService.getConversationName(conversation).toLowerCase().includes(searchTerm);
- });
- this.numberOfConversationsPassingFilter =
- this.displayedStarredConversations.length +
- this.displayedChannelConversations.length +
- this.displayedOneToOneChats.length +
- this.displayedGroupChats.length;
-
- this.cdr.detectChanges();
- },
- });
- }
-
- ngOnDestroy() {
- this.ngUnsubscribe.next();
- this.ngUnsubscribe.complete();
- }
-
- private subscribeToActiveConversation() {
- this.metisConversationService.activeConversation$.pipe(takeUntil(this.ngUnsubscribe)).subscribe((activeConversation: ConversationDTO) => {
- this.activeConversation = activeConversation;
- });
- }
-
- private subscribeToConversationsOfUser() {
- this.metisConversationService.conversationsOfUser$.pipe(takeUntil(this.ngUnsubscribe)).subscribe((conversations: ConversationDTO[]) => {
- this.onConversationsUpdate(conversations);
- });
- }
-
- onSearchQueryInput($event: Event) {
- const searchTerm = ($event.target as HTMLInputElement).value?.trim().toLowerCase() ?? '';
- this.search$.next({
- searchTerm,
- force: false,
- });
- }
-
- onConversationsUpdate(conversations: ConversationDTO[]) {
- this.allConversations = conversations ?? [];
-
- this.starredConversations = this.allConversations
- .filter((conversation) => conversation.isFavorite)
- .sort((a, b) => {
- // sort by last message date
- const aLastMessageDate = a.lastMessageDate ? a.lastMessageDate : a.creationDate;
- const bLastMessageDate = b.lastMessageDate ? b.lastMessageDate : b.creationDate;
- // newest messages at the top of the list
- return bLastMessageDate!.isAfter(aLastMessageDate!) ? 1 : -1;
- });
- this.channelConversations = this.allConversations
- .filter((conversation) => isChannelDTO(conversation) && !conversation.isFavorite)
- .map((channel) => channel as Channel)
- .sort((a, b) => a.name!.localeCompare(b.name!));
- this.oneToOneChats = this.allConversations
- .filter((conversation) => isOneToOneChatDTO(conversation) && !conversation.isFavorite)
- .map((oneToOneChat) => oneToOneChat as OneToOneChatDTO)
- .sort((a, b) => {
- // sort by last message date
- const aLastMessageDate = a.lastMessageDate ? a.lastMessageDate : a.creationDate;
- const bLastMessageDate = b.lastMessageDate ? b.lastMessageDate : b.creationDate;
- // newest messages at the top of the list
- return bLastMessageDate!.isAfter(aLastMessageDate!) ? 1 : -1;
- });
- this.groupChats = this.allConversations
- .filter((conversation) => isGroupChatDTO(conversation) && !conversation.isFavorite)
- .map((groupChatDTO) => groupChatDTO as GroupChatDTO)
- .sort((a, b) => {
- // sort by last message date
- const aLastMessageDate = a.lastMessageDate ? a.lastMessageDate : a.creationDate;
- const bLastMessageDate = b.lastMessageDate ? b.lastMessageDate : b.creationDate;
- // newest messages at the top of the list
- return bLastMessageDate!.isAfter(aLastMessageDate!) ? 1 : -1;
- });
- this.search$.next({
- searchTerm: this.searchTerm,
- force: true,
- });
- }
-
- ngAfterViewInit(): void {
- // allows the conversation sidebar to be resized towards the right-hand side
- interact('.expanded-conversations')
- .resizable({
- edges: { left: false, right: '.draggable-right', bottom: false, top: false },
- modifiers: [
- // Set maximum width of the conversation sidebar
- interact.modifiers!.restrictSize({
- min: { width: 230, height: 0 },
- max: { width: 500, height: 4000 },
- }),
- ],
- inertia: true,
- })
- .on('resizestart', function (event: any) {
- event.target.classList.add('card-resizable');
- })
- .on('resizeend', function (event: any) {
- event.target.classList.remove('card-resizable');
- })
- .on('resizemove', function (event: any) {
- const target = event.target;
- target.style.width = event.rect.width + 'px';
- });
- }
-
- onSettingsDidChange() {
- this.metisConversationService
- .forceRefresh()
- .pipe(takeUntil(this.ngUnsubscribe))
- .subscribe({
- complete: () => {},
- });
- }
-
- openCreateChannelDialog(event: MouseEvent) {
- event.stopPropagation();
- const modalRef: NgbModalRef = this.modalService.open(ChannelsCreateDialogComponent, defaultFirstLayerDialogOptions);
- modalRef.componentInstance.course = this.course;
- modalRef.componentInstance.initialize();
- from(modalRef.result)
- .pipe(
- catchError(() => EMPTY),
- takeUntil(this.ngUnsubscribe),
- )
- .subscribe((channelToCreate: ChannelDTO) => {
- this.metisConversationService.createChannel(channelToCreate).subscribe({
- complete: () => {
- this.metisConversationService.forceRefresh().subscribe({
- complete: () => {},
- });
- },
- });
- });
- }
-
- openCreateGroupChatDialog(event: MouseEvent) {
- event.stopPropagation();
- const modalRef: NgbModalRef = this.modalService.open(GroupChatCreateDialogComponent, defaultFirstLayerDialogOptions);
- modalRef.componentInstance.course = this.course;
- modalRef.componentInstance.initialize();
- from(modalRef.result)
- .pipe(
- catchError(() => EMPTY),
- takeUntil(this.ngUnsubscribe),
- )
- .subscribe((chatPartners: UserPublicInfoDTO[]) => {
- this.metisConversationService.createGroupChat(chatPartners?.map((partner) => partner.login!)).subscribe({
- complete: () => {
- this.metisConversationService.forceRefresh().subscribe({
- complete: () => {},
- });
- },
- });
- });
- }
-
- openCreateOneToOneChatDialog(event: MouseEvent) {
- event.stopPropagation();
- const modalRef: NgbModalRef = this.modalService.open(OneToOneChatCreateDialogComponent, defaultFirstLayerDialogOptions);
- modalRef.componentInstance.course = this.course;
- modalRef.componentInstance.initialize();
- from(modalRef.result)
- .pipe(
- catchError(() => EMPTY),
- takeUntil(this.ngUnsubscribe),
- )
- .subscribe((chatPartner: UserPublicInfoDTO) => {
- if (chatPartner?.login) {
- this.metisConversationService.createOneToOneChat(chatPartner.login).subscribe({
- complete: () => {
- this.metisConversationService.forceRefresh().subscribe({
- complete: () => {},
- });
- },
- });
- }
- });
- }
-
- openChannelOverviewDialog(event: MouseEvent, subType: ChannelSubType) {
- event.stopPropagation();
- const modalRef: NgbModalRef = this.modalService.open(ChannelsOverviewDialogComponent, defaultFirstLayerDialogOptions);
- modalRef.componentInstance.course = this.course;
- modalRef.componentInstance.createChannelFn = subType === ChannelSubType.GENERAL ? this.metisConversationService.createChannel : undefined;
- modalRef.componentInstance.channelSubType = subType;
- modalRef.componentInstance.initialize();
- from(modalRef.result)
- .pipe(
- catchError(() => EMPTY),
- takeUntil(this.ngUnsubscribe),
- )
- .subscribe((result) => {
- const [newActiveConversation, isModificationPerformed] = result;
- if (isModificationPerformed) {
- // when new active conversation is explictely set, we do not need to notify subscribers in the force refresh
- this.metisConversationService.forceRefresh(!newActiveConversation, true).subscribe({
- complete: () => {
- if (newActiveConversation) {
- this.metisConversationService.setActiveConversation(newActiveConversation);
- }
- },
- });
- } else {
- if (newActiveConversation) {
- this.metisConversationService.setActiveConversation(newActiveConversation);
- }
- }
- });
- }
-
- onConversationSelected($event: ConversationDTO) {
- this.metisConversationService.setActiveConversation($event);
- }
-
- updateConversations() {
- this.onConversationsUpdate([...this.allConversations]);
- }
-
- private setDisplayedChannels(channels: ChannelDTO[]): void {
- this.displayedChannelConversations = channels;
- this.displayedGeneralChannels = this.filterChannelsOfType(ChannelSubType.GENERAL);
- this.displayedExerciseChannels = this.filterChannelsOfType(ChannelSubType.EXERCISE);
- this.displayedLectureChannels = this.filterChannelsOfType(ChannelSubType.LECTURE);
- this.displayedExamChannels = this.filterChannelsOfType(ChannelSubType.EXAM);
- }
-
- private filterChannelsOfType(subType: ChannelSubType): ChannelDTO[] {
- return this.displayedChannelConversations.filter((channel) => channel.subType === subType);
- }
-
- openCodeOfConduct() {
- this.metisConversationService.setCodeOfConduct();
- }
-}
diff --git a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.html b/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.html
deleted file mode 100644
index 4a70da5b2d6e..000000000000
--- a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.html
+++ /dev/null
@@ -1,64 +0,0 @@
-@if (conversation) {
-
-
-
- @if (conversationAsChannel) {
-
- }
- @if (getAsGroupChat(conversation); as groupChatDTO) {
-
- }
- {{ conversationService.getConversationName(conversation) }}
-
-
-
- {{ conversation.unreadMessagesCount }}
-
-
-
-
-
-
-
- @if (conversationAsChannel?.subTypeReferenceId) {
-
- {{ channelSubTypeReferenceTranslationKey | artemisTranslate }}
-
- }
- @if (!isOneToOneChat(conversation)) {
-
- }
-
-
-
-
-
-
-
-}
diff --git a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.scss b/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.scss
deleted file mode 100644
index ad1ca54a41d5..000000000000
--- a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.scss
+++ /dev/null
@@ -1,49 +0,0 @@
-@import '../../conversation-selection-sidebar.component.scss';
-
-.conversation-list-entry {
- cursor: pointer;
- display: flex;
- padding: 0.2rem;
- justify-content: space-between;
- color: var(--metis-conversation-sidebar);
-
- .dropdown-toggle::after {
- content: none;
- }
-
- &.active {
- background-color: var(--metis-light-blue);
- color: var(--metis-conversation-sidebar-active);
- }
-
- &.muted {
- color: var(--metis-conversation-sidebar-muted);
- }
-
- .interaction {
- visibility: hidden;
- }
-
- &:hover {
- color: var(--metis-conversation-sidebar-active);
-
- .interaction {
- visibility: visible;
- }
-
- .sidebar-button {
- @include active-icon;
- }
- }
-
- &.conversation-name {
- font-size: 0.8rem;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-}
-
-a.sub-type-reference:link {
- text-decoration: none !important;
-}
diff --git a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.ts b/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.ts
deleted file mode 100644
index 244ee8137875..000000000000
--- a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.ts
+++ /dev/null
@@ -1,190 +0,0 @@
-import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core';
-import { ConversationDTO, shouldNotifyRecipient } from 'app/entities/metis/conversation/conversation.model';
-import { ChannelDTO, getAsChannelDTO } from 'app/entities/metis/conversation/channel.model';
-import { ConversationService } from 'app/shared/metis/conversations/conversation.service';
-import { faEllipsis } from '@fortawesome/free-solid-svg-icons';
-import { EMPTY, Subject, debounceTime, distinctUntilChanged, from, takeUntil } from 'rxjs';
-import { mergeWith } from 'rxjs/operators';
-import { Course } from 'app/entities/course.model';
-import { AlertService } from 'app/core/util/alert.service';
-import { onError } from 'app/shared/util/global.utils';
-import { HttpErrorResponse } from '@angular/common/http';
-import { getAsGroupChatDTO } from 'app/entities/metis/conversation/group-chat.model';
-import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
-import {
- ConversationDetailDialogComponent,
- ConversationDetailTabs,
-} from 'app/overview/course-conversations/dialogs/conversation-detail-dialog/conversation-detail-dialog.component';
-import { isOneToOneChatDTO } from 'app/entities/metis/conversation/one-to-one-chat.model';
-import { defaultFirstLayerDialogOptions, getChannelSubTypeReferenceTranslationKey } from 'app/overview/course-conversations/other/conversation.util';
-import { catchError } from 'rxjs/operators';
-import { MetisService } from 'app/shared/metis/metis.service';
-import { NotificationService } from 'app/shared/notification/notification.service';
-
-@Component({
- // eslint-disable-next-line @angular-eslint/component-selector
- selector: '[jhi-conversation-sidebar-entry]',
- templateUrl: './conversation-sidebar-entry.component.html',
- styleUrls: ['./conversation-sidebar-entry.component.scss'],
- encapsulation: ViewEncapsulation.None,
-})
-export class ConversationSidebarEntryComponent implements OnInit, OnDestroy {
- private ngUnsubscribe = new Subject();
-
- favorite$ = new Subject();
- hide$ = new Subject();
- mute$ = new Subject();
-
- @Input()
- course: Course;
-
- @Input()
- conversation: ConversationDTO;
-
- @Input()
- activeConversation: ConversationDTO | undefined;
-
- @Output()
- settingsDidChange = new EventEmitter();
-
- @Output()
- conversationIsFavoriteDidChange = new EventEmitter();
-
- @Output()
- conversationIsHiddenDidChange = new EventEmitter();
-
- @Output()
- conversationIsMutedDidChange = new EventEmitter();
-
- conversationAsChannel?: ChannelDTO;
- channelSubTypeReferenceTranslationKey?: string;
- channelSubTypeReferenceRouterLink?: string;
-
- faEllipsis = faEllipsis;
-
- constructor(
- public conversationService: ConversationService,
- private metisService: MetisService,
- private notificationService: NotificationService,
- private alertService: AlertService,
- private modalService: NgbModal,
- ) {}
-
- get isConversationUnread(): boolean {
- // do not show unread count for open conversation that the user is currently reading
- if (this.isActiveConversation || !this.conversation) {
- return false;
- } else {
- return !!this.conversation.unreadMessagesCount && this.conversation.unreadMessagesCount > 0;
- }
- }
-
- get isActiveConversation() {
- return this.activeConversation && this.conversation && this.activeConversation.id! === this.conversation.id!;
- }
-
- getAsGroupChat = getAsGroupChatDTO;
-
- isOneToOneChat = isOneToOneChatDTO;
-
- onHiddenClicked(event: MouseEvent) {
- event.stopPropagation();
- this.hide$.next(!this.conversation.isHidden);
- }
-
- onFavoriteClicked($event: MouseEvent) {
- $event.stopPropagation();
- this.favorite$.next(!this.conversation.isFavorite);
- }
-
- onMuteClicked($event: MouseEvent) {
- $event.stopPropagation();
- this.mute$.next(!this.conversation.isMuted);
- }
-
- openConversationDetailDialog(event: MouseEvent) {
- event.stopPropagation();
- const modalRef: NgbModalRef = this.modalService.open(ConversationDetailDialogComponent, defaultFirstLayerDialogOptions);
- modalRef.componentInstance.course = this.course;
- modalRef.componentInstance.activeConversation = this.conversation;
- modalRef.componentInstance.selectedTab = ConversationDetailTabs.SETTINGS;
- modalRef.componentInstance.initialize();
- from(modalRef.result)
- .pipe(
- catchError(() => EMPTY),
- takeUntil(this.ngUnsubscribe),
- )
- .subscribe(() => {
- this.settingsDidChange.emit();
- });
- }
-
- private updateConversationIsFavorite() {
- this.favorite$.pipe(debounceTime(100), distinctUntilChanged(), takeUntil(this.ngUnsubscribe)).subscribe((isFavorite) => {
- if (!this.course.id || !this.conversation.id) return;
-
- this.conversationService.updateIsFavorite(this.course.id, this.conversation.id, isFavorite).subscribe({
- next: () => {
- this.conversation.isFavorite = isFavorite;
- this.conversationIsFavoriteDidChange.emit();
- },
- error: (errorResponse: HttpErrorResponse) => onError(this.alertService, errorResponse),
- });
- });
- }
-
- private updateConversationIsHidden() {
- this.hide$.pipe(debounceTime(100), distinctUntilChanged(), takeUntil(this.ngUnsubscribe)).subscribe((isHidden) => {
- if (!this.course.id || !this.conversation.id) return;
-
- this.conversationService.updateIsHidden(this.course.id, this.conversation.id, isHidden).subscribe({
- next: () => {
- this.conversation.isHidden = isHidden;
- this.conversationIsHiddenDidChange.emit();
- },
- error: (errorResponse: HttpErrorResponse) => onError(this.alertService, errorResponse),
- });
- });
- }
-
- private updateConversationIsMuted() {
- this.mute$.pipe(debounceTime(100), distinctUntilChanged(), takeUntil(this.ngUnsubscribe)).subscribe((isMuted) => {
- if (!this.course.id || !this.conversation.id) return;
-
- this.conversationService.updateIsMuted(this.course.id, this.conversation.id, isMuted).subscribe({
- next: () => {
- this.conversation.isMuted = isMuted;
- this.conversationIsMutedDidChange.emit();
- },
- error: (errorResponse: HttpErrorResponse) => onError(this.alertService, errorResponse),
- });
- });
- }
-
- private updateConversationShouldNotifyRecipient() {
- this.conversationIsHiddenDidChange.pipe(mergeWith(this.conversationIsMutedDidChange), takeUntil(this.ngUnsubscribe)).subscribe(() => {
- if (!this.conversation.id) return;
-
- if (shouldNotifyRecipient(this.conversation)) {
- this.notificationService.unmuteNotificationsForConversation(this.conversation.id);
- } else {
- this.notificationService.muteNotificationsForConversation(this.conversation.id);
- }
- });
- }
-
- ngOnInit(): void {
- this.updateConversationIsFavorite();
- this.updateConversationIsHidden();
- this.updateConversationIsMuted();
- this.updateConversationShouldNotifyRecipient();
- this.conversationAsChannel = getAsChannelDTO(this.conversation);
- this.channelSubTypeReferenceTranslationKey = getChannelSubTypeReferenceTranslationKey(this.conversationAsChannel?.subType);
- this.channelSubTypeReferenceRouterLink = this.metisService.getLinkForChannelSubType(this.conversationAsChannel);
- }
-
- ngOnDestroy() {
- this.ngUnsubscribe.next();
- this.ngUnsubscribe.complete();
- }
-}
diff --git a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.html b/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.html
deleted file mode 100644
index bc4ba8d0a5a5..000000000000
--- a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.html
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
diff --git a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.scss b/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.scss
deleted file mode 100644
index 91c05af4a8f8..000000000000
--- a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.scss
+++ /dev/null
@@ -1,35 +0,0 @@
-@import '../conversation-selection-sidebar.component.scss';
-
-.sidebar-section {
- .section-header {
- display: flex;
- justify-content: space-between;
- cursor: pointer;
- padding: 0.2rem;
- color: var(--metis-conversation-sidebar);
-
- &:hover {
- color: var(--metis-conversation-sidebar-active);
-
- .sidebar-button {
- @include active-icon;
- }
- }
- }
-
- .conversation-list {
- margin: 0;
- padding: 0;
- list-style-type: none;
- }
-
- .hidden-conversation-divider {
- cursor: pointer;
- color: var(--metis-conversation-sidebar);
-
- &:hover {
- text-decoration: underline;
- color: var(--metis-conversation-sidebar-active);
- }
- }
-}
diff --git a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.ts b/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.ts
deleted file mode 100644
index 3f547add1af6..000000000000
--- a/src/main/webapp/app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-import { Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef, ViewEncapsulation } from '@angular/core';
-import { faChevronRight, faMessage } from '@fortawesome/free-solid-svg-icons';
-import { ConversationDTO } from 'app/entities/metis/conversation/conversation.model';
-import { ConversationService } from 'app/shared/metis/conversations/conversation.service';
-import { Course } from 'app/entities/course.model';
-import { LocalStorageService } from 'ngx-webstorage';
-
-@Component({
- selector: 'jhi-conversation-sidebar-section',
- templateUrl: './conversation-sidebar-section.component.html',
- styleUrls: ['./conversation-sidebar-section.component.scss'],
- encapsulation: ViewEncapsulation.None,
-})
-export class ConversationSidebarSectionComponent implements OnInit {
- @Output() conversationSelected = new EventEmitter();
- @Output() settingsDidChange = new EventEmitter();
- @Output() conversationIsFavoriteDidChange = new EventEmitter();
- @Output() conversationIsHiddenDidChange = new EventEmitter();
- @Output() conversationIsMutedDidChange = new EventEmitter();
-
- @Input() label: string;
- @Input() course: Course;
- @Input() activeConversation?: ConversationDTO;
- @Input() headerKey: string;
- @Input() searchTerm: string;
- @Input() hideIfEmpty = true;
-
- @Input() set conversations(conversations: ConversationDTO[]) {
- this.hiddenConversations = [];
- this.mutedConversations = [];
- this.visibleConversations = [];
- this.allConversations = conversations ?? [];
- conversations.forEach((conversation) => {
- if (conversation.isHidden) {
- this.hiddenConversations.push(conversation);
- } else {
- if (conversation.isMuted && !conversation.isFavorite) {
- this.mutedConversations.push(conversation);
- } else {
- this.visibleConversations.push(conversation);
- }
- }
- });
- this.numberOfConversations = this.allConversations.length;
- }
-
- @ContentChild(TemplateRef) sectionButtons: TemplateRef;
-
- readonly PREFIX = 'collapsed.';
-
- isCollapsed: boolean;
- isHiddenConversationListPresented = false;
-
- numberOfConversations = 0;
- allConversations: ConversationDTO[] = [];
- visibleConversations: ConversationDTO[] = [];
- mutedConversations: ConversationDTO[] = [];
- hiddenConversations: ConversationDTO[] = [];
-
- // icon imports
- faChevronRight = faChevronRight;
- faMessage = faMessage;
-
- constructor(
- public conversationService: ConversationService,
- public localStorageService: LocalStorageService,
- ) {}
-
- ngOnInit(): void {
- this.isCollapsed = !!this.localStorageService.retrieve(this.storageKey);
- this.localStorageService.store(this.storageKey, this.isCollapsed);
- }
-
- get storageKey() {
- return this.PREFIX + this.headerKey;
- }
-
- get anyConversationUnread(): boolean {
- // do not show unread badge for open conversation that the user is currently reading
- let containsUnreadConversation = false;
- for (const conversation of this.allConversations) {
- if (
- conversation.unreadMessagesCount &&
- conversation.unreadMessagesCount > 0 &&
- !(this.activeConversation && this.activeConversation.id === conversation.id) &&
- this.isCollapsed
- ) {
- containsUnreadConversation = true;
- break;
- }
- }
- return containsUnreadConversation;
- }
-
- get anyHiddenConversationUnread(): boolean {
- // do not show unread badge for open conversation that the user is currently reading
- let containsUnreadConversation = false;
- for (const conversation of this.hiddenConversations) {
- if (
- conversation.unreadMessagesCount &&
- conversation.unreadMessagesCount > 0 &&
- !(this.activeConversation && this.activeConversation.id === conversation.id) &&
- !this.isHiddenConversationListPresented
- ) {
- containsUnreadConversation = true;
- break;
- }
- }
- return containsUnreadConversation;
- }
-
- conversationsTrackByFn = (index: number, conversation: ConversationDTO): number => conversation.id!;
-
- toggleCollapsed() {
- this.isCollapsed = !this.isCollapsed;
- this.localStorageService.store(this.storageKey, this.isCollapsed);
- }
-
- hide() {
- const noMatchesInSearch = this.searchTerm && this.searchTerm.length > 0 && !this.allConversations?.length;
- const emptyConversations = this.hideIfEmpty && !this.allConversations.length;
- return noMatchesInSearch || emptyConversations;
- }
-}
diff --git a/src/main/webapp/app/shared/metis/metis.service.ts b/src/main/webapp/app/shared/metis/metis.service.ts
index 644fbeb9de9c..62728044a811 100644
--- a/src/main/webapp/app/shared/metis/metis.service.ts
+++ b/src/main/webapp/app/shared/metis/metis.service.ts
@@ -153,19 +153,6 @@ export class MetisService implements OnDestroy {
this.posts$.next(posts);
}
- /**
- * fetches all post tags used in the current course, informs all subscribing components
- */
- // TODO: unused, delete
- updateCoursePostTags(): void {
- this.postService
- .getAllPostTagsByCourseId(this.courseId)
- .pipe(map((res: HttpResponse) => res.body!.filter((tag) => !!tag)))
- .subscribe((tags: string[]) => {
- this.tags$.next(tags);
- });
- }
-
/**
* fetches all posts for a course, optionally fetching posts only for a certain context, i.e. a lecture, exercise or specified course-wide-context,
* informs all components that subscribed on posts by sending the newly fetched posts
@@ -535,16 +522,6 @@ export class MetisService implements OnDestroy {
return { routerLinkComponents, displayName, queryParams };
}
- /**
- * Invokes the post service to get a top-k-list of course posts with high similarity scores when compared with a certain strategy
- * @param {Post} tempPost that is currently created and compared against existing course posts on updates in the form group
- * @return {Observable} array of similar posts that were found in the course
- */
- // TODO: unused, remove
- getSimilarPosts(tempPost: Post): Observable {
- return this.postService.computeSimilarityScoresWithCoursePosts(tempPost, this.courseId).pipe(map((res: HttpResponse) => res.body!));
- }
-
/**
* Creates (and updates) the websocket channel for receiving messages in dedicated channels;
* On message reception, subsequent actions for updating the dependent components are defined based on the MetisPostAction encapsulated in the MetisPostDTO (message payload);
diff --git a/src/test/javascript/spec/component/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.spec.ts b/src/test/javascript/spec/component/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.spec.ts
deleted file mode 100644
index c47567019a75..000000000000
--- a/src/test/javascript/spec/component/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component.spec.ts
+++ /dev/null
@@ -1,378 +0,0 @@
-import { ComponentFixture, TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing';
-import { ConversationSelectionSidebarComponent } from 'app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-selection-sidebar.component';
-import { ConversationDTO } from 'app/entities/metis/conversation/conversation.model';
-import { Type } from '@angular/core';
-import { MockComponent, MockPipe, MockProvider } from 'ng-mocks';
-import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe';
-import { FaIconComponent } from '@fortawesome/angular-fontawesome';
-import { NgbDropdownMocksModule } from '../../../../../helpers/mocks/directive/ngbDropdownMocks.module';
-import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
-import { MetisConversationService } from 'app/shared/metis/metis-conversation.service';
-import { ConversationService } from 'app/shared/metis/conversations/conversation.service';
-import { AccountService } from 'app/core/auth/account.service';
-import { generateExampleChannelDTO, generateExampleGroupChatDTO, generateOneToOneChatDTO } from '../../helpers/conversationExampleModels';
-import { BehaviorSubject, EMPTY } from 'rxjs';
-import { By } from '@angular/platform-browser';
-import { ChannelDTO, ChannelSubType } from 'app/entities/metis/conversation/channel.model';
-import { ChannelsCreateDialogComponent } from 'app/overview/course-conversations/dialogs/channels-create-dialog/channels-create-dialog.component';
-import { defaultFirstLayerDialogOptions } from 'app/overview/course-conversations/other/conversation.util';
-import { UserPublicInfoDTO } from 'app/core/user/user.model';
-import { AbstractDialogComponent } from 'app/overview/course-conversations/dialogs/abstract-dialog.component';
-import { GroupChatCreateDialogComponent } from 'app/overview/course-conversations/dialogs/group-chat-create-dialog/group-chat-create-dialog.component';
-import { OneToOneChatCreateDialogComponent } from 'app/overview/course-conversations/dialogs/one-to-one-chat-create-dialog/one-to-one-chat-create-dialog.component';
-import { GroupChatDTO } from 'app/entities/metis/conversation/group-chat.model';
-import { ChannelsOverviewDialogComponent } from 'app/overview/course-conversations/dialogs/channels-overview-dialog/channels-overview-dialog.component';
-import { ConversationSidebarSectionComponent } from 'app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component';
-import { MockLocalStorageService } from '../../../../../helpers/mocks/service/mock-local-storage.service';
-import { LocalStorageService } from 'ngx-webstorage';
-import { NgbCollapseMocksModule } from '../../../../../helpers/mocks/directive/ngbCollapseMocks.module';
-import { ConversationSidebarEntryComponent } from 'app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component';
-import { TranslateService } from '@ngx-translate/core';
-import { GroupChatIconComponent } from 'app/overview/course-conversations/other/group-chat-icon/group-chat-icon.component';
-import { ChannelIconComponent } from 'app/overview/course-conversations/other/channel-icon/channel-icon.component';
-import { NgbTooltipMocksModule } from '../../../../../helpers/mocks/directive/ngbTooltipMocks.module';
-import { MetisService } from 'app/shared/metis/metis.service';
-import { CourseInformationSharingConfiguration } from 'app/entities/course.model';
-import { NotificationService } from 'app/shared/notification/notification.service';
-
-const examples: (ConversationDTO | undefined)[] = [
- undefined,
- generateOneToOneChatDTO({}),
- generateExampleGroupChatDTO({}),
- generateExampleChannelDTO({}),
- generateExampleChannelDTO({ subType: ChannelSubType.EXERCISE }),
- generateExampleChannelDTO({ subType: ChannelSubType.LECTURE }),
- generateExampleChannelDTO({ subType: ChannelSubType.EXAM }),
-];
-
-examples.forEach((activeConversation) => {
- describe(
- 'ConversationSelectionSidebarComponent with ' +
- (activeConversation instanceof ChannelDTO ? activeConversation.subType + ' ' : '') +
- (activeConversation?.type || 'no active conversation'),
- () => {
- let component: ConversationSelectionSidebarComponent;
- let fixture: ComponentFixture;
- let metisConversationService: MetisConversationService;
- const course = { id: 1, courseInformationSharingConfiguration: CourseInformationSharingConfiguration.COMMUNICATION_AND_MESSAGING } as any;
- const canCreateChannel = jest.fn();
- let allConversations: ConversationDTO[] = [];
-
- const visibleGroupChat = generateExampleGroupChatDTO({ id: 3 });
- const favoriteGroupChat = generateExampleGroupChatDTO({ id: 4, isFavorite: true });
- const mutedGroupChat = generateExampleGroupChatDTO({ id: 101, isMuted: true });
- const hiddenGroupChat = generateExampleGroupChatDTO({ id: 2, isHidden: true });
-
- const visibleChannel = generateExampleChannelDTO({ id: 5 });
- const favoriteChannel = generateExampleChannelDTO({ id: 7, isFavorite: true });
- const mutedChannel = generateExampleChannelDTO({ id: 102, isMuted: true });
- const hiddenChannel = generateExampleChannelDTO({ id: 6, isHidden: true });
-
- const visibleExerciseChannel = generateExampleChannelDTO({ id: 8, subType: ChannelSubType.EXERCISE });
- const favoriteExerciseChannel = generateExampleChannelDTO({ id: 10, isFavorite: true, subType: ChannelSubType.EXERCISE });
- const mutedExerciseChannel = generateExampleChannelDTO({ id: 103, isMuted: true, subType: ChannelSubType.EXERCISE });
- const hiddenExerciseChannel = generateExampleChannelDTO({ id: 9, isHidden: true, subType: ChannelSubType.EXERCISE });
-
- const visibleLectureChannel = generateExampleChannelDTO({ id: 11, subType: ChannelSubType.LECTURE });
- const favoriteLectureChannel = generateExampleChannelDTO({ id: 13, isFavorite: true, subType: ChannelSubType.LECTURE });
- const mutedLectureChannel = generateExampleChannelDTO({ id: 104, isMuted: true, subType: ChannelSubType.LECTURE });
- const hiddenLectureChannel = generateExampleChannelDTO({ id: 12, isHidden: true, subType: ChannelSubType.LECTURE });
-
- const visibleExamChannel = generateExampleChannelDTO({ id: 14, subType: ChannelSubType.EXAM });
- const hiddenExamChannel = generateExampleChannelDTO({ id: 15, isHidden: true, subType: ChannelSubType.EXAM });
- const mutedExamChannel = generateExampleChannelDTO({ id: 105, isMuted: true, subType: ChannelSubType.EXAM });
- const favoriteExamChannel = generateExampleChannelDTO({ id: 16, isFavorite: true, subType: ChannelSubType.EXAM });
-
- const visibleOneToOneChat = generateOneToOneChatDTO({ id: 17 });
- const favoriteOneToOneChat = generateOneToOneChatDTO({ id: 19, isFavorite: true });
- const mutedOneToOneChat = generateOneToOneChatDTO({ id: 106, isMuted: true });
- const hiddenOneToOneChat = generateOneToOneChatDTO({ id: 18, isHidden: true });
-
- beforeEach(waitForAsync(() => {
- TestBed.configureTestingModule({
- imports: [NgbDropdownMocksModule, NgbCollapseMocksModule, NgbTooltipMocksModule],
- declarations: [
- ConversationSelectionSidebarComponent,
- ConversationSidebarSectionComponent,
- ConversationSidebarEntryComponent,
- MockComponent(FaIconComponent),
- MockPipe(ArtemisTranslatePipe),
- MockComponent(GroupChatIconComponent),
- MockComponent(ChannelIconComponent),
- ],
- providers: [
- MockProvider(TranslateService),
- MockProvider(NgbModal),
- MockProvider(MetisConversationService),
- MockProvider(NotificationService),
- MockProvider(AccountService),
- MockProvider(MetisService),
- { provide: LocalStorageService, useClass: MockLocalStorageService },
- MockProvider(ConversationService, {
- getConversationName: (conversation: ConversationDTO) => {
- return conversation.id + '';
- },
- }),
- ],
- }).compileComponents();
- }));
-
- beforeEach(() => {
- allConversations = [
- visibleChannel,
- favoriteChannel,
- mutedChannel,
- hiddenChannel,
-
- visibleExerciseChannel,
- favoriteExerciseChannel,
- mutedExerciseChannel,
- hiddenExerciseChannel,
-
- visibleLectureChannel,
- favoriteLectureChannel,
- mutedLectureChannel,
- hiddenLectureChannel,
-
- visibleExamChannel,
- favoriteExamChannel,
- mutedExamChannel,
- hiddenExamChannel,
-
- visibleGroupChat,
- favoriteGroupChat,
- mutedGroupChat,
- hiddenGroupChat,
-
- visibleOneToOneChat,
- favoriteOneToOneChat,
- mutedOneToOneChat,
- hiddenOneToOneChat,
- ];
-
- canCreateChannel.mockReturnValue(true);
- metisConversationService = TestBed.inject(MetisConversationService);
- Object.defineProperty(metisConversationService, 'course', { get: () => course });
- Object.defineProperty(metisConversationService, 'activeConversation$', { get: () => new BehaviorSubject(activeConversation).asObservable() });
- Object.defineProperty(metisConversationService, 'conversationsOfUser$', {
- get: () => new BehaviorSubject(allConversations).asObservable(),
- });
- Object.defineProperty(metisConversationService, 'forceRefresh', { value: () => EMPTY });
- Object.defineProperty(metisConversationService, 'setActiveConversation', { value: () => {} });
-
- fixture = TestBed.createComponent(ConversationSelectionSidebarComponent);
- component = fixture.componentInstance;
- component.canCreateChannel = canCreateChannel;
- });
-
- it('should create', fakeAsync(() => {
- fixture.detectChanges();
- tick(301);
- expect(component).toBeTruthy();
- }));
-
- it('should set properties correctly', fakeAsync(() => {
- fixture.detectChanges();
- tick(301);
- expect(component.course).toEqual(course);
- expect(component.activeConversation).toEqual(activeConversation);
- allConversations.forEach((conversation) => {
- expect(component.allConversations).toContain(conversation);
- });
-
- expect(component.starredConversations).toContain(favoriteChannel);
- expect(component.starredConversations).toContain(favoriteGroupChat);
- expect(component.starredConversations).toContain(favoriteOneToOneChat);
- expect(component.starredConversations).toHaveLength(6);
- expect(component.starredConversations).toEqual(component.displayedStarredConversations);
-
- expect(component.channelConversations).toContain(visibleChannel);
- expect(component.channelConversations).toContain(mutedChannel);
- expect(component.channelConversations).toContain(hiddenChannel);
- expect(component.channelConversations).toHaveLength(12);
- expect(component.channelConversations).toEqual(component.displayedChannelConversations);
-
- expect(component.groupChats).toContain(visibleGroupChat);
- expect(component.groupChats).toContain(mutedGroupChat);
- expect(component.groupChats).toContain(hiddenGroupChat);
- expect(component.groupChats).toHaveLength(3);
- expect(component.groupChats).toEqual(component.displayedGroupChats);
-
- expect(component.oneToOneChats).toContain(visibleOneToOneChat);
- expect(component.oneToOneChats).toContain(mutedOneToOneChat);
- expect(component.oneToOneChats).toContain(hiddenOneToOneChat);
- expect(component.oneToOneChats).toHaveLength(3);
- expect(component.oneToOneChats).toEqual(component.displayedOneToOneChats);
- }));
-
- it('should filter conversations correctly when search term is entered', fakeAsync(() => {
- fixture.detectChanges();
- tick(301);
- const inputField = fixture.debugElement.query(By.css('input'));
- inputField.nativeElement.value = visibleGroupChat.id + '';
- inputField.nativeElement.dispatchEvent(new Event('input'));
- tick(301);
- expect(component.searchTerm).toEqual(visibleGroupChat.id + '');
- expect(component.displayedStarredConversations).toHaveLength(1);
- expect(component.displayedChannelConversations).toHaveLength(1);
- expect(component.displayedGroupChats).toHaveLength(1);
- expect(component.displayedGroupChats).toContain(visibleGroupChat);
- expect(component.displayedOneToOneChats).toHaveLength(0);
- }));
-
- it('should not show create channel button if user is missing the permission', fakeAsync(() => {
- fixture.detectChanges();
- tick(301);
- canCreateChannel.mockReturnValue(false);
- fixture.detectChanges();
- expect(fixture.debugElement.nativeElement.querySelector('#createChannel')).toBeFalsy();
- }));
-
- it('should open create channel dialog when button is pressed', fakeAsync(() => {
- const createChannelSpy = jest.fn().mockReturnValue(EMPTY);
- Object.defineProperty(metisConversationService, 'createChannel', { value: createChannelSpy });
- createConversationDialogTest(new ChannelDTO(), ChannelsCreateDialogComponent, 'createChannel');
- fixture.whenStable().then(() => {
- expect(createChannelSpy).toHaveBeenCalledOnce();
- });
- }));
-
- it('should open create group chat dialog when button is pressed', fakeAsync(() => {
- const createGroupChatSpy = jest.fn().mockReturnValue(EMPTY);
- Object.defineProperty(metisConversationService, 'createGroupChat', { value: createGroupChatSpy });
- createConversationDialogTest([new UserPublicInfoDTO()], GroupChatCreateDialogComponent, 'createGroupChat');
- fixture.whenStable().then(() => {
- expect(createGroupChatSpy).toHaveBeenCalledOnce();
- });
- }));
-
- it('should open one to one chat dialog when button is pressed', fakeAsync(() => {
- const createOneToOneChatSpy = jest.fn().mockReturnValue(EMPTY);
- Object.defineProperty(metisConversationService, 'createOneToOneChat', { value: createOneToOneChatSpy });
- const chatPartner = new UserPublicInfoDTO();
- chatPartner.login = 'test';
- createConversationDialogTest(chatPartner, OneToOneChatCreateDialogComponent, 'createOneToOne');
- fixture.whenStable().then(() => {
- expect(createOneToOneChatSpy).toHaveBeenCalledOnce();
- });
- }));
-
- it('should open channel overview dialog when button is pressed', fakeAsync(() => {
- fixture.detectChanges();
- tick(301);
- const modalService = TestBed.inject(NgbModal);
- const mockModalRef = {
- componentInstance: {
- course: undefined,
- createChannelFn: undefined,
- initialize: () => {},
- },
- result: Promise.resolve([new GroupChatDTO(), true]),
- };
- const openDialogSpy = jest.spyOn(modalService, 'open').mockReturnValue(mockModalRef as unknown as NgbModalRef);
- fixture.detectChanges();
-
- const dialogOpenButton = fixture.debugElement.nativeElement.querySelector('#channelOverview');
- dialogOpenButton.click();
- tick(301);
- fixture.whenStable().then(() => {
- expect(openDialogSpy).toHaveBeenCalledOnce();
- expect(openDialogSpy).toHaveBeenCalledWith(ChannelsOverviewDialogComponent, defaultFirstLayerDialogOptions);
- expect(mockModalRef.componentInstance.course).toEqual(course);
- });
- }));
-
- it('should refresh when settings are changed', fakeAsync(() => {
- fixture.detectChanges();
- tick(301);
-
- const forceRefreshMock = jest.spyOn(metisConversationService, 'forceRefresh').mockReturnValue(EMPTY);
- component.onSettingsDidChange();
- expect(forceRefreshMock).toHaveBeenCalledOnce();
- }));
-
- it('should run conversations update when favorite status is changed', fakeAsync(() => {
- fixture.detectChanges();
- tick(301);
- const onConversationsUpdateSpy = jest.spyOn(component, 'onConversationsUpdate');
- component.updateConversations();
- tick(301);
- expect(onConversationsUpdateSpy).toHaveBeenCalledOnce();
- expect(onConversationsUpdateSpy).toHaveBeenCalledWith(component.allConversations);
- }));
-
- it('should run conversations update when hidden status is changed', fakeAsync(() => {
- fixture.detectChanges();
- tick(301);
- const onConversationsUpdateSpy = jest.spyOn(component, 'onConversationsUpdate');
- component.updateConversations();
- tick(301);
- expect(onConversationsUpdateSpy).toHaveBeenCalledOnce();
- expect(onConversationsUpdateSpy).toHaveBeenCalledWith(component.allConversations);
- }));
-
- it('should run conversations update when muted status is changed', fakeAsync(() => {
- fixture.detectChanges();
- tick(301);
- const onConversationsUpdateSpy = jest.spyOn(component, 'onConversationsUpdate');
- component.updateConversations();
- tick(301);
- expect(onConversationsUpdateSpy).toHaveBeenCalledOnce();
- expect(onConversationsUpdateSpy).toHaveBeenCalledWith(component.allConversations);
- }));
-
- it('should open code of conduct', () => {
- const metisSpy = jest.spyOn(metisConversationService, 'setCodeOfConduct');
- component.openCodeOfConduct();
- expect(metisSpy).toHaveBeenCalledOnce();
- });
-
- it('should hide buttons if messaging disabled', fakeAsync(() => {
- fixture.detectChanges();
- tick(301);
- component.course = { id: 1, courseInformationSharingConfiguration: CourseInformationSharingConfiguration.COMMUNICATION_ONLY } as any;
- component.isMessagingEnabled = false;
- fixture.detectChanges();
- tick(301);
-
- const channelButton = fixture.debugElement.query(By.css('#channelButton'));
- const exerciseChannelButton = fixture.debugElement.query(By.css('#exerciseChannelButton'));
- const lectureChannelButton = fixture.debugElement.query(By.css('#lectureChannelButton'));
- const examChannelButton = fixture.debugElement.query(By.css('#examChannelButton'));
- const groupChatButton = fixture.debugElement.query(By.css('#createGroupChat'));
- const oneToOneChatButton = fixture.debugElement.query(By.css('#createOneToOne'));
-
- expect(channelButton).toBeNull();
- expect(exerciseChannelButton).toBeNull();
- expect(lectureChannelButton).toBeNull();
- expect(examChannelButton).toBeNull();
- expect(groupChatButton).toBeNull();
- expect(oneToOneChatButton).toBeNull();
- }));
-
- function createConversationDialogTest(modalReturnValue: any, dialog: Type, buttonId: string) {
- fixture.detectChanges();
- tick(301);
- const modalService = TestBed.inject(NgbModal);
- const mockModalRef = {
- componentInstance: {
- course: undefined,
- initialize: () => {},
- },
- result: Promise.resolve(modalReturnValue),
- };
- const openDialogSpy = jest.spyOn(modalService, 'open').mockReturnValue(mockModalRef as unknown as NgbModalRef);
- fixture.detectChanges();
-
- const dialogOpenButton = fixture.debugElement.nativeElement.querySelector('#' + buttonId);
- dialogOpenButton.click();
- tick(301);
- fixture.whenStable().then(() => {
- expect(openDialogSpy).toHaveBeenCalledOnce();
- expect(openDialogSpy).toHaveBeenCalledWith(dialog, defaultFirstLayerDialogOptions);
- expect(mockModalRef.componentInstance.course).toEqual(course);
- });
- }
- },
- );
-});
diff --git a/src/test/javascript/spec/component/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.spec.ts b/src/test/javascript/spec/component/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.spec.ts
deleted file mode 100644
index bb0b84a8475b..000000000000
--- a/src/test/javascript/spec/component/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component.spec.ts
+++ /dev/null
@@ -1,242 +0,0 @@
-import { ComponentFixture, TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing';
-import { Location } from '@angular/common';
-import { RouterTestingModule } from '@angular/router/testing';
-import { ConversationSidebarEntryComponent } from 'app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-entry/conversation-sidebar-entry.component';
-import { NgbDropdownMocksModule } from '../../../../../../../helpers/mocks/directive/ngbDropdownMocks.module';
-import { MockComponent, MockPipe, MockProvider } from 'ng-mocks';
-import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe';
-import { FaIconComponent } from '@fortawesome/angular-fontawesome';
-import { ConversationDTO } from 'app/entities/metis/conversation/conversation.model';
-import { generateExampleChannelDTO, generateExampleGroupChatDTO, generateOneToOneChatDTO } from '../../../../helpers/conversationExampleModels';
-import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
-import { AlertService } from 'app/core/util/alert.service';
-import { ConversationService } from 'app/shared/metis/conversations/conversation.service';
-import { HttpResponse } from '@angular/common/http';
-import { of } from 'rxjs';
-import { ChannelIconComponent } from 'app/overview/course-conversations/other/channel-icon/channel-icon.component';
-import { GroupChatIconComponent } from 'app/overview/course-conversations/other/group-chat-icon/group-chat-icon.component';
-import {
- ConversationDetailDialogComponent,
- ConversationDetailTabs,
-} from 'app/overview/course-conversations/dialogs/conversation-detail-dialog/conversation-detail-dialog.component';
-import { defaultFirstLayerDialogOptions } from 'app/overview/course-conversations/other/conversation.util';
-import { isOneToOneChatDTO } from 'app/entities/metis/conversation/one-to-one-chat.model';
-import { ChannelDTO, ChannelSubType } from 'app/entities/metis/conversation/channel.model';
-import { MetisService } from 'app/shared/metis/metis.service';
-import { MockMetisService } from '../../../../../../../helpers/mocks/service/mock-metis-service.service';
-import { CourseLectureDetailsComponent } from 'app/overview/course-lectures/course-lecture-details.component';
-import { ExamDetailComponent } from 'app/exam/manage/exams/exam-detail.component';
-import { CourseExerciseDetailsComponent } from 'app/overview/exercise-details/course-exercise-details.component';
-import { NotificationService } from 'app/shared/notification/notification.service';
-import { MockNotificationService } from '../../../../../../../helpers/mocks/service/mock-notification.service';
-import { Course } from 'app/entities/course.model';
-
-const examples: (() => ConversationDTO)[] = [
- () => generateOneToOneChatDTO({}),
- () => generateExampleGroupChatDTO({}),
- () => generateExampleChannelDTO({}),
- () => generateExampleChannelDTO({ subType: ChannelSubType.EXERCISE, subTypeReferenceId: 1 }),
- () => generateExampleChannelDTO({ subType: ChannelSubType.LECTURE, subTypeReferenceId: 1 }),
- () => generateExampleChannelDTO({ subType: ChannelSubType.EXAM, subTypeReferenceId: 1 }),
-];
-
-const configureTestBed = () => {
- TestBed.configureTestingModule({
- imports: [
- NgbDropdownMocksModule,
- RouterTestingModule.withRoutes([
- { path: 'courses/:courseId/lectures/:lectureId', component: CourseLectureDetailsComponent },
- { path: 'courses/:courseId/exercises/:exerciseId', component: CourseExerciseDetailsComponent },
- { path: 'courses/:courseId/exams/:examId', component: ExamDetailComponent },
- ]),
- ],
- declarations: [
- ConversationSidebarEntryComponent,
- MockPipe(ArtemisTranslatePipe),
- MockComponent(FaIconComponent),
- MockComponent(ChannelIconComponent),
- MockComponent(GroupChatIconComponent),
- ],
- providers: [
- MockProvider(ConversationService),
- MockProvider(AlertService),
- MockProvider(NgbModal),
- { provide: MetisService, useClass: MockMetisService },
- { provide: NotificationService, useClass: MockNotificationService },
- ],
- }).compileComponents();
-};
-
-examples.forEach((conversation) => {
- const testDescription = conversation();
-
- describe('ConversationSidebarEntryComponent with ' + (testDescription instanceof ChannelDTO ? testDescription.subType + ' ' : '') + testDescription.type, () => {
- let component: ConversationSidebarEntryComponent;
- let fixture: ComponentFixture;
- let conversationService: ConversationService;
- let updateIsFavoriteSpy: jest.SpyInstance;
- let updateIsHiddenSpy: jest.SpyInstance;
- let updateIsMutedSpy: jest.SpyInstance;
- let location: Location;
- let notificationService: NotificationService;
- const course = { id: 1 } as any;
- const activeConversation = generateExampleGroupChatDTO({ id: 99 });
-
- beforeEach(waitForAsync(configureTestBed));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(ConversationSidebarEntryComponent);
- conversationService = TestBed.inject(ConversationService);
- updateIsFavoriteSpy = jest.spyOn(conversationService, 'updateIsFavorite').mockReturnValue(of(new HttpResponse()));
- updateIsHiddenSpy = jest.spyOn(conversationService, 'updateIsHidden').mockReturnValue(of(new HttpResponse()));
- updateIsMutedSpy = jest.spyOn(conversationService, 'updateIsMuted').mockReturnValue(of(new HttpResponse()));
-
- location = TestBed.inject(Location);
- notificationService = TestBed.inject(NotificationService);
-
- component = fixture.componentInstance;
- component.conversation = conversation();
- component.activeConversation = activeConversation;
- component.course = course;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-
- it('should call updateIsFavorite when button is clicked', fakeAsync(() => {
- const conversationFavoriteStatusChangeSpy = jest.spyOn(component.conversationIsFavoriteDidChange, 'emit');
- const button = fixture.debugElement.nativeElement.querySelector('.favorite');
- button.click();
- tick(501);
- expect(updateIsFavoriteSpy).toHaveBeenCalledOnce();
- expect(updateIsFavoriteSpy).toHaveBeenCalledWith(course.id, component.conversation.id, true);
- expect(conversationFavoriteStatusChangeSpy).toHaveBeenCalledOnce();
- }));
-
- it('should call updateIsHidden when button is clicked', fakeAsync(() => {
- const conversationIsHiddenDidChangeSpy = jest.spyOn(component.conversationIsHiddenDidChange, 'emit');
- const button = fixture.debugElement.nativeElement.querySelector('.hide');
- button.click();
- tick(501);
- expect(updateIsHiddenSpy).toHaveBeenCalledOnce();
- expect(updateIsHiddenSpy).toHaveBeenCalledWith(course.id, component.conversation.id, true);
- expect(conversationIsHiddenDidChangeSpy).toHaveBeenCalledOnce();
- }));
-
- it('should call updateIsMuted when button is clicked', fakeAsync(() => {
- const conversationIsMutedDidChangeSpy = jest.spyOn(component.conversationIsMutedDidChange, 'emit');
- const button = fixture.debugElement.nativeElement.querySelector('.mute');
- button.click();
- tick(501);
- expect(updateIsMutedSpy).toHaveBeenCalledOnce();
- expect(updateIsMutedSpy).toHaveBeenCalledWith(course.id, component.conversation.id, true);
- expect(conversationIsMutedDidChangeSpy).toHaveBeenCalledOnce();
- }));
-
- it('should update the notification service`s muted conversations', fakeAsync(() => {
- const button = fixture.debugElement.nativeElement.querySelector('.hide');
- const muteNotificationsForConversationSpy = jest.spyOn(notificationService, 'muteNotificationsForConversation').mockReturnValue();
- button.click();
- tick(501);
- expect(muteNotificationsForConversationSpy).toHaveBeenCalledOnce();
- const unmuteNotificationsForConversationSpy = jest.spyOn(notificationService, 'unmuteNotificationsForConversation').mockReturnValue();
- button.click();
- tick(501);
- expect(unmuteNotificationsForConversationSpy).toHaveBeenCalledOnce();
- }));
-
- it('should open conversation detail with setting tab if setting button is clicked', fakeAsync(() => {
- if (isOneToOneChatDTO(component.conversation)) {
- const button = fixture.debugElement.nativeElement.querySelector('.setting');
- expect(button).toBeFalsy(); // should not be present for one-to-one chats
- } else {
- const button = fixture.debugElement.nativeElement.querySelector('.setting');
- const modalService = TestBed.inject(NgbModal);
- const mockModalRef = {
- componentInstance: {
- course: undefined,
- activeConversation,
- selectedTab: undefined,
- initialize: () => {},
- },
- result: Promise.resolve(),
- };
- const openDialogSpy = jest.spyOn(modalService, 'open').mockReturnValue(mockModalRef as unknown as NgbModalRef);
- button.click();
- fixture.whenStable().then(() => {
- expect(openDialogSpy).toHaveBeenCalledOnce();
- expect(openDialogSpy).toHaveBeenCalledWith(ConversationDetailDialogComponent, defaultFirstLayerDialogOptions);
- expect(mockModalRef.componentInstance.course).toEqual(course);
- expect(mockModalRef.componentInstance.activeConversation).toEqual(component.conversation);
- expect(mockModalRef.componentInstance.selectedTab).toEqual(ConversationDetailTabs.SETTINGS);
- });
- }
- }));
-
- if (testDescription instanceof ChannelDTO && testDescription.subType !== ChannelSubType.GENERAL) {
- it(
- 'should navigate to ' + testDescription.subType,
- fakeAsync(() => {
- const button = fixture.debugElement.nativeElement.querySelector('.sub-type-reference');
- button.click();
- tick();
-
- // Assert that the router has navigated to the correct link
- expect(location.path()).toBe('/courses/1/' + testDescription.subType + 's/1');
- }),
- );
- }
- });
-});
-
-describe('ConversationSidebarEntryComponent without conversation.id', () => {
- let component: ConversationSidebarEntryComponent;
- let fixture: ComponentFixture;
- let conversationService: ConversationService;
- let updateIsFavoriteSpy: jest.SpyInstance;
- let updateIsHiddenSpy: jest.SpyInstance;
- let updateIsMutedSpy: jest.SpyInstance;
-
- beforeEach(waitForAsync(configureTestBed));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(ConversationSidebarEntryComponent);
- conversationService = TestBed.inject(ConversationService);
- updateIsFavoriteSpy = jest.spyOn(conversationService, 'updateIsFavorite').mockReturnValue(of(new HttpResponse()));
- updateIsHiddenSpy = jest.spyOn(conversationService, 'updateIsHidden').mockReturnValue(of(new HttpResponse()));
- updateIsMutedSpy = jest.spyOn(conversationService, 'updateIsMuted').mockReturnValue(of(new HttpResponse()));
-
- component = fixture.componentInstance;
- component.conversation = new ChannelDTO();
- component.activeConversation = component.conversation;
- component.course = new Course();
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-
- it('should not call updateIsFavorite when button is clicked', fakeAsync(() => {
- const button = fixture.debugElement.nativeElement.querySelector('.favorite');
- button.click();
- tick(501);
- expect(updateIsFavoriteSpy).not.toHaveBeenCalled();
- }));
-
- it('should not call updateIsHidden when button is clicked', fakeAsync(() => {
- const button = fixture.debugElement.nativeElement.querySelector('.hide');
- button.click();
- tick(501);
- expect(updateIsHiddenSpy).not.toHaveBeenCalled();
- }));
-
- it('should not call updateIsMuted when button is clicked', fakeAsync(() => {
- const button = fixture.debugElement.nativeElement.querySelector('.mute');
- button.click();
- tick(501);
- expect(updateIsMutedSpy).not.toHaveBeenCalled();
- }));
-});
diff --git a/src/test/javascript/spec/component/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.spec.ts b/src/test/javascript/spec/component/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.spec.ts
deleted file mode 100644
index 6102e2077ac6..000000000000
--- a/src/test/javascript/spec/component/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component.spec.ts
+++ /dev/null
@@ -1,118 +0,0 @@
-import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
-import { Course } from 'app/entities/course.model';
-import { ConversationDTO } from 'app/entities/metis/conversation/conversation.model';
-import { Component, EventEmitter, Input, Output } from '@angular/core';
-import { generateExampleChannelDTO, generateExampleGroupChatDTO, generateOneToOneChatDTO } from '../../../helpers/conversationExampleModels';
-import { MockComponent, MockPipe, MockProvider } from 'ng-mocks';
-import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe';
-import { NgbCollapseMocksModule } from '../../../../../../helpers/mocks/directive/ngbCollapseMocks.module';
-import { MockLocalStorageService } from '../../../../../../helpers/mocks/service/mock-local-storage.service';
-import { ConversationService } from 'app/shared/metis/conversations/conversation.service';
-import { ConversationSidebarSectionComponent } from 'app/overview/course-conversations/layout/conversation-selection-sidebar/conversation-sidebar-section/conversation-sidebar-section.component';
-import { LocalStorageService } from 'ngx-webstorage';
-import { FaIconComponent } from '@fortawesome/angular-fontawesome';
-
-@Component({
- // eslint-disable-next-line @angular-eslint/component-selector
- selector: '[jhi-conversation-sidebar-entry]',
- template: '',
-})
-class ConversationSidebarEntryStubComponent {
- @Input()
- course: Course;
-
- @Input()
- conversation: ConversationDTO;
-
- @Input()
- activeConversation: ConversationDTO | undefined;
-
- @Output()
- settingsDidChange = new EventEmitter();
-
- @Output()
- conversationIsFavoriteDidChange = new EventEmitter();
-
- @Output()
- conversationIsHiddenDidChange = new EventEmitter();
-
- @Output()
- conversationIsMutedDidChange = new EventEmitter();
-}
-
-const examples: (ConversationDTO | undefined)[] = [undefined, generateOneToOneChatDTO({}), generateExampleGroupChatDTO({}), generateExampleChannelDTO({})];
-examples.forEach((activeConversation) => {
- describe('ConversationSidebarSectionComponent with ' + (activeConversation?.type || 'no active conversation'), () => {
- let component: ConversationSidebarSectionComponent;
- let fixture: ComponentFixture;
- const course = { id: 1 } as Course;
-
- const visibleConversation = generateExampleChannelDTO({ id: 2, isHidden: false });
- const mutedConversation = generateExampleChannelDTO({ id: 3, unreadMessagesCount: 1, isMuted: true });
- const hiddenConversation = generateExampleChannelDTO({ id: 4, unreadMessagesCount: 1, isHidden: true });
-
- beforeEach(waitForAsync(() => {
- TestBed.configureTestingModule({
- imports: [NgbCollapseMocksModule],
- declarations: [ConversationSidebarSectionComponent, ConversationSidebarEntryStubComponent, MockComponent(FaIconComponent), MockPipe(ArtemisTranslatePipe)],
- providers: [{ provide: LocalStorageService, useClass: MockLocalStorageService }, MockProvider(ConversationService)],
- }).compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(ConversationSidebarSectionComponent);
- component = fixture.componentInstance;
- component.course = course;
- component.activeConversation = activeConversation;
- component.label = 'label';
- component.headerKey = 'headerKey';
- component.conversations = [hiddenConversation, mutedConversation, visibleConversation];
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-
- it('should separate hidden, muted, and visible conversations', () => {
- expect(component.visibleConversations).toEqual([visibleConversation]);
- expect(component.mutedConversations).toEqual([mutedConversation]);
- expect(component.hiddenConversations).toEqual([hiddenConversation]);
- expect(component.allConversations).toEqual([hiddenConversation, mutedConversation, visibleConversation]);
- expect(component.numberOfConversations).toBe(3);
- });
-
- it('should store collapsed status in local storage', () => {
- expect(component.localStorageService.retrieve(component.storageKey)).toBeFalse();
- component.toggleCollapsed();
- expect(component.localStorageService.retrieve(component.storageKey)).toBeTrue();
- component.toggleCollapsed();
- });
-
- it('should display a conversation is unread', () => {
- component.toggleCollapsed();
- expect(component.anyConversationUnread).toBeTrue();
- expect(component.anyHiddenConversationUnread).toBeTrue();
- component.toggleCollapsed();
- });
-
- it('should hide if empty only if hideIfEmpty is set', () => {
- component.allConversations = [];
- expect(component.hide()).toBeTrue();
-
- component.hideIfEmpty = false;
- expect(component.hide()).toBeFalse();
- });
-
- it('should hide if search term is entered and conversations are empty and ignore hideIfEmpty flag', () => {
- component.allConversations = [];
- component.hideIfEmpty = false;
-
- component.searchTerm = 'test';
- expect(component.hide()).toBeTrue();
-
- component.searchTerm = '';
- expect(component.hide()).toBeFalse();
- });
- });
-});
diff --git a/src/test/javascript/spec/service/metis/metis.service.spec.ts b/src/test/javascript/spec/service/metis/metis.service.spec.ts
index 98aaaedf1e01..54ba1f1d5db5 100644
--- a/src/test/javascript/spec/service/metis/metis.service.spec.ts
+++ b/src/test/javascript/spec/service/metis/metis.service.spec.ts
@@ -1,7 +1,7 @@
import { TestBed, fakeAsync, tick } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { Post } from 'app/entities/metis/post.model';
-import { Course, CourseInformationSharingConfiguration } from 'app/entities/course.model';
+import { Course } from 'app/entities/course.model';
import { MockPostService } from '../../helpers/mocks/service/mock-post.service';
import { MockAnswerPostService } from '../../helpers/mocks/service/mock-answer-post.service';
import { MetisService } from 'app/shared/metis/metis.service';
@@ -182,23 +182,11 @@ describe('Metis Service', () => {
postsSub.unsubscribe();
}));
- it('should update post tags', () => {
- const postServiceSpy = jest.spyOn(postService, 'getAllPostTagsByCourseId');
- metisService.updateCoursePostTags();
- expect(postServiceSpy).toHaveBeenCalledOnce();
- });
-
it('should get posts for course', () => {
const postServiceSpy = jest.spyOn(postService, 'getPosts');
metisService.getFilteredPosts({ courseId: course.id });
expect(postServiceSpy).toHaveBeenCalledOnce();
});
-
- it('should get similar posts within course', () => {
- const postServiceSpy = jest.spyOn(postService, 'computeSimilarityScoresWithCoursePosts');
- metisService.getSimilarPosts(post);
- expect(postServiceSpy).toHaveBeenCalledOnce();
- });
});
describe('Invoke answer post service methods', () => {
@@ -307,15 +295,6 @@ describe('Metis Service', () => {
expect(metisUserIsAuthorOfPostingReturn).toBeFalse();
});
- it('should not fetch course post tags if communication is not enabled', () => {
- const updateCoursePostTagsSpy = jest.spyOn(metisService, 'updateCoursePostTags');
- course.courseInformationSharingConfiguration = CourseInformationSharingConfiguration.MESSAGING_ONLY;
- metisService.setCourse(course);
- const getCourseReturn = metisService.getCourse();
- expect(getCourseReturn).toEqual(course);
- expect(updateCoursePostTagsSpy).not.toHaveBeenCalled();
- });
-
it('should set course when current course has different id', () => {
metisService.setCourse(course);
const newCourse = new Course();