forked from voxel51/fiftyone
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Single Query Routing and Recoil Syncing (voxel51#2742)
🚀 🚀 🚀 🚀 🚀 --------- Co-authored-by: Lanny W <lanzhenwang9@gmail.com>
- Loading branch information
1 parent
b2c889a
commit 491c237
Showing
329 changed files
with
10,543 additions
and
7,249 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# FiftyOne App | ||
|
||
The FiftyOne App is a lightweight single page app around the `@fiftyone/core` | ||
components. It is the client controller for syncing session state with the | ||
server. | ||
|
||
## Contracts | ||
|
||
### Receiving session updates | ||
|
||
Session updates are received by the App via | ||
[`useEventSource`](./src/useEventSource.ts). Hooks that handle events are | ||
registered in the [`./src/useEvents`](./src/useEvents/) directory. To add a new | ||
event, add a new `EventHandlerHook` in the directory and register it in | ||
[`./useEvents/index.ts`](./src/useEvents/index.ts) with a corresponding server | ||
event name (in came case). | ||
|
||
### Writing session updates | ||
|
||
The core session values are defined in `@fiftyone/state` as `sessionAtom`s. | ||
When a `sessionAtom` is written to via a `recoil` set call, the value | ||
immediately takes effect in the `sessionAtom`. Side effects of writing to the | ||
atom can be registered in [`./src/useWriter`](./src/useWriters/index.ts). These | ||
side effects are enumerated by the `RegisteredWriter` type and derive from | ||
`@fiftyone/state`'s `Session` definition. | ||
|
||
### Updating via Setters | ||
|
||
The complex case of handling state updates that affect other recoil state is | ||
encapsulated in [`./src/useSetters`](./src/useSetters/). One example of this is | ||
updating the `view` in the App. The `view` atom in `@fiftyone/state` is | ||
implemented as a | ||
[`graphQLSyncFragmentAtom`](../relay/src/graphQLSyncFragmentAtom.ts) because | ||
its value is tied to the current page query. Setting the atom is handled with | ||
indirection by including the `selectorEffect` when creating the | ||
`graphQLSyncFragmentAtom`. This requires an associated setter registered in | ||
[`./src/useSetters/index.ts`](./src/useSetters/index.ts) that will control how | ||
to transition to the next page state. See | ||
[`./src/useSetters/onSetView.ts`](./src/useSetters/onSetView.ts) for a concrete | ||
example. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,32 @@ | ||
import { Loading, RouteRenderer } from "@fiftyone/components"; | ||
import * as fos from "@fiftyone/state"; | ||
import { RelayEnvironmentContext } from "@fiftyone/relay"; | ||
import { RelayEnvironmentKey } from "@fiftyone/state"; | ||
|
||
import React, { Suspense, useContext, useEffect } from "react"; | ||
import { Environment } from "react-relay"; | ||
import { useRecoilValue } from "recoil"; | ||
import { RecoilRelayEnvironmentProvider } from "recoil-relay"; | ||
|
||
const Renderer: React.FC = () => { | ||
const context = useContext(fos.RouterContext); | ||
|
||
return ( | ||
<Suspense fallback={<Loading>Pixelating...</Loading>}> | ||
<RouteRenderer router={context} /> | ||
</Suspense> | ||
); | ||
}; | ||
import React from "react"; | ||
import { RelayEnvironmentProvider } from "react-relay"; | ||
import { RecoilRelayEnvironment } from "recoil-relay"; | ||
import { IEnvironment } from "relay-runtime"; | ||
import Sync from "./Sync"; | ||
import { Queries, Renderer, RouterContext, RoutingContext } from "./routing"; | ||
|
||
const Network: React.FC<{ | ||
environment: Environment; | ||
context: fos.RoutingContext<any>; | ||
environment: IEnvironment; | ||
context: RoutingContext<Queries>; | ||
}> = ({ environment, context }) => { | ||
return ( | ||
<RecoilRelayEnvironmentProvider | ||
environment={environment} | ||
environmentKey={RelayEnvironmentKey} | ||
> | ||
<fos.RouterContext.Provider value={context}> | ||
<Renderer /> | ||
</fos.RouterContext.Provider> | ||
</RecoilRelayEnvironmentProvider> | ||
<RelayEnvironmentProvider environment={environment}> | ||
<RecoilRelayEnvironment | ||
environment={environment} | ||
environmentKey={RelayEnvironmentKey} | ||
> | ||
<RouterContext.Provider value={context}> | ||
<RelayEnvironmentContext.Provider value={environment}> | ||
<Sync> | ||
<Renderer /> | ||
</Sync> | ||
</RelayEnvironmentContext.Provider> | ||
</RouterContext.Provider> | ||
</RecoilRelayEnvironment> | ||
</RelayEnvironmentProvider> | ||
); | ||
}; | ||
|
||
export const NetworkRenderer = ({ makeRoutes }) => { | ||
const { context, environment } = fos.useRouter(makeRoutes, []); | ||
|
||
const isModalOpen = useRecoilValue(fos.isModalActive); | ||
|
||
useEffect(() => { | ||
document.body.classList.toggle("noscroll", isModalOpen); | ||
document.getElementById("modal")?.classList.toggle("modalon", isModalOpen); | ||
}, [isModalOpen]); | ||
|
||
return <Network environment={environment} context={context} />; | ||
}; | ||
|
||
export default Network; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { Loading, Pending } from "@fiftyone/components"; | ||
import { subscribe } from "@fiftyone/relay"; | ||
import { theme, themeConfig } from "@fiftyone/state"; | ||
import { useColorScheme } from "@mui/material"; | ||
import React, { Suspense, useEffect, useLayoutEffect } from "react"; | ||
import { | ||
atom, | ||
useRecoilState, | ||
useRecoilValue, | ||
useSetRecoilState, | ||
} from "recoil"; | ||
import { Queries } from "./makeRoutes"; | ||
import { Entry, useRouterContext } from "./routing"; | ||
|
||
export const pendingEntry = atom<boolean>({ | ||
key: "pendingEntry", | ||
default: false, | ||
}); | ||
|
||
export const entry = atom<Entry<Queries> | null>({ | ||
key: "Entry", | ||
default: null, | ||
dangerouslyAllowMutability: true, | ||
}); | ||
|
||
const ColorScheme = () => { | ||
const { setMode } = useColorScheme(); | ||
const current = useRecoilValue(themeConfig); | ||
const setTheme = useSetRecoilState(theme); | ||
useLayoutEffect(() => { | ||
if (current !== "browser") { | ||
setTheme(current); | ||
setMode(current); | ||
} | ||
}, [current, setMode, setTheme]); | ||
|
||
return null; | ||
}; | ||
|
||
const Renderer = () => { | ||
const [routeEntry, setRouteEntry] = useRecoilState(entry); | ||
const [pending, setPending] = useRecoilState(pendingEntry); | ||
const router = useRouterContext(); | ||
|
||
useEffect(() => { | ||
router.load().then(setRouteEntry); | ||
subscribe((_, { set }) => { | ||
set(entry, router.get()); | ||
set(pendingEntry, false); | ||
}); | ||
}, [router, setRouteEntry]); | ||
|
||
useEffect(() => { | ||
return router.subscribe( | ||
() => undefined, | ||
() => setPending(true) | ||
); | ||
}, [router, setPending]); | ||
|
||
const loading = <Loading>Pixelating...</Loading>; | ||
|
||
if (!routeEntry) return loading; | ||
|
||
return ( | ||
<Suspense fallback={loading}> | ||
<ColorScheme /> | ||
<Route route={routeEntry} /> | ||
{pending && <Pending />} | ||
</Suspense> | ||
); | ||
}; | ||
|
||
const Route = ({ route }: { route: Entry<Queries> }) => { | ||
const Component = route.component; | ||
|
||
useEffect(() => { | ||
document.dispatchEvent(new CustomEvent("page-change", { bubbles: true })); | ||
}, [route]); | ||
|
||
return <Component prepared={route.preloadedQuery} />; | ||
}; | ||
|
||
export default Renderer; |
Oops, something went wrong.