Skip to content

Commit

Permalink
Merge pull request #339 from milaiwi/tab-support
Browse files Browse the repository at this point in the history
Added Tab Support
  • Loading branch information
milaiwi authored Aug 15, 2024
2 parents 14e79ff + ba990dd commit accf879
Show file tree
Hide file tree
Showing 35 changed files with 1,077 additions and 474 deletions.
62 changes: 59 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))

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,57 @@ 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('add-current-open-files', (event, tab: Tab) => {
if (tab === null) return
const openTabs: Tab[] = store.get(StoreKeys.OpenTabs) || []
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)
})

ipcMain.handle('remove-current-open-files', (event, tabId: string, idx: number, newIndex: number) => {
// Ensure indices are within range
const openTabs: Tab[] = store.get(StoreKeys.OpenTabs) || []
if (idx < 0 || idx >= openTabs.length || newIndex < 0 || newIndex >= openTabs.length) return
openTabs[idx].lastAccessed = false
openTabs[newIndex].lastAccessed = true
const updatedTabs = openTabs.filter((tab) => tab.id !== tabId)
store.set(StoreKeys.OpenTabs, updatedTabs)
})

ipcMain.handle('clear-current-open-files', () => {
store.set(StoreKeys.OpenTabs, [])
})

ipcMain.handle('update-current-open-files', (event, draggedIndex: number, targetIndex: number) => {
const openTabs: Tab[] = store.get(StoreKeys.OpenTabs) || []
if (draggedIndex < 0 || draggedIndex >= openTabs.length || targetIndex < 0 || targetIndex >= openTabs.length) return
;[openTabs[draggedIndex], openTabs[targetIndex]] = [openTabs[targetIndex], openTabs[draggedIndex]]
store.set(StoreKeys.OpenTabs, openTabs)
})

ipcMain.handle('set-current-open-files', (event, tabs: Tab[]) => {
if (tabs) store.set(StoreKeys.OpenTabs, tabs)
})

ipcMain.handle('remove-current-open-files-by-path', (event, filePath: string) => {
if (!filePath) return
const openTabs: Tab[] = store.get(StoreKeys.OpenTabs) || []
// Filter out selected tab
const updatedTabs = openTabs.filter((tab) => tab.filePath !== filePath)
store.set(StoreKeys.OpenTabs, updatedTabs)
event.sender.send('remove-tab-after-deletion', updatedTabs)
})
}

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',
}
50 changes: 0 additions & 50 deletions electron/main/electron-utils/ipcHandlers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import * as fs from 'fs/promises'

import { app, BrowserWindow, dialog, ipcMain, Menu, MenuItem, shell } from 'electron'
import Store from 'electron-store'

Expand All @@ -15,57 +13,9 @@ const electronUtilsHandlers = (
url: string | undefined,
indexHtml: string,
) => {
ipcMain.handle('show-context-menu-item', (event) => {
const menu = new Menu()

menu.append(
new MenuItem({
label: 'New Note',
click: () => {
event.sender.send('add-new-note-listener')
},
}),
)

menu.append(
new MenuItem({
label: 'New Directory',
click: () => {
event.sender.send('add-new-directory-listener')
},
}),
)

const browserWindow = BrowserWindow.fromWebContents(event.sender)
if (browserWindow) menu.popup({ window: browserWindow })
})

ipcMain.handle('show-context-menu-file-item', async (event, file: FileInfoNode) => {
const menu = new Menu()

const stats = await fs.stat(file.path)
const isDirectory = stats.isDirectory()

if (isDirectory) {
menu.append(
new MenuItem({
label: 'New Note',
click: () => {
event.sender.send('add-new-note-listener', file.relativePath)
},
}),
)

menu.append(
new MenuItem({
label: 'New Directory',
click: () => {
event.sender.send('add-new-directory-listener', file.path)
},
}),
)
}

menu.append(
new MenuItem({
label: 'Delete',
Expand Down
2 changes: 2 additions & 0 deletions electron/main/path/ipcHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const pathHandlers = () => {

ipcMain.handle('path-relative', (event, from: string, to: string) => path.relative(from, to))

ipcMain.handle('path-absolute', (event, filePath: string) => path.isAbsolute(filePath))

ipcMain.handle('add-extension-if-no-extension-present', (event, pathString: string) =>
addExtensionToFilenameIfNoExtensionPresent(pathString, markdownExtensions, '.md'),
)
Expand Down
20 changes: 16 additions & 4 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 @@ -54,7 +55,6 @@ const electronUtils = {
openNewWindow: createIPCHandler<() => Promise<void>>('open-new-window'),
getReorAppVersion: createIPCHandler<() => Promise<string>>('get-reor-app-version'),
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'),
}

Expand Down Expand Up @@ -85,19 +85,30 @@ 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'),
getCurrentOpenTabs: createIPCHandler<() => Promise<Tab[]>>('get-current-open-files'),
setCurrentOpenTabs: createIPCHandler<(action: string, args: any) => Promise<void>>('set-current-open-files'),
addOpenTabs: createIPCHandler<(tab: Tab) => Promise<void>>('add-current-open-files'),
removeOpenTabs:
createIPCHandler<(tabId: string, idx: number, newIndex: number) => Promise<void>>('remove-current-open-files'),
clearOpenTabs: createIPCHandler<() => Promise<void>>('clear-current-open-files'),
updateOpenTabs:
createIPCHandler<(draggedIndex: number, targetIndex: number) => Promise<void>>('update-current-open-files'),
selectOpenTabs: createIPCHandler<(tabs: Tab[]) => Promise<void>>('set-current-open-files'),
removeOpenTabsByPath: createIPCHandler<(path: string) => Promise<void>>('remove-current-open-files-by-path'),
}

const fileSystem = {
Expand Down Expand Up @@ -131,6 +142,7 @@ const path = {
join: createIPCHandler<(...pathSegments: string[]) => Promise<string>>('join-path'),
dirname: createIPCHandler<(pathString: string) => Promise<string>>('path-dirname'),
relative: createIPCHandler<(from: string, to: string) => Promise<string>>('path-relative'),
isAbsolute: createIPCHandler<(filePath: string) => Promise<string>>('path-absolute'),
addExtensionIfNoExtensionPresent: createIPCHandler<(pathString: string) => Promise<string>>(
'add-extension-if-no-extension-present',
),
Expand Down
Loading

0 comments on commit accf879

Please sign in to comment.