Convert Configure Screen into the Main Application Window

- What
  - Convert the config screen into the main application window
    with configuration as just one of the functionality it provides
  - Rename config screen to main window to match new designation

- Why
  - System Tray isn't available everywhere (e.g Linux)
  - This requires moving functionality into a normal window for cross-compat
This commit is contained in:
Debanjum Singh Solanky 2022-08-13 01:39:46 +03:00
parent a6b2190f7a
commit a0759dd923
3 changed files with 35 additions and 28 deletions

View file

@ -18,7 +18,7 @@ from src.utils.config import SearchType, ProcessorType
from src.utils.helpers import merge_dicts, resolve_absolute_path
class ConfigureScreen(QtWidgets.QDialog):
class MainWindow(QtWidgets.QMainWindow):
"""Create Window to Configure Khoj
Allow user to
1. Configure content types to search
@ -26,8 +26,8 @@ class ConfigureScreen(QtWidgets.QDialog):
3. Save the configuration to khoj.yml
"""
def __init__(self, config_file: Path, parent=None):
super(ConfigureScreen, self).__init__(parent=parent)
def __init__(self, config_file: Path):
super(MainWindow, self).__init__()
self.config_file = config_file
# Load config from existing config, if exists, else load from default config
@ -45,24 +45,31 @@ class ConfigureScreen(QtWidgets.QDialog):
self.setFixedWidth(600)
# Initialize Configure Window Layout
layout = QtWidgets.QVBoxLayout()
self.setLayout(layout)
self.layout = QtWidgets.QVBoxLayout()
# Add Settings Panels for each Search Type to Configure Window Layout
self.search_settings_panels = []
for search_type in SearchType:
current_content_config = self.current_config['content-type'].get(search_type, {})
self.search_settings_panels += [self.add_settings_panel(current_content_config, search_type, layout)]
self.search_settings_panels += [self.add_settings_panel(current_content_config, search_type)]
# Add Conversation Processor Panel to Configure Screen
self.processor_settings_panels = []
conversation_type = ProcessorType.Conversation
current_conversation_config = self.current_config['processor'].get(conversation_type, {})
self.processor_settings_panels += [self.add_processor_panel(current_conversation_config, conversation_type, layout)]
self.processor_settings_panels += [self.add_processor_panel(current_conversation_config, conversation_type)]
self.add_action_panel(layout)
# Add Action Buttons Panel
self.add_action_panel()
def add_settings_panel(self, current_content_config: dict, search_type: SearchType, parent_layout: QtWidgets.QLayout):
# Set the central widget of the Window. Widget will expand
# to take up all the space in the window by default.
self.config_window = QtWidgets.QWidget()
self.config_window.setLayout(self.layout)
self.setCentralWidget(self.config_window)
def add_settings_panel(self, current_content_config: dict, search_type: SearchType):
"Add Settings Panel for specified Search Type. Toggle Editable Search Types"
# Get current files from config for given search type
if search_type == SearchType.Image:
@ -87,11 +94,11 @@ class ConfigureScreen(QtWidgets.QDialog):
# Add setting widgets for given search type to panel
search_type_layout.addWidget(enable_search_type)
search_type_layout.addWidget(input_files)
parent_layout.addWidget(search_type_settings)
self.layout.addWidget(search_type_settings)
return search_type_settings
def add_processor_panel(self, current_conversation_config: dict, processor_type: ProcessorType, parent_layout: QtWidgets.QLayout):
def add_processor_panel(self, current_conversation_config: dict, processor_type: ProcessorType):
"Add Conversation Processor Panel"
# Get current settings from config for given processor type
current_openai_api_key = current_conversation_config.get('openai-api-key', None)
@ -111,11 +118,11 @@ class ConfigureScreen(QtWidgets.QDialog):
# Add setting widgets for given processor type to panel
processor_type_layout.addWidget(enable_conversation)
processor_type_layout.addWidget(input_field)
parent_layout.addWidget(processor_type_settings)
self.layout.addWidget(processor_type_settings)
return processor_type_settings
def add_action_panel(self, parent_layout: QtWidgets.QLayout):
def add_action_panel(self):
"Add Action Panel"
# Button to Save Settings
action_bar = QtWidgets.QWidget()
@ -127,7 +134,7 @@ class ConfigureScreen(QtWidgets.QDialog):
action_bar_layout.addWidget(self.configure_button)
action_bar_layout.addWidget(self.search_button)
parent_layout.addWidget(action_bar)
self.layout.addWidget(action_bar)
def get_default_config(self, search_type:SearchType=None, processor_type:ProcessorType=None):
"Get default config"
@ -139,13 +146,13 @@ class ConfigureScreen(QtWidgets.QDialog):
else:
return config
def add_error_message(self, message: str, parent_layout: QtWidgets.QLayout):
def add_error_message(self, message: str):
"Add Error Message to Configure Screen"
error_message = QtWidgets.QLabel()
error_message.setWordWrap(True)
error_message.setText(message)
error_message.setStyleSheet("color: red")
parent_layout.addWidget(error_message)
self.layout.addWidget(error_message)
def update_search_settings(self):
"Update config with search settings from UI"
@ -190,14 +197,14 @@ class ConfigureScreen(QtWidgets.QDialog):
yaml_utils.parse_config_from_string(self.new_config)
except Exception as e:
print(f"Error validating config: {e}")
self.add_error_message(f"Error validating config: {e}", self.layout())
self.add_error_message(f"Error validating config: {e}")
return False
else:
# Remove error message if present
for i in range(self.layout().count()):
current_widget = self.layout().itemAt(i).widget()
for i in range(self.layout.count()):
current_widget = self.layout.itemAt(i).widget()
if isinstance(current_widget, QtWidgets.QLabel) and current_widget.text().startswith("Error validating config:"):
self.layout().removeWidget(current_widget)
self.layout.removeWidget(current_widget)
current_widget.deleteLater()
# Save the config to app config file

