Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI tab backup #319

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5afc528
Starting adding tab support, but cannot extend directly from history.
mohamedilaiwi Jun 18, 2024
90bc82a
Added tab support with highlighting
mohamedilaiwi Jun 19, 2024
94295d0
Making LLMSession more Generic
mohamedilaiwi Jun 22, 2024
87a6ae6
parsing bug with chat and format
Jun 22, 2024
25e9dd0
Need to resolve answering questions properly
milaiwi Jun 22, 2024
5f59c9b
Merge branch 'create-dir-files-on-rightclick'
milaiwi Jun 26, 2024
dde3f79
Merge branch 'main' into add-tab-support
milaiwi Jun 26, 2024
5b7665e
Added new tab support
milaiwi Jun 26, 2024
f254e94
Refined some code
mohamedilaiwi Jun 27, 2024
8eb8e84
Refined UI even more
mohamedilaiwi Jul 9, 2024
47667e2
Merging UI and Tab Support
mohamedilaiwi Jul 9, 2024
cee70b6
Merge branch 'add-tab-support' into ui-tab-support
mohamedilaiwi Jul 9, 2024
7c9a9b9
Merged with add-tab-support
mohamedilaiwi Jul 9, 2024
4f34822
Added Tab Support with more UI Changes
mohamedilaiwi Jul 9, 2024
13ae394
More changes to UI. Added Scrolling
mohamedilaiwi Jul 10, 2024
9b456f5
Tab better UI.Does not display + on null tabs. Shifts tabs on delete
mohamedilaiwi Jul 12, 2024
b1e17c2
Temp save
mohamedilaiwi Jul 13, 2024
b62e4e4
Mostly complete. Need to add name dropping on hover.
mohamedilaiwi Jul 15, 2024
bc51bd5
Added displaying tab path when hovering
mohamedilaiwi Jul 15, 2024
2e23e7d
Complete
mohamedilaiwi Jul 16, 2024
a9ce1bd
Changes needed
mohamedilaiwi Jul 16, 2024
b79d432
Completely fixed
mohamedilaiwi Jul 17, 2024
b5f38e9
Complete with fixed merge conflicts
mohamedilaiwi Jul 17, 2024
6f9c6a4
replaceWord added. cleaned up codebase
mohamedilaiwi Jul 21, 2024
df16e5d
Added replaceWord. Cleaned up codebase
mohamedilaiwi Jul 21, 2024
a1702d5
cleaned up sidebars. Final commit
milaiwi Jul 24, 2024
16589ff
Complete
milaiwi Jul 24, 2024
32a86f4
force line ending lf
samlhuillier Jul 29, 2024
66ba83c
test no notarize unless on main branch
samlhuillier Jul 29, 2024
3402938
update release notarize script
samlhuillier Jul 29, 2024
2bc39af
Revert "update release notarize script"
samlhuillier Jul 29, 2024
d6be068
notarize on release intentional
samlhuillier Jul 29, 2024
83478f3
Merge branch 'fix/test-line-endings' into ui-tab-backup
samlhuillier Jul 29, 2024
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
73 changes: 70 additions & 3 deletions electron/main/electron-store/ipcHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ import path from 'path'

import { ipcMain } from 'electron'
import Store from 'electron-store'

import WindowsManager from '../common/windowManager'

import {
Tab,
EmbeddingModelConfig,
EmbeddingModelWithLocalPath,
EmbeddingModelWithRepo,
StoreKeys,
StoreSchema,
} from './storeConfig'

import WindowsManager from '../common/windowManager'

import { initializeAndMaybeMigrateStore } from './storeSchemaMigrator'
import { ChatHistory } from '@/components/Chat/chatUtils'

