Skip to content

Commit e6e46cf

Browse files
committed
more improvements
1 parent 16bda85 commit e6e46cf

File tree

10 files changed

+211
-148
lines changed

10 files changed

+211
-148
lines changed

front_end/panels/ai_chat/ui/AIChatPanel.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -793,14 +793,11 @@ export class AIChatPanel extends UI.Panel.Panel {
793793
#setupMCPIntegration(): void {
794794
const initAndRefresh = async () => {
795795
try {
796-
const mcpConfig = getMCPConfig();
797-
// Only auto-connect if both enabled and autostart are true
798-
if (mcpConfig.enabled && mcpConfig.autostart) {
799-
await MCPRegistry.init();
800-
await MCPRegistry.refresh();
801-
const status = MCPRegistry.getStatus();
802-
logger.info('MCP autostart completed', status);
803-
}
796+
// Always attempt to connect to MCP on startup
797+
await MCPRegistry.init();
798+
await MCPRegistry.refresh();
799+
const status = MCPRegistry.getStatus();
800+
logger.info('MCP auto-connect completed', status);
804801
} catch (err) {
805802
logger.error('Failed to initialize MCP', err);
806803
}
@@ -2086,7 +2083,8 @@ export class AIChatPanel extends UI.Panel.Panel {
20862083
}
20872084

20882085
#onHelpClick(): void {
2089-
HelpDialog.show();
2086+
// Open external getting started docs in a new tab
2087+
UI.UIUtils.openInNewTab('https://browseroperator.io/docs/getting-started/');
20902088
}
20912089

20922090
/**

front_end/panels/ai_chat/ui/ChatView.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,12 @@ export class ChatView extends HTMLElement {
288288
this.#selectedPromptType = data.selectedAgentType;
289289
}
290290

291-
// Check if we should exit the first message view state
292-
// We're no longer in first message view if there are user messages
293-
const hasUserMessages = data.messages && Array.isArray(data.messages) ?
291+
// Check if we should show the centered first-message view
292+
// Only show it if there are no user messages AND at most one message (welcome)
293+
const messageCount = data.messages && Array.isArray(data.messages) ? data.messages.length : 0;
294+
const hasUserMessages = data.messages && Array.isArray(data.messages) ?
294295
data.messages.some(msg => msg && msg.entity === ChatMessageEntity.USER) : false;
295-
this.#isFirstMessageView = !hasUserMessages;
296+
this.#isFirstMessageView = !hasUserMessages && messageCount <= 1;
296297

297298
// Controller owns session message upserts; no UI sync required
298299

front_end/panels/ai_chat/ui/HelpDialog.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ const UIStrings = {
3535
*/
3636
importantNotice: 'Important Notice',
3737
/**
38-
*@description Alpha version warning
38+
*@description Beta version warning
3939
*/
40-
alphaVersionWarning: 'Alpha Version: This is an alpha version of the Browser Operator - AI Assistant feature. Do not use it for production or sensitive data.',
40+
betaVersionWarning: 'Beta Version: This is an beta version of the Browser Operator - AI Assistant feature. Do not use it for production or sensitive data.',
4141
/**
4242
*@description Data sharing notice
4343
*/
@@ -214,7 +214,7 @@ export class HelpDialog {
214214

215215
const disclaimerWarning = document.createElement('p');
216216
disclaimerWarning.className = 'help-disclaimer-warning';
217-
disclaimerWarning.textContent = i18nString(UIStrings.alphaVersionWarning);
217+
disclaimerWarning.textContent = i18nString(UIStrings.betaVersionWarning);
218218
disclaimerSection.appendChild(disclaimerWarning);
219219

220220
const disclaimerNote = document.createElement('p');

front_end/panels/ai_chat/ui/SettingsDialog.ts

Lines changed: 148 additions & 121 deletions
Large diffs are not rendered by default.

front_end/panels/ai_chat/ui/chatView.css

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
overflow: hidden;
1212
font-family: var(--default-font-family);
1313
background-color: var(--sys-color-cdt-base-container);
14+
/* Reserve space for overlayed input bar within nested scrollers */
15+
--ai-input-bar-reserved-space: 120px;
1416
--message-max-width: 80%;
1517
--message-horizontal-padding: var(--sys-size-5);
1618
--primary-color: var(--color-primary);
@@ -41,16 +43,30 @@ ai-input-bar {
4143
width: 100%;
4244
}
4345

46+
/* Float input bar above content; messages scroll behind */
47+
.chat-view-container > ai-input-bar {
48+
position: absolute;
49+
left: 0;
50+
right: 0;
51+
bottom: 0;
52+
z-index: 5;
53+
}
54+
55+
/* Center the input bar in first-message (centered) view */
56+
/* In centered view the input is rendered inside centered-content, so no overlay positioning needed */
57+
4458
.chat-view-container {
4559
display: flex;
4660
flex-direction: column;
4761
height: 100%;
4862
width: 100%;
4963
position: relative;
64+
overflow: hidden; /* Ensure only the message list scrolls */
5065
backdrop-filter: blur(10px);
5166
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
5267
}
5368

69+
/* Legacy selector kept for backwards compatibility (unused by ai-message-list) */
5470
.messages-container {
5571
flex: 1 1 auto;
5672
overflow-y: auto;
@@ -59,7 +75,7 @@ ai-input-bar {
5975
scroll-behavior: smooth;
6076
padding: 12px 16px;
6177
background-color: var(--color-background);
62-
padding-bottom: calc(12px + 80px);
78+
padding-bottom: var(--ai-input-bar-reserved-space);
6379
min-height: 100px;
6480
}
6581

@@ -84,6 +100,12 @@ ai-input-bar {
84100
animation: expandToFull 0.5s cubic-bezier(0.4, 0, 0.2, 1);
85101
}
86102

103+
/* In expanded (conversation) view, reserve bottom space so the floating
104+
input bar does not overlap the last messages. */
105+
.chat-view-container.expanded-view {
106+
padding-bottom: 150px; /* tune if input height changes */
107+
}
108+
87109
@keyframes expandToFull {
88110
from { opacity: 0.8; }
89111
to { opacity: 1; }
@@ -531,8 +553,7 @@ ai-input-bar {
531553
display: flex;
532554
justify-content: flex-end;
533555
padding: 4px 0;
534-
margin-top: 8px;
535-
margin-bottom: 8px;
556+
margin-bottom: 28px;
536557
border-top: 1px solid var(--color-details-hairline);
537558
opacity: 0.8;
538559
transition: opacity var(--transition-fast);

front_end/panels/ai_chat/ui/input/InputBar.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export class InputBar extends HTMLElement {
9696
.options=${this.#modelOptions}
9797
.selected=${this.#selectedModel}
9898
.disabled=${this.#modelSelectorDisabled}
99+
.preferAbove=${!this.#centered}
99100
@change=${(e: CustomEvent) => {
100101
const value = (e.detail as any)?.value as string | undefined;
101102
if (value) {

front_end/panels/ai_chat/ui/message/MessageList.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ export class MessageList extends HTMLElement {
6565
scroll-behavior: smooth;
6666
padding: 12px 16px;
6767
background-color: var(--color-background);
68-
/* Reduced bottom padding since input bar is no longer sticky */
69-
padding-bottom: 16px;
68+
padding-bottom: 12px;
7069
min-height: 100px;
7170
position: relative;
7271
z-index: 0;

front_end/panels/ai_chat/ui/message/StructuredResponseRender.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ export function renderStructuredResponse(
3939
</div>
4040
` : state.aiState === 'opened' ? html`
4141
<div class="deep-research-actions">
42-
<button class="view-document-btn" @click=${open} title="Open full report in document viewer">📄 View Full Report</button>
42+
<button class="view-document-btn" @click=${open} title="Open in full screen document viewer">📄 View Full Screen</button>
4343
</div>
4444
` : html`
4545
<div class="inline-markdown-report">
4646
<div class="inline-report-header"><h3>Full Research Report</h3></div>
4747
<div class="inline-report-content">${renderMarkdown(data.markdownReport, markdownRenderer, open)}</div>
4848
</div>
4949
<div class="deep-research-actions">
50-
<button class="view-document-btn" @click=${open} title="Open full report in document viewer">📄 ${state.isLastMessage ? '' : 'View Full Report'}</button>
50+
<button class="view-document-btn" @click=${open} title="Open in full screen document viewer">📄 ${state.isLastMessage ? '' : 'View Full Screen'}</button>
5151
</div>
5252
`}
5353
</div>

front_end/panels/ai_chat/ui/model_selector/ModelSelector.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,37 @@ export class ModelSelector extends HTMLElement {
1919
#open = false;
2020
#query = '';
2121
#highlighted = 0;
22+
#preferAbove = false;
23+
#forceSearchable = false;
2224

2325
get options(): ModelOption[] { return this.#options; }
2426
set options(v: ModelOption[]) { this.#options = v || []; this.#render(); }
2527
get selected(): string | undefined { return this.#selected; }
2628
set selected(v: string | undefined) { this.#selected = v; this.#render(); }
2729
get disabled(): boolean { return this.#disabled; }
2830
set disabled(v: boolean) { this.#disabled = !!v; this.#render(); }
31+
get preferAbove(): boolean { return this.#preferAbove; }
32+
set preferAbove(v: boolean) { this.#preferAbove = !!v; this.#render(); }
33+
get forceSearchable(): boolean { return this.#forceSearchable; }
34+
set forceSearchable(v: boolean) { this.#forceSearchable = !!v; this.#render(); }
2935

3036
connectedCallback(): void { this.#render(); }
3137

3238
#emitChange(value: string): void {
3339
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value }}));
3440
}
3541

36-
#toggle = (e: Event) => { e.preventDefault(); if (!this.#disabled) { this.#open = !this.#open; this.#render(); } };
42+
#toggle = (e: Event) => {
43+
e.preventDefault();
44+
if (this.#disabled) return;
45+
const wasOpen = this.#open;
46+
this.#open = !this.#open;
47+
this.#render();
48+
if (!wasOpen && this.#open) {
49+
// Notify host that the selector opened (used to lazily refresh models)
50+
this.dispatchEvent(new CustomEvent('model-selector-focus', {bubbles: true}));
51+
}
52+
};
3753
#onSearch = (e: Event) => { this.#query = (e.target as HTMLInputElement).value; this.#highlighted = 0; this.#render(); };
3854
#onKeydown = (e: KeyboardEvent) => {
3955
const filtered = this.#filtered();
@@ -49,7 +65,7 @@ export class ModelSelector extends HTMLElement {
4965
return this.#options.filter(o => o.label.toLowerCase().includes(q) || o.value.toLowerCase().includes(q));
5066
}
5167

52-
#isSearchable(): boolean { return (this.#options?.length || 0) >= 20; }
68+
#isSearchable(): boolean { return this.#forceSearchable || (this.#options?.length || 0) >= 20; }
5369

5470
#render(): void {
5571
const selectedLabel = this.#options.find(o => o.value === this.#selected)?.label || this.#selected || 'Select Model';
@@ -72,7 +88,7 @@ export class ModelSelector extends HTMLElement {
7288
<span class="dropdown-arrow">${this.#open ? '▲' : '▼'}</span>
7389
</button>
7490
${this.#open ? html`
75-
<div class="model-dropdown below" @click=${(e: Event) => e.stopPropagation()}>
91+
<div class="model-dropdown ${this.#preferAbove ? 'above' : 'below'}" @click=${(e: Event) => e.stopPropagation()}>
7692
<input class="model-search" type="text" placeholder="Search models..." @input=${this.#onSearch} @keydown=${this.#onKeydown} .value=${this.#query}>
7793
<div class="model-options">
7894
${filtered.map((o, i) => html`

front_end/ui/components/markdown_view/MarkdownView.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ export class MarkdownLitRenderer {
320320
class="view-document-btn"
321321
@click=${() => this.openTableInViewer(token)}
322322
title="Open table in full document viewer for better viewing">
323-
📊 View Full Table
323+
📊 View Full Screen
324324
</button>
325325
</div>
326326
` : ''}

0 commit comments

Comments
 (0)