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

View File

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

View File

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