Expand Down Expand Up @@ -114,6 +115,13 @@ export const registerStoreHandlers = (store: Store<StoreSchema>, windowsManager:

ipcMain.handle('get-sb-compact', () => store.get(StoreKeys.IsSBCompact))

ipcMain.handle('get-editor-flex-center', () => store.get(StoreKeys.EditorFlexCenter))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain what this feature does? I tried it in settings and didn't notice any changes in the editor nor anywhere else

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: I now see a slight difference in padding - do you have strong opinions on adding this feature? I think it wouldn't really be clear to the user what "Editor Flex" is + I think we should just have a standard default for things like padding so that we reduce user load in having to make decisions

Copy link
Collaborator Author

@milaiwi milaiwi Jul 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference in padding depends on your screen size. On a Mac or small monitor, the difference is negligible. However, on a standard monitor (21–24 inches), like the one I use, it significantly impacts the UI. I can try to change the name and subcaption to make it more clearer.

I think we should just have a standard default for things like padding so that we reduce user load in having to make decisions

I don't think this impacts user load that much.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok sounds good. Why don't we even say something in the subcaption like "this is useful if you have a big monitor"?

Copy link
Collaborator

@samlhuillier samlhuillier Jul 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or perhaps there's even some kind of standard tailwind/css config for this kind of thing where you adjust padding based on screen size?


ipcMain.handle('set-editor-flex-center', (event, setEditorFlexCenter) => {
store.set(StoreKeys.EditorFlexCenter, setEditorFlexCenter)
event.sender.send('editor-flex-center-changed', setEditorFlexCenter)
})

ipcMain.handle('set-analytics-mode', (event, isAnalytics) => {
store.set(StoreKeys.Analytics, isAnalytics)
})
Expand Down Expand Up @@ -191,9 +199,68 @@ export const registerStoreHandlers = (store: Store<StoreSchema>, windowsManager:
const chatHistoriesMap = store.get(StoreKeys.ChatHistories)
const allChatHistories = chatHistoriesMap[vaultDir] || []
const filteredChatHistories = allChatHistories.filter((item) => item.id !== chatID)

chatHistoriesMap[vaultDir] = filteredChatHistories.reverse()
store.set(StoreKeys.ChatHistories, chatHistoriesMap)
})

ipcMain.handle('get-current-open-files', () => store.get(StoreKeys.OpenTabs) || [])

ipcMain.handle('set-current-open-files', (event, action, args) => {
const openTabs: Tab[] = store.get(StoreKeys.OpenTabs) || []

const addTab = ({ tab }: { tab: Tab }) => {
if (tab === null) return
const existingTab = openTabs.findIndex((item) => item.filePath === tab.filePath)

/* If tab is already open, do not do anything */
if (existingTab !== -1) return

openTabs.push(tab)
store.set(StoreKeys.OpenTabs, openTabs)
}

const removeTab = ({ tabId, idx, newIndex }: { tabId: string; idx: number; newIndex: number }) => {
openTabs[idx].lastAccessed = false
openTabs[newIndex].lastAccessed = true
const updatedTabs = openTabs.filter((tab) => tab.id !== tabId)
store.set(StoreKeys.OpenTabs, updatedTabs)
Comment on lines +223 to +227
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logic: Potential issue: Ensure idx and newIndex are valid indices to avoid runtime errors.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add the checking the bot recommends here @milaiwi ?

Copy link
Collaborator Author

@milaiwi milaiwi Jul 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'll go ahead and add it, but either way I'm pretty sure it is not possible for idx and newIndex not to be valid since tabId is guaranteed to exist which means idx and newIndex must exist.

}

const clearAllTabs = () => {
store.set(StoreKeys.OpenTabs, [])
}

const updateTab = ({ draggedIndex, targetIndex }: { draggedIndex: number; targetIndex: number }) => {
// Swap dragged and target
;[openTabs[draggedIndex], openTabs[targetIndex]] = [openTabs[targetIndex], openTabs[draggedIndex]]
store.set(StoreKeys.OpenTabs, openTabs)
}

const selectTab = ({ tabs }: { tabs: Tab[] }) => {
store.set(StoreKeys.OpenTabs, tabs)
}

switch (action) {
case 'add':
addTab(args)
break
case 'remove':
removeTab(args)
break
case 'update':
updateTab(args)
break
case 'select':
selectTab(args)
break
case 'clear':
clearAllTabs()
break
default:
throw new Error('Unsupported action type')
}
})
}

