diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx
index 43b9f14..05c7214 100644
--- a/src/renderer/src/App.tsx
+++ b/src/renderer/src/App.tsx
@@ -1,5 +1,5 @@
import { useCallback, useState } from 'react'
-import { Anchor, FolderOpen, Plus, Settings, Sparkles, TerminalSquare } from 'lucide-react'
+import { Anchor, Boxes, FolderOpen, Plus, Settings, Sparkles, TerminalSquare } from 'lucide-react'
import { ProjectDetail } from './components/projects/ProjectDetail'
import { ProjectList } from './components/projects/ProjectList'
import { TerminalPanel } from './components/terminal/TerminalPanel'
@@ -7,6 +7,7 @@ import { StatusBar } from './components/layout/StatusBar'
import { Toaster } from './components/ui/Toaster'
import { CreateProjectModal } from './components/create/CreateProjectModal'
import { SettingsModal } from './components/settings/SettingsModal'
+import { GlobalModuleManager } from './components/modules/GlobalModuleManager'
import { useAppStore } from './stores/appStore'
import { useTerminalEvents } from './hooks/useTerminalEvents'
import { useAppliedTheme } from './hooks/useAppliedTheme'
@@ -17,6 +18,7 @@ function App(): React.JSX.Element {
const selectedProjectName = useAppStore((s) => s.selectedProjectName)
const [isCreateOpen, setIsCreateOpen] = useState(false)
const [isSettingsOpen, setIsSettingsOpen] = useState(false)
+ const [isModulesOpen, setIsModulesOpen] = useState(false)
useTerminalEvents()
useAppliedTheme()
useKeyboardShortcuts({
@@ -64,6 +66,9 @@ function App(): React.JSX.Element {
+
+
+
{selectedProjectName ? (
@@ -126,6 +131,7 @@ function App(): React.JSX.Element {
{isCreateOpen && setIsCreateOpen(false)} />}
{isSettingsOpen && setIsSettingsOpen(false)} />}
+ {isModulesOpen && setIsModulesOpen(false)} />}
)
}
diff --git a/src/renderer/src/components/create/CreateProjectModal.tsx b/src/renderer/src/components/create/CreateProjectModal.tsx
index ded7ffb..319b000 100644
--- a/src/renderer/src/components/create/CreateProjectModal.tsx
+++ b/src/renderer/src/components/create/CreateProjectModal.tsx
@@ -12,7 +12,7 @@ import {
} from 'lucide-react'
import { useCreateProject } from '../../hooks/useCreateProject'
import { useAppStore } from '../../stores/appStore'
-import { useAvailableModules, useInstallAvailableModule, useInstallModulePackage, useModuleRegistry } from '../../hooks/useModules'
+import { useModuleRegistry } from '../../hooks/useModules'
import { GenericSetup } from './types/GenericSetup'
import { ExternalModuleSetup } from './types/ExternalModuleSetup'
import type { TypeSetupHandle } from './types/shared'
@@ -52,9 +52,6 @@ export function CreateProjectModal({ onClose }: { onClose: () => void }): React.
const selectProject = useAppStore((s) => s.selectProject)
const setupRef = useRef(null)
const { data: moduleRegistry = [] } = useModuleRegistry()
- const installPackage = useInstallModulePackage()
- const installAvailable = useInstallAvailableModule()
- const { data: availableModules = [], isLoading: availableLoading } = useAvailableModules()
const applicationModules = moduleRegistry.filter((module) => module.category === 'application')
const selectedModule = applicationModules.find((module) => module.id === projectType)
const getTypeLabel = (type: string): string => applicationModules.find((module) => module.id === type)?.name ?? 'project'
@@ -264,15 +261,7 @@ export function CreateProjectModal({ onClose }: { onClose: () => void }): React.
)
})}
- {applicationModules.length === 0 &&
-
Available application modules
-
Choose a module to add to Aurora.
-
- {availableModules.filter((item) => item.manifest.category === 'application').map((item) =>
{item.manifest.name}
{item.manifest.description} · v{item.manifest.version}
)}
- {!availableLoading && availableModules.filter((item) => item.manifest.category === 'application').length === 0 &&
No packages were found beside Aurora.
}
-
-
-
}
+ {applicationModules.length === 0 && No application modules installed
Close this window and use Modules at the bottom of the sidebar to install one.
}
diff --git a/src/renderer/src/components/modules/GlobalModuleManager.tsx b/src/renderer/src/components/modules/GlobalModuleManager.tsx
new file mode 100644
index 0000000..64617d5
--- /dev/null
+++ b/src/renderer/src/components/modules/GlobalModuleManager.tsx
@@ -0,0 +1,48 @@
+import { Boxes, Download, RefreshCw, Trash2, X } from 'lucide-react'
+import { useAvailableModules, useInstallAvailableModule, useInstallModulePackage, useModuleRegistry, useUninstallModulePackage } from '../../hooks/useModules'
+
+function compareVersions(left: string, right: string): number {
+ const a = left.split(/[.-]/).map((part) => Number(part) || 0)
+ const b = right.split(/[.-]/).map((part) => Number(part) || 0)
+ for (let index = 0; index < Math.max(a.length, b.length); index += 1) {
+ if ((a[index] ?? 0) !== (b[index] ?? 0)) return (a[index] ?? 0) - (b[index] ?? 0)
+ }
+ return 0
+}
+
+export function GlobalModuleManager({ onClose }: { onClose: () => void }): React.JSX.Element {
+ const { data: available = [], isLoading } = useAvailableModules()
+ const { data: installed = [] } = useModuleRegistry()
+ const install = useInstallAvailableModule()
+ const uninstall = useUninstallModulePackage()
+ const installFromFolder = useInstallModulePackage()
+ const installedById = new Map(installed.map((module) => [module.id, module]))
+
+ return
+
+
+
+ {isLoading ?
Loading available modules…
: available.length === 0 ?
No modules found
Place module packages beside Aurora or choose a local package folder.
:
+ {available.map(({ manifest, sourcePath }) => {
+ const current = installedById.get(manifest.id)
+ const updateAvailable = current ? compareVersions(manifest.version, current.version) > 0 : false
+ const busy = install.isPending || uninstall.isPending
+ return
+
+ {manifest.name}
{current ? `Installed ${current.version}` : `Available ${manifest.version}`}{manifest.description}
+
+ {!current && }
+ {current && }
+ {current && }
+
+
+ })}
+
}
+
+
+
+
+}