@openstack_dev/gatsby-theme-marketing-oif-core 1.0.35-beta.6 → 1.0.36

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.
package/.nvmrc CHANGED
@@ -1 +1 @@
1
- 20.19.4
1
+ 22.22.1
@@ -0,0 +1,80 @@
1
+ # Yarn Install Warnings Fix Plan
2
+
3
+ Created: 2026-03-20
4
+ Status: VERIFIED
5
+ Approved: Yes
6
+ Iterations: 0
7
+ Worktree: No
8
+ Type: Bugfix
9
+
10
+ ## Summary
11
+
12
+ **Symptom:** ~80 warnings during `yarn install` — duplicate dependencies, unmet peer deps, incorrect peer dep versions, workspaces misconfiguration.
13
+ **Trigger:** Running `yarn install` on the project.
14
+ **Root Cause:** Multiple independent issues in `package.json`:
15
+
16
+ 1. `babel-preset-gatsby` listed in BOTH `dependencies` (^3.13.2) AND `devDependencies` (^3.14.0) — collision (2 warnings)
17
+ 2. `core-js` at ^2.6.11 but `babel-preset-gatsby` needs ^3.0.0 (1 warning)
18
+ 3. `immutable` at ^5.0.0-beta.5 — beta version, netlify-cms-lib-widgets wants ^3.7.6 (1 warning — not fixable, but beta should be upgraded to stable)
19
+ 4. Missing `"private": true` — workspaces warning (1 warning)
20
+ 5. `react-dnd` pinned at 15.1.1 but `openstack-uicore-foundation` peer dep wants ^16.0.0, and `react-dnd-html5-backend` is already at 16.0.1 (1 warning)
21
+
22
+ **Remaining ~74 warnings are upstream issues** — packages declaring old peer deps (React 16/17, redux 3, etc.) that must be fixed in their respective repositories. These include:
23
+ - `openstack-uicore-foundation@4.1.70` — 14 warnings (declares React ^16, redux ^3, redux-persist ^5, plus 6 unmet optional peer deps)
24
+ - `decap-cms-app` internals — ~15 warnings (old react/redux peer deps in transitive deps)
25
+ - `@ncwidgets/file-relation` + `@ncwidgets/id` — 5 warnings (declare React ^16, netlify-cms-app ^2)
26
+ - `gatsby` internals — ~5 warnings (eslint-config-react-app, experimental react-server-dom-webpack)
27
+ - `gatsby-plugin-decap-cms` — 4 warnings (webpack peer deps provided internally by gatsby)
28
+ - `gatsby-plugin-google-fonts-v2@1.0.1` — 6 warnings (declares gatsby ^3||^4, no newer version exists)
29
+ - `gatsby-plugin-netlify`, `gatsby-plugin-sass` — 2 warnings (webpack peer deps)
30
+ - Direct deps providing openstack-uicore-foundation peer deps (react-select@2, react-tooltip@3, react-tabs@3, react-slick@0.27, react-avatar-editor@11, react-block-image@1, react-rte@0.16) — ~15 warnings (declare React <18, but exist to satisfy openstack-uicore-foundation peer deps)
31
+ - `slick-carousel@1.8.1` — 1 warning (unmet jquery peer dep)
32
+ - `navigation-widget@1.0.27` — 1 warning (declares React ^16)
33
+ - `geotiff@2.0.4` — 1 warning (invalid "browsers" engine — transitive dep)
34
+
35
+ ## Investigation
36
+
37
+ - None of the warning-causing direct dependencies (react-select, react-tooltip, react-tabs, react-slick, react-avatar-editor, react-block-image, react-rte, react-dnd, sweetalert2, core-js, immutable, netlify-cms-lib-widgets) are imported anywhere in `src/`. They exist solely as peer dep providers for `openstack-uicore-foundation`.
38
+ - This is a Gatsby theme (`@openstack_dev/gatsby-theme-marketing-oif-core`) — child projects inherit its dependencies. Removing peer dep providers would break child themes.
39
+ - `@ncwidgets/file-relation` and `@ncwidgets/id` ARE used in `src/cms/cms.js` for CMS widget registration.
40
+ - Yarn v1 (classic) has no mechanism to suppress peer dependency warnings.
41
+
42
+ ## Fix Approach
43
+
44
+ **Files:** `package.json`
45
+ **Strategy:** Fix the 5 actionable issues in `package.json`. Document upstream issues for future reference.
46
+
47
+ **Changes:**
48
+ 1. Remove `"babel-preset-gatsby": "^3.13.2"` from `dependencies` (keep `"^3.14.0"` in `devDependencies`)
49
+ 2. Upgrade `"core-js"` from `"^2.6.11"` to `"^3.0.0"` (satisfies babel-preset-gatsby peer dep)
50
+ 3. Upgrade `"immutable"` from `"^5.0.0-beta.5"` to `"^5.1.5"` (stable release)
51
+ 4. Add `"private": true` to package.json (suppresses workspaces warning)
52
+ 5. Upgrade `"react-dnd"` from `"15.1.1"` to `"^16.0.1"` (matches openstack-uicore-foundation peer dep and existing react-dnd-html5-backend@16.0.1)
53
+
54
+ **Expected result:** Reduces warnings from ~80 to ~74. The remaining warnings require upstream package updates.
55
+
56
+ ## Progress
57
+
58
+ - [x] Task 1: Fix actionable package.json warnings
59
+ - [x] Task 2: Verify yarn install and build
60
+ **Tasks:** 2 | **Done:** 2
61
+
62
+ ## Tasks
63
+
64
+ ### Task 1: Fix actionable package.json warnings
65
+
66
+ **Objective:** Apply the 5 package.json changes to eliminate actionable warnings
67
+ **Files:** `package.json`
68
+ **Changes:**
69
+ 1. Remove `babel-preset-gatsby` from `dependencies` (line 53)
70
+ 2. Change `core-js` from `"^2.6.11"` to `"^3.0.0"` (line 60)
71
+ 3. Change `immutable` from `"^5.0.0-beta.5"` to `"^5.1.5"` (line 95)
72
+ 4. Add `"private": true` after `"description"` field
73
+ 5. Change `react-dnd` from `"15.1.1"` to `"^16.0.1"` (line 115)
74
+ **TDD:** N/A (configuration change, no unit tests applicable)
75
+ **Verify:** `yarn install 2>&1 | grep -c "^warning"` — count should decrease by ~6
76
+
77
+ ### Task 2: Verify yarn install and build
78
+
79
+ **Objective:** Confirm reduced warnings and no regressions
80
+ **Verify:** `yarn install` (count warnings), `yarn build` or `yarn develop` (confirm no build breakage from core-js/react-dnd upgrade)
package/gatsby-browser.js CHANGED
@@ -1,6 +1,3 @@
1
- import React from "react";
2
- import { ReduxWrapper } from "./src/state/ReduxWrapper";
1
+ import { ReduxWrapperWithCacheProvider } from "./src/state/ReduxWrapper";
3
2
 