export function getDefaultEmbeddingModelConfig(store: Store<StoreSchema>): EmbeddingModelConfig {
Expand Down
13 changes: 13 additions & 0 deletions electron/main/electron-store/storeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ export type HardwareConfig = {
useVulkan: boolean
}

export type Tab = {
id: string // Unique ID for the tab, useful for operations
filePath: string // Path to the file open in the tab
title: string // Title of the tab
lastAccessed: boolean
// timeOpened: Date; // Timestamp to preserve order
// isDirty: boolean; // Flag to indicate unsaved changes
}

export interface StoreSchema {
hasUserOpenedAppBefore: boolean
schemaVersion: number
Expand All @@ -72,6 +81,8 @@ export interface StoreSchema {
isSBCompact: boolean
DisplayMarkdown: boolean
spellCheck: string
EditorFlexCenter: boolean
OpenTabs: Tab[]
}

export enum StoreKeys {
Expand All @@ -91,4 +102,6 @@ export enum StoreKeys {
IsSBCompact = 'isSBCompact',
DisplayMarkdown = 'DisplayMarkdown',
SpellCheck = 'spellCheck',
EditorFlexCenter = 'editorFlexCenter',
OpenTabs = 'OpenTabs',
}
18 changes: 14 additions & 4 deletions electron/main/electron-utils/ipcHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const electronUtilsHandlers = (
new MenuItem({
label: 'New Note',
click: () => {
event.sender.send('add-new-note-listener')
event.sender.send('add-new-note-response')
},
}),
)
Expand All @@ -29,7 +29,7 @@ const electronUtilsHandlers = (
new MenuItem({
label: 'New Directory',
click: () => {
event.sender.send('add-new-directory-listener')
event.sender.send('add-new-directory-response')
},
}),
)
Expand All @@ -49,7 +49,7 @@ const electronUtilsHandlers = (
new MenuItem({
label: 'New Note',
click: () => {
event.sender.send('add-new-note-listener', file.relativePath)
event.sender.send('add-new-note-response', file.relativePath)
},
}),
)
Expand All @@ -58,7 +58,7 @@ const electronUtilsHandlers = (
new MenuItem({
label: 'New Directory',
click: () => {
event.sender.send('add-new-directory-listener', file.path)
event.sender.send('add-new-directory-response', file.path)
},
}),
)
Expand Down Expand Up @@ -153,6 +153,16 @@ const electronUtilsHandlers = (
})

ipcMain.handle('get-reor-app-version', async () => app.getVersion())

// Used on EmptyPage.tsx to create a new file
ipcMain.handle('empty-new-note-listener', (event, relativePath) => {
event.sender.send('add-new-note-response', relativePath)
})

// Used on EmptyPage.tsx to create a new directory
ipcMain.handle('empty-new-directory-listener', (event, relativePath) => {
event.sender.send('add-new-directory-response', relativePath)
})
}

export default electronUtilsHandlers
11 changes: 8 additions & 3 deletions electron/main/llm/ipcHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MessageStreamEvent } from '@anthropic-ai/sdk/resources'
import { ipcMain, IpcMainInvokeEvent } from 'electron'
import Store from 'electron-store'
import { ProgressResponse } from 'ollama'
import { ChatCompletionChunk } from 'openai/resources/chat/completions'
import { ChatCompletionChunk, ChatCompletionMessageParam } from 'openai/resources/chat/completions'

import { LLMConfig, StoreKeys, StoreSchema } from '../electron-store/storeConfig'

Expand Down Expand Up @@ -44,13 +44,18 @@ export const registerLLMSessionHandlers = (store: Store<StoreSchema>) => {
event.sender.send('anthropicTokenStream', chatHistory.id, chunk)
}

const transformedChatHistory: ChatCompletionMessageParam[] = chatHistory.displayableChatHistory.map((message) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the reason for this change out of interest?

Something to note is that we are going to move the LLM calling logic all to the renderer process, it'll make it so much easier to not have to deal with all this messy logic with chunks being passed via IPC 😅

const { messageType, context, visibleContent, ...rest } = message
return rest
})

