diff --git a/packages/apps/esm-login-app/src/CurrentUserContext.tsx b/packages/apps/esm-login-app/src/CurrentUserContext.tsx deleted file mode 100644 index 06ed1fd6f..000000000 --- a/packages/apps/esm-login-app/src/CurrentUserContext.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React, { useContext, useState, useMemo, useEffect } from "react"; -import { getCurrentUser, LoggedInUser } from "@openmrs/esm-framework"; - -const CurrentUser = React.createContext({ - current: undefined, - setCurrent() {}, -}); - -interface UserState { - loading: boolean; - current: LoggedInUser | undefined; -} - -export interface User { - current: LoggedInUser | undefined; - setCurrent(user: LoggedInUser): void; -} - -export function useCurrentUser() { - const value = useContext(CurrentUser); - return value.current; -} - -export const CurrentUserContext: React.FC = ({ children }) => { - const [user, setUser] = useState({ - current: undefined, - loading: true, - }); - const value = useMemo( - () => ({ - current: user.current, - setCurrent: (current: LoggedInUser) => - setUser((state) => ({ - ...state, - current, - })), - }), - [user] - ); - - useEffect(() => { - const sub = getCurrentUser({ - includeAuthStatus: true, - }).subscribe(({ user }) => - setUser({ - current: user, - loading: false, - }) - ); - return () => sub.unsubscribe(); - }, []); - - return {children}; -}; diff --git a/packages/apps/esm-login-app/src/choose-location/choose-location.component.tsx b/packages/apps/esm-login-app/src/choose-location/choose-location.component.tsx index 880b827b5..1409bcca8 100644 --- a/packages/apps/esm-login-app/src/choose-location/choose-location.component.tsx +++ b/packages/apps/esm-login-app/src/choose-location/choose-location.component.tsx @@ -6,9 +6,9 @@ import { navigate, useConfig, setSessionLocation, + useSession, } from "@openmrs/esm-framework"; import { useLoginLocations } from "./choose-location.resource"; -import { useCurrentUser } from "../CurrentUserContext"; import type { StaticContext } from "react-router"; export interface LoginReferrer { @@ -27,7 +27,7 @@ export const ChooseLocation: React.FC = ({ const returnToUrl = new URLSearchParams(location?.search).get("returnToUrl"); const referrer = location?.state?.referrer; const config = useConfig(); - const user = useCurrentUser(); + const { user } = useSession(); const { locationData, isLoading } = useLoginLocations( config.chooseLocation.useLoginLocationTag ); @@ -39,8 +39,10 @@ export const ChooseLocation: React.FC = ({ : Promise.resolve(); sessionDefined.then(() => { - // console.log("referrer: ", referrer); - if (referrer && referrer !== "/") { + if ( + referrer && + !["/", "/login", "/login/location"].includes(referrer) + ) { navigate({ to: "${openmrsSpaBase}" + referrer }); return; } @@ -55,6 +57,8 @@ export const ChooseLocation: React.FC = ({ [referrer, config.links.loginSuccess, returnToUrl] ); + // Handle cases where the location picker is disabled, there is only one + // location, or there are no locations. useEffect(() => { if (!isLoading) { if (!config.chooseLocation.enabled || locationData?.length === 1) { @@ -72,6 +76,11 @@ export const ChooseLocation: React.FC = ({ isLoading, ]); + if (!isLoading && !user) { + navigate({ to: "${openmrsSpaBase}/login" }); + return null; + } + if (!isLoading || !isLoginEnabled) { return ( (getUrl, openmrsFetch); if (error) { - showNotification({ - title: error.name, - description: error.message, - kind: "error", - }); + console.error(error); + reportError(error); } const memoizedLocationData = useMemo(() => { diff --git a/packages/apps/esm-login-app/src/choose-location/choose-location.test.tsx b/packages/apps/esm-login-app/src/choose-location/choose-location.test.tsx index 99e1d8698..0fa35ee8e 100644 --- a/packages/apps/esm-login-app/src/choose-location/choose-location.test.tsx +++ b/packages/apps/esm-login-app/src/choose-location/choose-location.test.tsx @@ -1,6 +1,11 @@ import { waitFor } from "@testing-library/react"; import renderWithRouter from "../test-helpers/render-with-router"; -import { navigate, openmrsFetch, useConfig } from "@openmrs/esm-framework"; +import { + navigate, + openmrsFetch, + useConfig, + useSession, +} from "@openmrs/esm-framework"; import { mockSetSessionLocation, mockSoleLoginLocation, @@ -12,13 +17,13 @@ const mockedNavigate = navigate as jest.Mock; const mockedOpenmrsFetch = openmrsFetch as jest.Mock; const mockedUseConfig = useConfig as jest.Mock; -jest.mock("../CurrentUserContext", () => ({ - useCurrentUser() { - return { - display: "Testy McTesterface", - }; +const mockUseSession = useSession as jest.Mock; + +mockUseSession.mockReturnValue({ + user: { + display: "Testy McTesterface", }, -})); +}); describe("ChooseLocation: ", () => { beforeEach(() => { diff --git a/packages/apps/esm-login-app/src/login/login.component.tsx b/packages/apps/esm-login-app/src/login/login.component.tsx index f92073693..6e45b4bdb 100644 --- a/packages/apps/esm-login-app/src/login/login.component.tsx +++ b/packages/apps/esm-login-app/src/login/login.component.tsx @@ -4,9 +4,8 @@ import ArrowRight24 from "@carbon/icons-react/es/arrow--right/24"; import { Button, InlineNotification, TextInput } from "carbon-components-react"; import { RouteComponentProps } from "react-router-dom"; import { useTranslation } from "react-i18next"; -import { useConfig, interpolateUrl } from "@openmrs/esm-framework"; +import { useConfig, interpolateUrl, useSession } from "@openmrs/esm-framework"; import { performLogin } from "./login.resource"; -import { useCurrentUser } from "../CurrentUserContext"; import type { StaticContext } from "react-router"; const hidden: React.CSSProperties = { @@ -27,7 +26,7 @@ export interface LoginProps const Login: React.FC = ({ history, location, isLoginEnabled }) => { const config = useConfig(); - const user = useCurrentUser(); + const { user } = useSession(); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [errorMessage, setErrorMessage] = useState(""); diff --git a/packages/apps/esm-login-app/src/login/login.test.tsx b/packages/apps/esm-login-app/src/login/login.test.tsx index 00327e50e..49acd9abd 100644 --- a/packages/apps/esm-login-app/src/login/login.test.tsx +++ b/packages/apps/esm-login-app/src/login/login.test.tsx @@ -1,9 +1,12 @@ import { useState } from "react"; import { waitFor, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { setSessionLocation, useConfig } from "@openmrs/esm-framework"; +import { + setSessionLocation, + useConfig, + useSession, +} from "@openmrs/esm-framework"; import { performLogin } from "./login.resource"; -import { useCurrentUser } from "../CurrentUserContext"; import { mockConfig } from "../../__mocks__/config.mock"; import renderWithRouter from "../test-helpers/render-with-router"; import Login from "./login.component"; @@ -15,12 +18,8 @@ jest.mock("./login.resource", () => ({ })); const mockedSetSessionLocation = setSessionLocation as jest.Mock; -const mockedUseCurrentUser = useCurrentUser as jest.Mock; const mockedUseConfig = useConfig as jest.Mock; - -jest.mock("../CurrentUserContext", () => ({ - useCurrentUser: jest.fn(), -})); +const mockedUseSession = useSession as jest.Mock; const loginLocations = [ { uuid: "111", display: "Earth" }, @@ -31,7 +30,8 @@ describe(``, () => { beforeEach(() => { mockedLogin.mockReset(); mockedSetSessionLocation.mockReset(); - mockedUseCurrentUser.mockReset(); + mockedUseSession.mockReset(); + mockedUseSession.mockReturnValue({ authenticated: false }); mockedUseConfig.mockReturnValue(mockConfig); }); @@ -106,10 +106,10 @@ describe(``, () => { }); return Promise.resolve({ data: { authenticated: true } }); }); - mockedUseCurrentUser.mockImplementation(() => { + mockedUseSession.mockImplementation(() => { const [user, setUser] = useState(); refreshUser = setUser; - return user; + return { user, authenticated: !!user }; }); const wrapper = renderWithRouter( diff --git a/packages/apps/esm-login-app/src/redirect-logout/logout.resource.ts b/packages/apps/esm-login-app/src/redirect-logout/logout.resource.ts index a3d320336..bbf312479 100644 --- a/packages/apps/esm-login-app/src/redirect-logout/logout.resource.ts +++ b/packages/apps/esm-login-app/src/redirect-logout/logout.resource.ts @@ -1,7 +1,13 @@ -import { openmrsFetch, refetchCurrentUser } from "@openmrs/esm-framework"; +import { + clearCurrentUser, + openmrsFetch, + refetchCurrentUser, +} from "@openmrs/esm-framework"; -export function performLogout() { - return openmrsFetch("/ws/rest/v1/session", { +export async function performLogout() { + await openmrsFetch("/ws/rest/v1/session", { method: "DELETE", - }).then(refetchCurrentUser); + }); + clearCurrentUser(); + await refetchCurrentUser(); } diff --git a/packages/apps/esm-login-app/src/redirect-logout/redirect-logout.component.tsx b/packages/apps/esm-login-app/src/redirect-logout/redirect-logout.component.tsx index a4b8ef346..da3da42a6 100644 --- a/packages/apps/esm-login-app/src/redirect-logout/redirect-logout.component.tsx +++ b/packages/apps/esm-login-app/src/redirect-logout/redirect-logout.component.tsx @@ -1,8 +1,7 @@ import React, { useEffect } from "react"; import { RouteComponentProps } from "react-router-dom"; -import { navigate, useConfig } from "@openmrs/esm-framework"; +import { navigate, useConfig, useSession } from "@openmrs/esm-framework"; import { performLogout } from "./logout.resource"; -import { useCurrentUser } from "../CurrentUserContext"; export interface RedirectLogoutProps extends RouteComponentProps<{}> { isLoginEnabled: boolean; @@ -10,21 +9,21 @@ export interface RedirectLogoutProps extends RouteComponentProps<{}> { const RedirectLogout: React.FC = ({ isLoginEnabled }) => { const config = useConfig(); - const user = useCurrentUser(); + const session = useSession(); useEffect(() => { - if (!user || !isLoginEnabled) { + if (!session.authenticated || !isLoginEnabled) { navigate({ to: "${openmrsSpaBase}/login" }); } else { performLogout().then(() => { if (config.provider.type === "oauth2") { location.href = config.provider.logoutUrl; } else { - location.href = window.spaBase; + navigate({ to: "${openmrsSpaBase}/login" }); } }); } - }, [isLoginEnabled, user, config]); + }, [isLoginEnabled, session, config]); return null; }; diff --git a/packages/apps/esm-login-app/src/root.component.tsx b/packages/apps/esm-login-app/src/root.component.tsx index d46474190..317b9a3f1 100644 --- a/packages/apps/esm-login-app/src/root.component.tsx +++ b/packages/apps/esm-login-app/src/root.component.tsx @@ -3,7 +3,6 @@ import Login from "./login/login.component"; import ChooseLocation from "./choose-location/choose-location.component"; import RedirectLogout from "./redirect-logout/redirect-logout.component"; import { BrowserRouter, Route } from "react-router-dom"; -import { CurrentUserContext } from "./CurrentUserContext"; export interface RootProps { isLoginEnabled: boolean; @@ -11,31 +10,27 @@ export interface RootProps { const Root: React.FC = ({ isLoginEnabled }) => { return ( - - - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - - + + } + /> + ( + + )} + /> + ( + + )} + /> + ); }; diff --git a/packages/apps/esm-primary-navigation-app/src/root.component.tsx b/packages/apps/esm-primary-navigation-app/src/root.component.tsx index e66f0a83c..b20cbbf11 100644 --- a/packages/apps/esm-primary-navigation-app/src/root.component.tsx +++ b/packages/apps/esm-primary-navigation-app/src/root.component.tsx @@ -16,19 +16,19 @@ const Root: React.FC = () => { const openmrsSpaBase = window["getOpenmrsSpaBase"](); useEffect(() => { - const currentUserSub = getSynchronizedCurrentUser({ - includeAuthStatus: true, - }).subscribe((response) => { - setAllowedLocales(response.allowedLocales); + const currentUserSub = getSynchronizedCurrentUser().subscribe( + (response) => { + setAllowedLocales(response.allowedLocales); - if (response.authenticated) { - setUser(response.user); - } else { - setUser(false); - } + if (response.authenticated) { + setUser(response.user); + } else { + setUser(false); + } - createErrorHandler(); - }); + createErrorHandler(); + } + ); const currentSessionSub = getCurrentSession().subscribe(({ data }) => setUserSession(data) diff --git a/packages/apps/esm-primary-navigation-app/src/root.resource.tsx b/packages/apps/esm-primary-navigation-app/src/root.resource.tsx index 7b4bf89b2..4cf472eee 100644 --- a/packages/apps/esm-primary-navigation-app/src/root.resource.tsx +++ b/packages/apps/esm-primary-navigation-app/src/root.resource.tsx @@ -1,5 +1,4 @@ import { - CurrentUserWithResponseOption, getCurrentUser, getSynchronizationItemsFor, openmrsObservableFetch, @@ -15,10 +14,8 @@ export function getCurrentSession() { * Returns an observable producing the current user, but also applies any unsynchronized user property * changes to that user. */ -export function getSynchronizedCurrentUser( - opts: CurrentUserWithResponseOption -) { - return getCurrentUser(opts).pipe( +export function getSynchronizedCurrentUser() { + return getCurrentUser({ includeAuthStatus: true }).pipe( mergeMap(async (result) => { const { user } = result; diff --git a/packages/framework/esm-api/src/openmrs-fetch.ts b/packages/framework/esm-api/src/openmrs-fetch.ts index b12ca32b0..dc3b71b4f 100644 --- a/packages/framework/esm-api/src/openmrs-fetch.ts +++ b/packages/framework/esm-api/src/openmrs-fetch.ts @@ -1,7 +1,12 @@ /** @module @category API */ import { Observable } from "rxjs"; import isPlainObject from "lodash-es/isPlainObject"; -import { getConfig, navigate } from "@openmrs/esm-config"; +import { + getConfig, + interpolateString, + interpolateUrl, + navigate, +} from "@openmrs/esm-config"; import { FetchResponse } from "./types"; export const sessionEndpoint = "/ws/rest/v1/session"; diff --git a/packages/framework/esm-api/src/shared-api-objects/current-user.ts b/packages/framework/esm-api/src/shared-api-objects/current-user.ts index e1d87ba97..dd146c6ce 100644 --- a/packages/framework/esm-api/src/shared-api-objects/current-user.ts +++ b/packages/framework/esm-api/src/shared-api-objects/current-user.ts @@ -1,19 +1,32 @@ /** @module @category API */ -import { Observable, ReplaySubject } from "rxjs"; -import { filter, map, tap, mergeAll } from "rxjs/operators"; +import { reportError } from "@openmrs/esm-error-handling"; +import { createGlobalStore } from "@openmrs/esm-state"; +import { Observable } from "rxjs"; import { openmrsFetch, sessionEndpoint } from "../openmrs-fetch"; import type { LoggedInUser, - CurrentUserWithResponseOption, - CurrentUserWithoutResponseOption, - CurrentUserOptions, SessionLocation, Privilege, Role, Session, } from "../types"; -const userSubject = new ReplaySubject>(1); +export type SessionStore = LoadedSessionStore | UnloadedSessionStore; + +export type LoadedSessionStore = { + loaded: true; + session: Session; +}; + +export type UnloadedSessionStore = { + loaded: false; + session: null; +}; + +const sessionStore = createGlobalStore("session", { + loaded: false, + session: null, +}); let lastFetchTimeMillis = 0; /** @@ -54,30 +67,51 @@ let lastFetchTimeMillis = 0; * even after the UI component is gone from the screen. This is a memory * leak and source of bugs. */ -function getCurrentUser(): Observable; -function getCurrentUser( - opts: CurrentUserWithResponseOption -): Observable; -function getCurrentUser( - opts: CurrentUserWithoutResponseOption -): Observable; +function getCurrentUser(): Observable; +function getCurrentUser(opts: { includeAuthStatus: true }): Observable; +function getCurrentUser(opts: { + includeAuthStatus: false; +}): Observable; function getCurrentUser( - opts: CurrentUserOptions = { includeAuthStatus: false } -): Observable { - if (lastFetchTimeMillis < Date.now() - 1000 * 60) { + opts = { includeAuthStatus: true } +): Observable { + if ( + lastFetchTimeMillis < Date.now() - 1000 * 60 || + !sessionStore.getState().loaded + ) { refetchCurrentUser(); } - return userSubject.asObservable().pipe( - mergeAll(), - tap(setUserLanguage), - map((r) => (opts.includeAuthStatus ? r : r.user)), - filter(Boolean) - ) as Observable; + return new Observable((subscriber) => { + const handler = (state) => { + if (state.loaded) { + if (opts.includeAuthStatus) { + subscriber.next(state.session); + } else { + subscriber.next(state.session?.user); + } + } + }; + handler(sessionStore.getState()); + // The observable subscribe function should return an unsubscribe function, + // which happens to be exactly what Unistore `subscribe` returns. + return sessionStore.subscribe(handler); + }); } export { getCurrentUser }; +export function getSessionStore() { + if ( + lastFetchTimeMillis < Date.now() - 1000 * 60 || + !sessionStore.getState().loaded + ) { + refetchCurrentUser(); + } + + return sessionStore; +} + function setUserLanguage(data: Session) { const locale = data?.user?.userProperties?.defaultLocale ?? data.locale; const htmlLang = document.documentElement.getAttribute("lang"); @@ -113,17 +147,35 @@ function isSuperUser(user: { roles: Array }) { * ``` */ export function refetchCurrentUser() { - lastFetchTimeMillis = Date.now(); - userSubject.next( + return new Promise((resolve, reject) => { + lastFetchTimeMillis = Date.now(); openmrsFetch(sessionEndpoint) - .then((res) => - typeof res.data === "object" ? res.data : Promise.reject() - ) - .catch(() => ({ - sessionId: "", - authenticated: false, - })) - ); + .then((res) => { + if (typeof res?.data === "object") { + setUserLanguage(res.data); + resolve(res.data); + sessionStore.setState({ loaded: true, session: res.data }); + } else { + reject(); + return Promise.reject(); + } + }) + .catch((err) => { + reportError(`Failed to fetch new session information: ${err}`); + reject(err); + return { + sessionId: "", + authenticated: false, + }; + }); + }); +} + +export function clearCurrentUser() { + sessionStore.setState({ + loaded: true, + session: { authenticated: false, sessionId: "" }, + }); } export function userHasAccess( @@ -134,23 +186,29 @@ export function userHasAccess( } export function getLoggedInUser() { + let user; + let unsubscribe; return new Promise((res, rej) => { - const sub = getCurrentUser().subscribe((user) => { - res(user); - sub.unsubscribe(); - }, rej); + const handler = (state: SessionStore) => { + if (state.loaded && state.session.user) { + user = state.session.user; + res(state.session.user); + unsubscribe && unsubscribe(); + } + }; + handler(sessionStore.getState()); + if (!user) { + unsubscribe = sessionStore.subscribe(handler); + } }); } export function getSessionLocation() { return new Promise((res, rej) => { - const sub = getCurrentUser({ includeAuthStatus: true }).subscribe( - (session) => { - res(session.sessionLocation); - sub.unsubscribe(); - }, - rej - ); + const sub = getCurrentUser().subscribe((session) => { + res(session.sessionLocation); + sub.unsubscribe(); + }, rej); }); } diff --git a/packages/framework/esm-api/src/types/user-resource.ts b/packages/framework/esm-api/src/types/user-resource.ts index f2dd122f1..d1710caa2 100644 --- a/packages/framework/esm-api/src/types/user-resource.ts +++ b/packages/framework/esm-api/src/types/user-resource.ts @@ -1,15 +1,3 @@ -export interface CurrentUserOptions { - includeAuthStatus?: boolean; -} - -export interface CurrentUserWithResponseOption extends CurrentUserOptions { - includeAuthStatus: true; -} - -export interface CurrentUserWithoutResponseOption extends CurrentUserOptions { - includeAuthStatus: false; -} - export interface Session { allowedLocales?: Array; authenticated: boolean; diff --git a/packages/framework/esm-framework/docs/API.md b/packages/framework/esm-framework/docs/API.md index 6c3bb066b..b233b9f01 100644 --- a/packages/framework/esm-framework/docs/API.md +++ b/packages/framework/esm-framework/docs/API.md @@ -6,11 +6,13 @@ ### API Functions +- [clearCurrentUser](API.md#clearcurrentuser) - [fetchCurrentPatient](API.md#fetchcurrentpatient) - [getCurrentUser](API.md#getcurrentuser) - [getLocations](API.md#getlocations) - [getLoggedInUser](API.md#getloggedinuser) - [getSessionLocation](API.md#getsessionlocation) +- [getSessionStore](API.md#getsessionstore) - [getVisitTypes](API.md#getvisittypes) - [getVisitsForPatient](API.md#getvisitsforpatient) - [makeUrl](API.md#makeurl) @@ -172,6 +174,23 @@ ___ +### LoadedSessionStore + +Ƭ **LoadedSessionStore**: `Object` + +#### Type declaration + +| Name | Type | +| :------ | :------ | +| `loaded` | ``true`` | +| `session` | [`Session`](interfaces/Session.md) | + +#### Defined in + +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:16](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L16) + +___ + ### NullablePatient Ƭ **NullablePatient**: `fhir.Patient` \| ``null`` @@ -192,6 +211,33 @@ ___ ___ +### SessionStore + +Ƭ **SessionStore**: [`LoadedSessionStore`](API.md#loadedsessionstore) \| [`UnloadedSessionStore`](API.md#unloadedsessionstore) + +#### Defined in + +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:14](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L14) + +___ + +### UnloadedSessionStore + +Ƭ **UnloadedSessionStore**: `Object` + +#### Type declaration + +| Name | Type | +| :------ | :------ | +| `loaded` | ``false`` | +| `session` | ``null`` | + +#### Defined in + +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:21](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L21) + +___ + ## Date and Time Type aliases ### DateInput @@ -527,7 +573,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/openmrs-fetch.ts:7](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L7) +[packages/framework/esm-api/src/openmrs-fetch.ts:12](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L12) ___ @@ -672,6 +718,20 @@ ___ ## API Functions +### clearCurrentUser + +▸ **clearCurrentUser**(): `void` + +#### Returns + +`void` + +#### Defined in + +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:174](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L174) + +___ + ### fetchCurrentPatient ▸ **fetchCurrentPatient**(`patientUuid`, `contentOverrides?`): `Promise`<{ `data`: `Patient` }\> \| `Promise`<``null``\> @@ -695,7 +755,7 @@ ___ ### getCurrentUser -▸ **getCurrentUser**(): `Observable`<[`LoggedInUser`](interfaces/LoggedInUser.md)\> +▸ **getCurrentUser**(): `Observable`<[`Session`](interfaces/Session.md)\> The getCurrentUser function returns an observable that produces **zero or more values, over time**. It will produce zero values @@ -706,7 +766,7 @@ updated. #### Returns -`Observable`<[`LoggedInUser`](interfaces/LoggedInUser.md)\> +`Observable`<[`Session`](interfaces/Session.md)\> An Observable that produces zero or more values (as described above). The values produced will be a user object (if @@ -734,7 +794,7 @@ leak and source of bugs. #### Defined in -[packages/framework/esm-api/src/shared-api-objects/current-user.ts:57](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L57) +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:70](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L70) ▸ **getCurrentUser**(`opts`): `Observable`<[`Session`](interfaces/Session.md)\> @@ -742,7 +802,8 @@ leak and source of bugs. | Name | Type | | :------ | :------ | -| `opts` | [`CurrentUserWithResponseOption`](interfaces/CurrentUserWithResponseOption.md) | +| `opts` | `Object` | +| `opts.includeAuthStatus` | ``true`` | #### Returns @@ -750,7 +811,7 @@ leak and source of bugs. #### Defined in -[packages/framework/esm-api/src/shared-api-objects/current-user.ts:58](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L58) +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:71](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L71) ▸ **getCurrentUser**(`opts`): `Observable`<[`LoggedInUser`](interfaces/LoggedInUser.md)\> @@ -758,7 +819,8 @@ leak and source of bugs. | Name | Type | | :------ | :------ | -| `opts` | [`CurrentUserWithoutResponseOption`](interfaces/CurrentUserWithoutResponseOption.md) | +| `opts` | `Object` | +| `opts.includeAuthStatus` | ``false`` | #### Returns @@ -766,7 +828,7 @@ leak and source of bugs. #### Defined in -[packages/framework/esm-api/src/shared-api-objects/current-user.ts:61](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L61) +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:72](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L72) ___ @@ -794,7 +856,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/shared-api-objects/current-user.ts:136](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L136) +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:188](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L188) ___ @@ -808,7 +870,21 @@ ___ #### Defined in -[packages/framework/esm-api/src/shared-api-objects/current-user.ts:145](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L145) +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:206](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L206) + +___ + +### getSessionStore + +▸ **getSessionStore**(): `Store`<[`SessionStore`](API.md#sessionstore)\> + +#### Returns + +`Store`<[`SessionStore`](API.md#sessionstore)\> + +#### Defined in + +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:104](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L104) ___ @@ -873,7 +949,7 @@ makeUrl('/foo/bar'); #### Defined in -[packages/framework/esm-api/src/openmrs-fetch.ts:19](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L19) +[packages/framework/esm-api/src/openmrs-fetch.ts:24](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L24) ___ @@ -940,7 +1016,7 @@ free up memory and network resources and to prevent race conditions. #### Defined in -[packages/framework/esm-api/src/openmrs-fetch.ts:72](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L72) +[packages/framework/esm-api/src/openmrs-fetch.ts:77](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L77) ___ @@ -991,13 +1067,13 @@ To cancel the network request, simply call `subscription.unsubscribe();` #### Defined in -[packages/framework/esm-api/src/openmrs-fetch.ts:243](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L243) +[packages/framework/esm-api/src/openmrs-fetch.ts:248](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L248) ___ ### refetchCurrentUser -▸ **refetchCurrentUser**(): `void` +▸ **refetchCurrentUser**(): `Promise`<`unknown`\> The `refetchCurrentUser` function causes a network request to redownload the user. All subscribers to the current user will be notified of the @@ -1005,7 +1081,7 @@ new users once the new version of the user object is downloaded. #### Returns -`void` +`Promise`<`unknown`\> The same observable as returned by [getCurrentUser](API.md#getcurrentuser). @@ -1017,7 +1093,7 @@ refetchCurrentUser() #### Defined in -[packages/framework/esm-api/src/shared-api-objects/current-user.ts:115](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L115) +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:149](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L149) ___ @@ -1059,7 +1135,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/shared-api-objects/current-user.ts:157](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L157) +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:215](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L215) ___ @@ -1198,15 +1274,23 @@ ___ ### useSession -▸ **useSession**(): ``null`` \| [`Session`](interfaces/Session.md) +▸ **useSession**(): [`Session`](interfaces/Session.md) + +Gets the current user session information. Returns an object with +property `authenticated` == `false` if the user is not logged in. + +Uses Suspense. This hook will always either return a Session object +or throw for Suspense. It will never return `null`/`undefined`. #### Returns -``null`` \| [`Session`](interfaces/Session.md) +[`Session`](interfaces/Session.md) + +Current user session information #### Defined in -[packages/framework/esm-react-utils/src/useSessionUser.tsx:5](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-react-utils/src/useSessionUser.tsx#L5) +[packages/framework/esm-react-utils/src/useSession.tsx:17](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-react-utils/src/useSession.tsx#L17) ___ @@ -1269,7 +1353,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/shared-api-objects/current-user.ts:129](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L129) +[packages/framework/esm-api/src/shared-api-objects/current-user.ts:181](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/shared-api-objects/current-user.ts#L181) ___ diff --git a/packages/framework/esm-framework/docs/classes/OpenmrsFetchError.md b/packages/framework/esm-framework/docs/classes/OpenmrsFetchError.md index cd68b3850..75855079f 100644 --- a/packages/framework/esm-framework/docs/classes/OpenmrsFetchError.md +++ b/packages/framework/esm-framework/docs/classes/OpenmrsFetchError.md @@ -21,6 +21,7 @@ ### Other Properties +- [cause](OpenmrsFetchError.md#cause) - [message](OpenmrsFetchError.md#message) - [name](OpenmrsFetchError.md#name) - [stack](OpenmrsFetchError.md#stack) @@ -52,7 +53,7 @@ Error.constructor #### Defined in -[packages/framework/esm-api/src/openmrs-fetch.ts:281](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L281) +[packages/framework/esm-api/src/openmrs-fetch.ts:286](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L286) ## API Properties @@ -62,7 +63,7 @@ Error.constructor #### Defined in -[packages/framework/esm-api/src/openmrs-fetch.ts:294](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L294) +[packages/framework/esm-api/src/openmrs-fetch.ts:299](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L299) ___ @@ -72,12 +73,26 @@ ___ #### Defined in -[packages/framework/esm-api/src/openmrs-fetch.ts:295](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L295) +[packages/framework/esm-api/src/openmrs-fetch.ts:300](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/openmrs-fetch.ts#L300) ___ ## Other Properties +### cause + +• `Optional` **cause**: `Error` + +#### Inherited from + +Error.cause + +#### Defined in + +node_modules/typescript/lib/lib.es2022.error.d.ts:26 + +___ + ### message • **message**: `string` diff --git a/packages/framework/esm-framework/docs/interfaces/CurrentUserOptions.md b/packages/framework/esm-framework/docs/interfaces/CurrentUserOptions.md deleted file mode 100644 index be2dbe359..000000000 --- a/packages/framework/esm-framework/docs/interfaces/CurrentUserOptions.md +++ /dev/null @@ -1,27 +0,0 @@ -[@openmrs/esm-framework](../API.md) / CurrentUserOptions - -# Interface: CurrentUserOptions - -## Hierarchy - -- **`CurrentUserOptions`** - - ↳ [`CurrentUserWithResponseOption`](CurrentUserWithResponseOption.md) - - ↳ [`CurrentUserWithoutResponseOption`](CurrentUserWithoutResponseOption.md) - -## Table of contents - -### Properties - -- [includeAuthStatus](CurrentUserOptions.md#includeauthstatus) - -## Properties - -### includeAuthStatus - -• `Optional` **includeAuthStatus**: `boolean` - -#### Defined in - -[packages/framework/esm-api/src/types/user-resource.ts:2](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L2) diff --git a/packages/framework/esm-framework/docs/interfaces/CurrentUserWithResponseOption.md b/packages/framework/esm-framework/docs/interfaces/CurrentUserWithResponseOption.md deleted file mode 100644 index 605fc1599..000000000 --- a/packages/framework/esm-framework/docs/interfaces/CurrentUserWithResponseOption.md +++ /dev/null @@ -1,29 +0,0 @@ -[@openmrs/esm-framework](../API.md) / CurrentUserWithResponseOption - -# Interface: CurrentUserWithResponseOption - -## Hierarchy - -- [`CurrentUserOptions`](CurrentUserOptions.md) - - ↳ **`CurrentUserWithResponseOption`** - -## Table of contents - -### Properties - -- [includeAuthStatus](CurrentUserWithResponseOption.md#includeauthstatus) - -## Properties - -### includeAuthStatus - -• **includeAuthStatus**: ``true`` - -#### Overrides - -[CurrentUserOptions](CurrentUserOptions.md).[includeAuthStatus](CurrentUserOptions.md#includeauthstatus) - -#### Defined in - -[packages/framework/esm-api/src/types/user-resource.ts:6](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L6) diff --git a/packages/framework/esm-framework/docs/interfaces/CurrentUserWithoutResponseOption.md b/packages/framework/esm-framework/docs/interfaces/CurrentUserWithoutResponseOption.md deleted file mode 100644 index 51a6a488c..000000000 --- a/packages/framework/esm-framework/docs/interfaces/CurrentUserWithoutResponseOption.md +++ /dev/null @@ -1,29 +0,0 @@ -[@openmrs/esm-framework](../API.md) / CurrentUserWithoutResponseOption - -# Interface: CurrentUserWithoutResponseOption - -## Hierarchy - -- [`CurrentUserOptions`](CurrentUserOptions.md) - - ↳ **`CurrentUserWithoutResponseOption`** - -## Table of contents - -### Properties - -- [includeAuthStatus](CurrentUserWithoutResponseOption.md#includeauthstatus) - -## Properties - -### includeAuthStatus - -• **includeAuthStatus**: ``false`` - -#### Overrides - -[CurrentUserOptions](CurrentUserOptions.md).[includeAuthStatus](CurrentUserOptions.md#includeauthstatus) - -#### Defined in - -[packages/framework/esm-api/src/types/user-resource.ts:10](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L10) diff --git a/packages/framework/esm-framework/docs/interfaces/FetchResponse.md b/packages/framework/esm-framework/docs/interfaces/FetchResponse.md index aee84d02f..8e26c0b5f 100644 --- a/packages/framework/esm-framework/docs/interfaces/FetchResponse.md +++ b/packages/framework/esm-framework/docs/interfaces/FetchResponse.md @@ -52,7 +52,7 @@ Response.body #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2402 +node_modules/typescript/lib/lib.dom.d.ts:2432 ___ @@ -66,7 +66,7 @@ Response.bodyUsed #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2403 +node_modules/typescript/lib/lib.dom.d.ts:2433 ___ @@ -90,7 +90,7 @@ Response.headers #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11136 +node_modules/typescript/lib/lib.dom.d.ts:11265 ___ @@ -104,7 +104,7 @@ Response.ok #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11137 +node_modules/typescript/lib/lib.dom.d.ts:11266 ___ @@ -118,7 +118,7 @@ Response.redirected #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11138 +node_modules/typescript/lib/lib.dom.d.ts:11267 ___ @@ -132,7 +132,7 @@ Response.status #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11139 +node_modules/typescript/lib/lib.dom.d.ts:11268 ___ @@ -146,7 +146,7 @@ Response.statusText #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11140 +node_modules/typescript/lib/lib.dom.d.ts:11269 ___ @@ -160,7 +160,7 @@ Response.type #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11141 +node_modules/typescript/lib/lib.dom.d.ts:11270 ___ @@ -174,7 +174,7 @@ Response.url #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11142 +node_modules/typescript/lib/lib.dom.d.ts:11271 ## Methods @@ -192,7 +192,7 @@ Response.arrayBuffer #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2404 +node_modules/typescript/lib/lib.dom.d.ts:2434 ___ @@ -210,7 +210,7 @@ Response.blob #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2405 +node_modules/typescript/lib/lib.dom.d.ts:2435 ___ @@ -228,7 +228,7 @@ Response.clone #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11143 +node_modules/typescript/lib/lib.dom.d.ts:11272 ___ @@ -246,7 +246,7 @@ Response.formData #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2406 +node_modules/typescript/lib/lib.dom.d.ts:2436 ___ @@ -264,7 +264,7 @@ Response.json #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2407 +node_modules/typescript/lib/lib.dom.d.ts:2437 ___ @@ -282,4 +282,4 @@ Response.text #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2408 +node_modules/typescript/lib/lib.dom.d.ts:2438 diff --git a/packages/framework/esm-framework/docs/interfaces/LoggedInUser.md b/packages/framework/esm-framework/docs/interfaces/LoggedInUser.md index 39aa5945a..58b686e3b 100644 --- a/packages/framework/esm-framework/docs/interfaces/LoggedInUser.md +++ b/packages/framework/esm-framework/docs/interfaces/LoggedInUser.md @@ -30,7 +30,7 @@ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:34](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L34) +[packages/framework/esm-api/src/types/user-resource.ts:22](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L22) ___ @@ -40,7 +40,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:25](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L25) +[packages/framework/esm-api/src/types/user-resource.ts:13](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L13) ___ @@ -50,7 +50,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:33](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L33) +[packages/framework/esm-api/src/types/user-resource.ts:21](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L21) ___ @@ -60,7 +60,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:29](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L29) +[packages/framework/esm-api/src/types/user-resource.ts:17](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L17) ___ @@ -70,7 +70,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:30](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L30) +[packages/framework/esm-api/src/types/user-resource.ts:18](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L18) ___ @@ -80,7 +80,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:32](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L32) +[packages/framework/esm-api/src/types/user-resource.ts:20](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L20) ___ @@ -90,7 +90,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:31](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L31) +[packages/framework/esm-api/src/types/user-resource.ts:19](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L19) ___ @@ -100,7 +100,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:27](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L27) +[packages/framework/esm-api/src/types/user-resource.ts:15](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L15) ___ @@ -110,7 +110,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:28](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L28) +[packages/framework/esm-api/src/types/user-resource.ts:16](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L16) ___ @@ -120,7 +120,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:26](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L26) +[packages/framework/esm-api/src/types/user-resource.ts:14](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L14) ___ @@ -130,4 +130,4 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:24](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L24) +[packages/framework/esm-api/src/types/user-resource.ts:12](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L12) diff --git a/packages/framework/esm-framework/docs/interfaces/LoggedInUserFetchResponse.md b/packages/framework/esm-framework/docs/interfaces/LoggedInUserFetchResponse.md index 35832a470..010fbd649 100644 --- a/packages/framework/esm-framework/docs/interfaces/LoggedInUserFetchResponse.md +++ b/packages/framework/esm-framework/docs/interfaces/LoggedInUserFetchResponse.md @@ -44,7 +44,7 @@ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2402 +node_modules/typescript/lib/lib.dom.d.ts:2432 ___ @@ -58,7 +58,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2403 +node_modules/typescript/lib/lib.dom.d.ts:2433 ___ @@ -86,7 +86,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11136 +node_modules/typescript/lib/lib.dom.d.ts:11265 ___ @@ -100,7 +100,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11137 +node_modules/typescript/lib/lib.dom.d.ts:11266 ___ @@ -114,7 +114,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11138 +node_modules/typescript/lib/lib.dom.d.ts:11267 ___ @@ -128,7 +128,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11139 +node_modules/typescript/lib/lib.dom.d.ts:11268 ___ @@ -142,7 +142,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11140 +node_modules/typescript/lib/lib.dom.d.ts:11269 ___ @@ -156,7 +156,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11141 +node_modules/typescript/lib/lib.dom.d.ts:11270 ___ @@ -170,7 +170,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11142 +node_modules/typescript/lib/lib.dom.d.ts:11271 ## Methods @@ -188,7 +188,7 @@ node_modules/typescript/lib/lib.dom.d.ts:11142 #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2404 +node_modules/typescript/lib/lib.dom.d.ts:2434 ___ @@ -206,7 +206,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2405 +node_modules/typescript/lib/lib.dom.d.ts:2435 ___ @@ -224,7 +224,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:11143 +node_modules/typescript/lib/lib.dom.d.ts:11272 ___ @@ -242,7 +242,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2406 +node_modules/typescript/lib/lib.dom.d.ts:2436 ___ @@ -260,7 +260,7 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2407 +node_modules/typescript/lib/lib.dom.d.ts:2437 ___ @@ -278,4 +278,4 @@ ___ #### Defined in -node_modules/typescript/lib/lib.dom.d.ts:2408 +node_modules/typescript/lib/lib.dom.d.ts:2438 diff --git a/packages/framework/esm-framework/docs/interfaces/Person.md b/packages/framework/esm-framework/docs/interfaces/Person.md index 522c6af74..d44004a65 100644 --- a/packages/framework/esm-framework/docs/interfaces/Person.md +++ b/packages/framework/esm-framework/docs/interfaces/Person.md @@ -18,7 +18,7 @@ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:46](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L46) +[packages/framework/esm-api/src/types/user-resource.ts:34](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L34) ___ @@ -28,7 +28,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:47](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L47) +[packages/framework/esm-api/src/types/user-resource.ts:35](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L35) ___ @@ -38,4 +38,4 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:45](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L45) +[packages/framework/esm-api/src/types/user-resource.ts:33](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L33) diff --git a/packages/framework/esm-framework/docs/interfaces/Privilege.md b/packages/framework/esm-framework/docs/interfaces/Privilege.md index fcd7050be..fe95e1b63 100644 --- a/packages/framework/esm-framework/docs/interfaces/Privilege.md +++ b/packages/framework/esm-framework/docs/interfaces/Privilege.md @@ -18,7 +18,7 @@ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:52](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L52) +[packages/framework/esm-api/src/types/user-resource.ts:40](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L40) ___ @@ -28,7 +28,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:53](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L53) +[packages/framework/esm-api/src/types/user-resource.ts:41](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L41) ___ @@ -38,4 +38,4 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:51](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L51) +[packages/framework/esm-api/src/types/user-resource.ts:39](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L39) diff --git a/packages/framework/esm-framework/docs/interfaces/Role.md b/packages/framework/esm-framework/docs/interfaces/Role.md index 485bb784b..2a6ac7151 100644 --- a/packages/framework/esm-framework/docs/interfaces/Role.md +++ b/packages/framework/esm-framework/docs/interfaces/Role.md @@ -18,7 +18,7 @@ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:58](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L58) +[packages/framework/esm-api/src/types/user-resource.ts:46](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L46) ___ @@ -28,7 +28,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:59](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L59) +[packages/framework/esm-api/src/types/user-resource.ts:47](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L47) ___ @@ -38,4 +38,4 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:57](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L57) +[packages/framework/esm-api/src/types/user-resource.ts:45](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L45) diff --git a/packages/framework/esm-framework/docs/interfaces/Session.md b/packages/framework/esm-framework/docs/interfaces/Session.md index 67c028dc7..6abd8ef18 100644 --- a/packages/framework/esm-framework/docs/interfaces/Session.md +++ b/packages/framework/esm-framework/docs/interfaces/Session.md @@ -22,7 +22,7 @@ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:14](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L14) +[packages/framework/esm-api/src/types/user-resource.ts:2](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L2) ___ @@ -32,7 +32,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:15](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L15) +[packages/framework/esm-api/src/types/user-resource.ts:3](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L3) ___ @@ -49,7 +49,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:19](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L19) +[packages/framework/esm-api/src/types/user-resource.ts:7](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L7) ___ @@ -59,7 +59,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:16](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L16) +[packages/framework/esm-api/src/types/user-resource.ts:4](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L4) ___ @@ -69,7 +69,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:17](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L17) +[packages/framework/esm-api/src/types/user-resource.ts:5](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L5) ___ @@ -79,7 +79,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:20](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L20) +[packages/framework/esm-api/src/types/user-resource.ts:8](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L8) ___ @@ -89,4 +89,4 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:18](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L18) +[packages/framework/esm-api/src/types/user-resource.ts:6](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L6) diff --git a/packages/framework/esm-framework/docs/interfaces/SessionLocation.md b/packages/framework/esm-framework/docs/interfaces/SessionLocation.md index 28411a2be..36925a425 100644 --- a/packages/framework/esm-framework/docs/interfaces/SessionLocation.md +++ b/packages/framework/esm-framework/docs/interfaces/SessionLocation.md @@ -18,7 +18,7 @@ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:40](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L40) +[packages/framework/esm-api/src/types/user-resource.ts:28](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L28) ___ @@ -28,7 +28,7 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:41](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L41) +[packages/framework/esm-api/src/types/user-resource.ts:29](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L29) ___ @@ -38,4 +38,4 @@ ___ #### Defined in -[packages/framework/esm-api/src/types/user-resource.ts:39](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L39) +[packages/framework/esm-api/src/types/user-resource.ts:27](https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-api/src/types/user-resource.ts#L27) diff --git a/packages/framework/esm-framework/mock.tsx b/packages/framework/esm-framework/mock.tsx index e92eb8091..26072c29d 100644 --- a/packages/framework/esm-framework/mock.tsx +++ b/packages/framework/esm-framework/mock.tsx @@ -14,6 +14,10 @@ export { interpolateString, interpolateUrl } from "@openmrs/esm-config"; window.i18next = { ...window.i18next, language: "en" }; +// Needed for all mocks using stores +const availableStores: Record = {}; +const initialStates: Record = {}; + /* esm-globals */ export function setupPaths(config: any) { @@ -42,6 +46,13 @@ export function getCurrentUser() { return of({ authenticated: false }); } +export const mockSessionStore = createGlobalStore("mock-session-store", { + loaded: false, + session: null, +}); + +export const getSessionStore = jest.fn(() => mockSessionStore); + export const newWorkspaceItem = jest.fn(); export const fhirBaseUrl = "/ws/fhir2/R4"; @@ -54,10 +65,6 @@ interface StoreEntity { export type MockedStore = Store & { resetMock: () => void }; -const initialStates: Record = {}; - -const availableStores: Record = {}; - export const mockStores = availableStores; export function createGlobalStore( @@ -236,7 +243,10 @@ export const usePatient = jest.fn(() => ({ error: null, })); -export const useSession = jest.fn(() => null); +export const useSession = jest.fn(() => ({ + authenticated: false, + sessionId: "", +})); export const useLayoutType = jest.fn(() => "desktop"); diff --git a/packages/framework/esm-react-utils/src/index.ts b/packages/framework/esm-react-utils/src/index.ts index 4d2218649..4689d2d08 100644 --- a/packages/framework/esm-react-utils/src/index.ts +++ b/packages/framework/esm-react-utils/src/index.ts @@ -22,7 +22,7 @@ export * from "./useLayoutType"; export * from "./useLocations"; export * from "./useOnClickOutside"; export * from "./UserHasAccess"; -export * from "./useSessionUser"; +export { useSession } from "./useSession"; export * from "./useStore"; export * from "./useVisit"; export * from "./useVisitTypes"; diff --git a/packages/framework/esm-react-utils/src/public.ts b/packages/framework/esm-react-utils/src/public.ts index da89c1948..257aa4ea1 100644 --- a/packages/framework/esm-react-utils/src/public.ts +++ b/packages/framework/esm-react-utils/src/public.ts @@ -19,7 +19,7 @@ export * from "./useLayoutType"; export * from "./useLocations"; export * from "./useOnClickOutside"; export * from "./UserHasAccess"; -export * from "./useSessionUser"; +export { useSession } from "./useSession"; export * from "./useStore"; export * from "./useVisit"; export * from "./useVisitTypes"; diff --git a/packages/framework/esm-react-utils/src/useSession.test.tsx b/packages/framework/esm-react-utils/src/useSession.test.tsx new file mode 100644 index 000000000..752de9d5d --- /dev/null +++ b/packages/framework/esm-react-utils/src/useSession.test.tsx @@ -0,0 +1,84 @@ +import React, { Suspense } from "react"; +import { act, render, screen } from "@testing-library/react"; +import "@testing-library/jest-dom"; +import { useSession, __cleanup } from "./useSession.tsx"; +import { createGlobalStore } from "@openmrs/esm-state"; +import { SessionStore } from "@openmrs/esm-api"; + +const mockSessionStore = createGlobalStore("mockSessionStore", { + loaded: false, + session: null, +}); + +jest.mock("@openmrs/esm-api", () => ({ + getSessionStore: jest.fn(() => mockSessionStore), +})); + +function Component() { + const session = useSession(); + return
{JSON.stringify(session)}
; +} + +describe("useSession", () => { + beforeEach(() => { + __cleanup(); + mockSessionStore.setState({ loaded: false, session: null }); + }); + + it("should suspend and then resolve to the session", async () => { + render( + + + + ); + + expect(screen.getByText("suspended")).toBeInTheDocument(); + act(() => { + mockSessionStore.setState({ + loaded: true, + session: { authenticated: false, sessionId: "test1" }, + }); + }); + await screen.findByText(/"authenticated":false/); + }); + + it("should resolve immediately when the session is present", async () => { + mockSessionStore.setState({ + loaded: true, + session: { authenticated: false, sessionId: "test2" }, + }); + render( + + + + ); + expect(screen.getByText(/"authenticated":false/)).toBeInTheDocument(); + }); + + it("should not return stale data when re-created", async () => { + const { unmount } = render( + + + + ); + expect(screen.getByText("suspended")).toBeInTheDocument(); + act(() => { + mockSessionStore.setState({ + loaded: true, + session: { authenticated: true, sessionId: "test3" }, + }); + }); + await screen.findByText(/"authenticated":true/); + unmount(); + mockSessionStore.setState({ + loaded: true, + session: { authenticated: false, sessionId: "test3" }, + }); + render( + + + + ); + expect(screen.getByText(/"authenticated":false/)).toBeInTheDocument(); + }); +}); diff --git a/packages/framework/esm-react-utils/src/useSession.tsx b/packages/framework/esm-react-utils/src/useSession.tsx new file mode 100644 index 000000000..af305d643 --- /dev/null +++ b/packages/framework/esm-react-utils/src/useSession.tsx @@ -0,0 +1,117 @@ +/** @module @category API */ +import { getSessionStore, Session } from "@openmrs/esm-api"; +import { useState, useEffect } from "react"; + +let promise: undefined | Promise; +let unsubscribe: undefined | (() => void); + +/** + * Gets the current user session information. Returns an object with + * property `authenticated` == `false` if the user is not logged in. + * + * Uses Suspense. This hook will always either return a Session object + * or throw for Suspense. It will never return `null`/`undefined`. + * + * @returns Current user session information + */ +export function useSession(): Session { + // We have two separate variables for the session. + // + // `session` is a temporary variable, which starts as `null` every time this + // hook is executed. It is important that we can set and return this + // variable synchronously, because every time we `throw` for Suspense, this + // hook will unmount and a new instance will be created, destroying whatever + // state existed. Thus, if this hook were to try to always set and return + // `stateSession`, it would cause an infinite loop: + // 1. instance A mounts + // 2. instance A receives value, calls `setStateSession` + // 3. instance A throws + // 4. instance A unmounts + // 5. instance B mounts + // ... + // What would happen if we moved `session` to the module scope, so that it + // could be re-used across instances of this hook? Then we would have no way + // to tell whether the session was fresh. + // + // `stateSession` is React state, which is needed to update components using + // this hook when the session changes. + const [stateSession, setStateSession] = useState(null); + let session: Session | null = null; + + if (!stateSession) { + if (!promise) { + // If we haven't created a promise to throw yet, do that. + promise = new Promise((resolve) => { + const handleNewSession = ({ loaded, session: newSession }) => { + if (loaded) { + resolve(newSession); + session = newSession; + unsubscribe && unsubscribe(); + unsubscribe = undefined; + } + }; + handleNewSession(getSessionStore().getState()); + if (!session) { + unsubscribe = getSessionStore().subscribe(handleNewSession); + } + }); + } else { + // However, if we have created a promise to throw, but there's no `stateSession` + // yet, then it's probably just this hook's first render. Check to see if + // there's already a session that we can return. + const currentState = getSessionStore().getState(); + if (currentState.loaded) { + session = currentState.session; + } + } + + // If the session got set synchronously in the above block, then we can just + // return it rather than throwing. Otherwise, throw for Suspense. + if (session) { + setStateSession(session); + } else { + throw promise; + } + } + + // Once this hook is established (no longer throwing and getting re-created) + // we need to set up a subscription that will update its value the good + // old-fashioned React way. + useEffect(() => { + if (!unsubscribe) { + unsubscribe = getSessionStore().subscribe( + ({ loaded, session: newSession }) => { + if (loaded) { + session = newSession; + setStateSession(newSession); + } + } + ); + } + return () => { + unsubscribe && unsubscribe(); + unsubscribe = undefined; + }; + }, []); + + const result = stateSession || session; + if (!result) { + if (promise) { + console.warn( + "useSessionUser is in an unexpected state. Attempting to recover." + ); + throw promise; + } else { + throw Error("useSessionUser is in an invalid state."); + } + } + return result; +} + +/** + * For testing. + */ +export function __cleanup() { + promise = undefined; + unsubscribe = undefined; +} diff --git a/packages/framework/esm-react-utils/src/useSessionUser.tsx b/packages/framework/esm-react-utils/src/useSessionUser.tsx deleted file mode 100644 index 87d433e05..000000000 --- a/packages/framework/esm-react-utils/src/useSessionUser.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/** @module @category API */ -import { getCurrentUser, Session } from "@openmrs/esm-api"; -import { useState, useEffect } from "react"; - -export function useSession() { - const [session, setSession] = useState(null); - - useEffect(() => { - const sub = getCurrentUser({ includeAuthStatus: true }).subscribe( - (session) => setSession(session) - ); - - return () => sub.unsubscribe(); - }, [setSession]); - - return session; -} diff --git a/packages/shell/esm-app-shell/src/helpers.ts b/packages/shell/esm-app-shell/src/helpers.ts index f66eb7c9c..96515bace 100644 --- a/packages/shell/esm-app-shell/src/helpers.ts +++ b/packages/shell/esm-app-shell/src/helpers.ts @@ -1,8 +1,4 @@ -import { - getCurrentUser, - userHasAccess, - CurrentUserWithoutResponseOption, -} from "@openmrs/esm-api"; +import { getLoggedInUser, userHasAccess } from "@openmrs/esm-api"; const emptyLifecycle = { bootstrap() { @@ -16,10 +12,6 @@ const emptyLifecycle = { }, }; -const userOpts: CurrentUserWithoutResponseOption = { - includeAuthStatus: false, -}; - export function routePrefix(prefix: string, location: Location) { return location.pathname.startsWith(window.getOpenmrsSpaBase() + prefix); } @@ -35,17 +27,12 @@ export function wrapLifecycle( load: () => Promise, requiredPrivilege: string ): () => Promise { - return () => { - return new Promise((resolve) => { - const sub = getCurrentUser(userOpts).subscribe((user) => { - sub.unsubscribe(); - - if (user && userHasAccess(requiredPrivilege, user)) { - return resolve(load()); - } + return async () => { + const user = await getLoggedInUser(); + if (user && userHasAccess(requiredPrivilege, user)) { + return load(); + } - return resolve(emptyLifecycle); - }); - }); + return emptyLifecycle; }; } diff --git a/packages/tooling/webpack-config/src/index.ts b/packages/tooling/webpack-config/src/index.ts index d79fcca00..32b766b68 100644 --- a/packages/tooling/webpack-config/src/index.ts +++ b/packages/tooling/webpack-config/src/index.ts @@ -163,6 +163,9 @@ export default ( headers: { "Access-Control-Allow-Origin": "*", }, + devMiddleware: { + writeToDisk: true, + }, }, performance: { hints: mode === production && "warning",