4
- export const wrapRootElement = ({ element }) => (
5
- <ReduxWrapper element={element} />
6
- );
3
+ export const wrapRootElement = ReduxWrapperWithCacheProvider;
package/gatsby-ssr.js CHANGED
@@ -1,9 +1,7 @@
1
- import React from "react";
2
-
3
1
  import { JSDOM } from "jsdom";
4
2
  import { XMLHttpRequest } from "xmlhttprequest";
5
- import { HeadComponents } from "./src/components/head-components";
6
3
  import { ReduxWrapper } from "./src/state/ReduxWrapper";
4
+ import { HeadComponents } from "./src/components/head-components";
7
5
 
8
6
  export const onRenderBody = ({ setHeadComponents }) => {
9
7
  if (process.env.NODE_ENV === "production") {
@@ -11,15 +9,13 @@ export const onRenderBody = ({ setHeadComponents }) => {
11
9
  }
12
10
  };
13
11
 
14
- export const wrapRootElement = ({ element }) => (
15
- <ReduxWrapper element={element} />
16
- );
12
+ export const wrapRootElement = ReduxWrapper;
17
13
 
18
14
  // build enabler polyfills
19
15
  global.dom = new JSDOM("...");
20
16
  global.window = global.dom.window;
21
17
  global.document = global.dom.window.document;
22
- global.navigator = global.window.navigator;
18
+
23
19
  global.window.matchMedia = () => ({
24
20
  matches: false,
25
21
  addListener: () => {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openstack_dev/gatsby-theme-marketing-oif-core",
3
- "version": "1.0.35-beta.6",
3
+ "version": "1.0.36",
4
4
  "description": "Base theme for Marketing Sites",
5
5
  "author": "smarcet",
6
6
  "keywords": [
@@ -50,14 +50,13 @@
50
50
  "@types/markerclustererplus": "^2.1.33",
51
51
  "@types/react": "^16.9.42",
52
52
  "axios": "^0.19.2",
53
- "babel-preset-gatsby": "^3.13.2",
54
53
  "browser-tabs-lock": "^1.2.15",
55
54
  "buffer": "^6.0.3",
56
55
  "chain-function": "^1.0.1",
57
56
  "classnames": "^2.3.1",
58
57
  "clean-html": "^1.5.0",
59
58
  "codemirror": "^5.55.0",
60
- "core-js": "^2.6.11",
59
+ "core-js": "^3.0.0",
61
60
  "cross-env": "^7.0.3",
62
61
  "crypto-js": "^4.1.1",
63
62
  "decap-cms-app": "^3.1.9",
@@ -65,7 +64,7 @@
65
64
  "dropzone": "^5.7.2",
66
65
  "final-form": "4.20.7",
67
66
  "formik": "^2.2.9",
68
- "gatsby": "^5.8.1",
67
+ "gatsby": "5.16.0",
69
68
  "gatsby-alias-imports": "^1.0.6",
70
69
  "gatsby-plugin-cookiebot": "^1.0.3",
71
70
  "gatsby-plugin-decap-cms": "^4.0.4",
@@ -92,7 +91,7 @@
92
91
  "idtoken-verifier": "^2.2.2",
93
92
  "image-size": "^1.0.1",
94
93
  "immutability-helper": "2.9.1",
95
- "immutable": "^5.0.0-beta.5",
94
+ "immutable": "^5.1.5",
96
95
  "js-cookie": "^3.0.5",
97
96
  "js-yaml": "^4.1.0",
98
97
  "jsdom": "^16.2.2",
@@ -112,7 +111,7 @@
112
111
  "react-block-image": "^1.0.0",
113
112
  "react-bootstrap": "^0.33.1",
114
113
  "react-datetime": "^2.16.3",
115
- "react-dnd": "15.1.1",
114
+ "react-dnd": "^16.0.1",
116
115
  "react-dnd-html5-backend": "^16.0.1",
117
116
  "react-dom": "^18.2.0",
118
117
  "react-final-form": "6.5.9",
@@ -7,46 +7,47 @@ export default function AuthBootstrap() {
7
7
  const isLoggedUser = useSelector(
8
8
  (state) => state.loggedUserState.isLoggedUser
9
9
  );
10
+ const rehydrated = useSelector((state) => state._persist?.rehydrated);
10
11
  const ranRef = useRef(false);
11
-
12
- useEffect(() => {
13
- // already ran
14
- if (ranRef.current || isLoggedUser) return;
15
- ranRef.current = true;
16
-
17
- const controller = new AbortController();
18
-
19
- const run = async () => {
20
- try {
21
- const response = await fetch("/oidc/session/whoami", {
22
- method: "GET",
23
- credentials: "same-origin",
24
- signal: controller.signal
25
- });
26
-
27
- if (!response.ok) return;
28
-
29
- const data = await response.json();
30
- const email = data?.email;
31
-
32
- if (typeof email === "string" && /\S+@\S+\.\S+/.test(email)) {
33
- doLoginBasicLogin(getBackURL(), email);
34
- }
35
- } catch (err) {
36
- if (err?.name !== "AbortError") {
37
- console.error("AuthBootstrap whoami failed", err);
38
- }
12
+ const MIN_EMAIL_LENGTH = 3;
13
+
14
+ const checkLoginStatus = async () => {
15
+ try {
16
+ const response = await fetch("/oidc/session/whoami", {
17
+ method: "GET",
18
+ credentials: "same-origin"
19
+ });
20
+
21
+ if (!response.ok) return;
22
+ const data = await response.json();
23
+ if (
24
+ data.email &&
25
+ typeof data.email === "string" &&
26
+ data.email.includes("@") &&
27
+ data.email.includes(".") &&
28
+ data.email.length > MIN_EMAIL_LENGTH
29
+ ) {
30
+ ranRef.current = true;
31
+ doLoginBasicLogin(getBackURL(), data.email);
32
+ return;
39
33
  }
40
- };
41
-
42
- if (typeof window !== "undefined" && "requestIdleCallback" in window) {
43
- window.requestIdleCallback(run, { timeout: 1000 });
44
- } else {
45
- setTimeout(run, 0);
34
+ console.warn("Invalid or missing email in login response:", data.email);
35
+ } catch (error) {
36
+ console.error(
37
+ "Failed to check login status. Possible network error or invalid response.",
38
+ {
39
+ error,
40
+ attemptedUrl: "/oidc/session/whoami"
41
+ }
42
+ );
46
43
  }
44
+ };
47
45
 
48
- return () => controller.abort();
49
- }, [isLoggedUser]);
46
+ useEffect(() => {
47
+ if (rehydrated !== undefined && !rehydrated) return; // Only wait if persist exists
48
+ if (isLoggedUser || ranRef.current) return;
49
+ checkLoginStatus();
50
+ }, [rehydrated, isLoggedUser]);
50
51
 
51
52
  return null;
52
53
  }
@@ -1 +1 @@
1
- { "staticJsonFilesBuildTime": [], "lastBuild": 1740420798753 }
1
+ {"staticJsonFilesBuildTime":[],"lastBuild":1774023818781}
@@ -2,36 +2,25 @@ import * as React from "react";
2
2
  import { Provider } from "react-redux";
3
3
  import { PersistGate } from "redux-persist/integration/react";
4
4
  import { CacheProvider } from "@emotion/react";
5
-
6
- import { store, getPersistor } from "./store";
5
+ import { store, persistor } from "./store";
7
6
  import createEmotionCache from "../utils/createEmotionCache";
8
7
  import AuthBootstrap from "../components/AuthBootstrap";
9
8
 
10
- const isBrowser = typeof window !== "undefined";
11
-
12
9
  export function ReduxWrapper({ element }) {
13
- const [persistor, setPersistor] = React.useState(null);
14
- const cacheRef = React.useRef(null);
15
- if (!cacheRef.current) cacheRef.current = createEmotionCache();
16
-
17
- React.useEffect(() => {
18
- setPersistor(getPersistor());
19
- }, []);
10
+ return (
11
+ <Provider store={store}>
12
+ <PersistGate persistor={persistor}>{() => element}</PersistGate>
13
+ </Provider>
14
+ );
15
+ }
20
16
 
17
+ export function ReduxWrapperWithCacheProvider({ element }) {
18
+ const cache = createEmotionCache();
21
19
  return (
22
- <CacheProvider value={cacheRef.current}>
20
+ <CacheProvider value={cache}>
23
21
  <Provider store={store}>
24
- {isBrowser && persistor ? (
25
- <PersistGate persistor={persistor} loading={element}>
26
- <>
27
- <AuthBootstrap />
28
- {element}
29
- </>
30
- </PersistGate>
31
- ) : (
32
- // first render SSR === Client
33
- element
34
- )}
22
+ <AuthBootstrap />
23
+ <PersistGate persistor={persistor}>{() => element}</PersistGate>
35
24
  </Provider>
36
25
  </CacheProvider>
37
26
  );
@@ -1,40 +1,39 @@
1
1
  import { applyMiddleware, compose, createStore } from "redux";
2
2
  import { persistCombineReducers, persistStore } from "redux-persist";
3
+ import storage from "redux-persist/lib/storage";
3
4
  import thunk from "redux-thunk";
4
- import * as reducers from "../reducers";
5
-
6
- const isBrowser = typeof window !== "undefined";
7
5
 
8
- const createNoopStorage = () => ({
9
- getItem: () => Promise.resolve(null),
10
- setItem: () => Promise.resolve(),
11
- removeItem: () => Promise.resolve()
12
- });
13
-
14
- const storage = isBrowser
15
- ? require("redux-persist/lib/storage").default
16
- : createNoopStorage();
6
+ import * as reducers from "../reducers";
17
7
 
8
+ // Get from process.env because window is not set yet
18
9
  const clientId = process.env.GATSBY_OAUTH2_CLIENT_ID;
19
10
 
20
- const config = { key: `root_${clientId}`, storage };
21
- const states = { loggedUserState: reducers.loggedUserReducer };
11
+ const config = {
12
+ key: `root_${clientId}`,
13
+ storage,
14
+ blacklist: [
15
+ // this will be not saved to persistent storage see
16
+ // https://github.com/rt2zz/redux-persist#blacklist--whitelist
17
+ ],
18
+ };
19
+
20
+ const states = {
21
+ loggedUserState: reducers.loggedUserReducer,
22
+ };
22
23
 
23
- const composeEnhancers =
24
- typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
25
- ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
26
- : compose;
24
+ const composeEnhancers = typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
25
+ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
26
+ : compose;
27
27
 
28
28
  const enhancer = composeEnhancers(applyMiddleware(thunk));
29
29
 
30
- const persistedReducers = persistCombineReducers(config, states);
30
+ // Create store with persistor
31
+ export const { store, persistor } = (() => {
32
+ const persistedReducers = persistCombineReducers(config, states);
31
33
 
32
- export const store = createStore(persistedReducers, enhancer);
34
+ const store = createStore(persistedReducers, enhancer);
35
+ const onRehydrateComplete = () => {};
36
+ const persistor = persistStore(store, null, onRehydrateComplete);
33
37
 
34
- // lazy persistor
35
- let _persistor = null;
36
- export const getPersistor = () => {
37
- if (!isBrowser) return null;
38
- if (!_persistor) _persistor = persistStore(store);
39
- return _persistor;
40
- };
38
+ return { store, persistor };
39
+ })();
package/src/utils/url.js CHANGED
@@ -1,7 +1,8 @@
1
1
  export const getBackURL = () => {
2
2
  let backUrl = "/";
3
3
  if (typeof window !== "undefined") {
4
- backUrl = window.location.pathname;
4
+ backUrl =
5
+ window.location.pathname + window.location.search + window.location.hash;
5
6
  }
6
7
  return backUrl;
7
8
  };