switch (llmConfig.type) {
case LLMType.OpenAI:
await openAISession.streamingResponse(
llmName,
llmConfig,
isJSONMode,
chatHistory.displayableChatHistory,
transformedChatHistory,
handleOpenAIChunk,
store.get(StoreKeys.LLMGenerationParameters),
)
Expand All @@ -60,7 +65,7 @@ export const registerLLMSessionHandlers = (store: Store<StoreSchema>) => {
llmName,
llmConfig,
isJSONMode,
chatHistory.displayableChatHistory,
transformedChatHistory,
handleAnthropicChunk,
store.get(StoreKeys.LLMGenerationParameters),
)
Expand Down
12 changes: 9 additions & 3 deletions electron/preload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
HardwareConfig,
LLMConfig,
LLMGenerationParameters,
Tab,
} from 'electron/main/electron-store/storeConfig'
import {
AugmentPromptWithFileProps,
Expand Down Expand Up @@ -56,6 +57,8 @@ const electronUtils = {
showFileItemContextMenu: createIPCHandler<(file: FileInfoNode) => Promise<void>>('show-context-menu-file-item'),
showMenuItemContext: createIPCHandler<() => Promise<void>>('show-context-menu-item'),
showChatItemContext: createIPCHandler<(chatRow: ChatHistoryMetadata) => Promise<void>>('show-chat-menu-item'),
showCreateFileModal: createIPCHandler<(relativePath: string) => Promise<void>>('empty-new-note-listener'),
showCreateDirectoryModal: createIPCHandler<(relativePath: string) => Promise<void>>('empty-new-directory-listener'),
}

const electronStore = {
Expand Down Expand Up @@ -85,19 +88,22 @@ const electronStore = {
createIPCHandler<(params: LLMGenerationParameters) => Promise<void>>('set-llm-generation-params'),
getAnalyticsMode: createIPCHandler<() => Promise<boolean>>('get-analytics-mode'),
setAnalyticsMode: createIPCHandler<(isAnalytics: boolean) => Promise<void>>('set-analytics-mode'),
getSpellCheckMode: createIPCHandler<() => Promise<string>>('get-spellcheck-mode'),
setSpellCheckMode: createIPCHandler<(isSpellCheck: string) => Promise<void>>('set-spellcheck-mode'),
getSpellCheckMode: createIPCHandler<() => Promise<boolean>>('get-spellcheck-mode'),
setSpellCheckMode: createIPCHandler<(isSpellCheck: boolean) => Promise<void>>('set-spellcheck-mode'),
getHasUserOpenedAppBefore: createIPCHandler<() => Promise<boolean>>('has-user-opened-app-before'),
setHasUserOpenedAppBefore: createIPCHandler<() => Promise<void>>('set-user-has-opened-app-before'),
getAllChatHistories: createIPCHandler<() => Promise<ChatHistory[]>>('get-all-chat-histories'),
updateChatHistory: createIPCHandler<(chatHistory: ChatHistory) => Promise<void>>('update-chat-history'),
removeChatHistoryAtID: createIPCHandler<(chatID: string) => Promise<void>>('remove-chat-history-at-id'),
getChatHistory: createIPCHandler<(chatID: string) => Promise<ChatHistory>>('get-chat-history'),

getSBCompact: createIPCHandler<() => Promise<boolean>>('get-sb-compact'),
setSBCompact: createIPCHandler<(isSBCompact: boolean) => Promise<void>>('set-sb-compact'),
getDisplayMarkdown: createIPCHandler<() => Promise<boolean>>('get-display-markdown'),
setDisplayMarkdown: createIPCHandler<(displayMarkdown: boolean) => Promise<void>>('set-display-markdown'),
getEditorFlexCenter: createIPCHandler<() => Promise<boolean>>('get-editor-flex-center'),
setEditorFlexCenter: createIPCHandler<(editorFlexCenter: boolean) => Promise<void>>('set-editor-flex-center'),
getCurrentOpenFiles: createIPCHandler<() => Promise<Tab[]>>('get-current-open-files'),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use getCurrentOpenTabs here rather than getCurrentOpenFiles and for other cases where we are doing tab-based operations. I think it makes it clearer what the handlers are doing like that

setCurrentOpenFiles: createIPCHandler<(action: string, args: any) => Promise<void>>('set-current-open-files'),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the current convention in the repo is to have a separate handler for each kind of operation, so we'd have like add/remove etc. as separate handlers. I like this because it means we have strong typing for the handlers.

What do you think about this?

}

const fileSystem = {
Expand Down
Loading
Loading