+
@if (!previewMode) {
}
@@ -108,3 +135,44 @@
(channelReferenceClicked)="onChannelReferenceClicked($event)"
[hasChannelModerationRights]="hasChannelModerationRights"
/>
+
+
+
+
+
+
+
+
+
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 d88762caf808..1a6cf4b3ace2 100644
--- a/src/main/webapp/app/shared/metis/post/post.component.scss
+++ b/src/main/webapp/app/shared/metis/post/post.component.scss
@@ -14,3 +14,61 @@
.reference-hash {
color: inherit;
}
+
+.hover-actions {
+ position: absolute;
+ top: -1.8rem;
+ right: 1%;
+ display: flex;
+ gap: 10px;
+ visibility: hidden;
+ transition:
+ opacity 0.2s ease-in-out,
+ visibility 0.2s ease-in-out;
+ background: var(--metis-selection-option-background);
+ padding: 5px;
+ border-radius: 5px;
+ border: 0.01rem solid var(--metis-gray);
+}
+
+.message-container {
+ position: relative;
+ border-radius: 5px;
+ transition: background-color 0.3s ease;
+
+ &.force-hover {
+ background: var(--metis-selection-option-hover-background);
+
+ .hover-actions {
+ opacity: 1;
+ visibility: visible;
+ }
+ }
+}
+
+.message-content {
+ padding-left: 0.3rem;
+}
+
+.message-content:hover {
+ background: var(--metis-selection-option-hover-background);
+}
+
+.message-container:hover .hover-actions {
+ opacity: 1;
+ visibility: visible;
+}
+
+.clickable {
+ cursor: pointer;
+}
+
+.item-icon {
+ width: 20px;
+ height: 20px;
+ margin-right: 0.2rem;
+}
+
+.pinned-message {
+ background-color: var(--artemis-alert-warning-background);
+}
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 49b9dc7a8d3e..d70c13abae68 100644
--- a/src/main/webapp/app/shared/metis/post/post.component.ts
+++ b/src/main/webapp/app/shared/metis/post/post.component.ts
@@ -1,9 +1,26 @@
-import { AfterContentChecked, ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild, ViewContainerRef } from '@angular/core';
+import {
+ AfterContentChecked,
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+ EventEmitter,
+ HostListener,
+ Inject,
+ Input,
+ OnChanges,
+ OnInit,
+ Output,
+ Renderer2,
+ ViewChild,
+ ViewContainerRef,
+ input,
+} from '@angular/core';
import { Post } from 'app/entities/metis/post.model';
import { PostingDirective } from 'app/shared/metis/posting.directive';
+import { MetisService } from 'app/shared/metis/metis.service';
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { ContextInformation, DisplayPriority, PageType, RouteComponents } from '../metis.util';
-import { faBullhorn, faCheckSquare } from '@fortawesome/free-solid-svg-icons';
+import { faBullhorn, faComments, faPencilAlt, faSmile, faThumbtack, faTrash } from '@fortawesome/free-solid-svg-icons';
import dayjs from 'dayjs/esm';
import { PostFooterComponent } from 'app/shared/metis/posting-footer/post-footer/post-footer.component';
import { OneToOneChatService } from 'app/shared/metis/conversations/one-to-one-chat.service';
@@ -14,6 +31,10 @@ import { getAsChannelDTO } from 'app/entities/metis/conversation/channel.model';
import { AnswerPost } from 'app/entities/metis/answer-post.model';
import { AnswerPostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component';
import { animate, style, transition, trigger } from '@angular/animations';
+import { PostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component';
+import { PostReactionsBarComponent } from 'app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component';
+import { CdkOverlayOrigin } from '@angular/cdk/overlay';
+import { DOCUMENT } from '@angular/common';
@Component({
selector: 'jhi-post',
@@ -37,8 +58,12 @@ export class PostComponent extends PostingDirective
implements OnInit, OnC
@Input() showAnswers: boolean;
@Output() openThread = new EventEmitter();
@ViewChild('createAnswerPostModal') createAnswerPostModalComponent: AnswerPostCreateEditModalComponent;
+ @ViewChild('createEditModal') createEditModal!: PostCreateEditModalComponent;
@ViewChild('createEditAnswerPostContainer', { read: ViewContainerRef }) containerRef: ViewContainerRef;
@ViewChild('postFooter') postFooterComponent: PostFooterComponent;
+ showReactionSelector = false;
+ @ViewChild('emojiPickerTrigger') emojiPickerTrigger!: CdkOverlayOrigin;
+ static activeDropdownPost: PostComponent | null = null;
displayInlineInput = false;
routerLink: RouteComponents;
@@ -52,19 +77,99 @@ export class PostComponent extends PostingDirective implements OnInit, OnC
contextInformation: ContextInformation;
readonly PageType = PageType;
readonly DisplayPriority = DisplayPriority;
+ mayEditOrDelete: boolean = false;
+ canPin: boolean = false;
// Icons
- faBullhorn = faBullhorn;
- faCheckSquare = faCheckSquare;
+ readonly faBullhorn = faBullhorn;
+ readonly faComments = faComments;
+ readonly faPencilAlt = faPencilAlt;
+ readonly faSmile = faSmile;
+ readonly faTrash = faTrash;
+ readonly faThumbtack = faThumbtack;
+
+ isConsecutive = input(false);
+ dropdownPosition = { x: 0, y: 0 };
+ @ViewChild(PostReactionsBarComponent) private reactionsBarComponent!: PostReactionsBarComponent;
constructor(
+ public metisService: MetisService,
+ public changeDetector: ChangeDetectorRef,
private oneToOneChatService: OneToOneChatService,
private metisConversationService: MetisConversationService,
private router: Router,
+ public renderer: Renderer2,
+ @Inject(DOCUMENT) private document: Document,
) {
super();
}
+ get reactionsBar() {
+ return this.reactionsBarComponent;
+ }
+
+ isPinned(): boolean {
+ return this.posting.displayPriority === DisplayPriority.PINNED;
+ }
+
+ onMayEditOrDelete(value: boolean) {
+ this.mayEditOrDelete = value;
+ }
+
+ onCanPin(value: boolean) {
+ this.canPin = value;
+ }
+
+ onRightClick(event: MouseEvent) {
+ event.preventDefault();
+
+ if (PostComponent.activeDropdownPost && PostComponent.activeDropdownPost !== this) {
+ PostComponent.activeDropdownPost.showDropdown = false;
+ PostComponent.activeDropdownPost.enableBodyScroll();
+ PostComponent.activeDropdownPost.changeDetector.detectChanges();
+ }
+
+ PostComponent.activeDropdownPost = this;
+
+ this.dropdownPosition = {
+ x: event.clientX,
+ y: event.clientY,
+ };
+
+ this.showDropdown = true;
+ this.adjustDropdownPosition();
+ this.disableBodyScroll();
+ }
+
+ adjustDropdownPosition() {
+ const dropdownWidth = 200;
+ const screenWidth = window.innerWidth;
+
+ if (this.dropdownPosition.x + dropdownWidth > screenWidth) {
+ this.dropdownPosition.x = screenWidth - dropdownWidth - 10;
+ }
+ }
+
+ disableBodyScroll() {
+ const mainContainer = this.document.querySelector('.posting-infinite-scroll-container');
+ if (mainContainer) {
+ this.renderer.setStyle(mainContainer, 'overflow', 'hidden');
+ }
+ }
+
+ enableBodyScroll() {
+ const mainContainer = this.document.querySelector('.posting-infinite-scroll-container');
+ if (mainContainer) {
+ this.renderer.setStyle(mainContainer, 'overflow-y', 'auto');
+ }
+ }
+
+ @HostListener('document:click', ['$event'])
+ onClickOutside() {
+ this.showDropdown = false;
+ this.enableBodyScroll();
+ }
+
/**
* on initialization: evaluates post context and page type
*/
diff --git a/src/main/webapp/app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component.ts b/src/main/webapp/app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component.ts
index 4df22238350c..e061a67aa20a 100644
--- a/src/main/webapp/app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component.ts
+++ b/src/main/webapp/app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component.ts
@@ -1,10 +1,11 @@
-import { Component, Input, ViewContainerRef, ViewEncapsulation } from '@angular/core';
+import { Component, EventEmitter, Input, Output, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { PostingCreateEditModalDirective } from 'app/shared/metis/posting-create-edit-modal/posting-create-edit-modal.directive';
import { AnswerPost } from 'app/entities/metis/answer-post.model';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { MetisService } from 'app/shared/metis/metis.service';
import { FormBuilder, Validators } from '@angular/forms';
import { PostContentValidationPattern } from 'app/shared/metis/metis.util';
+import { Posting } from 'app/entities/metis/posting.model';
@Component({
selector: 'jhi-answer-post-create-edit-modal',
@@ -15,6 +16,7 @@ import { PostContentValidationPattern } from 'app/shared/metis/metis.util';
export class AnswerPostCreateEditModalComponent extends PostingCreateEditModalDirective {
@Input() createEditAnswerPostContainerRef: ViewContainerRef;
isInputOpen = false;
+ @Output() postingUpdated = new EventEmitter();
constructor(
protected metisService: MetisService,
@@ -46,6 +48,7 @@ export class AnswerPostCreateEditModalComponent extends PostingCreateEditModalDi
* resets the answer post content
*/
resetFormGroup(): void {
+ this.posting = this.posting || { content: '' };
this.formGroup = this.formBuilder.group({
// the pattern ensures that the content must include at least one non-whitespace character
content: [this.posting.content, [Validators.required, Validators.maxLength(this.maxContentLength), PostContentValidationPattern]],
@@ -78,7 +81,8 @@ export class AnswerPostCreateEditModalComponent extends PostingCreateEditModalDi
updatePosting(): void {
this.posting.content = this.formGroup.get('content')?.value;
this.metisService.updateAnswerPost(this.posting).subscribe({
- next: () => {
+ next: (updatedPost: AnswerPost) => {
+ this.postingUpdated.emit(updatedPost);
this.isLoading = false;
this.isInputOpen = false;
this.createEditAnswerPostContainerRef?.clear();
diff --git a/src/main/webapp/app/shared/metis/posting-footer/answer-post-footer/answer-post-footer.component.html b/src/main/webapp/app/shared/metis/posting-footer/answer-post-footer/answer-post-footer.component.html
deleted file mode 100644
index 2f0f537dece3..000000000000
--- a/src/main/webapp/app/shared/metis/posting-footer/answer-post-footer/answer-post-footer.component.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/src/main/webapp/app/shared/metis/posting-footer/answer-post-footer/answer-post-footer.component.scss b/src/main/webapp/app/shared/metis/posting-footer/answer-post-footer/answer-post-footer.component.scss
deleted file mode 100644
index 3ae49fc0e694..000000000000
--- a/src/main/webapp/app/shared/metis/posting-footer/answer-post-footer/answer-post-footer.component.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-.approved-badge {
- max-width: 130px;
- overflow: hidden;
- text-overflow: ellipsis;
- background-color: green;
-}
-
-.not-approved-badge {
- max-width: 130px;
- overflow: hidden;
- text-overflow: ellipsis;
- background-color: lightgray;
-}
diff --git a/src/main/webapp/app/shared/metis/posting-footer/answer-post-footer/answer-post-footer.component.ts b/src/main/webapp/app/shared/metis/posting-footer/answer-post-footer/answer-post-footer.component.ts
deleted file mode 100644
index 52d8bee21ca5..000000000000
--- a/src/main/webapp/app/shared/metis/posting-footer/answer-post-footer/answer-post-footer.component.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Component, EventEmitter, Input, Output } from '@angular/core';
-import { PostingFooterDirective } from 'app/shared/metis/posting-footer/posting-footer.directive';
-import { AnswerPost } from 'app/entities/metis/answer-post.model';
-
-@Component({
- selector: 'jhi-answer-post-footer',
- templateUrl: './answer-post-footer.component.html',
- styleUrls: ['./answer-post-footer.component.scss'],
-})
-export class AnswerPostFooterComponent extends PostingFooterDirective {
- @Input()
- isReadOnlyMode = false;
- @Input() isLastAnswer = false;
- @Output() openPostingCreateEditModal = new EventEmitter();
-}
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 c04bbd8392e7..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
@@ -12,19 +12,22 @@