@xh/hoist 72.1.0 → 72.3.0
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/CHANGELOG.md +44 -0
- package/admin/tabs/activity/clienterrors/ClientErrorsModel.ts +23 -4
- package/admin/tabs/cluster/instances/InstancesTabModel.ts +4 -3
- package/admin/tabs/cluster/instances/logs/LogDisplay.ts +12 -14
- package/admin/tabs/cluster/instances/logs/LogDisplayModel.ts +0 -2
- package/admin/tabs/cluster/instances/logs/LogViewer.ts +6 -5
- package/admin/tabs/cluster/instances/logs/LogViewerModel.ts +8 -1
- package/admin/tabs/cluster/instances/memory/MemoryMonitorModel.ts +1 -0
- package/admin/tabs/cluster/instances/services/DetailsModel.ts +1 -2
- package/admin/tabs/cluster/instances/services/DetailsPanel.ts +19 -14
- package/admin/tabs/cluster/instances/services/ServiceModel.ts +14 -6
- package/admin/tabs/cluster/instances/services/ServicePanel.ts +9 -10
- package/admin/tabs/cluster/instances/websocket/WebSocketColumns.ts +9 -0
- package/admin/tabs/cluster/instances/websocket/WebSocketModel.ts +2 -1
- package/admin/tabs/userData/roles/RoleModel.ts +1 -1
- package/admin/tabs/userData/roles/details/RoleDetailsModel.ts +2 -1
- package/admin/tabs/userData/roles/recategorize/RecategorizeDialogModel.ts +1 -1
- package/appcontainer/AppStateModel.ts +6 -1
- package/build/types/admin/tabs/activity/tracking/ActivityTrackingModel.d.ts +4 -1
- package/build/types/admin/tabs/cluster/instances/services/DetailsModel.d.ts +2 -3
- package/build/types/admin/tabs/cluster/instances/websocket/WebSocketColumns.d.ts +1 -0
- package/build/types/appcontainer/AppStateModel.d.ts +5 -1
- package/build/types/cmp/tab/TabContainerModel.d.ts +5 -5
- package/build/types/core/HoistProps.d.ts +1 -0
- package/build/types/core/XH.d.ts +5 -5
- package/build/types/core/types/Interfaces.d.ts +9 -0
- package/build/types/desktop/cmp/appOption/AutoRefreshAppOption.d.ts +1 -0
- package/build/types/desktop/cmp/appOption/ThemeAppOption.d.ts +1 -0
- package/build/types/desktop/cmp/tab/TabSwitcher.d.ts +1 -1
- package/build/types/kit/blueprint/Wrappers.d.ts +1 -1
- package/build/types/kit/swiper/index.d.ts +4 -4
- package/build/types/security/BaseOAuthClient.d.ts +25 -28
- package/build/types/security/Token.d.ts +0 -1
- package/build/types/security/Types.d.ts +39 -0
- package/build/types/security/authzero/AuthZeroClient.d.ts +3 -4
- package/build/types/security/msal/MsalClient.d.ts +14 -4
- package/build/types/svc/TrackService.d.ts +31 -1
- package/build/types/utils/js/BrowserUtils.d.ts +38 -1
- package/cmp/tab/TabContainerModel.ts +5 -5
- package/core/HoistProps.ts +1 -0
- package/core/XH.ts +13 -5
- package/core/exception/Exception.ts +19 -12
- package/core/types/Interfaces.ts +11 -0
- package/data/Store.ts +3 -0
- package/desktop/appcontainer/ExceptionDialog.ts +1 -1
- package/desktop/cmp/dash/canvas/DashCanvas.ts +2 -1
- package/desktop/cmp/grid/editors/BooleanEditor.ts +15 -3
- package/desktop/cmp/tab/TabSwitcher.ts +1 -1
- package/package.json +2 -2
- package/security/BaseOAuthClient.ts +52 -45
- package/security/Token.ts +0 -2
- package/security/Types.ts +51 -0
- package/security/authzero/AuthZeroClient.ts +6 -8
- package/security/msal/MsalClient.ts +130 -27
- package/svc/FetchService.ts +3 -2
- package/svc/TrackService.ts +94 -8
- package/svc/WebSocketService.ts +1 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/utils/js/BrowserUtils.ts +72 -21
- package/utils/react/LayoutPropUtils.ts +2 -1
|
@@ -19,6 +19,15 @@ export interface HoistUser {
|
|
|
19
19
|
hasRole(s: string): boolean;
|
|
20
20
|
hasGate(s: string): boolean;
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Options governing XH.reloadApp().
|
|
24
|
+
*/
|
|
25
|
+
export interface ReloadAppOptions {
|
|
26
|
+
/** Relative path to reload (e.g. 'mobile/'). Defaults to the existing location pathname. */
|
|
27
|
+
path?: string;
|
|
28
|
+
/** Should the query parameters be removed from the url before reload. Default false. */
|
|
29
|
+
removeQueryParams?: boolean;
|
|
30
|
+
}
|
|
22
31
|
/**
|
|
23
32
|
* Options for showing a "toast" notification that appears and then automatically dismisses.
|
|
24
33
|
*/
|
|
@@ -61,6 +61,7 @@ export declare const autoRefreshAppOption: ({ formFieldProps, inputProps }?: Aut
|
|
|
61
61
|
flexGrow?: string | number;
|
|
62
62
|
flexShrink?: string | number;
|
|
63
63
|
flexWrap?: import("csstype").Property.FlexWrap;
|
|
64
|
+
gap?: string | number;
|
|
64
65
|
alignItems?: string;
|
|
65
66
|
alignSelf?: string;
|
|
66
67
|
alignContent?: string;
|
|
@@ -59,6 +59,7 @@ export declare const themeAppOption: ({ formFieldProps, inputProps }?: ThemeAppO
|
|
|
59
59
|
flexGrow?: string | number;
|
|
60
60
|
flexShrink?: string | number;
|
|
61
61
|
flexWrap?: import("csstype").Property.FlexWrap;
|
|
62
|
+
gap?: string | number;
|
|
62
63
|
alignItems?: string;
|
|
63
64
|
alignSelf?: string;
|
|
64
65
|
alignContent?: string;
|
|
@@ -10,6 +10,6 @@ import '@xh/hoist/desktop/register';
|
|
|
10
10
|
*
|
|
11
11
|
* Overflowing tabs can be displayed in a dropdown menu if `enableOverflow` is true.
|
|
12
12
|
* Note that in order for tabs to overflow, the TabSwitcher or it's wrapper must have a
|
|
13
|
-
*
|
|
13
|
+
* maximum width.
|
|
14
14
|
*/
|
|
15
15
|
export declare const TabSwitcher: import("react").FC<TabSwitcherProps>, tabSwitcher: import("@xh/hoist/core").ElementFactory<TabSwitcherProps>;
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
import { Alert, Button, ButtonGroup, Callout, Card, Checkbox, ControlGroup, Dialog, Drawer, EditableText, FileInput, FormGroup, Hotkey, Hotkeys, InputGroup, Label, Menu, MenuDivider, MenuItem, Navbar, NavbarDivider, NavbarGroup, NavbarHeading, NumericInput, OverflowList, Overlay2 as Overlay, Popover, Radio, RadioGroup, RangeSlider, Slider, Switch, Tab, Tabs, Tag, TagInput, Text, TextArea, Tooltip, Tree } from '@blueprintjs/core';
|
|
3
3
|
import { DatePicker3 as DatePicker } from '@blueprintjs/datetime2';
|
|
4
4
|
export { Alert, Button, ButtonGroup, Callout, Card, Checkbox, ControlGroup, DatePicker, Dialog, Drawer, EditableText, FileInput, FormGroup, Hotkeys, Hotkey, InputGroup, Label, Menu, MenuItem, MenuDivider, Navbar, NavbarDivider, NavbarGroup, NavbarHeading, NumericInput, OverflowList, Overlay, Popover, Radio, RadioGroup, RangeSlider, Slider, Switch, Tab, Tabs, Tag, TagInput, TextArea, Text, Tooltip, Tree };
|
|
5
|
-
export declare const alert: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").AlertProps>, button: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").ButtonProps>, controlGroup: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").ControlGroupProps>, checkbox: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").CheckboxProps>, dialog: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").DialogProps>, datePicker: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/datetime2").DatePicker3Props>, menuDivider: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").MenuDividerProps>, menuItem: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").MenuItemProps>, navbarDivider: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").NavbarDividerProps>, numericInput: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").HTMLInputProps & import("@blueprintjs/core").NumericInputProps>, overflowList: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").OverflowListProps<any>>, popover: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").PopoverProps<import("@blueprintjs/core").DefaultPopoverTargetHTMLProps>>, radio: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").ControlProps>, rangeSlider: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").RangeSliderProps>, slider: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").SliderProps>, switchControl: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").SwitchProps>, textArea: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").TextAreaProps>, tree: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").TreeProps<unknown>>, tagInput: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").TagInputProps>, fileInput: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").FileInputProps>, overlay: import("@xh/hoist/core").ElementFactory<
|
|
5
|
+
export declare const alert: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").AlertProps>, button: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").ButtonProps>, controlGroup: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").ControlGroupProps>, checkbox: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").CheckboxProps>, dialog: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").DialogProps>, datePicker: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/datetime2").DatePicker3Props>, menuDivider: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").MenuDividerProps>, menuItem: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").MenuItemProps>, navbarDivider: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").NavbarDividerProps>, numericInput: import("@xh/hoist/core").ElementFactory<Omit<import("@blueprintjs/core").HTMLInputProps, "size"> & import("@blueprintjs/core").NumericInputProps>, overflowList: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").OverflowListProps<any>>, popover: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").PopoverProps<import("@blueprintjs/core").DefaultPopoverTargetHTMLProps>>, radio: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").ControlProps>, rangeSlider: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").RangeSliderProps>, slider: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").SliderProps>, switchControl: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").SwitchProps>, textArea: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").TextAreaProps>, tree: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").TreeProps<unknown>>, tagInput: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").TagInputProps>, fileInput: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").FileInputProps>, overlay: import("@xh/hoist/core").ElementFactory<Omit<import("@blueprintjs/core").Overlay2Props, "ref"> & import("react").RefAttributes<import("@blueprintjs/core").OverlayInstance>>, tooltip: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").TooltipProps<import("@blueprintjs/core").DefaultPopoverTargetHTMLProps>>;
|
|
6
6
|
export declare const buttonGroup: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").ButtonGroupProps>, callout: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").CalloutProps>, card: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").CardProps>, drawer: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").DrawerProps>, editableText: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").EditableTextProps>, formGroup: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").FormGroupProps>, hotkey: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").HotkeyProps>, hotkeys: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").HotkeysProps>, inputGroup: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").InputGroupProps>, label: import("@xh/hoist/core").ElementFactory<import("react").AllHTMLAttributes<HTMLLabelElement> & import("react").RefAttributes<HTMLLabelElement>>, menu: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").MenuProps>, navbar: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").NavbarProps>, navbarHeading: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").NavbarHeadingProps>, navbarGroup: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").NavbarGroupProps>, radioGroup: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").RadioGroupProps>, tabs: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").TabsProps>, tab: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").TabProps>, tag: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").TagProps>, text: import("@xh/hoist/core").ElementFactory<import("@blueprintjs/core").TextProps>;
|
|
@@ -13,13 +13,10 @@ export declare const swiper: import("@xh/hoist/core").ElementFactory<import("rea
|
|
|
13
13
|
onAutoplayResume?: (swiper: import("swiper/types/swiper-class").default) => void;
|
|
14
14
|
onAutoplayTimeLeft?: (swiper: import("swiper/types/swiper-class").default, timeLeft: number, percentage: number) => void;
|
|
15
15
|
onAutoplay?: (swiper: import("swiper/types/swiper-class").default) => void;
|
|
16
|
+
onKeyPress?: (swiper: import("swiper/types/swiper-class").default, keyCode: string) => void;
|
|
16
17
|
onHashChange?: (swiper: import("swiper/types/swiper-class").default) => void;
|
|
17
18
|
onHashSet?: (swiper: import("swiper/types/swiper-class").default) => void;
|
|
18
|
-
onKeyPress?: (swiper: import("swiper/types/swiper-class").default, keyCode: string) => void;
|
|
19
19
|
onScroll?: (swiper: import("swiper/types/swiper-class").default, event: WheelEvent) => void;
|
|
20
|
-
onScrollbarDragStart?: (swiper: import("swiper/types/swiper-class").default, event: MouseEvent | PointerEvent | TouchEvent) => void;
|
|
21
|
-
onScrollbarDragMove?: (swiper: import("swiper/types/swiper-class").default, event: MouseEvent | PointerEvent | TouchEvent) => void;
|
|
22
|
-
onScrollbarDragEnd?: (swiper: import("swiper/types/swiper-class").default, event: MouseEvent | PointerEvent | TouchEvent) => void;
|
|
23
20
|
onNavigationHide?: (swiper: import("swiper/types/swiper-class").default) => void;
|
|
24
21
|
onNavigationShow?: (swiper: import("swiper/types/swiper-class").default) => void;
|
|
25
22
|
onNavigationPrev?: (swiper: import("swiper/types/swiper-class").default) => void;
|
|
@@ -28,6 +25,9 @@ export declare const swiper: import("@xh/hoist/core").ElementFactory<import("rea
|
|
|
28
25
|
onPaginationUpdate?: (swiper: import("swiper/types/swiper-class").default, paginationEl: HTMLElement) => void;
|
|
29
26
|
onPaginationHide?: (swiper: import("swiper/types/swiper-class").default) => void;
|
|
30
27
|
onPaginationShow?: (swiper: import("swiper/types/swiper-class").default) => void;
|
|
28
|
+
onScrollbarDragStart?: (swiper: import("swiper/types/swiper-class").default, event: MouseEvent | PointerEvent | TouchEvent) => void;
|
|
29
|
+
onScrollbarDragMove?: (swiper: import("swiper/types/swiper-class").default, event: MouseEvent | PointerEvent | TouchEvent) => void;
|
|
30
|
+
onScrollbarDragEnd?: (swiper: import("swiper/types/swiper-class").default, event: MouseEvent | PointerEvent | TouchEvent) => void;
|
|
31
31
|
onZoomChange?: (swiper: import("swiper/types/swiper-class").default, scale: number, imageEl: HTMLElement, slideEl: HTMLElement) => void;
|
|
32
32
|
onInit?: (swiper: import("swiper/types/swiper-class").default) => any;
|
|
33
33
|
onBeforeDestroy?: (swiper: import("swiper/types/swiper-class").default) => void;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { HoistBase } from '@xh/hoist/core';
|
|
2
|
-
import { Token
|
|
2
|
+
import { Token } from '@xh/hoist/security/Token';
|
|
3
|
+
import { AccessTokenSpec, TokenMap } from './Types';
|
|
3
4
|
export type LoginMethod = 'REDIRECT' | 'POPUP';
|
|
4
|
-
export interface BaseOAuthClientConfig<S> {
|
|
5
|
+
export interface BaseOAuthClientConfig<S extends AccessTokenSpec> {
|
|
5
6
|
/** Client ID (GUID) of your app registered with your Oauth provider. */
|
|
6
7
|
clientId: string;
|
|
7
8
|
/**
|
|
@@ -23,38 +24,29 @@ export interface BaseOAuthClientConfig<S> {
|
|
|
23
24
|
* Governs an optional refresh timer that will work to keep the tokens fresh.
|
|
24
25
|
*
|
|
25
26
|
* A typical refresh will use the underlying provider cache, and should not result in
|
|
26
|
-
* network activity. However, if any token
|
|
27
|
+
* network activity. However, if any token would expire before the next autoRefresh,
|
|
27
28
|
* this client will force a call to the underlying provider to get the token.
|
|
28
29
|
*
|
|
29
30
|
* In order to allow aging tokens to be replaced in a timely manner, this value should be
|
|
30
31
|
* significantly shorter than both the minimum token lifetime that will be
|
|
31
|
-
* returned by the underlying API
|
|
32
|
+
* returned by the underlying API.
|
|
32
33
|
*
|
|
33
34
|
* Default is -1, disabling this behavior.
|
|
34
35
|
*/
|
|
35
36
|
autoRefreshSecs?: number;
|
|
36
|
-
/**
|
|
37
|
-
* During auto-refresh, if the remaining lifetime for any token is below this threshold,
|
|
38
|
-
* force the provider to skip the local cache and go directly to the underlying provider for
|
|
39
|
-
* new tokens and refresh tokens.
|
|
40
|
-
*
|
|
41
|
-
* Default is -1, disabling this behavior.
|
|
42
|
-
*/
|
|
43
|
-
autoRefreshSkipCacheSecs?: number;
|
|
44
37
|
/**
|
|
45
38
|
* Scopes to request - if any - beyond the core `['openid', 'email']` scopes, which
|
|
46
39
|
* this client will always request.
|
|
47
40
|
*/
|
|
48
41
|
idScopes?: string[];
|
|
49
42
|
/**
|
|
50
|
-
* Optional
|
|
51
|
-
*
|
|
52
|
-
* Map of code to a spec for an access token. The code is app-determined and
|
|
53
|
-
* will simply be used to get the loaded token via tha getAccessToken() method. The
|
|
54
|
-
* spec is implementation specific, but will typically include scopes to be loaded
|
|
55
|
-
* for the access token and potentially other meta-data required by the underlying provider.
|
|
43
|
+
* Optional spec for access tokens to be loaded and maintained to support access to one or more
|
|
44
|
+
* different back-end resources, distinct from the core Hoist auth flow via ID token.
|
|
56
45
|
*
|
|
57
|
-
*
|
|
46
|
+
* Map of key to a spec for an access token. The key is an arbitrary, app-determined string
|
|
47
|
+
* used to retrieve the loaded token via {@link getAccessTokenAsync}. The spec is implementation
|
|
48
|
+
* specific, but will typically include scopes to be loaded for the access token and potentially
|
|
49
|
+
* other metadata required by the underlying provider.
|
|
58
50
|
*/
|
|
59
51
|
accessTokens?: Record<string, S>;
|
|
60
52
|
}
|
|
@@ -63,13 +55,12 @@ export interface BaseOAuthClientConfig<S> {
|
|
|
63
55
|
* suitable concrete implementation to power a client-side OauthService. See `MsalClient` and
|
|
64
56
|
* `AuthZeroClient`
|
|
65
57
|
*
|
|
66
|
-
* Initialize such a service and this client within
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* flow as necessary.
|
|
58
|
+
* Initialize such a service and this client within an app's primary {@link HoistAuthModel} to use
|
|
59
|
+
* the tokens it acquires to authenticate with the Hoist server. (Note this requires a suitable
|
|
60
|
+
* server-side `AuthenticationService` implementation to validate the token and actually resolve
|
|
61
|
+
* the user.) On init, the client impl will initiate a pop-up or redirect flow as necessary.
|
|
71
62
|
*/
|
|
72
|
-
export declare abstract class BaseOAuthClient<C extends BaseOAuthClientConfig<S>, S> extends HoistBase {
|
|
63
|
+
export declare abstract class BaseOAuthClient<C extends BaseOAuthClientConfig<S>, S extends AccessTokenSpec> extends HoistBase {
|
|
73
64
|
/** Config loaded from UI server + init method. */
|
|
74
65
|
protected config: C;
|
|
75
66
|
/** ID Scopes */
|
|
@@ -101,9 +92,12 @@ export declare abstract class BaseOAuthClient<C extends BaseOAuthClientConfig<S>
|
|
|
101
92
|
*/
|
|
102
93
|
getAccessTokenAsync(key: string): Promise<Token>;
|
|
103
94
|
/**
|
|
104
|
-
* Get all
|
|
95
|
+
* Get all configured tokens.
|
|
105
96
|
*/
|
|
106
|
-
getAllTokensAsync(
|
|
97
|
+
getAllTokensAsync(opts?: {
|
|
98
|
+
eagerOnly?: boolean;
|
|
99
|
+
useCache?: boolean;
|
|
100
|
+
}): Promise<TokenMap>;
|
|
107
101
|
/**
|
|
108
102
|
* The last authenticated OAuth username.
|
|
109
103
|
*
|
|
@@ -144,7 +138,10 @@ export declare abstract class BaseOAuthClient<C extends BaseOAuthClientConfig<S>
|
|
|
144
138
|
protected restoreRedirectState(key: string): void;
|
|
145
139
|
/** Call after requesting the provider library redirect the user away for auth. */
|
|
146
140
|
protected maskAfterRedirectAsync(): Promise<void>;
|
|
147
|
-
protected fetchAllTokensAsync(
|
|
141
|
+
protected fetchAllTokensAsync(opts?: {
|
|
142
|
+
eagerOnly?: boolean;
|
|
143
|
+
useCache?: boolean;
|
|
144
|
+
}): Promise<TokenMap>;
|
|
148
145
|
protected getLocalStorage(key: string, defaultValue?: any): any;
|
|
149
146
|
protected setLocalStorage(key: string, value: any): void;
|
|
150
147
|
private fetchIdTokenSafeAsync;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Token } from './Token';
|
|
2
|
+
export interface AccessTokenSpec {
|
|
3
|
+
/**
|
|
4
|
+
* Mode governing when the access token should be requested from provider:
|
|
5
|
+
* - eager (or undefined) - load on overall initialization, but do not block on failure.
|
|
6
|
+
* Useful for tokens that an app is almost certain to require during a user session.
|
|
7
|
+
* - lazy - defer loading until first requested by client. Useful for tokens that might
|
|
8
|
+
* never be needed by the app during a given user session.
|
|
9
|
+
*/
|
|
10
|
+
fetchMode?: 'eager' | 'lazy';
|
|
11
|
+
/** Scopes for the desired access token.*/
|
|
12
|
+
scopes: string[];
|
|
13
|
+
}
|
|
14
|
+
export type TokenMap = Record<string, Token>;
|
|
15
|
+
/** Aggregated telemetry results, produced by {@link MsalClient} when enabled via config. */
|
|
16
|
+
export interface TelemetryResults {
|
|
17
|
+
/** Stats by event type - */
|
|
18
|
+
events: Record<string, TelemetryEventResults>;
|
|
19
|
+
}
|
|
20
|
+
/** Aggregated telemetry results for a single type of event. */
|
|
21
|
+
export interface TelemetryEventResults {
|
|
22
|
+
firstTime: Date;
|
|
23
|
+
lastTime: Date;
|
|
24
|
+
successCount: number;
|
|
25
|
+
failureCount: number;
|
|
26
|
+
/** Timing info (in ms) for event instances reported with duration. */
|
|
27
|
+
duration: {
|
|
28
|
+
count: number;
|
|
29
|
+
total: number;
|
|
30
|
+
average: number;
|
|
31
|
+
worst: number;
|
|
32
|
+
};
|
|
33
|
+
lastFailure?: {
|
|
34
|
+
time: Date;
|
|
35
|
+
duration: number;
|
|
36
|
+
code: string;
|
|
37
|
+
name: string;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Auth0ClientOptions } from '@auth0/auth0-spa-js';
|
|
2
|
-
import { Token
|
|
2
|
+
import { Token } from '@xh/hoist/security/Token';
|
|
3
|
+
import { AccessTokenSpec, TokenMap } from '../Types';
|
|
3
4
|
import { BaseOAuthClient, BaseOAuthClientConfig } from '../BaseOAuthClient';
|
|
4
5
|
export interface AuthZeroClientConfig extends BaseOAuthClientConfig<AuthZeroTokenSpec> {
|
|
5
6
|
/** Domain of your app registered with Auth0. */
|
|
@@ -24,9 +25,7 @@ export interface AuthZeroClientConfig extends BaseOAuthClientConfig<AuthZeroToke
|
|
|
24
25
|
*/
|
|
25
26
|
authZeroClientOptions?: Partial<Auth0ClientOptions>;
|
|
26
27
|
}
|
|
27
|
-
export interface AuthZeroTokenSpec {
|
|
28
|
-
/** Scopes for the desired access token.*/
|
|
29
|
-
scopes: string[];
|
|
28
|
+
export interface AuthZeroTokenSpec extends AccessTokenSpec {
|
|
30
29
|
/**
|
|
31
30
|
* Audience (i.e. API) identifier for AccessToken. Must be registered with Auth0.
|
|
32
31
|
* Note that this is required to ensure that issued token is a JWT and not an opaque string.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as msal from '@azure/msal-browser';
|
|
2
2
|
import { LogLevel } from '@azure/msal-browser';
|
|
3
|
-
import { Token
|
|
3
|
+
import { Token } from '@xh/hoist/security/Token';
|
|
4
4
|
import { BaseOAuthClient, BaseOAuthClientConfig } from '../BaseOAuthClient';
|
|
5
|
+
import { AccessTokenSpec, TelemetryResults, TokenMap } from '../Types';
|
|
5
6
|
export interface MsalClientConfig extends BaseOAuthClientConfig<MsalTokenSpec> {
|
|
6
7
|
/**
|
|
7
8
|
* Authority for your organization's tenant: `https://login.microsoftonline.com/[tenantId]`.
|
|
@@ -15,6 +16,12 @@ export interface MsalClientConfig extends BaseOAuthClientConfig<MsalTokenSpec> {
|
|
|
15
16
|
* The value of the domain hint is a registered domain for the tenant.
|
|
16
17
|
*/
|
|
17
18
|
domainHint?: string;
|
|
19
|
+
/**
|
|
20
|
+
* True to enable support for built-in telemetry provided by this class's internal MSAL client.
|
|
21
|
+
* Captured performance events will be summarized via {@link telemetryResults}.
|
|
22
|
+
* See https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/performance.md
|
|
23
|
+
*/
|
|
24
|
+
enableTelemetry?: boolean;
|
|
18
25
|
/**
|
|
19
26
|
* If specified, the client will use this value when initializing the app to enforce a minimum
|
|
20
27
|
* amount of time during which no further auth flow with the provider should be necessary.
|
|
@@ -44,9 +51,7 @@ export interface MsalClientConfig extends BaseOAuthClientConfig<MsalTokenSpec> {
|
|
|
44
51
|
*/
|
|
45
52
|
msalClientOptions?: Partial<msal.Configuration>;
|
|
46
53
|
}
|
|
47
|
-
export interface MsalTokenSpec {
|
|
48
|
-
/** Scopes for the desired access token. */
|
|
49
|
-
scopes: string[];
|
|
54
|
+
export interface MsalTokenSpec extends AccessTokenSpec {
|
|
50
55
|
/**
|
|
51
56
|
* Scopes to be added to the scopes requested during interactive and SSO logins.
|
|
52
57
|
* See the `scopes` property on `PopupRequest`, `RedirectRequest`, and `SSORequest`
|
|
@@ -81,6 +86,9 @@ export declare class MsalClient extends BaseOAuthClient<MsalClientConfig, MsalTo
|
|
|
81
86
|
private client;
|
|
82
87
|
private account;
|
|
83
88
|
private initialTokenLoad;
|
|
89
|
+
/** Enable telemetry via `enableTelemetry` ctor config, or via {@link enableTelemetry}. */
|
|
90
|
+
telemetryResults: TelemetryResults;
|
|
91
|
+
private _telemetryCbHandle;
|
|
84
92
|
constructor(config: MsalClientConfig);
|
|
85
93
|
protected doInitAsync(): Promise<TokenMap>;
|
|
86
94
|
protected doLoginPopupAsync(): Promise<void>;
|
|
@@ -88,6 +96,8 @@ export declare class MsalClient extends BaseOAuthClient<MsalClientConfig, MsalTo
|
|
|
88
96
|
protected fetchIdTokenAsync(useCache?: boolean): Promise<Token>;
|
|
89
97
|
protected fetchAccessTokenAsync(spec: MsalTokenSpec, useCache?: boolean): Promise<Token>;
|
|
90
98
|
protected doLogoutAsync(): Promise<void>;
|
|
99
|
+
enableTelemetry(): void;
|
|
100
|
+
disableTelemetry(): void;
|
|
91
101
|
private loginSsoAsync;
|
|
92
102
|
private createClientAsync;
|
|
93
103
|
private logFromMsal;
|
|
@@ -6,15 +6,45 @@ import { HoistService, TrackOptions } from '@xh/hoist/core';
|
|
|
6
6
|
*/
|
|
7
7
|
export declare class TrackService extends HoistService {
|
|
8
8
|
static instance: TrackService;
|
|
9
|
+
private clientHealthReportSources;
|
|
9
10
|
private oncePerSessionSent;
|
|
10
11
|
private pending;
|
|
11
12
|
initAsync(): Promise<void>;
|
|
12
|
-
get conf():
|
|
13
|
+
get conf(): ActivityTrackingConfig;
|
|
13
14
|
get enabled(): boolean;
|
|
14
15
|
/** Track User Activity. */
|
|
15
16
|
track(options: TrackOptions | string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Register a new source for client health report data. No-op if background health report is
|
|
19
|
+
* not generally enabled via `xhActivityTrackingConfig.clientHealthReport.intervalMins`.
|
|
20
|
+
*
|
|
21
|
+
* @param key - key under which to report the data - can be used to remove this source later.
|
|
22
|
+
* @param callback - function returning serializable to include with each report.
|
|
23
|
+
*/
|
|
24
|
+
addClientHealthReportSource(key: string, callback: () => any): void;
|
|
25
|
+
/** Unregister a previously-enabled source for client health report data. */
|
|
26
|
+
removeClientHealthReportSource(key: string): void;
|
|
16
27
|
private pushPendingAsync;
|
|
17
28
|
private pushPendingBuffered;
|
|
18
29
|
private toServerJson;
|
|
19
30
|
private logMessage;
|
|
31
|
+
private sendClientHealthReport;
|
|
20
32
|
}
|
|
33
|
+
interface ActivityTrackingConfig {
|
|
34
|
+
clientHealthReport?: Partial<TrackOptions> & {
|
|
35
|
+
intervalMins: number;
|
|
36
|
+
};
|
|
37
|
+
enabled: boolean;
|
|
38
|
+
logData: boolean;
|
|
39
|
+
maxDataLength: number;
|
|
40
|
+
maxRows?: {
|
|
41
|
+
default: number;
|
|
42
|
+
options: number[];
|
|
43
|
+
};
|
|
44
|
+
levels?: Array<{
|
|
45
|
+
username: string | '*';
|
|
46
|
+
category: string | '*';
|
|
47
|
+
severity: 'DEBUG' | 'INFO' | 'WARN';
|
|
48
|
+
}>;
|
|
49
|
+
}
|
|
50
|
+
export {};
|
|
@@ -1,4 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Extract information (if available) about the client browser's window, screen, and network speed.
|
|
3
3
|
*/
|
|
4
|
-
export declare function getClientDeviceInfo():
|
|
4
|
+
export declare function getClientDeviceInfo(): ClientDeviceInfo;
|
|
5
|
+
export interface ClientDeviceInfo {
|
|
6
|
+
window: {
|
|
7
|
+
devicePixelRatio: number;
|
|
8
|
+
screenX: number;
|
|
9
|
+
screenY: number;
|
|
10
|
+
innerWidth: number;
|
|
11
|
+
innerHeight: number;
|
|
12
|
+
outerWidth: number;
|
|
13
|
+
outerHeight: number;
|
|
14
|
+
};
|
|
15
|
+
screen?: {
|
|
16
|
+
availWidth: number;
|
|
17
|
+
availHeight: number;
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
colorDepth: number;
|
|
21
|
+
pixelDepth: number;
|
|
22
|
+
availLeft: number;
|
|
23
|
+
availTop: number;
|
|
24
|
+
orientation?: {
|
|
25
|
+
angle: number;
|
|
26
|
+
type: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
connection?: {
|
|
30
|
+
downlink: number;
|
|
31
|
+
effectiveType: string;
|
|
32
|
+
rtt: number;
|
|
33
|
+
};
|
|
34
|
+
memory: {
|
|
35
|
+
modelCount: number;
|
|
36
|
+
usedPctLimit?: number;
|
|
37
|
+
jsHeapSizeLimit?: number;
|
|
38
|
+
totalJSHeapSize?: number;
|
|
39
|
+
usedJSHeapSize?: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -108,7 +108,7 @@ export class TabContainerModel extends HoistModel implements Persistable<{active
|
|
|
108
108
|
@managed
|
|
109
109
|
refreshContextModel: RefreshContextModel;
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
protected lastActiveTabId: string;
|
|
112
112
|
|
|
113
113
|
constructor({
|
|
114
114
|
tabs = [],
|
|
@@ -342,7 +342,7 @@ export class TabContainerModel extends HoistModel implements Persistable<{active
|
|
|
342
342
|
// Implementation
|
|
343
343
|
//-------------------------
|
|
344
344
|
@action
|
|
345
|
-
|
|
345
|
+
protected setActiveTabIdInternal(id) {
|
|
346
346
|
const tab = this.findTab(id);
|
|
347
347
|
throwIf(!tab, `Unknown Tab ${id} in TabContainer.`);
|
|
348
348
|
throwIf(tab.disabled, `Cannot activate Tab ${id} because it is disabled!`);
|
|
@@ -351,7 +351,7 @@ export class TabContainerModel extends HoistModel implements Persistable<{active
|
|
|
351
351
|
this.forwardRouterToTab(id);
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
-
|
|
354
|
+
protected syncWithRouter() {
|
|
355
355
|
const {tabs, route} = this,
|
|
356
356
|
{router} = XH,
|
|
357
357
|
state = router.getState();
|
|
@@ -364,14 +364,14 @@ export class TabContainerModel extends HoistModel implements Persistable<{active
|
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
-
|
|
367
|
+
protected forwardRouterToTab(id) {
|
|
368
368
|
const {route} = this;
|
|
369
369
|
if (route && id) {
|
|
370
370
|
XH.router.forward(route, route + '.' + id);
|
|
371
371
|
}
|
|
372
372
|
}
|
|
373
373
|
|
|
374
|
-
|
|
374
|
+
protected calculateActiveTabId(tabs) {
|
|
375
375
|
let ret;
|
|
376
376
|
|
|
377
377
|
// try route
|
package/core/HoistProps.ts
CHANGED
package/core/XH.ts
CHANGED
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
MessageSpec,
|
|
55
55
|
PageState,
|
|
56
56
|
PlainObject,
|
|
57
|
+
ReloadAppOptions,
|
|
57
58
|
SizingMode,
|
|
58
59
|
TaskObserver,
|
|
59
60
|
Theme,
|
|
@@ -64,7 +65,7 @@ import {installServicesAsync} from './impl/InstallServices';
|
|
|
64
65
|
import {instanceManager} from './impl/InstanceManager';
|
|
65
66
|
import {HoistModel, ModelSelector, RefreshContextModel} from './model';
|
|
66
67
|
|
|
67
|
-
export const MIN_HOIST_CORE_VERSION = '
|
|
68
|
+
export const MIN_HOIST_CORE_VERSION = '28.0';
|
|
68
69
|
|
|
69
70
|
declare const xhAppCode: string;
|
|
70
71
|
declare const xhAppName: string;
|
|
@@ -392,18 +393,25 @@ export class XHApi {
|
|
|
392
393
|
/**
|
|
393
394
|
* Trigger a full reload of the current application.
|
|
394
395
|
*
|
|
395
|
-
* @param
|
|
396
|
-
*
|
|
396
|
+
* @param opts - options to govern reload. To support legacy usages, a provided
|
|
397
|
+
* string will be treated as `ReloadAppOptions.path`.
|
|
397
398
|
*
|
|
398
399
|
* This method will reload the entire application document in the browser - to trigger a
|
|
399
400
|
* refresh of the loadable content within the app, use {@link refreshAppAsync} instead.
|
|
400
401
|
*/
|
|
401
402
|
@action
|
|
402
|
-
reloadApp(
|
|
403
|
+
reloadApp(opts?: ReloadAppOptions | string) {
|
|
403
404
|
never().linkTo(this.appLoadModel);
|
|
405
|
+
|
|
406
|
+
opts = isString(opts) ? {path: opts} : (opts ?? {});
|
|
407
|
+
|
|
404
408
|
const {location} = window,
|
|
405
|
-
href =
|
|
409
|
+
href = opts.path
|
|
410
|
+
? `${location.origin}/${opts.path.replace(/^\/+/, '')}`
|
|
411
|
+
: location.href,
|
|
406
412
|
url = new URL(href);
|
|
413
|
+
|
|
414
|
+
if (opts.removeQueryParams) url.search = '';
|
|
407
415
|
// Add a unique query param to force a full reload without using the browser cache.
|
|
408
416
|
url.searchParams.set('xhCacheBuster', Date.now().toString());
|
|
409
417
|
document.location.assign(url);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import {PlainObject, XH} from '@xh/hoist/core';
|
|
8
8
|
import {FetchOptions} from '@xh/hoist/svc';
|
|
9
9
|
import {pluralize} from '@xh/hoist/utils/js';
|
|
10
|
-
import {isPlainObject} from 'lodash';
|
|
10
|
+
import {isPlainObject, truncate} from 'lodash';
|
|
11
11
|
import {FetchException, HoistException, TimeoutException, TimeoutExceptionConfig} from './Types';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -90,17 +90,16 @@ export class Exception {
|
|
|
90
90
|
// Try to "smart" decode as server provided JSON Exception (with a name)
|
|
91
91
|
try {
|
|
92
92
|
const cType = headers.get('Content-Type');
|
|
93
|
-
if (cType
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
93
|
+
if (cType?.includes('application/json')) {
|
|
94
|
+
const obj = safeParseJson(responseText),
|
|
95
|
+
message = obj ? obj.message : truncate(responseText?.trim(), {length: 255});
|
|
96
|
+
return this.createFetchException({
|
|
97
|
+
...defaults,
|
|
98
|
+
name: obj?.name ?? defaults.name,
|
|
99
|
+
message: message ?? statusText,
|
|
100
|
+
isRoutine: obj?.isRoutine ?? false,
|
|
101
|
+
serverDetails: obj ?? responseText
|
|
102
|
+
});
|
|
104
103
|
}
|
|
105
104
|
} catch (ignored) {}
|
|
106
105
|
|
|
@@ -222,6 +221,14 @@ export class Exception {
|
|
|
222
221
|
}
|
|
223
222
|
}
|
|
224
223
|
|
|
224
|
+
function safeParseJson(txt: string): PlainObject {
|
|
225
|
+
try {
|
|
226
|
+
return JSON.parse(txt);
|
|
227
|
+
} catch (ignored) {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
225
232
|
export function isHoistException(src: unknown): src is HoistException {
|
|
226
233
|
return src?.['isHoistException'];
|
|
227
234
|
}
|
package/core/types/Interfaces.ts
CHANGED
|
@@ -28,6 +28,17 @@ export interface HoistUser {
|
|
|
28
28
|
hasGate(s: string): boolean;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Options governing XH.reloadApp().
|
|
33
|
+
*/
|
|
34
|
+
export interface ReloadAppOptions {
|
|
35
|
+
/** Relative path to reload (e.g. 'mobile/'). Defaults to the existing location pathname. */
|
|
36
|
+
path?: string;
|
|
37
|
+
|
|
38
|
+
/** Should the query parameters be removed from the url before reload. Default false. */
|
|
39
|
+
removeQueryParams?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
31
42
|
/**
|
|
32
43
|
* Options for showing a "toast" notification that appears and then automatically dismisses.
|
|
33
44
|
*/
|
package/data/Store.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
isEmpty,
|
|
19
19
|
isFunction,
|
|
20
20
|
isNil,
|
|
21
|
+
isNull,
|
|
21
22
|
isString,
|
|
22
23
|
values,
|
|
23
24
|
remove as lodashRemove,
|
|
@@ -692,6 +693,8 @@ export class Store extends HoistBase {
|
|
|
692
693
|
* for backwards compat with app code predating support for multiple {@link summaryRecords}.
|
|
693
694
|
*/
|
|
694
695
|
get summaryRecord(): StoreRecord {
|
|
696
|
+
if (isNull(this.summaryRecords)) return null;
|
|
697
|
+
|
|
695
698
|
throwIf(
|
|
696
699
|
this.summaryRecords.length > 1,
|
|
697
700
|
'Store has multiple summary records - must access via Store.summaryRecords.'
|
|
@@ -79,7 +79,7 @@ export const dismissButton = hoistCmp.factory<ExceptionDialogModel>(({model}) =>
|
|
|
79
79
|
icon: Icon.refresh(),
|
|
80
80
|
text: 'Reload App',
|
|
81
81
|
autoFocus: true,
|
|
82
|
-
onClick: () => XH.reloadApp()
|
|
82
|
+
onClick: () => XH.reloadApp({removeQueryParams: true})
|
|
83
83
|
})
|
|
84
84
|
: button({
|
|
85
85
|
text: 'Close',
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
import {dashCanvasAddViewButton} from '@xh/hoist/desktop/cmp/button/DashCanvasAddViewButton';
|
|
19
19
|
import '@xh/hoist/desktop/register';
|
|
20
20
|
import {Classes, overlay} from '@xh/hoist/kit/blueprint';
|
|
21
|
-
import {TEST_ID} from '@xh/hoist/utils/js';
|
|
21
|
+
import {consumeEvent, TEST_ID} from '@xh/hoist/utils/js';
|
|
22
22
|
import classNames from 'classnames';
|
|
23
23
|
import ReactGridLayout, {WidthProvider} from 'react-grid-layout';
|
|
24
24
|
import {DashCanvasModel} from './DashCanvasModel';
|
|
@@ -125,6 +125,7 @@ const onContextMenu = (e, model) => {
|
|
|
125
125
|
x = clientX + model.ref.current.scrollLeft,
|
|
126
126
|
y = clientY + model.ref.current.scrollTop;
|
|
127
127
|
|
|
128
|
+
consumeEvent(e);
|
|
128
129
|
showContextMenu(
|
|
129
130
|
dashCanvasContextMenu({
|
|
130
131
|
dashCanvasModel: model,
|