Skip to content

Commit 19e3276

Browse files
authored
Merge branch 'main' into STRIPES-861-int
2 parents ba9179c + 5887b96 commit 19e3276

File tree

13 files changed

+305
-63
lines changed

13 files changed

+305
-63
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
* Load modules in parallel for greater efficiency. Refs STCOR-1021.
3535
* Increase default timeout to 60 seconds in useOkapiKy.js to match the value in Kong. Refs STCOR-1022.
3636
* Add `tr` Türkçe (Turkish) locale. Refs STCOR-1026.
37+
* Remove the `/users-keycloak/_self` (and `/bl-users/_self`) requests. They were included in `isAuthenticationRequest`, which caused them to bypass the RTR queue (`getPromise`). Fixes STCOR-1029.
38+
* Define a permission-set containing values necessary for session-init API requests. Refs STCOR-1031.
39+
* FOLIO Landing Page > Display text to link to FOLIO release notes. Refs STCOR-1017.
40+
* Settings > System Information > Add a link to Release Notes. Refs STCOR-1018.
3741

3842
## [11.0.0](https://github.com/folio-org/stripes-core/tree/v11.0.0) (2025-02-24)
3943
[Full Changelog](https://github.com/folio-org/stripes-core/compare/v10.2.0...v11.0.0)

package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
},
3232
"optionalOkapiInterfaces": {
3333
"consortia": "1.0",
34+
"locale": "1.0",
3435
"login-saml": "2.0",
3536
"roles": "1.1",
3637
"users-keycloak": "1.0"
@@ -59,6 +60,17 @@
5960
"permissionName": "mod-settings.global.write.stripes-core.prefs.manage",
6061
"displayName": "UI: update the tenant's preferences",
6162
"visible": false
63+
},
64+
{
65+
"permissionName": "stripes-core.settings.read",
66+
"displayName": "UI: read global tenant and user settings",
67+
"visible": false,
68+
"subPermissions": [
69+
"mod-settings.owner.read.stripes-core.prefs.manage",
70+
"mod-settings.global.read.stripes-core.prefs.manage",
71+
"mod-settings.entries.collection.get",
72+
"locale.item.get"
73+
]
6274
}
6375
]
6476
},

src/components/Front.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
display: flex;
1010
align-items: center;
1111
justify-content: center;
12+
flex-direction: column;
1213
}
1314

1415
h1.frontTitle {
@@ -23,3 +24,11 @@ h1.frontTitle {
2324
font-size: var(--font-size-large);
2425
}
2526
}
27+
28+
.releaseNotesWrap {
29+
font-size: var(--font-size-large);
30+
font-weight: var(--text-weight-bold);
31+
text-align: center;
32+
color: var(--color-link);
33+
margin-top: -10px;
34+
}

src/components/Front.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Headline } from '@folio/stripes-components';
55
import { FormattedMessage } from 'react-intl';
66

77
import Pluggable from '../Pluggable';
8+
import ReleaseNotesLink from './ReleaseNotesLink';
89

910
import css from './Front.css';
1011

@@ -15,6 +16,10 @@ const Front = ({ stripes }) => {
1516
<Pluggable type="frontpage">
1617
<div className={css.frontWrap}>
1718
<Headline faded tag="h1" margin="none" className={css.frontTitle}><FormattedMessage id={tag} /></Headline>
19+
20+
<div className={css.releaseNotesWrap}>
21+
<ReleaseNotesLink label={<FormattedMessage id="stripes-core.releaseNotes.front" />} />
22+
</div>
1823
</div>
1924
</Pluggable>
2025
);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@import "@folio/stripes-components/lib/variables.css";
2+
3+
.ReleaseNotesLink {
4+
color: inherit;
5+
6+
&:visited {
7+
color: inherit;
8+
}
9+
10+
& span {
11+
color: var(--color-link);
12+
margin-left: 5px;
13+
};
14+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import PropTypes from 'prop-types';
2+
3+
import { Icon } from '@folio/stripes-components';
4+
5+
import css from './ReleaseNotesLink.css';
6+
7+
const ReleaseNotesLink = ({ label }) => {
8+
return (
9+
<a
10+
href="https://folio-org.atlassian.net/wiki/spaces/REL/overview#Release-notes"
11+
target="_blank"
12+
rel="noopener noreferrer"
13+
className={css.ReleaseNotesLink}
14+
>
15+
{label}
16+
17+
<Icon icon="external-link" />
18+
</a>
19+
);
20+
};
21+
22+
ReleaseNotesLink.propTypes = {
23+
label: PropTypes.oneOfType([
24+
PropTypes.string,
25+
PropTypes.node,
26+
]).isRequired,
27+
};
28+
29+
export default ReleaseNotesLink;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './ReleaseNotesLink';

src/components/Root/FFetch.js

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
isAuthenticationRequest,
5656
isFolioApiRequest,
5757
isLogoutRequest,
58+
isValidSessionCheckRequest,
5859
rtr,
5960
} from './token-util';
6061
import {
@@ -88,6 +89,7 @@ export class FFetch {
8889
this.rtrConfig = rtrConfig;
8990
this.okapi = okapi;
9091
this.focusEventSet = false;
92+
this.rtrScheduled = false; // Track if RTR has been scheduled in this tab
9193
this.bc = new BroadcastChannel(RTR_ACTIVE_WINDOW_MSG_CHANNEL);
9294
this.setWindowIdMessageEvent();
9395
this.setDocumentFocusHandler();
@@ -309,8 +311,11 @@ export class FFetch {
309311
if (isFolioApiRequest(resource, this.okapi.url)) {
310312
this.logger.log('rtrv', 'will fetch', resource);
311313

312-
// on authentication, grab the response to kick of the rotation cycle,
313-
// then return the response
314+
// on authentication (login), grab the response to kick off the rotation cycle,
315+
// then return the response.
316+
// Note: _self endpoints are NOT included here - they go through the normal
317+
// RTR queue (getPromise) so they wait for any in-progress rotation to complete.
318+
// This prevents 401 errors for _self requests in-flight during RTR.
314319
if (isAuthenticationRequest(resource, this.okapi.url)) {
315320
this.logger.log('rtr', 'authn request', resource);
316321
return this.nativeFetch.apply(global, [resource, options && { ...options, ...OKAPI_FETCH_OPTIONS }])
@@ -351,6 +356,29 @@ export class FFetch {
351356
});
352357
}
353358

359+
// This block is only used to start RTR (rotateCallback) for new browser tabs.
360+
// New tabs inherit only AT from the login session and don't start RTR timer to get RT.
361+
// The first successful response will trigger rotateCallback to schedule RTR,
362+
// preventing 401 errors when AT expires.
363+
if (isValidSessionCheckRequest(resource, this.okapi.url)) {
364+
this.logger.log('rtr', 'session check request', resource);
365+
return getPromise(this.logger)
366+
.then(() => {
367+
this.logger.log('rtrv', 'post-rtr session check fetch', resource);
368+
return this.nativeFetch.apply(global, [resource, options && { ...options, ...OKAPI_FETCH_OPTIONS }]);
369+
})
370+
.then(res => {
371+
// On first successful session check, trigger rotateCallback to ensure
372+
// RTR is scheduled (only once per tab)
373+
if (res.ok && !this.rtrScheduled) {
374+
this.logger.log('rtr', 'session check success, scheduling RTR (first time)');
375+
this.rotateCallback();
376+
this.rtrScheduled = true;
377+
}
378+
return res;
379+
});
380+
}
381+
354382
return getPromise(this.logger)
355383
.then(() => {
356384
this.logger.log('rtrv', 'post-rtr-fetch', resource);

0 commit comments

Comments
 (0)