Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- New tab via Cmd+T no longer flashes focus back to the previous tab in the same window group
- Cmd+X with no selection cuts the current line, matching VS Code, Sublime, and Xcode (#1075)

### Added

- AI Chat: panel layout redesign. The right inspector now has a Details / AI Chat segmented picker at the top. The chat tab is composer-focused: empty state is a small icon and one-line title, and all chat actions live in a single-row composer footer (mention, slash commands, mode picker, model picker, history, new conversation, send). The mode picker (Ask / Edit / Agent) is saved to settings but does not yet change provider behavior.
- AI Chat: panel layout redesign. The right inspector has a Details / AI Chat segmented picker at the top, with conversation history and new-conversation actions trailing on the same row. The chat tab is composer-focused: composer is a pill-shaped input with an Apple Intelligence focus glow, and a single-row footer (mention, slash commands, mode picker, model picker, send). The mode picker (Ask / Edit / Agent) is saved to settings but does not yet change provider behavior.
- AI Chat: inline model picker in the composer with per-turn model attribution. Switch between configured providers and any of their available models without leaving the chat. The model that produced each assistant turn is shown in the message footer.
- AI Chat: slash commands `/explain`, `/optimize`, `/fix`, and `/help`. Type the command in the composer or pick from the slash menu next to the model picker. `/explain`, `/optimize`, and `/fix` operate on the current query in the active editor. `/help` lists the commands inline.
- AI Chat: attach context to a message via the `@` menu next to the slash menu, or by typing `@` directly in the composer.
Expand Down
82 changes: 6 additions & 76 deletions TablePro/Views/AIChat/AIChatPanelView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ struct AIChatPanelView: View {
@State private var isUserScrolledUp = false
@State private var lastAutoScrollTime: Date = .distantPast
@State private var mentionState = MentionPopoverState()
@State private var showClearConfirmation = false

private var hasConfiguredProvider: Bool {
settingsManager.ai.hasActiveProvider
Expand All @@ -42,17 +41,6 @@ struct AIChatPanelView: View {
inputArea
}
}
.alert(
String(localized: "Clear All Conversations?"),
isPresented: $showClearConfirmation
) {
Button(String(localized: "Clear"), role: .destructive) {
viewModel.clearConversation()
}
Button(String(localized: "Cancel"), role: .cancel) {}
} message: {
Text(String(localized: "This will permanently delete all conversation history."))
}
.onAppear {
viewModel.connection = connection
}
Expand Down Expand Up @@ -83,17 +71,11 @@ struct AIChatPanelView: View {
// MARK: - Empty States

private var emptyState: some View {
VStack(spacing: 6) {
Image(systemName: "sparkles")
.font(.system(size: 22))
.foregroundStyle(.secondary)
Text(String(localized: "Ask AI about your database"))
.font(.callout)
.foregroundStyle(.primary)
Text(String(localized: "AI responses may be inaccurate"))
.font(.caption)
.foregroundStyle(.secondary)
}
EmptyStateView(
icon: "sparkles",
title: String(localized: "Ask AI about your database"),
description: String(localized: "AI responses may be inaccurate")
)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}

Expand Down Expand Up @@ -234,7 +216,7 @@ struct AIChatPanelView: View {
onRemove: { viewModel.detach($0) }
)

ChatComposerTextView(
ChatComposerView(
text: $viewModel.inputText,
placeholder: String(localized: "Ask about your database..."),
minLines: 1,
Expand All @@ -258,8 +240,6 @@ struct AIChatPanelView: View {
modeMenu
modelPicker
Spacer()
historyMenu
newConversationButton
sendOrStopButton
}
}
Expand Down Expand Up @@ -301,56 +281,6 @@ struct AIChatPanelView: View {
.help(String(localized: "Chat mode"))
}

private var newConversationButton: some View {
Button {
viewModel.startNewConversation()
} label: {
Image(systemName: "square.and.pencil")
.font(.caption)
.foregroundStyle(.secondary)
}
.buttonStyle(.plain)
.help(String(localized: "New Conversation"))
}

private var historyMenu: some View {
Menu {
if !viewModel.conversations.isEmpty {
Section(String(localized: "Recent Conversations")) {
ForEach(viewModel.conversations) { conversation in
Button {
viewModel.switchConversation(to: conversation.id)
} label: {
HStack {
Text(conversation.title.isEmpty
? String(localized: "Untitled")
: conversation.title)
if conversation.id == viewModel.activeConversationID {
Image(systemName: "checkmark")
}
}
}
}
}
Divider()
}
Button(role: .destructive) {
showClearConfirmation = true
} label: {
Label(String(localized: "Clear Recents"), systemImage: "trash")
}
.disabled(viewModel.conversations.isEmpty)
} label: {
Image(systemName: "clock")
.font(.caption)
.foregroundStyle(.secondary)
}
.menuStyle(.borderlessButton)
.menuIndicator(.hidden)
.fixedSize()
.help(String(localized: "Conversation history"))
}

@ViewBuilder
private var sendOrStopButton: some View {
if viewModel.isStreaming {
Expand Down
Loading
Loading