Skip to content

Commit

Permalink
Merge pull request #5071 from voxel51/release/v1.0.2
Browse files Browse the repository at this point in the history
Release/v1.0.2
  • Loading branch information
findtopher authored Nov 8, 2024
2 parents 05e9822 + a0c4c78 commit 52321f1
Show file tree
Hide file tree
Showing 118 changed files with 2,538 additions and 1,071 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:

all-tests:
runs-on: ubuntu-latest
needs: [build, lint, test]
needs: [build, lint, test, e2e]
if: always()
steps:
- run: sh -c ${{
Expand Down
14 changes: 10 additions & 4 deletions app/packages/app/src/components/AnalyticsConsent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,23 @@ export default function AnalyticsConsent({
Help us improve FiftyOne
</Typography>
<Typography marginBottom={1}>
We use cookies to understand how FiftyOne is used and improve the product.
You can help us by enabling anonymous analytics.
We use cookies to understand how FiftyOne is used and improve the
product. You can help us by enabling anonymous analytics.
</Typography>
<Grid container gap={2} justifyContent="end" direction="row">
<Grid item alignContent="center">
<Link style={{ cursor: "pointer" }} onClick={handleDisable}>
<Link
style={{ cursor: "pointer" }}
onClick={handleDisable}
data-cy="btn-disable-cookies"
>
Disable
</Link>
</Grid>
<Grid item>
<Button variant="contained" onClick={handleEnable}>Enable</Button>
<Button variant="contained" onClick={handleEnable}>
Enable
</Button>
</Grid>
</Grid>
</Grid>
Expand Down
220 changes: 138 additions & 82 deletions app/packages/app/src/routing/RouterContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { Queries } from "../makeRoutes";
import type RouteDefinition from "./RouteDefinition";
import type { LocationState, MatchPathResult } from "./matchPath";

import { viewsAreEqual } from "@fiftyone/state";
import { NotFoundError, Resource, isNotebook } from "@fiftyone/utilities";
import { createBrowserHistory, createMemoryHistory } from "history";
import React from "react";
Expand Down Expand Up @@ -69,6 +70,8 @@ export const createRouter = <T extends OperationType>(
): Router<T> => {
const history = isNotebook() ? createMemoryHistory() : createBrowserHistory();

const getEntryResource = makeGetEntryResource<T>();

let currentEntryResource: Resource<Entry<T>>;
let nextCurrentEntryResource: Resource<Entry<T>>;

Expand All @@ -79,17 +82,27 @@ export const createRouter = <T extends OperationType>(
>();

const update = (location: FiftyOneLocation, action?: Action) => {
requestAnimationFrame(() => {
for (const [_, [__, onPending]] of subscribers) onPending?.();
});
currentEntryResource.load().then(({ cleanup }) => {
nextCurrentEntryResource = getEntryResource<T>(
environment,
routes,
location as FiftyOneLocation,
false,
handleError
);
try {
nextCurrentEntryResource = getEntryResource({
environment,
routes,
location: location as FiftyOneLocation,
hard: false,
handleError,
});
} catch (e) {
if (e instanceof Resource) {
// skip the page change if a resource is thrown
return;
}

throw e;
}

requestAnimationFrame(() => {
for (const [_, [__, onPending]] of subscribers) onPending?.();
});

const loadingResource = nextCurrentEntryResource;
loadingResource.load().then((entry) => {
Expand Down Expand Up @@ -135,13 +148,13 @@ export const createRouter = <T extends OperationType>(
load(hard = false) {
const runUpdate = !currentEntryResource || hard;
if (!currentEntryResource || hard) {
currentEntryResource = getEntryResource(
currentEntryResource = getEntryResource({
environment,
routes,
history.location as FiftyOneLocation,
hard,
handleError
);
handleError,
location: history.location as FiftyOneLocation,
routes,
});
}
runUpdate && update(history.location as FiftyOneLocation);
return currentEntryResource.load();
Expand Down Expand Up @@ -171,79 +184,122 @@ export const createRouter = <T extends OperationType>(
};
};

const getEntryResource = <T extends OperationType>(
environment: Environment,
routes: RouteDefinition<T>[],
location: FiftyOneLocation,
hard = false,
handleError?: (error: unknown) => void
): Resource<Entry<T>> => {
let route: RouteDefinition<T>;
let matchResult: MatchPathResult<T> | undefined = undefined;
for (let index = 0; index < routes.length; index++) {
route = routes[index];
const match = matchPath<T>(
location.pathname,
route,
location.search,
location.state
);

if (match) {
matchResult = match;
break;
const SKIP_EVENTS = new Set(["modal", "slice", "spaces"]);

const makeGetEntryResource = <T extends OperationType>() => {
let currentLocation: FiftyOneLocation;
let currentResource: Resource<Entry<T>>;

const isReusable = (location: FiftyOneLocation) => {
if (location.pathname !== currentLocation?.pathname) {
return false;
}
}

if (matchResult == null) {
throw new NotFoundError({ path: location.pathname });
}
if (!viewsAreEqual(location.state.view, currentLocation?.state.view)) {
return false;
}

const fetchPolicy = hard ? "network-only" : "store-or-network";
if (currentLocation) {
return (
SKIP_EVENTS.has(location.state.event || "") ||
SKIP_EVENTS.has(currentLocation?.state.event || "")
);
}

return new Resource(() => {
return Promise.all([route.component.load(), route.query.load()]).then(
([component, concreteRequest]) => {
const preloadedQuery = loadQuery(
environment,
concreteRequest,
matchResult.variables || {},
{
fetchPolicy,
}
);

let resolveEntry: (entry: Entry<T>) => void;
const promise = new Promise<Entry<T>>((resolve) => {
resolveEntry = resolve;
});
const subscription = fetchQuery(
environment,
concreteRequest,
matchResult.variables || {},
{ fetchPolicy }
).subscribe({
next: (data) => {
const { state: _, ...rest } = location;
resolveEntry({
state: matchResult.variables as LocationState<T>,
...rest,
component,
data,
concreteRequest,
preloadedQuery,
cleanup: () => {
subscription?.unsubscribe();
},
});
},
error: (error) => handleError?.(error),
});
return false;
};

return promise;
const getEntryResource = ({
environment,
handleError,
hard = false,
location,
routes,
}: {
current?: FiftyOneLocation;
environment: Environment;
routes: RouteDefinition<T>[];
location: FiftyOneLocation;
hard: boolean;
handleError?: (error: unknown) => void;
}): Resource<Entry<T>> => {
if (isReusable(location)) {
// throw the current resource (page) if it can be reused
throw currentResource;
}

let route: RouteDefinition<T>;
let matchResult: MatchPathResult<T> | undefined = undefined;
for (let index = 0; index < routes.length; index++) {
route = routes[index];
const match = matchPath<T>(
location.pathname,
route,
location.search,
location.state
);

if (match) {
matchResult = match;
break;
}
);
});
}

if (matchResult == null) {
throw new NotFoundError({ path: location.pathname });
}

const fetchPolicy = hard ? "network-only" : "store-or-network";

currentLocation = location;
currentResource = new Resource(() => {
return Promise.all([route.component.load(), route.query.load()]).then(
([component, concreteRequest]) => {
const preloadedQuery = loadQuery(
environment,
concreteRequest,
matchResult.variables || {},
{
fetchPolicy,
}
);

let resolveEntry: (entry: Entry<T>) => void;
const promise = new Promise<Entry<T>>((resolve) => {
resolveEntry = resolve;
});
const subscription = fetchQuery(
environment,
concreteRequest,
matchResult.variables || {},
{ fetchPolicy }
).subscribe({
next: (data) => {
const { state: _, ...rest } = location;
resolveEntry({
state: matchResult.variables as LocationState<T>,
...rest,
component,
data,
concreteRequest,
preloadedQuery,
cleanup: () => {
subscription?.unsubscribe();
},
});
},
error: (error) => handleError?.(error),
});

return promise;
}
);
});

return currentResource;
};

return getEntryResource;
};

export const RouterContext = React.createContext<
Expand Down
2 changes: 1 addition & 1 deletion app/packages/app/src/routing/matchPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const compilePath = (path: string) =>
});

export type LocationState<T extends OperationType = OperationType> = {
event?: "modal";
event?: "modal" | "slice" | "spaces";
fieldVisibility?: State.FieldVisibilityStage;
groupSlice?: string;
modalSelector?: ModalSelector;
Expand Down
6 changes: 5 additions & 1 deletion app/packages/app/src/useEvents/useSetGroupSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ const useSetGroupSlice: EventHandlerHook = ({ router, session }) => {
session.current.sessionGroupSlice = slice;
});

router.push(pathname, { ...router.location.state, groupSlice: slice });
router.push(pathname, {
...router.location.state,
event: "slice",
groupSlice: slice,
});
},
[router, session]
);
Expand Down
4 changes: 2 additions & 2 deletions app/packages/app/src/useEvents/useSetSpaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ const useSetSpaces: EventHandlerHook = ({ router }) => {
(payload) => {
setter("sessionSpaces", payload.spaces);
const state = router.history.location.state as LocationState;
router.history.replace(
router.replace(
resolveURL({
currentPathname: router.history.location.pathname,
currentSearch: router.history.location.search,
extra: {
workspace: payload.spaces._name ?? null,
},
}),
{ ...state, workspace: payload.spaces }
{ ...state, event: "spaces", workspace: payload.spaces }
);
},
[router, setter]
Expand Down
6 changes: 5 additions & 1 deletion app/packages/app/src/useWriters/onSetGroupSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ const onSetGroupSlice: RegisteredWriter<"sessionGroupSlice"> =

const pathname = router.history.location.pathname + string;

router.push(pathname, { ...router.location.state, groupSlice: slice });
router.push(pathname, {
...router.location.state,
event: "slice",
groupSlice: slice,
});

if (env().VITE_NO_STATE) return;
commitMutation<setGroupSliceMutation>(environment, {
Expand Down
4 changes: 2 additions & 2 deletions app/packages/app/src/useWriters/onSetSessionSpaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ const onSetSessionSpaces: RegisteredWriter<"sessionSpaces"> =
({ environment, router, subscription }) =>
(spaces) => {
const state = router.history.location.state as LocationState;
router.history.replace(
router.replace(
resolveURL({
currentPathname: router.history.location.pathname,
currentSearch: router.history.location.search,
extra: {
workspace: spaces._name || null,
},
}),
{ ...state, workspace: spaces._name || null }
{ ...state, event: "spaces", workspace: spaces._name || null }
);

commitMutation<setSpacesMutation>(environment, {
Expand Down
6 changes: 4 additions & 2 deletions app/packages/components/src/components/AdaptiveMenu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ export default function AdaptiveMenu(props: AdaptiveMenuPropsType) {
if (!containerElem) return;
hideOverflowingNodes(containerElem, (_: number, lastVisibleItemId) => {
const lastVisibleItem = itemsById[lastVisibleItemId];
const computedHidden = items.length - lastVisibleItem.index - 1;
setHidden(computedHidden);
if (lastVisibleItem?.index) {
const computedHidden = items.length - lastVisibleItem.index - 1;
setHidden(computedHidden);
}
});
}

Expand Down
Loading

0 comments on commit 52321f1

Please sign in to comment.