From 036cda143151794ef18cc3730ad34c3384532cf1 Mon Sep 17 00:00:00 2001 From: Tykayn Date: Tue, 19 Aug 2025 16:19:55 +0200 Subject: [PATCH] add options dropdown --- old-sae-airwatch/src/app/chatbot/chatbot.html | 10 +- .../feedback-button.stories.ts | 131 ++++++++++++++++++ .../app/chatbot/message-box/message-box.scss | 22 +-- .../message-box/message-box.stories.ts | 14 +- .../src/app/chatbot/new-input/new-input.html | 12 +- .../options-dropdown/options-dropdown.html | 21 +++ .../options-dropdown/options-dropdown.scss | 24 ++++ .../options-dropdown/options-dropdown.spec.ts | 23 +++ .../options-dropdown/options-dropdown.ts | 17 +++ .../chatbot/prompt-input/prompt-input.html | 1 + .../app/chatbot/prompt-input/prompt-input.ts | 3 +- .../time-separator/time-separator.scss | 10 +- .../chatbot/tools-options/tools-options.scss | 7 + .../chatbot/warning-bugs/warning-bugs.html | 2 +- .../src/stories/alert-box.stories.ts | 89 ++++++++++++ 15 files changed, 357 insertions(+), 29 deletions(-) create mode 100644 old-sae-airwatch/src/app/chatbot/feedback-button/feedback-button.stories.ts create mode 100644 old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.html create mode 100644 old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.scss create mode 100644 old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.spec.ts create mode 100644 old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.ts create mode 100644 old-sae-airwatch/src/stories/alert-box.stories.ts diff --git a/old-sae-airwatch/src/app/chatbot/chatbot.html b/old-sae-airwatch/src/app/chatbot/chatbot.html index 95a2cbc..9aef305 100644 --- a/old-sae-airwatch/src/app/chatbot/chatbot.html +++ b/old-sae-airwatch/src/app/chatbot/chatbot.html @@ -119,13 +119,13 @@ @if (appState.displayConversationListPanelLarge) { -
- + + - - + + -
+ } @else {
diff --git a/old-sae-airwatch/src/app/chatbot/feedback-button/feedback-button.stories.ts b/old-sae-airwatch/src/app/chatbot/feedback-button/feedback-button.stories.ts new file mode 100644 index 0000000..5e8b0f4 --- /dev/null +++ b/old-sae-airwatch/src/app/chatbot/feedback-button/feedback-button.stories.ts @@ -0,0 +1,131 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import { FeedbackButton } from './feedback-button'; +import { moduleMetadata } from '@storybook/angular'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { Store, StoreModule } from '@ngrx/store'; +import { ApiService } from '../../services/api-service'; +import { reducers } from '../../reducers'; + +// Mock ApiService +class MockApiService { + async sendUserFeedback(feedback: string): Promise { + // Simulate API call + return new Promise((resolve) => { + setTimeout(() => { + resolve({ success: true }); + }, 1000); + }); + } +} + +const meta: Meta = { + title: 'Components/FeedbackButton', + component: FeedbackButton, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + CommonModule, + FormsModule, + StoreModule.forRoot(reducers) + ], + providers: [ + Store, + { provide: ApiService, useClass: MockApiService } + ] + }) + ], + argTypes: { + isModalOpen: { + control: 'boolean', + description: 'Whether the feedback modal is open' + }, + feedbackText: { + control: 'text', + description: 'The feedback text entered by the user' + }, + isSubmitting: { + control: 'boolean', + description: 'Whether the feedback is being submitted' + }, + submitSuccess: { + control: 'boolean', + description: 'Whether the feedback was submitted successfully' + }, + submitError: { + control: 'boolean', + description: 'Whether there was an error submitting the feedback' + } + } +}; + +export default meta; +type Story = StoryObj; + +// Default state - just the button +export const Default: Story = { + args: { + isModalOpen: false, + feedbackText: '', + isSubmitting: false, + submitSuccess: false, + submitError: false + } +}; + +// Modal open state +export const ModalOpen: Story = { + args: { + isModalOpen: true, + feedbackText: '', + isSubmitting: false, + submitSuccess: false, + submitError: false + } +}; + +// Modal with text entered +export const WithFeedbackText: Story = { + args: { + isModalOpen: true, + feedbackText: 'This is some feedback text that the user has entered.', + isSubmitting: false, + submitSuccess: false, + submitError: false + } +}; + +// Submitting state +export const Submitting: Story = { + args: { + isModalOpen: true, + feedbackText: 'This is some feedback text that the user has entered.', + isSubmitting: true, + submitSuccess: false, + submitError: false + } +}; + +// Success state +export const SubmitSuccess: Story = { + args: { + isModalOpen: true, + feedbackText: 'This is some feedback text that the user has entered.', + isSubmitting: false, + submitSuccess: true, + submitError: false + } +}; + +// Error state +export const SubmitError: Story = { + args: { + isModalOpen: true, + feedbackText: 'This is some feedback text that the user has entered.', + isSubmitting: false, + submitSuccess: false, + submitError: true + } +}; + diff --git a/old-sae-airwatch/src/app/chatbot/message-box/message-box.scss b/old-sae-airwatch/src/app/chatbot/message-box/message-box.scss index e1a6cf6..856b6cf 100644 --- a/old-sae-airwatch/src/app/chatbot/message-box/message-box.scss +++ b/old-sae-airwatch/src/app/chatbot/message-box/message-box.scss @@ -25,30 +25,30 @@ } -.user-more-infos { - margin-top: -35px; - margin-left: 39px; -} .message { + + .user-more-infos { + margin-top: -35px; + margin-left: 39px; + } + &.user { - background: #232432; - color: #8b8ecf; + background: white; + color: #000; } &.llm { - //background: #232432; - .message-content { - color: #8b8ecf; + color: #000; } .actions { .button { - background: #0d0e15; - color: grey; + background: rgba(59, 135, 204, 0.7); + color: black; } } diff --git a/old-sae-airwatch/src/app/chatbot/message-box/message-box.stories.ts b/old-sae-airwatch/src/app/chatbot/message-box/message-box.stories.ts index c4b5c48..3d31702 100644 --- a/old-sae-airwatch/src/app/chatbot/message-box/message-box.stories.ts +++ b/old-sae-airwatch/src/app/chatbot/message-box/message-box.stories.ts @@ -57,7 +57,19 @@ export const AIMessage: Story = { }) } }; - +export const AIMessageExpanded: Story = { + args: { + kind: 'llm', + content: 'Je suis un assistant IA qui répond à vos questions. Voici une réponse détaillée qui peut contenir du HTML et des listes:
  • Point 1
  • Point 2
', + message: new ChatbotMessage({ + kind: 'llm', + user: {}, + content: 'Je suis un assistant IA qui répond à vos questions. Voici une réponse détaillée qui peut contenir du HTML et des listes:
  • Point 1
  • Point 2
', + name: 'Assistant' + }), + expanded: true, + } +}; export const LongAIMessage: Story = { args: { kind: 'llm', diff --git a/old-sae-airwatch/src/app/chatbot/new-input/new-input.html b/old-sae-airwatch/src/app/chatbot/new-input/new-input.html index 95056d9..eb64de1 100644 --- a/old-sae-airwatch/src/app/chatbot/new-input/new-input.html +++ b/old-sae-airwatch/src/app/chatbot/new-input/new-input.html @@ -1,22 +1,16 @@
- - -
- chatbot image
How can we - assist - + assist + you today?
- - - tools: +
diff --git a/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.html b/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.html new file mode 100644 index 0000000..b690eaa --- /dev/null +++ b/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.html @@ -0,0 +1,21 @@ +
+
+ +
+
+ +
+ + +
+
diff --git a/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.scss b/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.scss new file mode 100644 index 0000000..f9ecba5 --- /dev/null +++ b/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.scss @@ -0,0 +1,24 @@ +.options-dropdown{ + padding: 10px; + .button{ + padding: 6px; + &:hover{ + background: cornflowerblue; + } + } + + .is-mode-structured, + .is-mode-other, + { + background: red; + border-radius: 100px; + width: 20px; + position: relative; + left: 10px; + top: 10px; + } + + .dropdown-item{ + background: white; + } +} diff --git a/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.spec.ts b/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.spec.ts new file mode 100644 index 0000000..8e580f5 --- /dev/null +++ b/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OptionsDropdown } from './options-dropdown'; + +describe('OptionsDropdown', () => { + let component: OptionsDropdown; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [OptionsDropdown] + }) + .compileComponents(); + + fixture = TestBed.createComponent(OptionsDropdown); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.ts b/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.ts new file mode 100644 index 0000000..e619926 --- /dev/null +++ b/old-sae-airwatch/src/app/chatbot/options-dropdown/options-dropdown.ts @@ -0,0 +1,17 @@ +import {Component, Input} from '@angular/core'; +import {NgClass} from '@angular/common'; + +@Component({ + selector: 'app-options-dropdown', + + templateUrl: './options-dropdown.html', + styleUrl: './options-dropdown.scss' +}) +export class OptionsDropdown { + + @Input() public mode: 'auto' | 'structured' = 'auto' + + changeModeOption(mode: 'auto' | 'structured') { + this.mode = mode; + } +} diff --git a/old-sae-airwatch/src/app/chatbot/prompt-input/prompt-input.html b/old-sae-airwatch/src/app/chatbot/prompt-input/prompt-input.html index db13378..f2c8f77 100644 --- a/old-sae-airwatch/src/app/chatbot/prompt-input/prompt-input.html +++ b/old-sae-airwatch/src/app/chatbot/prompt-input/prompt-input.html @@ -9,6 +9,7 @@ placeholder="Ask questions, request or a web search" type="text"> + diff --git a/old-sae-airwatch/src/app/chatbot/prompt-input/prompt-input.ts b/old-sae-airwatch/src/app/chatbot/prompt-input/prompt-input.ts index b53b863..3661ae3 100644 --- a/old-sae-airwatch/src/app/chatbot/prompt-input/prompt-input.ts +++ b/old-sae-airwatch/src/app/chatbot/prompt-input/prompt-input.ts @@ -7,10 +7,11 @@ import {ChatbotMessage} from '../../services/chatbot.message.type'; import {ChatbotConversation} from '../../services/conversations.service'; import {ApiService, OpenMeteoResponse} from '../../services/api-service'; import {interval, Subscription} from 'rxjs'; +import {OptionsDropdown} from '../options-dropdown/options-dropdown'; @Component({ selector: 'app-prompt-input', - imports: [CommonModule, FormsModule], + imports: [CommonModule, FormsModule, OptionsDropdown], templateUrl: './prompt-input.html', styleUrl: './prompt-input.scss' }) diff --git a/old-sae-airwatch/src/app/chatbot/time-separator/time-separator.scss b/old-sae-airwatch/src/app/chatbot/time-separator/time-separator.scss index c98630c..712dacf 100644 --- a/old-sae-airwatch/src/app/chatbot/time-separator/time-separator.scss +++ b/old-sae-airwatch/src/app/chatbot/time-separator/time-separator.scss @@ -10,11 +10,19 @@ padding: 0; width: auto; + &.time-ago { + color: #1E1F22; + + font-size: 10px; + font-style: normal; + font-weight: 400; + line-height: 8px; + margin-top: -32px; margin-bottom: 16px; text-align: center; - width: auto; + width: 100px !important; padding: 16px 0; } } diff --git a/old-sae-airwatch/src/app/chatbot/tools-options/tools-options.scss b/old-sae-airwatch/src/app/chatbot/tools-options/tools-options.scss index e15bf06..94eb796 100644 --- a/old-sae-airwatch/src/app/chatbot/tools-options/tools-options.scss +++ b/old-sae-airwatch/src/app/chatbot/tools-options/tools-options.scss @@ -4,4 +4,11 @@ padding-top: 1rem; border-top: solid 0.5px #b7b7b7; + app-toggle-button { + margin-bottom: 10px; + display: inline-block; + + app-toggle-button { + margin-left: 10px; + } + } } diff --git a/old-sae-airwatch/src/app/chatbot/warning-bugs/warning-bugs.html b/old-sae-airwatch/src/app/chatbot/warning-bugs/warning-bugs.html index f8fd440..6f89f4d 100644 --- a/old-sae-airwatch/src/app/chatbot/warning-bugs/warning-bugs.html +++ b/old-sae-airwatch/src/app/chatbot/warning-bugs/warning-bugs.html @@ -3,5 +3,5 @@ message="System error - I couldn't process your request. Please try again in few moments"> } @else { + message="AI can make mistakes - consider verifying important information."> } diff --git a/old-sae-airwatch/src/stories/alert-box.stories.ts b/old-sae-airwatch/src/stories/alert-box.stories.ts new file mode 100644 index 0000000..3f14f50 --- /dev/null +++ b/old-sae-airwatch/src/stories/alert-box.stories.ts @@ -0,0 +1,89 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import { AlertBox } from 'sae-lib/alert-box/alert-box'; +import { moduleMetadata } from '@storybook/angular'; +import { CommonModule } from '@angular/common'; + +const meta: Meta = { + title: 'Components/AlertBox', + component: AlertBox, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [CommonModule], + providers: [] + }) + ], + argTypes: { + message: { + control: 'text', + description: 'Message à afficher dans l\'alerte' + }, + _alertKind: { + control: 'select', + options: ['info', 'success', 'primary', 'secondary', 'warning', 'danger', 'error'], + description: 'Type d\'alerte' + } + }, +}; + +export default meta; +type Story = StoryObj; + +export const Warning: Story = { + args: { + message: 'Ceci est un message d\'avertissement', + _alertKind: 'warning' + }, +}; + +export const Success: Story = { + args: { + message: 'Opération réussie !', + _alertKind: 'success' + }, +}; + +export const Info: Story = { + args: { + message: 'Information importante', + _alertKind: 'info' + }, +}; + +export const Primary: Story = { + args: { + message: 'Message principal', + _alertKind: 'primary' + }, +}; + +export const Secondary: Story = { + args: { + message: 'Message secondaire', + _alertKind: 'secondary' + }, +}; + +export const Danger: Story = { + args: { + message: 'Attention danger !', + _alertKind: 'danger' + }, +}; + +export const Error: Story = { + args: { + message: 'Une erreur est survenue', + _alertKind: 'error' + }, +}; + +export const WithContent: Story = { + args: { + _alertKind: 'warning' + }, + render: (args) => ({ + props: args, + template: `Contenu personnalisé via ng-content` + }) +};