From 6978928db996c0cc5389cd46ba1ddd4897c7361c Mon Sep 17 00:00:00 2001 From: Jamie Pine <32987599+jamiepine@users.noreply.github.com> Date: Sat, 18 Jun 2022 01:35:51 -0700 Subject: [PATCH] Eng 142 fix interface hot reload (#252) * fix interface hot reloading * AppPropsContext exsiting in App.tsx was the issue :D * type export fix --- .vscode/settings.json | 2 + apps/desktop/src/index.tsx | 1 - apps/desktop/vite.config.ts | 1 - apps/web/src/App.tsx | 1 - packages/interface/src/App.tsx | 206 +----------------- packages/interface/src/AppLayout.tsx | 35 +++ packages/interface/src/AppPropsContext.tsx | 19 ++ packages/interface/src/AppRouter.tsx | 64 ++++++ packages/interface/src/ErrorFallback.tsx | 25 +++ packages/interface/src/NotFound.tsx | 22 ++ .../src/components/device/Device.tsx | 4 +- .../src/components/file/FileList.tsx | 27 +-- .../src/components/file/FileThumb.tsx | 4 +- .../src/components/file/Inspector.tsx | 21 +- .../interface/src/components/file/Sidebar.tsx | 7 +- .../src/components/layout/TopBar.tsx | 2 +- .../interface/src/hooks/useCoreEvents.tsx | 2 +- .../interface/src/hooks/useExplorerState.ts | 23 ++ packages/interface/src/index.ts | 2 +- packages/interface/src/screens/Content.tsx | 1 - packages/interface/src/screens/Debug.tsx | 53 ++--- packages/interface/src/screens/Explorer.tsx | 18 +- packages/interface/src/screens/Overview.tsx | 2 +- packages/interface/src/screens/Settings.tsx | 8 +- packages/interface/src/screens/Tag.tsx | 5 +- .../src/screens/settings/GeneralSettings.tsx | 26 --- 26 files changed, 256 insertions(+), 325 deletions(-) create mode 100644 packages/interface/src/AppLayout.tsx create mode 100644 packages/interface/src/AppPropsContext.tsx create mode 100644 packages/interface/src/AppRouter.tsx create mode 100644 packages/interface/src/ErrorFallback.tsx create mode 100644 packages/interface/src/NotFound.tsx create mode 100644 packages/interface/src/hooks/useExplorerState.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index f4fc75ad0..726086dd7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,7 @@ "consts", "countup", "creationdate", + "fontsource", "ipfs", "Keepsafe", "pathctx", @@ -13,6 +14,7 @@ "quicktime", "repr", "Roadmap", + "subpackage", "svgr", "tailwindcss", "titlebar", diff --git a/apps/desktop/src/index.tsx b/apps/desktop/src/index.tsx index 1f779c080..692f7149e 100644 --- a/apps/desktop/src/index.tsx +++ b/apps/desktop/src/index.tsx @@ -65,7 +65,6 @@ function App() { return ( */} (null); - -export type Platform = 'browser' | 'macOS' | 'windows' | 'linux'; - -export interface AppProps { - transport: BaseTransport; - platform: Platform; - convertFileSrc: (url: string) => string; - openDialog: (options: { directory?: boolean }) => Promise; - onClose?: () => void; - onMinimize?: () => void; - onFullscreen?: () => void; - onOpen?: (path: string) => void; - isFocused?: boolean; - useMemoryRouter: boolean; - demoMode?: boolean; -} - -function AppLayout() { - const appProps = useContext(AppPropsContext); - - const isWindowRounded = appProps?.platform === 'macOS'; - const hasWindowBorder = appProps?.platform !== 'browser' && appProps?.platform !== 'windows'; - - return ( -
{ - // TODO: allow this on some UI text at least - // disable default browser context menu - e.preventDefault(); - return false; - }} - className={clsx( - 'flex flex-row h-screen overflow-hidden text-gray-900 select-none dark:text-white', - isWindowRounded && 'rounded-xl', - hasWindowBorder && 'border border-gray-200 dark:border-gray-500' - )} - > - -
- {/* */} - -
- -
-
-
- ); -} - -function SettingsRoutes({ modal = false }) { - return ( - - - } /> : } - > - } /> - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - - ); -} - -function Router() { - let location = useLocation(); - let state = location.state as { backgroundLocation?: Location }; - - useEffect(() => { - console.log({ url: location.pathname }); - }, [state]); - - return ( - <> - - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - {state?.backgroundLocation && } - - ); -} - -function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) { - return ( -
-

APP CRASHED

-

We're past the event horizon...

-
Error: {error.message}
-
- - -
-
- ); -} - -function NotFound() { - const navigate = useNavigate(); - return ( -
-

Error: 404

-

You chose nothingness.

-
- -
-
- ); -} - -function MemoryRouterContainer() { +function RouterContainer() { useCoreEvents(); return ( - + ); } -function BrowserRouterContainer() { - useCoreEvents(); - return ( - - - - ); -} - -export function bindCoreEvent() {} - export default function App(props: AppProps) { // TODO: This is a hack and a better solution should probably be found. // This exists so that the queryClient can be accessed within the subpackage '@sd/client'. @@ -218,13 +32,11 @@ export default function App(props: AppProps) { return ( <> - {/* @ts-ignore */} {}}> - {/* @ts-ignore */} - {props.useMemoryRouter ? : } + diff --git a/packages/interface/src/AppLayout.tsx b/packages/interface/src/AppLayout.tsx new file mode 100644 index 000000000..b7ce72912 --- /dev/null +++ b/packages/interface/src/AppLayout.tsx @@ -0,0 +1,35 @@ +import clsx from 'clsx'; +import React, { useContext } from 'react'; +import { Outlet } from 'react-router-dom'; + +import { AppPropsContext } from './AppPropsContext'; +import { Sidebar } from './components/file/Sidebar'; + +export function AppLayout() { + const appProps = useContext(AppPropsContext); + + const isWindowRounded = appProps?.platform === 'macOS'; + const hasWindowBorder = appProps?.platform !== 'browser' && appProps?.platform !== 'windows'; + + return ( +
{ + // TODO: allow this on some UI text at least / disable default browser context menu + e.preventDefault(); + return false; + }} + className={clsx( + 'flex flex-row h-screen overflow-hidden text-gray-900 select-none dark:text-white', + isWindowRounded && 'rounded-xl', + hasWindowBorder && 'border border-gray-200 dark:border-gray-500' + )} + > + +
+
+ +
+
+
+ ); +} diff --git a/packages/interface/src/AppPropsContext.tsx b/packages/interface/src/AppPropsContext.tsx new file mode 100644 index 000000000..20c92e910 --- /dev/null +++ b/packages/interface/src/AppPropsContext.tsx @@ -0,0 +1,19 @@ +import { BaseTransport } from '@sd/client'; +import { createContext } from 'react'; + +export const AppPropsContext = createContext(null); + +export type Platform = 'browser' | 'macOS' | 'windows' | 'linux'; + +export interface AppProps { + transport: BaseTransport; + platform: Platform; + convertFileSrc: (url: string) => string; + openDialog: (options: { directory?: boolean }) => Promise; + onClose?: () => void; + onMinimize?: () => void; + onFullscreen?: () => void; + onOpen?: (path: string) => void; + isFocused?: boolean; + demoMode?: boolean; +} diff --git a/packages/interface/src/AppRouter.tsx b/packages/interface/src/AppRouter.tsx new file mode 100644 index 000000000..2c3bbfde1 --- /dev/null +++ b/packages/interface/src/AppRouter.tsx @@ -0,0 +1,64 @@ +import React, { useEffect } from 'react'; +import { Route, Routes, useLocation } from 'react-router-dom'; + +import { AppLayout } from './AppLayout'; +import { NotFound } from './NotFound'; +import { ContentScreen } from './screens/Content'; +import { DebugScreen } from './screens/Debug'; +import { ExplorerScreen } from './screens/Explorer'; +import { OverviewScreen } from './screens/Overview'; +import { PhotosScreen } from './screens/Photos'; +import { RedirectPage } from './screens/Redirect'; +import { SettingsScreen } from './screens/Settings'; +import { TagScreen } from './screens/Tag'; +import AppearanceSettings from './screens/settings/AppearanceSettings'; +import ContactsSettings from './screens/settings/ContactsSettings'; +import ExperimentalSettings from './screens/settings/ExperimentalSettings'; +import GeneralSettings from './screens/settings/GeneralSettings'; +import KeysSettings from './screens/settings/KeysSetting'; +import LibrarySettings from './screens/settings/LibrarySettings'; +import LocationSettings from './screens/settings/LocationSettings'; +import SecuritySettings from './screens/settings/SecuritySettings'; +import SharingSettings from './screens/settings/SharingSettings'; +import SyncSettings from './screens/settings/SyncSettings'; +import TagsSettings from './screens/settings/TagsSettings'; + +export function AppRouter() { + let location = useLocation(); + let state = location.state as { backgroundLocation?: Location }; + + useEffect(() => { + console.log({ url: location.pathname }); + }, [state]); + + return ( + <> + + }> + } /> + } /> + } /> + } /> + } /> + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + } /> + } /> + } /> + + + + ); +} diff --git a/packages/interface/src/ErrorFallback.tsx b/packages/interface/src/ErrorFallback.tsx new file mode 100644 index 000000000..0f05d4e9f --- /dev/null +++ b/packages/interface/src/ErrorFallback.tsx @@ -0,0 +1,25 @@ +import { Button } from '@sd/ui'; +import React from 'react'; +import { FallbackProps } from 'react-error-boundary'; + +export function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) { + return ( +
+

APP CRASHED

+

We're past the event horizon...

+
Error: {error.message}
+
+ + +
+
+ ); +} diff --git a/packages/interface/src/NotFound.tsx b/packages/interface/src/NotFound.tsx new file mode 100644 index 000000000..c48e8141e --- /dev/null +++ b/packages/interface/src/NotFound.tsx @@ -0,0 +1,22 @@ +import { Button } from '@sd/ui'; +import React from 'react'; +import { useNavigate } from 'react-router'; + +export function NotFound() { + const navigate = useNavigate(); + return ( +
+

Error: 404

+

You chose nothingness.

+
+ +
+
+ ); +} diff --git a/packages/interface/src/components/device/Device.tsx b/packages/interface/src/components/device/Device.tsx index 724ecd1af..d9fb49107 100644 --- a/packages/interface/src/components/device/Device.tsx +++ b/packages/interface/src/components/device/Device.tsx @@ -25,7 +25,7 @@ export function Device(props: DeviceProps) { } return ( -
+
{props.type === 'phone' && } @@ -44,7 +44,7 @@ export function Device(props: DeviceProps) {
{props.runningJob && ( -
+
void; - locationId: number; - setLocationId: (index: number) => void; - newThumbnails: Record; - addNewThumbnail: (cas_id: string) => void; -}; - -export const useExplorerState = create((set) => ({ - selectedRowIndex: 1, - setSelectedRowIndex: (index) => set((state) => ({ ...state, selectedRowIndex: index })), - locationId: -1, - setLocationId: (id: number) => set((state) => ({ ...state, locationId: id })), - newThumbnails: {}, - addNewThumbnail: (cas_id: string) => - set((state) => ({ - ...state, - newThumbnails: { ...state.newThumbnails, [cas_id]: true } - })) -})); - interface IColumn { column: string; key: string; diff --git a/packages/interface/src/components/file/FileThumb.tsx b/packages/interface/src/components/file/FileThumb.tsx index cf306d230..e47a39243 100644 --- a/packages/interface/src/components/file/FileThumb.tsx +++ b/packages/interface/src/components/file/FileThumb.tsx @@ -3,7 +3,7 @@ import { FilePath } from '@sd/core'; import clsx from 'clsx'; import React, { useContext } from 'react'; -import { AppPropsContext } from '../../App'; +import { AppPropsContext } from '../../AppPropsContext'; import icons from '../../assets/icons'; import { Folder } from '../icons/Folder'; @@ -17,7 +17,7 @@ export default function FileThumb(props: { const { data: client } = useBridgeQuery('NodeGetState'); if (props.file.is_dir) { - return ; + return ; } if (client?.data_path && (props.file.file?.has_thumbnail || props.hasThumbnailOverride)) { diff --git a/packages/interface/src/components/file/Inspector.tsx b/packages/interface/src/components/file/Inspector.tsx index f537c1de2..fdfaf8715 100644 --- a/packages/interface/src/components/file/Inspector.tsx +++ b/packages/interface/src/components/file/Inspector.tsx @@ -1,6 +1,6 @@ import { Transition } from '@headlessui/react'; import { ShareIcon } from '@heroicons/react/solid'; -import { FilePath } from '@sd/core'; +import { FilePath, LocationResource } from '@sd/core'; import { Button, TextArea } from '@sd/ui'; import moment from 'moment'; import { Heart, Link } from 'phosphor-react'; @@ -16,7 +16,7 @@ interface MetaItemProps { const MetaItem = (props: MetaItemProps) => { return ( -
+
{props.title}
{typeof props.value === 'string' ? (

{props.value}

@@ -29,12 +29,15 @@ const MetaItem = (props: MetaItemProps) => { const Divider = () =>
; -export const Inspector = (props: { selectedFile?: FilePath; locationId: number }) => { - // const { selectedRowIndex } = useExplorerState(); - // const isOpen = !!props.selectedFile; - +export const Inspector = (props: { + locationId: number; + location?: LocationResource; + selectedFile?: FilePath; +}) => { const file_path = props.selectedFile; + let full_path = `${props.location?.path}/${file_path?.materialized_path}`; + return ( -
+
{!!file_path && ( -
+
)} - + = (props) => { diff --git a/packages/interface/src/components/layout/TopBar.tsx b/packages/interface/src/components/layout/TopBar.tsx index f1d065e2e..e046d2e19 100644 --- a/packages/interface/src/components/layout/TopBar.tsx +++ b/packages/interface/src/components/layout/TopBar.tsx @@ -15,7 +15,7 @@ import { import React, { DetailedHTMLProps, HTMLAttributes } from 'react'; import { useNavigate } from 'react-router-dom'; -import { useExplorerState } from '../file/FileList'; +import { useExplorerState } from '../../hooks/useExplorerState'; import { Shortcut } from '../primitive/Shortcut'; import { DefaultProps } from '../primitive/types'; diff --git a/packages/interface/src/hooks/useCoreEvents.tsx b/packages/interface/src/hooks/useCoreEvents.tsx index 45763f5e6..d59e0050a 100644 --- a/packages/interface/src/hooks/useCoreEvents.tsx +++ b/packages/interface/src/hooks/useCoreEvents.tsx @@ -4,7 +4,7 @@ import { useContext, useEffect } from 'react'; import { useQueryClient } from 'react-query'; import { AppPropsContext } from '../App'; -import { useExplorerState } from '../components/file/FileList'; +import { useExplorerState } from './useExplorerState'; export function useCoreEvents() { const client = useQueryClient(); diff --git a/packages/interface/src/hooks/useExplorerState.ts b/packages/interface/src/hooks/useExplorerState.ts new file mode 100644 index 000000000..ef2a5ce17 --- /dev/null +++ b/packages/interface/src/hooks/useExplorerState.ts @@ -0,0 +1,23 @@ +import create from 'zustand'; + +type ExplorerState = { + selectedRowIndex: number; + setSelectedRowIndex: (index: number) => void; + locationId: number; + setLocationId: (index: number) => void; + newThumbnails: Record; + addNewThumbnail: (cas_id: string) => void; +}; + +export const useExplorerState = create((set) => ({ + selectedRowIndex: 1, + setSelectedRowIndex: (index) => set((state) => ({ ...state, selectedRowIndex: index })), + locationId: -1, + setLocationId: (id: number) => set((state) => ({ ...state, locationId: id })), + newThumbnails: {}, + addNewThumbnail: (cas_id: string) => + set((state) => ({ + ...state, + newThumbnails: { ...state.newThumbnails, [cas_id]: true } + })) +})); diff --git a/packages/interface/src/index.ts b/packages/interface/src/index.ts index e08a37a48..eefb2853f 100644 --- a/packages/interface/src/index.ts +++ b/packages/interface/src/index.ts @@ -1,5 +1,5 @@ import App from './App'; -import { AppProps, Platform } from './App'; +import { AppProps, Platform } from './AppPropsContext'; export type { AppProps, Platform }; diff --git a/packages/interface/src/screens/Content.tsx b/packages/interface/src/screens/Content.tsx index af7c148a6..cc8117f79 100644 --- a/packages/interface/src/screens/Content.tsx +++ b/packages/interface/src/screens/Content.tsx @@ -1,4 +1,3 @@ -// import { useBridgeCommand, useBridgeQuery } from '@sd/client'; import React from 'react'; export const ContentScreen: React.FC<{}> = (props) => { diff --git a/packages/interface/src/screens/Debug.tsx b/packages/interface/src/screens/Debug.tsx index e34b99c66..58d2480c6 100644 --- a/packages/interface/src/screens/Debug.tsx +++ b/packages/interface/src/screens/Debug.tsx @@ -2,45 +2,36 @@ import { useBridgeCommand, useBridgeQuery } from '@sd/client'; import { Button } from '@sd/ui'; import React, { useContext } from 'react'; -import { AppPropsContext } from '../App'; +import { AppPropsContext } from '../AppPropsContext'; import CodeBlock from '../components/primitive/Codeblock'; export const DebugScreen: React.FC<{}> = (props) => { - const appPropsContext = useContext(AppPropsContext); - const { data: client } = useBridgeQuery('NodeGetState'); - const { data: jobs } = useBridgeQuery('JobGetRunning'); - const { data: jobHistory } = useBridgeQuery('JobGetHistory'); - // const { mutate: purgeDB } = useBridgeCommand('PurgeDatabase', { - // onMutate: () => { - // alert('Database purged'); - // } - // }); - const { mutate: identifyFiles } = useBridgeCommand('IdentifyUniqueFiles'); - return ( -
-
-

Developer Debugger

-
- - + const appPropsContext = useContext(AppPropsContext); + const { data: client } = useBridgeQuery('NodeGetState'); + const { data: jobs } = useBridgeQuery('JobGetRunning'); + const { data: jobHistory } = useBridgeQuery('JobGetHistory'); + // const { mutate: purgeDB } = useBridgeCommand('PurgeDatabase', { + // onMutate: () => { + // alert('Database purged'); + // } + // }); + const { mutate: identifyFiles } = useBridgeCommand('IdentifyUniqueFiles'); + return ( +
+
+

Developer Debugger

+

Running Jobs

diff --git a/packages/interface/src/screens/Explorer.tsx b/packages/interface/src/screens/Explorer.tsx index c60a92e9e..3cc4178bb 100644 --- a/packages/interface/src/screens/Explorer.tsx +++ b/packages/interface/src/screens/Explorer.tsx @@ -1,10 +1,11 @@ import { useBridgeQuery } from '@sd/client'; -import React, { useEffect } from 'react'; +import React from 'react'; import { useParams, useSearchParams } from 'react-router-dom'; -import { FileList, useExplorerState } from '../components/file/FileList'; +import { FileList } from '../components/file/FileList'; import { Inspector } from '../components/file/Inspector'; import { TopBar } from '../components/layout/TopBar'; +import { useExplorerState } from '../hooks/useExplorerState'; export const ExplorerScreen: React.FC<{}> = () => { let [searchParams] = useSearchParams(); @@ -13,22 +14,20 @@ export const ExplorerScreen: React.FC<{}> = () => { let { id } = useParams(); let location_id = Number(id); - let [limit, setLimit] = React.useState(100); - - useEffect(() => { - console.log({ location_id, path, limit }); - }, [location_id, path]); + const [limit, setLimit] = React.useState(100); const { selectedRowIndex } = useExplorerState(); + // Current Location + const { data: currentLocation } = useBridgeQuery('SysGetLocation', { id: location_id }); + + // Current Directory const { data: currentDir } = useBridgeQuery( 'LibGetExplorerDir', { location_id: location_id!, path, limit }, { enabled: !!location_id } ); - console.log({ currentDir }); - return (
@@ -36,6 +35,7 @@ export const ExplorerScreen: React.FC<{}> = () => { {currentDir?.contents && ( diff --git a/packages/interface/src/screens/Overview.tsx b/packages/interface/src/screens/Overview.tsx index bca3659b4..38617eb0d 100644 --- a/packages/interface/src/screens/Overview.tsx +++ b/packages/interface/src/screens/Overview.tsx @@ -10,7 +10,7 @@ import Skeleton from 'react-loading-skeleton'; import 'react-loading-skeleton/dist/skeleton.css'; import create from 'zustand'; -import { AppPropsContext } from '../App'; +import { AppPropsContext } from '../AppPropsContext'; import { Device } from '../components/device/Device'; import Dialog from '../components/layout/Dialog'; diff --git a/packages/interface/src/screens/Settings.tsx b/packages/interface/src/screens/Settings.tsx index 71f137e14..6def4f63d 100644 --- a/packages/interface/src/screens/Settings.tsx +++ b/packages/interface/src/screens/Settings.tsx @@ -1,25 +1,19 @@ -// import { dummyIFile, FileList } from '../components/file/FileList'; import { CloudIcon, CogIcon, KeyIcon, LockClosedIcon, - PhotographIcon, TagIcon, TerminalIcon, UsersIcon } from '@heroicons/react/outline'; import clsx from 'clsx'; -import { Book, Database, HardDrive, PaintBrush } from 'phosphor-react'; +import { Database, HardDrive, PaintBrush } from 'phosphor-react'; import React from 'react'; import { Outlet } from 'react-router-dom'; import { SidebarLink } from '../components/file/Sidebar'; -//@ts-ignore -// import { Spline } from 'react-spline'; -// import WINDOWS_SCENE from '../assets/spline/scene.json'; - const Icon = ({ component: Icon, ...props }: any) => ( ); diff --git a/packages/interface/src/screens/Tag.tsx b/packages/interface/src/screens/Tag.tsx index e75ae1201..ad4f43fd5 100644 --- a/packages/interface/src/screens/Tag.tsx +++ b/packages/interface/src/screens/Tag.tsx @@ -9,10 +9,7 @@ export const TagScreen: React.FC<{}> = () => { return (
-

- Note: This is a pre-alpha build of Spacedrive, many features are yet to be - functional. -

+

{id}

); }; diff --git a/packages/interface/src/screens/settings/GeneralSettings.tsx b/packages/interface/src/screens/settings/GeneralSettings.tsx index 43c0487fc..e908b3789 100644 --- a/packages/interface/src/screens/settings/GeneralSettings.tsx +++ b/packages/interface/src/screens/settings/GeneralSettings.tsx @@ -15,32 +15,6 @@ export default function GeneralSettings() { title="General Settings" description="Basic settings related to this client." /> - - {/* -
- setTempWatchDir(e.target.value)} - placeholder="/users/jamie/Desktop" - /> - -
-
*/} -