add options dropdown
This commit is contained in:
parent
e6d85c7257
commit
036cda1431
15 changed files with 357 additions and 29 deletions
|
@ -119,13 +119,13 @@
|
|||
|
||||
@if (appState.displayConversationListPanelLarge) {
|
||||
|
||||
<div class="search-button is-expanded is-clickable">
|
||||
<i class="ri-search-line"></i>
|
||||
<!-- <div class="search-button is-expanded is-clickable">-->
|
||||
<!-- <i class="ri-search-line"></i>-->
|
||||
|
||||
<input type="text" class="no-borders" placeholder="Search a chat" value="blah">
|
||||
<i class="funnel ri-filter-3-line"></i>
|
||||
<!-- <input type="text" class="no-borders" placeholder="Search a chat" value="blah">-->
|
||||
<!-- <i class="funnel ri-filter-3-line"></i>-->
|
||||
|
||||
</div>
|
||||
<!-- </div>-->
|
||||
} @else {
|
||||
|
||||
<div class="search-button is-clickable">
|
||||
|
|
|
@ -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<any> {
|
||||
// Simulate API call
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve({ success: true });
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const meta: Meta<FeedbackButton> = {
|
||||
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<FeedbackButton>;
|
||||
|
||||
// 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
|
||||
}
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <strong>HTML</strong> et des listes:<ul><li>Point 1</li><li>Point 2</li></ul>',
|
||||
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 <strong>HTML</strong> et des listes:<ul><li>Point 1</li><li>Point 2</li></ul>',
|
||||
name: 'Assistant'
|
||||
}),
|
||||
expanded: true,
|
||||
}
|
||||
};
|
||||
export const LongAIMessage: Story = {
|
||||
args: {
|
||||
kind: 'llm',
|
||||
|
|
|
@ -1,22 +1,16 @@
|
|||
<div class="new-input">
|
||||
<div class="main-conversation-container">
|
||||
|
||||
<!-- new input-->
|
||||
|
||||
<div class="welcome-text">
|
||||
<div class="welcome-icon">
|
||||
<!-- <i class="ri-robot-2-line"></i>-->
|
||||
<img alt="chatbot image" src="/chatbot.png">
|
||||
</div>
|
||||
How can we
|
||||
<span class="emphasis">
|
||||
assist
|
||||
</span>
|
||||
assist
|
||||
</span>
|
||||
you today?
|
||||
</div>
|
||||
|
||||
<app-prompt-input></app-prompt-input>
|
||||
tools:
|
||||
<app-tools-options [hideDisabledButtons]="false"></app-tools-options>
|
||||
<app-prompt-input></app-prompt-input>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<div class="options-dropdown is-mode-{{mode}}" >
|
||||
<div class="button">
|
||||
<i class="ri-settings-2-line "></i>
|
||||
<div class="indicator"></div>
|
||||
</div>
|
||||
|
||||
<div class="dropwdown">
|
||||
<div class="dropdown-item" (click)="changeModeOption('auto')">
|
||||
<i class="ri-settings-2-line "></i>
|
||||
<div class="label">
|
||||
Auto mode
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown-item" (click)="changeModeOption('structured')">
|
||||
<i class="ri-settings-2-line "></i>
|
||||
<div class="label">
|
||||
Structured mode
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { OptionsDropdown } from './options-dropdown';
|
||||
|
||||
describe('OptionsDropdown', () => {
|
||||
let component: OptionsDropdown;
|
||||
let fixture: ComponentFixture<OptionsDropdown>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [OptionsDropdown]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(OptionsDropdown);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
placeholder="Ask questions, request or a web search" type="text">
|
||||
|
||||
|
||||
<app-options-dropdown></app-options-dropdown>
|
||||
<button (click)="submitMessage()" class="submit">
|
||||
<i class="ri-send-plane-2-line"></i>
|
||||
</button>
|
||||
|
|
|
@ -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'
|
||||
})
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
message="System error - I couldn't process your request. Please try again in few moments"></sae-alert-box>
|
||||
} @else {
|
||||
<sae-alert-box _alertKind="warning"
|
||||
message="AI can make mistakes - consider verifying important information."></sae-alert-box>
|
||||
message="<strong>AI can make mistakes</strong> - consider verifying important information."></sae-alert-box>
|
||||
}
|
||||
|
|
89
old-sae-airwatch/src/stories/alert-box.stories.ts
Normal file
89
old-sae-airwatch/src/stories/alert-box.stories.ts
Normal file
|
@ -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<AlertBox> = {
|
||||
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<AlertBox>;
|
||||
|
||||
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: `<sae-alert-box [_alertKind]="'warning'">Contenu personnalisé via ng-content</sae-alert-box>`
|
||||
})
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue