@openstack_dev/gatsby-theme-marketing-oif-core 1.0.33-beta.2 → 1.0.34-beta.4
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/package.json +1 -1
- package/src/components/AuthBootstrap.js +50 -0
- package/src/components/Link.js +76 -42
- package/src/state/ReduxWrapper.js +2 -0
- package/src/utils/url.js +7 -0
package/package.json
CHANGED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { useSelector } from "react-redux";
|
|
3
|
+
import { doLoginBasicLogin } from "openstack-uicore-foundation/lib/security/methods";
|
|
4
|
+
import { getBackURL } from "../utils/url";
|
|
5
|
+
|
|
6
|
+
export default function AuthBootstrap() {
|
|
7
|
+
const isLoggedUser = useSelector(
|
|
8
|
+
(state) => state.loggedUserState.isLoggedUser
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const checkLoginStatus = async () => {
|
|
12
|
+
try {
|
|
13
|
+
const response = await fetch("/oidc/session/whoami", {
|
|
14
|
+
method: "GET",
|
|
15
|
+
credentials: "same-origin"
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
if (response.ok) {
|
|
19
|
+
const data = await response.json();
|
|
20
|
+
if (
|
|
21
|
+
data.email &&
|
|
22
|
+
typeof data.email === "string" &&
|
|
23
|
+
/\S+@\S+\.\S+/.test(data.email)
|
|
24
|
+
) {
|
|
25
|
+
doLoginBasicLogin(getBackURL(), data.email);
|
|
26
|
+
} else {
|
|
27
|
+
console.warn(
|
|
28
|
+
"Invalid or missing email in login response:",
|
|
29
|
+
data.email
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(
|
|
35
|
+
"Failed to check login status. Possible network error or invalid response.",
|
|
36
|
+
{
|
|
37
|
+
error,
|
|
38
|
+
attemptedUrl: "/oidc/session/whoami"
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (!isLoggedUser) checkLoginStatus();
|
|
46
|
+
}, [isLoggedUser]);
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
return null;
|
|
50
|
+
}
|
package/src/components/Link.js
CHANGED
|
@@ -1,46 +1,39 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Link as GatsbyLink } from "gatsby";
|
|
3
|
-
// Since DOM elements <a> cannot receive activeClassName
|
|
4
|
-
// and partiallyActive, destructure the prop here and
|
|
5
|
-
// pass it only to GatsbyLink
|
|
6
|
-
function Link({ children, to, activeClassName, partiallyActive, ...other }) {
|
|
7
|
-
// Tailor the following test to your environment.
|
|
8
3
|
|
|
9
|
-
|
|
10
|
-
const isAbsoluteUrl = /^(https?:)?\/\//i.test(to);
|
|
11
|
-
const isHash = to.startsWith("#");
|
|
4
|
+
/* global __PATH_PREFIX__ */
|
|
12
5
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
const normalizePrefix = (p) => {
|
|
7
|
+
if (!p) return "";
|
|
8
|
+
const trimmed = String(p).replace(/\/+$/, ""); // remove trailing slash
|
|
9
|
+
return trimmed === "/" ? "" : trimmed; // Gatsby uses "" for root
|
|
10
|
+
};
|
|
18
11
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// - it’s a single-slash path
|
|
22
|
-
// - and it’s inside the current prefix (or there is no prefix)
|
|
23
|
-
const isSingleSlashPath = /^\/(?!\/)/.test(to);
|
|
12
|
+
const isAbsoluteUrl = (url = "") => /^(https?:)?\/\//i.test(url);
|
|
13
|
+
const isSingleSlashPath = (url = "") => /^\/(?!\/)/.test(url);
|
|
24
14
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
15
|
+
const stripPrefix = (path, prefix) => {
|
|
16
|
+
if (!prefix) return path;
|
|
17
|
+
if (path === prefix) return "/";
|
|
18
|
+
if (path.startsWith(`${prefix }/`)) return path.slice(prefix.length) || "/";
|
|
19
|
+
return path;
|
|
20
|
+
};
|
|
29
21
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
{children}
|
|
40
|
-
</GatsbyLink>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
22
|
+
function Link({
|
|
23
|
+
children,
|
|
24
|
+
to = "",
|
|
25
|
+
activeClassName,
|
|
26
|
+
partiallyActive,
|
|
27
|
+
...other
|
|
28
|
+
}) {
|
|
29
|
+
const email = /\S+@\S+\.\S+/.test(to);
|
|
30
|
+
const hash = to.startsWith("#");
|
|
43
31
|
|
|
32
|
+
const rawPrefix =
|
|
33
|
+
typeof __PATH_PREFIX__ !== "undefined" ? __PATH_PREFIX__ : "";
|
|
34
|
+
const prefix = normalizePrefix(rawPrefix);
|
|
35
|
+
|
|
36
|
+
// Email
|
|
44
37
|
if (email) {
|
|
45
38
|
const href = /^mailto:/.test(to) ? to : `mailto:${to}`;
|
|
46
39
|
return (
|
|
@@ -50,8 +43,8 @@ function Link({ children, to, activeClassName, partiallyActive, ...other }) {
|
|
|
50
43
|
);
|
|
51
44
|
}
|
|
52
45
|
|
|
53
|
-
//
|
|
54
|
-
if (isAbsoluteUrl) {
|
|
46
|
+
// Absolute URL -> new tab
|
|
47
|
+
if (isAbsoluteUrl(to)) {
|
|
55
48
|
return (
|
|
56
49
|
<a href={to} target="_blank" rel="noreferrer" {...other}>
|
|
57
50
|
{children}
|
|
@@ -59,8 +52,44 @@ function Link({ children, to, activeClassName, partiallyActive, ...other }) {
|
|
|
59
52
|
);
|
|
60
53
|
}
|
|
61
54
|
|
|
62
|
-
// Hash
|
|
63
|
-
if (
|
|
55
|
+
// Hash -> same tab
|
|
56
|
+
if (hash) {
|
|
57
|
+
return (
|
|
58
|
+
<a href={to} {...other}>
|
|
59
|
+
{children}
|
|
60
|
+
</a>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Not a normal "/path" -> default anchor same tab
|
|
65
|
+
if (!isSingleSlashPath(to)) {
|
|
66
|
+
return (
|
|
67
|
+
<a href={to} {...other}>
|
|
68
|
+
{children}
|
|
69
|
+
</a>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// If we are running with a prefix (/__PATH_PREFIX__):
|
|
74
|
+
// - Links already under /__PATH_PREFIX__ are INTERNAL, but must be de-prefixed for GatsbyLink
|
|
75
|
+
// - Links outside /__PATH_PREFIX__ (e.g. /software) should be plain <a> to avoid prefixing
|
|
76
|
+
if (prefix) {
|
|
77
|
+
const isPrefixed = to === prefix || to.startsWith(`${prefix}/`);
|
|
78
|
+
if (isPrefixed) {
|
|
79
|
+
const normalizedTo = stripPrefix(to, prefix); // "/marketplace/distros" -> "/distros"
|
|
80
|
+
return (
|
|
81
|
+
<GatsbyLink
|
|
82
|
+
to={normalizedTo}
|
|
83
|
+
activeClassName={activeClassName}
|
|
84
|
+
partiallyActive={partiallyActive}
|
|
85
|
+
{...other}
|
|
86
|
+
>
|
|
87
|
+
{children}
|
|
88
|
+
</GatsbyLink>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// base site path
|
|
64
93
|
return (
|
|
65
94
|
<a href={to} {...other}>
|
|
66
95
|
{children}
|
|
@@ -68,11 +97,16 @@ function Link({ children, to, activeClassName, partiallyActive, ...other }) {
|
|
|
68
97
|
);
|
|
69
98
|
}
|
|
70
99
|
|
|
71
|
-
//
|
|
100
|
+
// No prefix site: normal Gatsby internal
|
|
72
101
|
return (
|
|
73
|
-
<
|
|
102
|
+
<GatsbyLink
|
|
103
|
+
to={to}
|
|
104
|
+
activeClassName={activeClassName}
|
|
105
|
+
partiallyActive={partiallyActive}
|
|
106
|
+
{...other}
|
|
107
|
+
>
|
|
74
108
|
{children}
|
|
75
|
-
</
|
|
109
|
+
</GatsbyLink>
|
|
76
110
|
);
|
|
77
111
|
}
|
|
78
112
|
|
|
@@ -4,6 +4,7 @@ import { PersistGate } from "redux-persist/integration/react";
|
|
|
4
4
|
import { CacheProvider } from "@emotion/react";
|
|
5
5
|
import { store, persistor } from "./store";
|
|
6
6
|
import createEmotionCache from "../utils/createEmotionCache";
|
|
7
|
+
import AuthBootstrap from "../components/AuthBootstrap";
|
|
7
8
|
|
|
8
9
|
export function ReduxWrapper({ element }) {
|
|
9
10
|
return (
|
|
@@ -18,6 +19,7 @@ export function ReduxWrapperWithCacheProvider({ element }) {
|
|
|
18
19
|
return (
|
|
19
20
|
<CacheProvider value={cache}>
|
|
20
21
|
<Provider store={store}>
|
|
22
|
+
<AuthBootstrap />
|
|
21
23
|
<PersistGate persistor={persistor}>{() => element}</PersistGate>
|
|
22
24
|
</Provider>
|
|
23
25
|
</CacheProvider>
|