From 440c76425f669f26f1a96614217bb2008548bb34 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Thu, 4 Apr 2024 19:19:58 +0200 Subject: [PATCH] Refactored and Improved Dependency manager --- src/renderer/contexts/DependencyContext.tsx | 385 ++++++++++---------- src/renderer/global.scss | 4 + 2 files changed, 201 insertions(+), 188 deletions(-) diff --git a/src/renderer/contexts/DependencyContext.tsx b/src/renderer/contexts/DependencyContext.tsx index ee2664246..8836eab9a 100644 --- a/src/renderer/contexts/DependencyContext.tsx +++ b/src/renderer/contexts/DependencyContext.tsx @@ -20,13 +20,6 @@ import { ModalFooter, ModalHeader, ModalOverlay, - Popover, - PopoverArrow, - PopoverBody, - PopoverCloseButton, - PopoverContent, - PopoverHeader, - PopoverTrigger, Progress, Select, Spacer, @@ -67,11 +60,6 @@ import { BackendContext } from './BackendContext'; import { GlobalContext } from './GlobalNodeState'; import { useSettings } from './SettingsContext'; -const installModes = { - NORMAL: 'Normal', - MANUAL_COPY: 'Manual/Copy', -}; - export interface DependencyContextValue { openDependencyManager: () => void; availableUpdates: number; @@ -82,6 +70,11 @@ export const DependencyContext = createContext> availableUpdates: 0, }); +enum InstallMode { + NORMAL = 'normal', + COPY = 'copy', +} + const formatBytes = (bytes: number): string => { const KB = 1024 ** 1; const MB = 1024 ** 2; @@ -194,6 +187,7 @@ const PackageView = memo( whiteSpace: 'pre-line', }} label={p.description} + openDelay={200} px={2} py={1} > @@ -391,24 +385,154 @@ const FeaturesAccordion = memo(({ features, featureStates }: FeaturesAccordionPr ); }); +interface FeaturesSectionProps { + processingDeps: boolean; +} +const FeaturesSection = memo(({ processingDeps }: FeaturesSectionProps) => { + const { packages, featureStates, refreshFeatureStates } = useContext(BackendContext); + + const features = useMemo(() => packages.flatMap((p) => p.features), [packages]); + const [isRefreshingFeatureStates, setIsRefreshingFeatureStates] = useState(false); + + return ( + + + + + Features + + + + + + + ); +}); + +interface PythonSectionProps { + installMode: InstallMode; + setInstallMode: (mode: InstallMode) => void; + isConsoleOpen: boolean; + setIsConsoleOpen: (open: boolean) => void; + isDisabled: boolean; +} +const PythonSection = memo( + ({ + installMode, + setInstallMode, + isConsoleOpen, + setIsConsoleOpen, + isDisabled, + }: PythonSectionProps) => { + const { useSystemPython } = useSettings(); + const { pythonInfo } = useContext(BackendContext); + + return ( + + + Python ({pythonInfo.version}) [{useSystemPython ? 'System' : 'Integrated'}] + + + + + + + + {'The dependency install mode. ChaiNNer supports 2 ways of installing packages:\n\n' + + '- Normal: This is the default installation mode. This mode will automatically handle the dependency install for you and will report progress along the way.\n' + + '- Manual/Copy: Copy the pip install command to your clipboard for you to run in your own terminal. You will have to manually restart chaiNner afterwards.'} + + } + openDelay={500} + px={2} + py={0} + > +
+ +
+
+
+
+ +
+
+ ); + } +); + export const DependencyProvider = memo(({ children }: React.PropsWithChildren) => { const { isOpen, onOpen, onClose } = useDisclosure(); - const { showAlert } = useContext(AlertBoxContext); - const { useSystemPython } = useSettings(); - const { - backend, - url, - pythonInfo, - backendDownRef, - packages, - featureStates, - refreshFeatureStates, - } = useContext(BackendContext); + const { showAlert, sendToast } = useContext(AlertBoxContext); + const { backend, url, pythonInfo, backendDownRef, packages } = useContext(BackendContext); const { hasRelevantUnsavedChangesRef } = useContext(GlobalContext); const [isConsoleOpen, setIsConsoleOpen] = useState(false); - const [installMode, setInstallMode] = useState(installModes.NORMAL); + const [installMode, setInstallMode] = useState(InstallMode.NORMAL); const { data: installedPyPi, refetch: refetchInstalledPyPi } = useQuery({ queryKey: 'dependencies', @@ -484,26 +608,25 @@ export const DependencyProvider = memo(({ children }: React.PropsWithChildren { navigator.clipboard .writeText(command) .then(() => { - onPopoverToggle(); - setTimeout(() => { - onPopoverClose(); - }, 5000); + sendToast({ + status: 'success', + title: 'Command copied to clipboard', + description: + 'Open up an external terminal, paste the command, and run it. When it is done running, manually restart chaiNNer.', + duration: 5_000, + id: 'copy-to-clipboard-toast', + }); }) .catch(log.error); }; const installPackage = (pkg: Package) => { // TODO: Make this feature get the command from the backend directly - if (installMode === installModes.MANUAL_COPY) { + if (installMode === InstallMode.COPY) { const deps = pkg.dependencies.map((p) => `${p.pypiName}==${p.version}`); const findLinks = getFindLinks(pkg.dependencies).flatMap((l) => [ '--extra-index-url', @@ -527,14 +650,37 @@ export const DependencyProvider = memo(({ children }: React.PropsWithChildren backend.installPackage(pkg)); }; - const uninstallPackage = (pkg: Package) => { - if (installMode === installModes.MANUAL_COPY) { + const uninstallPackage = async (pkg: Package) => { + if (installMode === InstallMode.COPY) { const deps = pkg.dependencies.map((p) => p.pypiName); const args = [pythonInfo.python, '-m', 'pip', 'uninstall', ...deps]; const cmd = args.join(' '); copyCommandToClipboard(cmd); return; } + + const button = await showAlert({ + type: AlertType.WARN, + title: 'Uninstall', + message: `Are you sure you want to uninstall ${pkg.name}?`, + buttons: ['Cancel', 'Uninstall'], + defaultId: 0, + }); + if (button === 0) return; + + if (hasRelevantUnsavedChangesRef.current) { + const saveButton = await showAlert({ + type: AlertType.WARN, + title: 'Unsaved Changes', + message: + `You might lose your unsaved changes by uninstalling ${pkg.name}.` + + `\n\nAre you sure you want to uninstall ${pkg.name}?`, + buttons: ['Cancel', 'Uninstall'], + defaultId: 0, + }); + if (saveButton === 0) return; + } + setOverallProgress(0); setModifyingPackage(pkg); changePackages(() => backend.uninstallPackage(pkg)); @@ -567,9 +713,6 @@ export const DependencyProvider = memo(({ children }: React.PropsWithChildren packages.flatMap((p) => p.features), [packages]); - const [isRefreshingFeatureStates, setIsRefreshingFeatureStates] = useState(false); - return ( {children} @@ -591,85 +734,21 @@ export const DependencyProvider = memo(({ children }: React.PropsWithChildren - + + - Python ({pythonInfo.version}) [ - {useSystemPython ? 'System' : 'Integrated'}] + Packages - - - - - - - - - - Command copied to clipboard. - - - - - Open up an external terminal, paste the - command, and run it. When it is done - running, manually restart chaiNNer. - - - - - - {'The dependency install mode. ChaiNNer supports 2 ways of installing packages:\n\n' + - '- Normal: This is the default installation mode. This mode will automatically handle the dependency install for you and will report progress along the way.\n' + - '- Manual/Copy: Copy the pip install command to your clipboard for you to run in your own terminal. You will have to manually restart chaiNner afterwards.'} - - } - openDelay={500} - px={2} - py={0} - > -
- -
-
-
-
- -
-
+ {!installedPyPi ? ( ) : ( @@ -685,32 +764,7 @@ export const DependencyProvider = memo(({ children }: React.PropsWithChildren installPackage(p); const uninstall = () => { - showAlert({ - type: AlertType.WARN, - title: 'Uninstall', - message: `Are you sure you want to uninstall ${p.name}?`, - buttons: ['Cancel', 'Uninstall'], - defaultId: 0, - }) - .then(async (button) => { - if (button === 0) return; - - if (hasRelevantUnsavedChangesRef.current) { - const saveButton = await showAlert({ - type: AlertType.WARN, - title: 'Unsaved Changes', - message: - `You might lose your unsaved changes by uninstalling ${p.name}.` + - `\n\nAre you sure you want to uninstall ${p.name}?`, - buttons: ['Cancel', 'Uninstall'], - defaultId: 0, - }); - if (saveButton === 0) return; - } - - uninstallPackage(p); - }) - .catch(log.error); + uninstallPackage(p).catch(log.error); }; return ( @@ -721,7 +775,7 @@ export const DependencyProvider = memo(({ children }: React.PropsWithChildren */} {isConsoleOpen && } - - - - Features - - - - - +
diff --git a/src/renderer/global.scss b/src/renderer/global.scss index dc9e92b28..ecf610764 100644 --- a/src/renderer/global.scss +++ b/src/renderer/global.scss @@ -40,6 +40,10 @@ } } +:root { + --toast-z-index: 6001; +} + html { overflow: hidden; }