slice-machine-ui 2.18.1-alpha.jp-unauthorized-error.3 → 2.18.1-alpha.jp-unauthorized-error-improvement.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/out/404.html +1 -1
  2. package/out/_next/static/{6PcBvU_g2QBnuMafU4iYu → bWd9YPY0k1NsrjJCNbscH}/_buildManifest.js +1 -1
  3. package/out/_next/static/chunks/{248-bdbfde18c5a04eae.js → 248-bcf03aa3c62e7dfb.js} +1 -1
  4. package/out/_next/static/chunks/34-50c64778da33cff6.js +1 -0
  5. package/out/_next/static/chunks/422-c9192a1dbdd2ae0e.js +1 -0
  6. package/out/_next/static/chunks/429-1137c819c2bf6b66.js +3 -0
  7. package/out/_next/static/chunks/{489-6edb99e269996dd1.js → 489-77d1fe67b6d0f0f8.js} +1 -1
  8. package/out/_next/static/chunks/630-c34de0401b8a0375.js +1 -0
  9. package/out/_next/static/chunks/pages/{_app-2fd7ba7c1a132cb4.js → _app-d298cdfd4509fb06.js} +40 -40
  10. package/out/_next/static/chunks/pages/changelog-3901f2fc937d9648.js +1 -0
  11. package/out/_next/static/chunks/pages/changes-62d4e18795217cba.js +1 -0
  12. package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-7102c23f96cd1768.js → [customTypeId]-816acb31b652239b.js} +1 -1
  13. package/out/_next/static/chunks/pages/{labs-d79597003a1ff74e.js → labs-5f5c63fb1f7d4b92.js} +1 -1
  14. package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-d4bc920a5efffa0a.js → [pageTypeId]-669d5479e81b638b.js} +1 -1
  15. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-eca10940c9083d4c.js +1 -0
  16. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-b4700a6332ea828c.js +1 -0
  17. package/out/_next/static/chunks/pages/slices-bf63f937b184b470.js +1 -0
  18. package/out/changelog.html +1 -1
  19. package/out/changes.html +1 -1
  20. package/out/custom-types/[customTypeId].html +1 -1
  21. package/out/custom-types.html +1 -1
  22. package/out/index.html +1 -1
  23. package/out/labs.html +1 -1
  24. package/out/page-types/[pageTypeId].html +1 -1
  25. package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
  26. package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
  27. package/out/slices.html +1 -1
  28. package/package.json +3 -6
  29. package/src/errorBoundaries.tsx +150 -0
  30. package/src/features/auth/LogoutButton.tsx +42 -36
  31. package/src/features/builder/fields/contentRelationship/ContentRelationshipFieldPicker.tsx +3 -3
  32. package/src/features/changes/StatusBadge.tsx +1 -9
  33. package/src/features/customTypes/customTypesBuilder/PageSnippetDialog/PageSnippetDialog.tsx +3 -3
  34. package/src/features/customTypes/customTypesTable/CustomTypesTablePage.tsx +3 -3
  35. package/src/features/environments/actions/useSetEnvironment.ts +22 -0
  36. package/src/features/environments/useActiveEnvironment.ts +17 -9
  37. package/src/features/environments/useEnvironments.ts +11 -8
  38. package/src/features/labs/labsList/LabsPage.tsx +3 -3
  39. package/src/features/navigation/Navigation.tsx +31 -8
  40. package/src/features/navigation/NavigationItem.tsx +9 -3
  41. package/src/features/navigation/SliceMachineVersion.tsx +1 -6
  42. package/src/features/slices/sliceBuilder/FloatingBackButton.tsx +3 -3
  43. package/src/features/slices/sliceBuilder/McpPromoLink.tsx +29 -0
  44. package/src/features/sync/actions/pushChanges.ts +1 -0
  45. package/src/features/sync/getUnSyncChanges.ts +23 -7
  46. package/src/legacy/components/AppLayout/index.tsx +10 -85
  47. package/src/legacy/components/ChangesEmptyState/UnauthenticatedView.tsx +31 -0
  48. package/src/legacy/components/ChangesEmptyState/index.ts +1 -1
  49. package/src/legacy/components/ChangesItems/ChangesItems.tsx +3 -3
  50. package/src/legacy/components/LoginModal/index.tsx +13 -5
  51. package/src/legacy/components/Navigation/ChangesItem.tsx +2 -6
  52. package/src/legacy/components/Navigation/Environment.tsx +2 -7
  53. package/src/legacy/components/Navigation/SideNavEnvironmentSelector/SideNavEnvironmentSelector.tsx +3 -8
  54. package/src/legacy/components/Simulator/index.tsx +3 -3
  55. package/src/legacy/lib/builders/CustomTypeBuilder/TabZone/index.tsx +3 -3
  56. package/src/legacy/lib/builders/SliceBuilder/index.tsx +2 -0
  57. package/src/legacy/lib/models/common/ModelStatus/index.ts +6 -1
  58. package/src/modules/userContext/index.ts +6 -3
  59. package/src/modules/userContext/types.ts +1 -1
  60. package/src/pages/_app.tsx +88 -95
  61. package/src/pages/changes.tsx +4 -5
  62. package/src/queryClient.tsx +24 -0
  63. package/test/__testutils__/index.tsx +13 -10
  64. package/out/_next/static/chunks/157-54b8336d20b41933.js +0 -3
  65. package/out/_next/static/chunks/34-8d9d9b2944824750.js +0 -1
  66. package/out/_next/static/chunks/385-b949173dfa03dd3e.js +0 -1
  67. package/out/_next/static/chunks/630-bb6e3db525588f16.js +0 -1
  68. package/out/_next/static/chunks/pages/changelog-21b960abba5abf71.js +0 -1
  69. package/out/_next/static/chunks/pages/changes-7919746009a45ad8.js +0 -1
  70. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-b127d948a17968d3.js +0 -1
  71. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-98f85d5fb8d5c704.js +0 -1
  72. package/out/_next/static/chunks/pages/slices-046e5e978ffc3a42.js +0 -1
  73. package/src/ErrorBoundary.tsx +0 -47
  74. package/src/features/environments/actions/setEnvironment.ts +0 -18
  75. package/src/legacy/components/ChangesEmptyState/AuthErrorPage.tsx +0 -44
  76. /package/out/_next/static/{6PcBvU_g2QBnuMafU4iYu → bWd9YPY0k1NsrjJCNbscH}/_ssgManifest.js +0 -0