View file

@ -8,7 +8,7 @@ from PyQt6 import QtGui, QtWidgets
from src.utils import constants
def create_system_tray(gui: QtWidgets.QApplication, configure_screen: QtWidgets.QDialog):
def create_system_tray(gui: QtWidgets.QApplication, main_window: QtWidgets.QMainWindow):
"""Create System Tray with Menu. Menu contain options to
1. Open Search Page on the Web Interface
2. Open App Configuration Screen
@ -25,7 +25,7 @@ def create_system_tray(gui: QtWidgets.QApplication, configure_screen: QtWidgets.
menu = QtWidgets.QMenu()
menu_actions = [
('Search', lambda: webbrowser.open('http://localhost:8000/')),
('Configure', configure_screen.show),
('Configure', main_window.show),
('Quit', gui.quit),
]

View file

@ -15,7 +15,7 @@ from src.configure import configure_server
from src.router import router
from src.utils import constants, state
from src.utils.cli import cli
from src.interface.desktop.configure_screen import ConfigureScreen
from src.interface.desktop.main_window import MainWindow
from src.interface.desktop.system_tray import create_system_tray
@ -38,24 +38,24 @@ def run():
else:
# Setup GUI
gui = QtWidgets.QApplication([])
configure_screen = ConfigureScreen(args.config_file)
main_window = MainWindow(args.config_file)
# System tray is only available on Windows, MacOS.
# On Linux (Gnome) the System tray is not supported.
# Since only the Configure Window is available
# Since only the Main Window is available
# Quitting it should quit the application
if system() in ['Windows', 'Darwin']:
gui.setQuitOnLastWindowClosed(False)
tray = create_system_tray(gui, configure_screen)
tray = create_system_tray(gui, main_window)
tray.show()
# Setup Server
configure_server(args, required=False)
server = ServerThread(app, args.host, args.port, args.socket)
# Show Configure Screen on Linux (etc.) or First Run Experience
# Show Main Window on First Run Experience or if on Linux
if args.config is None or system() not in ['Windows', 'Darwin']:
configure_screen.show()
main_window.show()
# Setup Signal Handlers
signal.signal(signal.SIGINT, sigint_handler)