Skip to content

Commit 1562e6b

Browse files
committed
Merge branch 'main' into backend_biome_up
2 parents 689577a + 461f78d commit 1562e6b

19 files changed

+1815
-1366
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,6 @@ This section provides clear and concise instructions for installing RocketAdmin
100100

101101
## Usage
102102

103-
1. After installation rocketadmin will create a user with email admin@email.local and autogenerated password. The message will be `Admin user created with email: "admin@email.local" and password: "<password>"`
104-
2. You can sign in using these credentials. We recommend to change email and password after first login
103+
1. After installation, open RocketAdmin in your browser at `http://localhost:8080`. You will be redirected to the setup page.
104+
2. On the setup page, create your admin account by entering your email and password.
105+
3. After completing the setup, sign in with your new credentials.

frontend/src/app/components/dashboard/db-table-view/db-table-ai-panel/db-table-ai-panel.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ <h2 class="mat-heading-2 ai-panel-sidebar__title">
2323
<div class="ai-message-chain">
2424
<div *ngFor="let message of messagesChain" class="{{message.type}}-message">
2525
<span style="white-space: pre-wrap" *ngIf="message.type == 'user'">{{message.text}}</span>
26-
<markdown *ngIf="message.type == 'ai'" mermaid>{{message.text}}</markdown>
26+
<markdown *ngIf="message.type == 'ai'" mermaid [data]="message.text"></markdown>
2727
</div>
2828
</div>
2929
</div>

frontend/src/app/components/dashboard/db-table-view/db-table-ai-panel/db-table-ai-panel.component.spec.ts

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,35 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
33
import { MatIconTestingModule } from '@angular/material/icon/testing';
44
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
55
import { Angulartics2Module } from 'angulartics2';
6-
import { MarkdownService } from 'ngx-markdown';
7-
import { of, throwError } from 'rxjs';
6+
import { of } from 'rxjs';
7+
import { AiService } from 'src/app/services/ai.service';
88
import { ConnectionsService } from 'src/app/services/connections.service';
99
import { TableStateService } from 'src/app/services/table-state.service';
1010
import { TablesService } from 'src/app/services/tables.service';
1111
import { DbTableAiPanelComponent } from './db-table-ai-panel.component';
1212