@@ -13,34 +13,33 @@ import "@/styles/starry-night.css";
13
13
  import "@/styles/tabs.css";
14
14
  import "@/styles/toaster.css";
15
15
 
16
+ import { ThemeProvider, TooltipProvider } from "@prismicio/editor-ui";
16
17
  import {
17
- Box,
18
- DefaultErrorMessage,
19
- ThemeProvider,
20
- TooltipProvider,
21
- } from "@prismicio/editor-ui";
22
- import { ConnectedRouter } from "connected-next-router";
18
+ isInvalidActiveEnvironmentError,
19
+ isUnauthorizedError,
20
+ } from "@slicemachine/manager/client";
21
+ import { useSuspenseQuery } from "@tanstack/react-query";
22
+ import { ConnectedRouter as StoreConnectedRouter } from "connected-next-router";
23
23
  import type { NextPage } from "next";
24
24
  import type { AppContext, AppInitialProps } from "next/app";
25
25
  import dynamic from "next/dynamic";
26
26
  import Head from "next/head";
27
27
  import Router from "next/router";
28
- import { type FC, type ReactNode, Suspense, useEffect, useState } from "react";
28
+ import { type FC, type ReactNode, Suspense, useEffect } from "react";
29
29
  import { Provider } from "react-redux";
30
- import type { Store } from "redux";
31
- import type { Persistor } from "redux-persist/es/types";
32
30
  import { PersistGate } from "redux-persist/integration/react";
33
31
  import { ThemeProvider as ThemeUIThemeProvider, useThemeUI } from "theme-ui";
34
32
 
35
33
  import { getState } from "@/apiClient";
36
- import { ErrorBoundary } from "@/ErrorBoundary";
34
+ import { AppStateErrorBoundary } from "@/errorBoundaries";
35
+ import { useActiveEnvironment } from "@/features/environments/useActiveEnvironment";
37
36
  import { AutoSyncProvider } from "@/features/sync/AutoSyncProvider";
38
37
  import { RouteChangeProvider } from "@/hooks/useRouteChange";
39
38
  import SliceMachineApp from "@/legacy/components/App";
40
39
  import LoadingPage from "@/legacy/components/LoadingPage";
41
40
  import ToastContainer from "@/legacy/components/ToasterContainer";
42
41
  import { normalizeFrontendCustomTypes } from "@/legacy/lib/models/common/normalizers/customType";
43
- import type ServerState from "@/legacy/lib/models/server/ServerState";
42
+ import { QueryClientProvider } from "@/queryClient";
44
43
  import configureStore from "@/redux/store";
45
44
  import theme from "@/theme";
46
45
 
@@ -68,50 +67,11 @@ const RemoveDarkMode: FC<RemoveDarkModeProps> = ({ children }) => {
68
67
  return <>{children}</>;
69
68
  };
70
69
 
