diff --git a/web-app/src/app/app.component.ts b/web-app/src/app/app.component.ts index 4f75cfae024..d5076ef3054 100644 --- a/web-app/src/app/app.component.ts +++ b/web-app/src/app/app.component.ts @@ -1,3 +1,4 @@ +import { HttpClient } from '@angular/common/http'; import { Component, ElementRef, Inject, OnInit, Renderer2 } from '@angular/core'; import { NavigationEnd, NavigationError, RouteConfigLoadStart, Router } from '@angular/router'; import { I18NService } from '@core'; @@ -10,7 +11,10 @@ import { ThemeService } from './service/theme.service'; @Component({ selector: 'app-root', - template: ` ` + template: ` + + + ` }) export class AppComponent implements OnInit { constructor( diff --git a/web-app/src/app/shared/components/chat-message/chat-message.component.css b/web-app/src/app/shared/components/chat-message/chat-message.component.css new file mode 100644 index 00000000000..f9ec38ef1ca --- /dev/null +++ b/web-app/src/app/shared/components/chat-message/chat-message.component.css @@ -0,0 +1,46 @@ +.message { + margin-bottom: 5px; + padding: 5px; + border-radius: 4px; + background-color: #f1f1f1; + max-width: 100%; + word-wrap: break-word; + display: flex; + align-items: center; +} + +.message p { + margin: 0; + flex-grow: 1; +} + +.copy-btn { + border: none; + background: transparent; + cursor: pointer; + font-size: 1rem; + margin-right: 5px; + color: #3f51b5; +} + +.copy-btn:hover { + color: #0056b3; +} + +.hint { + position: absolute; + top: -10px; + left: 50%; + transform: translateX(-50%); + background-color: #3f51b5; + color: white; + padding: 3px 8px; + border-radius: 4px; + font-size: 0.75rem; + opacity: 0; + transition: opacity 0.3s ease-in-out; +} + +.copy-btn .hint { + opacity: 1; +} diff --git a/web-app/src/app/shared/components/chat-message/chat-message.component.html b/web-app/src/app/shared/components/chat-message/chat-message.component.html new file mode 100644 index 00000000000..79dcc93254f --- /dev/null +++ b/web-app/src/app/shared/components/chat-message/chat-message.component.html @@ -0,0 +1,10 @@ +
+

{{ message.sender }}: {{ message.text }}

+ +
+
+

{{ message.sender }}: {{ message.text }}

+
diff --git a/web-app/src/app/shared/components/chat-message/chat-message.component.ts b/web-app/src/app/shared/components/chat-message/chat-message.component.ts new file mode 100644 index 00000000000..51eaebb4a4f --- /dev/null +++ b/web-app/src/app/shared/components/chat-message/chat-message.component.ts @@ -0,0 +1,23 @@ +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'app-chat-message', + templateUrl: './chat-message.component.html', + styleUrls: ['./chat-message.component.css'], +}) +export class ChatMessageComponent { + @Input() message!: { sender: string; text: string }; + copied: boolean = false; + + copyToClipboard(text: string) { + navigator.clipboard.writeText(text).then( + () => { + this.copied = true; + setTimeout(() => this.copied = false, 2000); // Reset hint after 2 seconds + }, + (err) => { + console.error('Failed to copy text: ', err); + } + ); + } +} diff --git a/web-app/src/app/shared/components/chatbot/chatbot.component.css b/web-app/src/app/shared/components/chatbot/chatbot.component.css new file mode 100644 index 00000000000..b77bfa9bbf4 --- /dev/null +++ b/web-app/src/app/shared/components/chatbot/chatbot.component.css @@ -0,0 +1,96 @@ +.float { + position: fixed; + bottom: 2rem; + right: 2rem; + border: none; + background: transparent; + padding: 0; + cursor: pointer; +} + +.float img { + width: 3rem; + height: 3rem; +} + +.popup { + position: fixed; + bottom: 5rem; + right: 2rem; + width: 310px; + max-height: 400px; + border: 1px solid #ccc; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + background-color: white; + z-index: 1000; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.popup-content { + padding: 10px; + display: flex; + flex-direction: column; + align-items: flex-start; + height: 100%; +} + +.close-btn { + align-self: flex-end; + border: none; + background: transparent; + cursor: pointer; + font-size: 1rem; +} + +.chat-window { + display: flex; + flex-direction: column; + flex-grow: 1; + width: 100%; +} + +.chat-messages { + flex-grow: 1; + overflow-y: auto; /* Enables vertical scrolling */ + max-height: 200px; /* Set a maximum height for the chat window */ + margin-bottom: 10px; + width: 100%; + padding-right: 5px; /* Optional: Adds some padding for better readability */ +} + +.input-container { + display: flex; + align-items: center; + width: 100%; +} + +input[type='text'] { + flex-grow: 1; + padding: 5px; + border: 1px solid #ccc; + border-radius: 4px; + margin-right: 5px; +} + +button { + border: none; + background-color: #3f51b5; + color: white; + padding: 6px 10px; + border-radius: 4px; + cursor: pointer; + margin-right: 5px; + height: 34px; +} + +.reset-btn { + background-color: #dc3545; + margin-right: 0; +} + +.reset-btn:hover { + background-color: #c82333; +} diff --git a/web-app/src/app/shared/components/chatbot/chatbot.component.html b/web-app/src/app/shared/components/chatbot/chatbot.component.html new file mode 100644 index 00000000000..daf50b7a9af --- /dev/null +++ b/web-app/src/app/shared/components/chatbot/chatbot.component.html @@ -0,0 +1,19 @@ + + diff --git a/web-app/src/app/shared/components/chatbot/chatbot.component.ts b/web-app/src/app/shared/components/chatbot/chatbot.component.ts new file mode 100644 index 00000000000..3562193a057 --- /dev/null +++ b/web-app/src/app/shared/components/chatbot/chatbot.component.ts @@ -0,0 +1,46 @@ +import { Component } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +@Component({ + selector: 'app-chatbot', + templateUrl: './chatbot.component.html', + styleUrls: ['./chatbot.component.css'], +}) +export class ChatbotComponent { + isPopupVisible = false; + userInput = ''; + messages: { sender: string; text: string }[] = []; + + constructor(private http: HttpClient) { } + + togglePopup() { + this.isPopupVisible = !this.isPopupVisible; + } + + sendMessage() { + if (this.userInput.trim()) { + // Add user's message to the chat window + this.messages.push({ sender: 'You', text: this.userInput }); + + // Send the message to the AI backend + this.http.post('/api/ai', { text: this.userInput }).subscribe( + (response: any) => { + // Add AI's response to the chat window + this.messages.push({ sender: 'AI', text: "sample answer" }); + }, + (error) => { + // Handle error response + this.messages.push({ sender: 'AI', text: 'Error communicating with AI' }); + console.error('Error communicating with AI:', error); + } + ); + + // Clear the input field + this.userInput = ''; + } + } + + resetChat() { + this.messages = []; + } +} diff --git a/web-app/src/app/shared/shared.module.ts b/web-app/src/app/shared/shared.module.ts index bea3cd89d07..baf17b18b45 100644 --- a/web-app/src/app/shared/shared.module.ts +++ b/web-app/src/app/shared/shared.module.ts @@ -24,6 +24,8 @@ import { I18nElsePipe } from './pipe/i18n-else.pipe'; import { TimezonePipe } from './pipe/timezone.pipe'; import { SHARED_DELON_MODULES } from './shared-delon.module'; import { SHARED_ZORRO_MODULES } from './shared-zorro.module'; +import { ChatbotComponent } from './components/chatbot/chatbot.component'; +import { ChatMessageComponent } from './components/chat-message/chat-message.component'; const ThirdModules: Array> = []; const COMPONENTS: Array> = [ @@ -34,7 +36,9 @@ const COMPONENTS: Array> = [ MetricsFieldInputComponent, ToolbarComponent, FormFieldComponent, - MonitorSelectMenuComponent + MonitorSelectMenuComponent, + ChatbotComponent, + ChatMessageComponent ]; const DIRECTIVES: Array> = [TimezonePipe, I18nElsePipe, ElapsedTimePipe]; @@ -73,4 +77,4 @@ const DIRECTIVES: Array> = [TimezonePipe, I18nElsePipe, ElapsedTimePi ...DIRECTIVES ] }) -export class SharedModule {} +export class SharedModule { } diff --git a/web-app/src/assets/img/chatbot-icon.svg b/web-app/src/assets/img/chatbot-icon.svg new file mode 100644 index 00000000000..b3de5b15fec --- /dev/null +++ b/web-app/src/assets/img/chatbot-icon.svg @@ -0,0 +1,7 @@ + + chatbot + +