13+
async function* mockStream(...chunks: string[]): AsyncGenerator<string> {
14+
for (const chunk of chunks) {
15+
yield chunk;
16+
}
17+
}
18+
1319
describe('DbTableAiPanelComponent', () => {
1420
let component: DbTableAiPanelComponent;
1521
let fixture: ComponentFixture<DbTableAiPanelComponent>;
16-
let tablesService: TablesService;
1722
let tableStateService: TableStateService;
1823

19-
const mockMarkdownService = {
20-
parse: vi.fn().mockReturnValue('parsed markdown'),
21-
};
22-
2324
const mockConnectionsService = {
2425
currentConnectionID: '12345678',
2526
};
2627

2728
const mockTablesService = {
2829
currentTableName: 'users',
29-
createAIthread: vi.fn(),
30-
requestAImessage: vi.fn(),
30+
};
31+
32+
const mockAiService: Partial<AiService> = {
33+
createThread: vi.fn(),
34+
sendMessage: vi.fn(),
3135
};
3236

3337
const mockTableStateService = {
@@ -41,16 +45,15 @@ describe('DbTableAiPanelComponent', () => {
4145
imports: [Angulartics2Module.forRoot(), DbTableAiPanelComponent, BrowserAnimationsModule, MatIconTestingModule],
4246
providers: [
4347
provideHttpClient(),
44-
{ provide: MarkdownService, useValue: mockMarkdownService },
4548
{ provide: ConnectionsService, useValue: mockConnectionsService },
4649
{ provide: TablesService, useValue: mockTablesService },
50+
{ provide: AiService, useValue: mockAiService },
4751
{ provide: TableStateService, useValue: mockTableStateService },
4852
],
4953
}).compileComponents();
5054

5155
fixture = TestBed.createComponent(DbTableAiPanelComponent);
5256
component = fixture.componentInstance;
53-
tablesService = TestBed.inject(TablesService);
5457
tableStateService = TestBed.inject(TableStateService);
5558
fixture.detectChanges();
5659
});
@@ -77,7 +80,10 @@ describe('DbTableAiPanelComponent', () => {
7780
});
7881

7982
it('should create thread on Enter key when no thread exists', () => {
80-
mockTablesService.createAIthread.mockReturnValue(of({ threadId: 'thread-123', responseMessage: 'AI response' }));
83+
(mockAiService.createThread as ReturnType<typeof vi.fn>).mockResolvedValue({
84+
threadId: 'thread-123',
85+
stream: mockStream('AI response'),
86+
});
8187

8288
component.message = 'Test message';
8389
component.threadID = null;
@@ -86,11 +92,16 @@ describe('DbTableAiPanelComponent', () => {
8692
Object.defineProperty(event, 'preventDefault', { value: vi.fn() });
8793
component.onKeydown(event);
8894

89-
expect(mockTablesService.createAIthread).toHaveBeenCalledWith('12345678', 'users', 'Test message');
95+
expect(mockAiService.createThread).toHaveBeenCalledWith(
96+
'12345678',
97+
'users',
98+
'Test message',
99+
expect.any(AbortSignal),
100+
);
90101
});
91102

92103
it('should send message on Enter key when thread exists', () => {
93-
mockTablesService.requestAImessage.mockReturnValue(of('AI response'));
104+
(mockAiService.sendMessage as ReturnType<typeof vi.fn>).mockResolvedValue(mockStream('AI response'));
94105

95106
component.message = 'Follow up message';
96107
component.threadID = 'existing-thread';
@@ -99,55 +110,65 @@ describe('DbTableAiPanelComponent', () => {
99110
Object.defineProperty(event, 'preventDefault', { value: vi.fn() });
100111
component.onKeydown(event);
101112

102-
expect(mockTablesService.requestAImessage).toHaveBeenCalledWith(
113+
expect(mockAiService.sendMessage).toHaveBeenCalledWith(
103114
'12345678',
104115
'users',
105116
'existing-thread',
106117
'Follow up message',
118+
expect.any(AbortSignal),
107119
);
108120
});
109121

110-
it('should add user message to chain when creating thread', () => {
111-
mockTablesService.createAIthread.mockReturnValue(of({ threadId: 'thread-123', responseMessage: 'AI response' }));
122+
it('should add user message to chain when creating thread', async () => {
123+
(mockAiService.createThread as ReturnType<typeof vi.fn>).mockResolvedValue({
124+
threadId: 'thread-123',
125+
stream: mockStream('AI response'),
126+
});
112127

113128
component.message = 'User question';
114-
component.createThread();
129+
await component.createThread();
115130

116131
expect(component.messagesChain[0]).toEqual({
117132
type: 'user',
118133
text: 'User question',
119134
});
120135
});
121136

122-
it('should add AI response to chain after thread creation', () => {
123-
mockTablesService.createAIthread.mockReturnValue(of({ threadId: 'thread-123', responseMessage: 'AI response' }));
137+
it('should add AI response to chain after thread creation', async () => {
138+
(mockAiService.createThread as ReturnType<typeof vi.fn>).mockResolvedValue({
139+
threadId: 'thread-123',
140+
stream: mockStream('AI response'),
141+
});
124142

125143
component.message = 'User question';
126-
component.createThread();
144+
await component.createThread();
127145

128146
expect(component.threadID).toBe('thread-123');
129147
expect(component.messagesChain[1]).toEqual({
130148
type: 'ai',
131-
text: 'parsed markdown',
149+
text: 'AI response',
132150
});
133151
});
134152

135-
it('should handle error when creating thread', () => {
136-
mockTablesService.createAIthread.mockReturnValue(throwError(() => 'Error message'));
153+
it('should handle error when creating thread', async () => {
154+
(mockAiService.createThread as ReturnType<typeof vi.fn>).mockRejectedValue('Error message');
137155

138156
component.message = 'User question';
139-
component.createThread();
157+
await component.createThread();
140158

141159
expect(component.messagesChain[1]).toEqual({
142160
type: 'ai-error',
143161
text: 'Error message',
144162
});
145163
});
146164

147-
it('should use suggested message when provided to createThread', () => {
148-
mockTablesService.createAIthread.mockReturnValue(of({ threadId: 'thread-123', responseMessage: 'AI response' }));
165+
it('should use suggested message when provided to createThread', async () => {
166+
(mockAiService.createThread as ReturnType<typeof vi.fn>).mockResolvedValue({
167+
threadId: 'thread-123',
168+
stream: mockStream('AI response'),
169+
});
149170

150-
component.createThread('Suggested question');
171+
await component.createThread('Suggested question');
151172

152173
expect(component.messagesChain[0].text).toBe('Suggested question');
153174
});
@@ -157,12 +178,12 @@ describe('DbTableAiPanelComponent', () => {
157178
expect(mockTableStateService.handleViewAIpanel).toHaveBeenCalled();
158179
});
159180

160-
it('should clear message after sending', () => {
161-
mockTablesService.requestAImessage.mockReturnValue(of('AI response'));
181+
it('should clear message after sending', async () => {
182+
(mockAiService.sendMessage as ReturnType<typeof vi.fn>).mockResolvedValue(mockStream('AI response'));
162183

163184
component.message = 'Test message';
164185
component.threadID = 'thread-123';
165-
component.sendMessage();
186+
await component.sendMessage();
166187

167188
expect(component.message).toBe('');
168189
expect(component.charactrsNumber).toBe(0);

0 commit comments

Comments
 (0)