71
- function App({
72
- Component,
73
- pageProps,
74
- }: AppContextWithComponentLayout & AppInitialProps) {
75
- const [serverState, setServerState] = useState<ServerState | null>(null);
76
- const [smStore, setSMStore] = useState<{
77
- store: Store;
78
- persistor: Persistor;
79
- } | null>(null);
70
+ function App(props: AppContextWithComponentLayout & AppInitialProps) {
71
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
72
+ const { Component, pageProps } = props;
80
73
 
81
- useEffect(() => {
82
- async function getInitialState() {
83
- const serverState = await getState();
84
- setServerState(serverState);
85
- }
86
- void getInitialState();
87
- }, []);
88
-
89
- useEffect(() => {
90
- if (!serverState || smStore) {
91
- return;
92
- }
93
-
94
- const normalizedCustomTypes = normalizeFrontendCustomTypes(
95
- serverState.customTypes,
96
- serverState.remoteCustomTypes,
97
- );
98
-
99
- const { store, persistor } = configureStore({
100
- environment: serverState.env,
101
- availableCustomTypes: {
102
- ...normalizedCustomTypes,
103
- },
104
- slices: {
105
- libraries: serverState.libraries,
106
- remoteSlices: serverState.remoteSlices,
107
- },
108
- });
109
-
110
- setSMStore({ store, persistor });
111
- }, [serverState, smStore]);
112
-
113
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
114
- const ComponentLayout = Component.CustomLayout || SliceMachineApp;
74
+ const ComponentLayout = Component.CustomLayout ?? SliceMachineApp;
115
75
 
116
76
  return (
117
77
  <>
@@ -119,50 +79,83 @@ function App({
119
79
  <title>Slice Machine</title>
120
80
  </Head>
121
81
  <ThemeUIThemeProvider theme={theme}>
122
- <RemoveDarkMode>
123
- <ThemeProvider mode="light">
124
- <TooltipProvider>
125
- {!smStore || !serverState ? (
126
- <LoadingPage />
127
- ) : (
128
- <Provider store={smStore.store}>
129
- <ConnectedRouter Router={Router}>
130
- <PersistGate loading={null} persistor={smStore.persistor}>
131
- <ErrorBoundary
132
- renderError={() => (
133
- <Box
134
- justifyContent="center"
135
- width="100%"
136
- padding={80}
137
- >
138
- <DefaultErrorMessage
139
- title="Error"
140
- description="An error occurred while rendering the app."
141
- />
142
- </Box>
143
- )}
144
- >
145
- <Suspense fallback={<LoadingPage />}>
146
- <AutoSyncProvider>
147
- <RouteChangeProvider>
148
- <ComponentLayout>
149
- <Component {...pageProps} />
150
- </ComponentLayout>
151
- </RouteChangeProvider>
152
- </AutoSyncProvider>
153
- </Suspense>
154
- </ErrorBoundary>
155
- </PersistGate>
156
- </ConnectedRouter>
157
- <ToastContainer />
158
- </Provider>
159
- )}
160
- </TooltipProvider>
161
- </ThemeProvider>
162
- </RemoveDarkMode>
82
+ <QueryClientProvider>
83
+ <RemoveDarkMode>
84
+ <ThemeProvider mode="light">
85
+ <TooltipProvider>
86
+ <AppStateErrorBoundary>
87
+ <Suspense fallback={<LoadingPage />}>
88
+ <AppStateValidator>
89
+ <AppStateWrapper>
90
+ <AutoSyncProvider>
91
+ <ComponentLayout>
92
+ <Component {...pageProps} />
93
+ </ComponentLayout>
94
+ </AutoSyncProvider>
95
+ </AppStateWrapper>
96
+ </AppStateValidator>
97
+ </Suspense>
98
+ </AppStateErrorBoundary>
99
+ <ToastContainer />
100
+ </TooltipProvider>
101
+ </ThemeProvider>
102
+ </RemoveDarkMode>
103
+ </QueryClientProvider>
163
104
  </ThemeUIThemeProvider>
164
105
  </>
165
106
  );
166
107
  }
167
108
 
109
+ /** This is where we should check for unwanted states that should prevent the
110
+ * user from using the app, and trigger the {@link AppStateErrorBoundary} to
111
+ * display something explaining why. */
112
+ function AppStateValidator(props: { children: ReactNode }) {
113
+ const activeEnvironment = useActiveEnvironment({ suspense: true });
114
+
115
+ if (
116
+ isUnauthorizedError(activeEnvironment.error) ||
117
+ isInvalidActiveEnvironmentError(activeEnvironment.error)
118
+ ) {
119
+ throw activeEnvironment.error;
120
+ }
121
+
122
+ return <>{props.children}</>;
123
+ }
124
+
125
+ function AppStateWrapper({ children }: { children: ReactNode }) {
126
+ const { data: state } = useSuspenseQuery({
127
+ queryKey: ["getInitialState"],
128
+ queryFn: async () => {
129
+ const serverState = await getState();
130
+ const { store, persistor } = configureStore({
131
+ environment: serverState.env,
132
+ availableCustomTypes: {
133
+ ...normalizeFrontendCustomTypes(
134
+ serverState.customTypes,
135
+ serverState.remoteCustomTypes,
136
+ ),
137
+ },
138
+ slices: {
139
+ libraries: serverState.libraries,
140
+ remoteSlices: serverState.remoteSlices,
141
+ },
142
+ });
143
+
144
+ return { serverState, store, persistor };
145
+ },
146
+ staleTime: Infinity,
147
+ gcTime: Infinity,
148
+ });
149
+
150
+ return (
151
+ <Provider store={state.store}>
152
+ <StoreConnectedRouter Router={Router}>
153
+ <PersistGate loading={null} persistor={state.persistor}>
154
+ <RouteChangeProvider>{children}</RouteChangeProvider>
155
+ </PersistGate>
156
+ </StoreConnectedRouter>
157
+ </Provider>
158
+ );
159
+ }
160
+
168
161
  export default dynamic(() => Promise.resolve(App), { ssr: false });
@@ -25,8 +25,8 @@ import {
25
25
  AppLayoutHeader,
26
26
  } from "@/legacy/components/AppLayout";
27
27
  import {
28
- AuthErrorPage,
29
28
  OfflinePage,
29
+ UnauthenticatedView,
30
30
  } from "@/legacy/components/ChangesEmptyState";
31
31
  import { ChangesItems } from "@/legacy/components/ChangesItems";
32
32
  import {
@@ -114,8 +114,8 @@ const Changes: React.FunctionComponent = () => {
114
114
  if (!isOnline) {
115
115
  return <OfflinePage />;
116
116
  }
117
- if (authStatus === AuthStatus.FORBIDDEN) {
118
- return <AuthErrorPage authStatus={authStatus} />;
117
+ if (authStatus === AuthStatus.UNAUTHENTICATED) {
118
+ return <UnauthenticatedView />;
119
119
  }
120
120
  if (numberOfChanges === 0) {
121
121
  return (
@@ -160,8 +160,7 @@ const Changes: React.FunctionComponent = () => {
160
160
  disabled={
161
161
  numberOfChanges === 0 ||
162
162
  !isOnline ||
163
- authStatus === AuthStatus.UNAUTHORIZED ||
164
- authStatus === AuthStatus.FORBIDDEN ||
163
+ authStatus !== AuthStatus.AUTHORIZED ||
165
164
  isSyncing
166
165
  }
167
166
  loading={isSyncing}
@@ -0,0 +1,24 @@
1
+ import {
2
+ QueryClient,
3
+ QueryClientProvider as RCQueryClientProvider,
4
+ } from "@tanstack/react-query";
5
+ import { ReactNode } from "react";
6
+
7
+ export const queryClient = new QueryClient({
8
+ defaultOptions: {
9
+ queries: {
10
+ staleTime: 5 * 60 * 1000,
11
+ gcTime: 10 * 60 * 1000,
12
+ retry: false,
13
+ refetchOnWindowFocus: "always",
14
+ },
15
+ },
16
+ });
17
+
18
+ export function QueryClientProvider(props: { children: ReactNode }) {
19
+ return (
20
+ <RCQueryClientProvider client={queryClient}>
21
+ {props.children}
22
+ </RCQueryClientProvider>
23
+ );
24
+ }
@@ -5,7 +5,8 @@ import { Provider } from "react-redux";
5
5
  import { AnyAction, Store } from "redux";
6
6
  import { BaseStyles, ThemeProvider as ThemeUIThemeProvider } from "theme-ui";
7
7
 
8
- import { ErrorBoundary } from "@/ErrorBoundary";
8
+ import { DefaultErrorBoundary } from "@/errorBoundaries";
9
+ import { QueryClientProvider } from "@/queryClient";
9
10
 
10
11
  import configureStore from "../../src/redux/store";
11
12
  import type { SliceMachineStoreType } from "../../src/redux/type";
@@ -44,15 +45,17 @@ function render(
44
45
  children: any;
45
46
  }) {
46
47
  return (
47
- <ThemeUIThemeProvider theme={theme}>
48
- <TooltipProvider>
49
- <BaseStyles>
50
- <Provider store={store}>
51
- <ErrorBoundary>{children}</ErrorBoundary>
52
- </Provider>
53
- </BaseStyles>
54
- </TooltipProvider>
55
- </ThemeUIThemeProvider>
48
+ <QueryClientProvider>
49
+ <ThemeUIThemeProvider theme={theme}>
50
+ <TooltipProvider>
51
+ <BaseStyles>
52
+ <Provider store={store}>
53
+ <DefaultErrorBoundary>{children}</DefaultErrorBoundary>
54
+ </Provider>
55
+ </BaseStyles>
56
+ </TooltipProvider>
57
+ </ThemeUIThemeProvider>
58
+ </QueryClientProvider>
56
59
  );
57
60
  }
58
61
  return {