@imposium-hub/components 2.5.18 → 2.6.0-1
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/dist/cjs/Util.js +1 -2
- package/dist/cjs/Util.js.map +1 -1
- package/dist/cjs/components/app-wrapper/AppWrapper.d.ts +32 -21
- package/dist/cjs/components/app-wrapper/AppWrapper.js +244 -208
- package/dist/cjs/components/app-wrapper/AppWrapper.js.map +1 -1
- package/dist/cjs/components/app-wrapper/AppWrapperV2.d.ts +3 -9
- package/dist/cjs/components/app-wrapper/AppWrapperV2.js +119 -45
- package/dist/cjs/components/app-wrapper/AppWrapperV2.js.map +1 -1
- package/dist/cjs/components/app-wrapper/AppWrapperV3.d.ts +1 -1
- package/dist/cjs/components/app-wrapper/AppWrapperV3.js +7 -44
- package/dist/cjs/components/app-wrapper/AppWrapperV3.js.map +1 -1
- package/dist/cjs/components/assets/StoryTableNameFilter.d.ts +9 -2
- package/dist/cjs/components/assets/StoryTableNameFilter.js +3 -13
- package/dist/cjs/components/assets/StoryTableNameFilter.js.map +1 -1
- package/dist/cjs/components/compositions/TextLayer.js +0 -1
- package/dist/cjs/components/compositions/TextLayer.js.map +1 -1
- package/dist/cjs/components/context-menu/AnimateComponent.d.ts +6 -6
- package/dist/cjs/components/context-menu/AnimateComponent.js.map +1 -1
- package/dist/cjs/components/context-menu/ContextMenu.d.ts +12 -27
- package/dist/cjs/components/context-menu/ContextMenu.js +2 -15
- package/dist/cjs/components/context-menu/ContextMenu.js.map +1 -1
- package/dist/cjs/components/context-menu/ContextMenuItem.d.ts +6 -18
- package/dist/cjs/components/context-menu/ContextMenuItem.js +2 -21
- package/dist/cjs/components/context-menu/ContextMenuItem.js.map +1 -1
- package/dist/cjs/components/context-menu/ContextMenuTrigger.d.ts +6 -16
- package/dist/cjs/components/context-menu/ContextMenuTrigger.js +2 -20
- package/dist/cjs/components/context-menu/ContextMenuTrigger.js.map +1 -1
- package/dist/cjs/components/context-menu/SubMenu.d.ts +4 -12
- package/dist/cjs/components/context-menu/SubMenu.js +2 -17
- package/dist/cjs/components/context-menu/SubMenu.js.map +1 -1
- package/dist/cjs/components/data-table/Paginator.d.ts +16 -1
- package/dist/cjs/components/data-table/Paginator.js +1 -1
- package/dist/cjs/components/data-table/Paginator.js.map +1 -1
- package/dist/cjs/components/font-picker/font-manager/constants.d.ts +4 -0
- package/dist/cjs/components/font-picker/font-manager/constants.js +5 -1
- package/dist/cjs/components/font-picker/font-manager/constants.js.map +1 -1
- package/dist/cjs/components/header/Header.d.ts +8 -9
- package/dist/cjs/components/header/Header.js +95 -160
- package/dist/cjs/components/header/Header.js.map +1 -1
- package/dist/cjs/components/header/ProjectDropdown.d.ts +13 -0
- package/dist/cjs/components/header/ProjectDropdown.js +128 -0
- package/dist/cjs/components/header/ProjectDropdown.js.map +1 -0
- package/dist/cjs/components/header/StoryDropdown.d.ts +6 -0
- package/dist/cjs/components/header/StoryDropdown.js +111 -0
- package/dist/cjs/components/header/StoryDropdown.js.map +1 -0
- package/dist/cjs/components/modal/Modal.d.ts +1 -1
- package/dist/cjs/components/modal/Modal.js +2 -3
- package/dist/cjs/components/modal/Modal.js.map +1 -1
- package/dist/cjs/components/portal/Portal.d.ts +0 -2
- package/dist/cjs/components/portal/Portal.js.map +1 -1
- package/dist/cjs/components/publish-wizard/PublishWizard.d.ts +1 -3
- package/dist/cjs/components/publish-wizard/PublishWizard.js.map +1 -1
- package/dist/cjs/components/publish-wizard/publish/EmailWorkflow.js.map +1 -1
- package/dist/cjs/constants/copy.d.ts +3 -0
- package/dist/cjs/constants/copy.js +3 -0
- package/dist/cjs/constants/copy.js.map +1 -1
- package/dist/cjs/index.d.ts +4 -7
- package/dist/cjs/index.js +11 -17
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/redux/actions/asset-uploads.js +0 -1
- package/dist/cjs/redux/actions/asset-uploads.js.map +1 -1
- package/dist/cjs/services/API.d.ts +10 -3
- package/dist/cjs/services/API.js +230 -84
- package/dist/cjs/services/API.js.map +1 -1
- package/dist/cjs/services/Session.d.ts +0 -11
- package/dist/cjs/services/Session.js +3 -126
- package/dist/cjs/services/Session.js.map +1 -1
- package/dist/cjs/utils/modal.d.ts +2 -0
- package/dist/cjs/utils/modal.js +11 -0
- package/dist/cjs/utils/modal.js.map +1 -0
- package/dist/cjs/utils/pendo.d.ts +24 -0
- package/dist/cjs/utils/pendo.js +62 -0
- package/dist/cjs/utils/pendo.js.map +1 -0
- package/dist/cjs/utils/routing.d.ts +2 -0
- package/dist/cjs/utils/routing.js +10 -1
- package/dist/cjs/utils/routing.js.map +1 -1
- package/dist/esm/Util.js +1 -2
- package/dist/esm/Util.js.map +1 -1
- package/dist/esm/components/app-wrapper/AppWrapper.d.ts +32 -21
- package/dist/esm/components/app-wrapper/AppWrapper.js +143 -172
- package/dist/esm/components/app-wrapper/AppWrapper.js.map +1 -1
- package/dist/esm/components/app-wrapper/AppWrapperV2.d.ts +3 -9
- package/dist/esm/components/app-wrapper/AppWrapperV2.js +30 -33
- package/dist/esm/components/app-wrapper/AppWrapperV2.js.map +1 -1
- package/dist/esm/components/app-wrapper/AppWrapperV3.d.ts +1 -1
- package/dist/esm/components/app-wrapper/AppWrapperV3.js +5 -42
- package/dist/esm/components/app-wrapper/AppWrapperV3.js.map +1 -1
- package/dist/esm/components/assets/StoryTableNameFilter.d.ts +9 -2
- package/dist/esm/components/assets/StoryTableNameFilter.js +3 -13
- package/dist/esm/components/assets/StoryTableNameFilter.js.map +1 -1
- package/dist/esm/components/compositions/TextLayer.js +0 -1
- package/dist/esm/components/compositions/TextLayer.js.map +1 -1
- package/dist/esm/components/context-menu/AnimateComponent.d.ts +6 -6
- package/dist/esm/components/context-menu/AnimateComponent.js.map +1 -1
- package/dist/esm/components/context-menu/ContextMenu.d.ts +12 -27
- package/dist/esm/components/context-menu/ContextMenu.js +2 -4
- package/dist/esm/components/context-menu/ContextMenu.js.map +1 -1
- package/dist/esm/components/context-menu/ContextMenuItem.d.ts +6 -18
- package/dist/esm/components/context-menu/ContextMenuItem.js +2 -10
- package/dist/esm/components/context-menu/ContextMenuItem.js.map +1 -1
- package/dist/esm/components/context-menu/ContextMenuTrigger.d.ts +6 -16
- package/dist/esm/components/context-menu/ContextMenuTrigger.js +2 -9
- package/dist/esm/components/context-menu/ContextMenuTrigger.js.map +1 -1
- package/dist/esm/components/context-menu/SubMenu.d.ts +4 -12
- package/dist/esm/components/context-menu/SubMenu.js +2 -6
- package/dist/esm/components/context-menu/SubMenu.js.map +1 -1
- package/dist/esm/components/data-table/Paginator.d.ts +16 -1
- package/dist/esm/components/data-table/Paginator.js +1 -1
- package/dist/esm/components/data-table/Paginator.js.map +1 -1
- package/dist/esm/components/font-picker/font-manager/constants.d.ts +4 -0
- package/dist/esm/components/font-picker/font-manager/constants.js +4 -0
- package/dist/esm/components/font-picker/font-manager/constants.js.map +1 -1
- package/dist/esm/components/header/Header.d.ts +8 -9
- package/dist/esm/components/header/Header.js +93 -147
- package/dist/esm/components/header/Header.js.map +1 -1
- package/dist/esm/components/header/ProjectDropdown.d.ts +13 -0
- package/dist/esm/components/header/ProjectDropdown.js +101 -0
- package/dist/esm/components/header/ProjectDropdown.js.map +1 -0
- package/dist/esm/components/header/StoryDropdown.d.ts +6 -0
- package/dist/esm/components/header/StoryDropdown.js +82 -0
- package/dist/esm/components/header/StoryDropdown.js.map +1 -0
- package/dist/esm/components/modal/Modal.d.ts +1 -1
- package/dist/esm/components/modal/Modal.js +2 -3
- package/dist/esm/components/modal/Modal.js.map +1 -1
- package/dist/esm/components/portal/Portal.d.ts +0 -2
- package/dist/esm/components/portal/Portal.js.map +1 -1
- package/dist/esm/components/publish-wizard/PublishWizard.d.ts +1 -3
- package/dist/esm/components/publish-wizard/PublishWizard.js.map +1 -1
- package/dist/esm/components/publish-wizard/publish/EmailWorkflow.js.map +1 -1
- package/dist/esm/constants/copy.d.ts +3 -0
- package/dist/esm/constants/copy.js +3 -0
- package/dist/esm/constants/copy.js.map +1 -1
- package/dist/esm/index.d.ts +4 -7
- package/dist/esm/index.js +4 -7
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/redux/actions/asset-uploads.js +0 -1
- package/dist/esm/redux/actions/asset-uploads.js.map +1 -1
- package/dist/esm/services/API.d.ts +10 -3
- package/dist/esm/services/API.js +74 -27
- package/dist/esm/services/API.js.map +1 -1
- package/dist/esm/services/Session.d.ts +0 -11
- package/dist/esm/services/Session.js +3 -84
- package/dist/esm/services/Session.js.map +1 -1
- package/dist/esm/utils/modal.d.ts +2 -0
- package/dist/esm/utils/modal.js +7 -0
- package/dist/esm/utils/modal.js.map +1 -0
- package/dist/esm/utils/pendo.d.ts +24 -0
- package/dist/esm/utils/pendo.js +52 -0
- package/dist/esm/utils/pendo.js.map +1 -0
- package/dist/esm/utils/routing.d.ts +2 -0
- package/dist/esm/utils/routing.js +7 -0
- package/dist/esm/utils/routing.js.map +1 -1
- package/dist/styles.css +0 -5
- package/dist/styles.less +0 -1
- package/less/components/button.less +0 -1
- package/package.json +5 -2
- package/src/Util.ts +1 -2
- package/src/components/app-wrapper/AppWrapper.tsx +245 -257
- package/src/components/assets/StoryTableNameFilter.tsx +6 -22
- package/src/components/compositions/TextLayer.tsx +0 -1
- package/src/components/context-menu/AnimateComponent.tsx +12 -1
- package/src/components/context-menu/ContextMenu.tsx +16 -8
- package/src/components/context-menu/ContextMenuItem.tsx +12 -11
- package/src/components/context-menu/ContextMenuTrigger.tsx +12 -10
- package/src/components/context-menu/SubMenu.tsx +6 -8
- package/src/components/data-table/Paginator.tsx +19 -6
- package/src/components/font-picker/font-manager/constants.ts +5 -0
- package/src/components/header/Header.tsx +130 -242
- package/src/components/header/ProjectDropdown.tsx +174 -0
- package/src/components/modal/Modal.tsx +7 -10
- package/src/components/portal/Portal.tsx +1 -2
- package/src/components/publish-wizard/PublishWizard.tsx +1 -1
- package/src/components/publish-wizard/publish/EmailWorkflow.tsx +7 -1
- package/src/constants/copy.ts +3 -0
- package/src/index.ts +6 -14
- package/src/redux/actions/asset-uploads.ts +0 -1
- package/src/services/API.ts +92 -30
- package/src/utils/modal.ts +9 -0
- package/src/utils/pendo.ts +61 -0
- package/src/utils/routing.ts +10 -0
- package/src/components/auth-gate/AuthGate.tsx +0 -84
- package/src/redux/actions/auth.ts +0 -30
- package/src/redux/reducers/auth.ts +0 -33
- package/src/services/Auth0.ts +0 -82
- package/src/services/Session.ts +0 -153
package/dist/styles.less
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imposium-hub/components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0-1",
|
|
4
4
|
"description": "React & Typescript component / asset library for Imposium front-ends",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -36,7 +36,6 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@imposium-hub/react-color": "^2.19.4",
|
|
38
38
|
"ansi_up": "^5.1.0",
|
|
39
|
-
"auth0-js": "^9.11.3",
|
|
40
39
|
"cogo-toast": "^4.2.3",
|
|
41
40
|
"export-to-csv": "^0.2.1",
|
|
42
41
|
"file-saver": "^2.0.5",
|
|
@@ -51,6 +50,7 @@
|
|
|
51
50
|
"react-transition-group": "^4.4.5"
|
|
52
51
|
},
|
|
53
52
|
"peerDependencies": {
|
|
53
|
+
"@auth0/auth0-react": "^2.3.0",
|
|
54
54
|
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
|
55
55
|
"@fortawesome/free-brands-svg-icons": "^6.1.1",
|
|
56
56
|
"@fortawesome/free-solid-svg-icons": "^6.1.1",
|
|
@@ -71,9 +71,12 @@
|
|
|
71
71
|
"react-spinners": "^0.6.1",
|
|
72
72
|
"react-table": "^7.7.0",
|
|
73
73
|
"react-tooltip": "^5.27.0",
|
|
74
|
+
"react-router": "^3.2.6",
|
|
74
75
|
"smpte-timecode": "^1.2.3"
|
|
75
76
|
},
|
|
76
77
|
"devDependencies": {
|
|
78
|
+
"react-router": "^3.2.6",
|
|
79
|
+
"@auth0/auth0-react": "^2.3.0",
|
|
77
80
|
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
|
78
81
|
"@fortawesome/free-brands-svg-icons": "^6.1.1",
|
|
79
82
|
"@fortawesome/free-solid-svg-icons": "^6.1.1",
|
package/src/Util.ts
CHANGED
|
@@ -1,308 +1,296 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import NoAccess from '../no-access/NoAccess';
|
|
3
2
|
import Header from '../header/Header';
|
|
4
|
-
import SessionService from '../../services/Session';
|
|
5
|
-
import AuthService, { IIdentity } from '../../services/Auth0';
|
|
6
|
-
import { connect } from 'react-redux';
|
|
7
|
-
import { bindActionCreators } from 'redux';
|
|
8
|
-
import { login, clearCachedAuth } from '../../redux/actions/auth';
|
|
9
3
|
import { validateAccessLevel } from '../../Util';
|
|
10
|
-
import { setAccessData } from '../../redux/actions/access';
|
|
11
4
|
import { ConfirmModal } from '../confirm-modal/ConfirmModal';
|
|
5
|
+
import { IImposiumAPI } from '../../services/API';
|
|
6
|
+
import { useAuth0 } from '@auth0/auth0-react';
|
|
7
|
+
import { replaceRoute } from '../../utils/routing';
|
|
8
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
9
|
+
import { faExclamationTriangle } from '@fortawesome/pro-light-svg-icons';
|
|
12
10
|
|
|
13
11
|
export interface IAppWrapperProps {
|
|
14
|
-
children: React.ReactChildren;
|
|
15
|
-
auth0Domain: string;
|
|
16
|
-
auth0ClientId: string;
|
|
17
|
-
organizationId: string;
|
|
18
12
|
baseUrl: string;
|
|
19
|
-
|
|
13
|
+
api: IImposiumAPI;
|
|
14
|
+
organizationId: string;
|
|
20
15
|
serviceId: number;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface IAppWrapperState {
|
|
34
|
-
blockRender: boolean;
|
|
35
|
-
restrictAccess: boolean;
|
|
16
|
+
unsavedChanges: boolean;
|
|
17
|
+
setAccessData(getAccessData): void;
|
|
18
|
+
onAuthenticated: (orgId: string, storyId?: string) => any;
|
|
19
|
+
allowNoStories?: boolean;
|
|
20
|
+
saveStory?(): void;
|
|
21
|
+
storyId?: string;
|
|
22
|
+
CrMLink?: string;
|
|
23
|
+
hideStoryPicker?: boolean;
|
|
24
|
+
hideDocs?: boolean;
|
|
25
|
+
hideOrgPicker?: boolean;
|
|
36
26
|
}
|
|
37
27
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
private static readonly RESTRICTED_BLOCK: JSX.Element = (
|
|
47
|
-
<NoAccess
|
|
48
|
-
key='restriction-msg'
|
|
49
|
-
type='restrict'
|
|
50
|
-
/>
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
constructor(p: IAppWrapperProps) {
|
|
54
|
-
super(p);
|
|
55
|
-
|
|
56
|
-
this.state = {
|
|
57
|
-
blockRender: true,
|
|
58
|
-
restrictAccess: false
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
public componentDidMount = (): void => {
|
|
63
|
-
const { auth0ClientId, auth0Domain } = this.props;
|
|
64
|
-
|
|
65
|
-
AuthService.bindToClient(auth0ClientId, auth0Domain);
|
|
66
|
-
|
|
67
|
-
const validAccessLevel = validateAccessLevel(
|
|
68
|
-
this.props.organizationId,
|
|
69
|
-
this.props.serviceId,
|
|
70
|
-
this.props.access
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
if (!this.state.restrictAccess && !validAccessLevel) {
|
|
74
|
-
this.setState({ restrictAccess: true });
|
|
75
|
-
}
|
|
28
|
+
export const APP_WRAPPER_ERROR_STATES = {
|
|
29
|
+
UNAUTHORIZED_ORG: 'UNAUTHORIZED_ORG',
|
|
30
|
+
NO_ORGS_FOUND: 'NO_ORGS_FOUND',
|
|
31
|
+
NO_STORIES: 'NO_STORIES',
|
|
32
|
+
UNAUTHORIZED_APP: 'UNAUTHORIZED_APP',
|
|
33
|
+
STORY_NOT_FOUND: 'STORY_NOT_FOUND'
|
|
34
|
+
};
|
|
76
35
|
|
|
77
|
-
|
|
78
|
-
|
|
36
|
+
export const AppWrapper: React.FC<IAppWrapperProps> = (props) => {
|
|
37
|
+
const [blockRender, setBlockRender] = React.useState(true);
|
|
38
|
+
const {
|
|
39
|
+
children,
|
|
40
|
+
organizationId,
|
|
41
|
+
storyId,
|
|
42
|
+
hideStoryPicker,
|
|
43
|
+
hideDocs,
|
|
44
|
+
hideOrgPicker,
|
|
45
|
+
CrMLink,
|
|
46
|
+
baseUrl,
|
|
47
|
+
api,
|
|
48
|
+
serviceId,
|
|
49
|
+
unsavedChanges,
|
|
50
|
+
saveStory,
|
|
51
|
+
allowNoStories
|
|
52
|
+
} = props;
|
|
53
|
+
const { isAuthenticated, isLoading, getAccessTokenSilently, loginWithRedirect, logout, user } =
|
|
54
|
+
useAuth0();
|
|
55
|
+
const [errorState, setErrorState] = React.useState(null);
|
|
56
|
+
|
|
57
|
+
React.useEffect(() => {
|
|
58
|
+
void doCheckSession(true);
|
|
59
|
+
}, [isAuthenticated, isLoading]);
|
|
60
|
+
|
|
61
|
+
React.useEffect(() => {
|
|
62
|
+
void doCheckSession(false);
|
|
63
|
+
}, [organizationId, storyId]);
|
|
64
|
+
|
|
65
|
+
const getCachedStoryAndOrgForService = (freshAccess, sId) => {
|
|
66
|
+
const service = freshAccess.services.find((s) => s.id === sId);
|
|
67
|
+
if (service) {
|
|
68
|
+
return {
|
|
69
|
+
story_id: service.story_id,
|
|
70
|
+
organization_id: service.organization_id
|
|
71
|
+
};
|
|
79
72
|
}
|
|
80
|
-
|
|
81
|
-
// Always check the session
|
|
82
|
-
this.doCheckSession(true);
|
|
83
73
|
};
|
|
84
74
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const { auth } = this.props;
|
|
90
|
-
let validAccessLevel: boolean;
|
|
91
|
-
|
|
92
|
-
if (auth) {
|
|
93
|
-
const {
|
|
94
|
-
idTokenPayload: { exp }
|
|
95
|
-
} = auth;
|
|
96
|
-
const validSession: boolean = AuthService.checkExpiry(exp);
|
|
97
|
-
|
|
98
|
-
if (!validSession) {
|
|
99
|
-
this.props.clearCachedAuth();
|
|
100
|
-
this.doCheckSession();
|
|
101
|
-
}
|
|
75
|
+
const validateStoryExists = (freshAccess, oId, sId) => {
|
|
76
|
+
const org = freshAccess.organizations.find((o) => o.id === oId);
|
|
77
|
+
if (!org) {
|
|
78
|
+
return false;
|
|
102
79
|
}
|
|
103
80
|
|
|
104
|
-
|
|
105
|
-
this.props.organizationId !== prevProps.organizationId ||
|
|
106
|
-
this.props.access !== prevProps.access
|
|
107
|
-
) {
|
|
108
|
-
validAccessLevel = validateAccessLevel(
|
|
109
|
-
this.props.organizationId,
|
|
110
|
-
this.props.serviceId,
|
|
111
|
-
this.props.access
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
if (!this.state.restrictAccess && !validAccessLevel) {
|
|
115
|
-
this.setState({ restrictAccess: true });
|
|
116
|
-
}
|
|
81
|
+
const story = org.stories.find((s) => s.id === sId);
|
|
117
82
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
83
|
+
if (!story) {
|
|
84
|
+
return false;
|
|
121
85
|
}
|
|
122
|
-
};
|
|
123
86
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
*/
|
|
127
|
-
private propagateCreds = (freshAccess, freshIdentity): void => {
|
|
128
|
-
const { storyId, organizationId, onAuthenticated } = this.props;
|
|
129
|
-
|
|
130
|
-
let initialStoryId = storyId;
|
|
131
|
-
let initialOrganizationId = organizationId;
|
|
87
|
+
return true;
|
|
88
|
+
};
|
|
132
89
|
|
|
133
|
-
|
|
90
|
+
const propagateCreds = (freshAccess): void => {
|
|
91
|
+
const {
|
|
92
|
+
storyId: initialStoryId,
|
|
93
|
+
organizationId: initialOrganizationId,
|
|
94
|
+
onAuthenticated
|
|
95
|
+
} = props;
|
|
96
|
+
|
|
97
|
+
// If an org and story ID was passed in, we're following a deeplink. Verify we have access to it, and if so, propagate those IDs and set them on the service
|
|
98
|
+
if (initialOrganizationId && initialStoryId) {
|
|
99
|
+
// Validate the user has access to the orgId and storyID passed in, if not, show the "Unauthorized" interface
|
|
100
|
+
const validAccessLevel = validateAccessLevel(
|
|
101
|
+
initialOrganizationId,
|
|
102
|
+
serviceId,
|
|
103
|
+
freshAccess
|
|
104
|
+
);
|
|
134
105
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
106
|
+
if (validAccessLevel) {
|
|
107
|
+
// Check to see if the story exists, if not, show the error state
|
|
108
|
+
const storyExists = validateStoryExists(
|
|
109
|
+
freshAccess,
|
|
110
|
+
initialOrganizationId,
|
|
111
|
+
initialStoryId
|
|
140
112
|
);
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return { orgId: org.id, storyId: story.id };
|
|
145
|
-
}
|
|
113
|
+
if (!storyExists) {
|
|
114
|
+
setErrorState(APP_WRAPPER_ERROR_STATES.STORY_NOT_FOUND);
|
|
115
|
+
return;
|
|
146
116
|
}
|
|
117
|
+
|
|
118
|
+
api.init(baseUrl, getAccessTokenSilently, initialOrganizationId);
|
|
119
|
+
onAuthenticated(initialOrganizationId, initialStoryId);
|
|
120
|
+
setBlockRender(false);
|
|
121
|
+
setErrorState(null);
|
|
122
|
+
} else {
|
|
123
|
+
setErrorState(APP_WRAPPER_ERROR_STATES.UNAUTHORIZED_APP);
|
|
124
|
+
return;
|
|
147
125
|
}
|
|
148
|
-
return null;
|
|
149
|
-
};
|
|
150
126
|
|
|
151
|
-
|
|
152
|
-
if (!initialOrganizationId && initialStoryId) {
|
|
153
|
-
const
|
|
154
|
-
|
|
127
|
+
// If no orgID or storyID was passed in from the URL use the cached orgID and story ID on the service
|
|
128
|
+
} else if (!initialOrganizationId && !initialStoryId) {
|
|
129
|
+
const { story_id, organization_id } = getCachedStoryAndOrgForService(
|
|
130
|
+
freshAccess,
|
|
131
|
+
serviceId
|
|
155
132
|
);
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
133
|
+
|
|
134
|
+
// No org was found to show the user
|
|
135
|
+
if (!organization_id) {
|
|
136
|
+
setErrorState(APP_WRAPPER_ERROR_STATES.NO_ORGS_FOUND);
|
|
137
|
+
return;
|
|
160
138
|
}
|
|
161
|
-
}
|
|
162
139
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
140
|
+
const validAccessLevel = validateAccessLevel(organization_id, serviceId, freshAccess);
|
|
141
|
+
|
|
142
|
+
if (validAccessLevel) {
|
|
143
|
+
api.init(baseUrl, getAccessTokenSilently, organization_id);
|
|
144
|
+
onAuthenticated(organization_id, story_id);
|
|
145
|
+
replaceRoute(`/${organization_id}/${story_id}`);
|
|
146
|
+
setBlockRender(false);
|
|
147
|
+
setErrorState(null);
|
|
169
148
|
} else {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
149
|
+
setErrorState(APP_WRAPPER_ERROR_STATES.UNAUTHORIZED_APP);
|
|
150
|
+
}
|
|
151
|
+
} else if (initialOrganizationId) {
|
|
152
|
+
if (allowNoStories) {
|
|
153
|
+
const validAccessLevel = validateAccessLevel(
|
|
154
|
+
initialOrganizationId,
|
|
155
|
+
serviceId,
|
|
156
|
+
freshAccess
|
|
157
|
+
);
|
|
158
|
+
if (validAccessLevel) {
|
|
159
|
+
api.init(baseUrl, getAccessTokenSilently, initialOrganizationId);
|
|
160
|
+
onAuthenticated(initialOrganizationId, null);
|
|
161
|
+
setBlockRender(false);
|
|
162
|
+
setErrorState(null);
|
|
179
163
|
} else {
|
|
180
|
-
|
|
181
|
-
initialStoryId = null;
|
|
164
|
+
setErrorState(APP_WRAPPER_ERROR_STATES.UNAUTHORIZED_APP);
|
|
182
165
|
}
|
|
166
|
+
} else {
|
|
167
|
+
setErrorState(APP_WRAPPER_ERROR_STATES.NO_STORIES);
|
|
183
168
|
}
|
|
184
169
|
}
|
|
185
|
-
|
|
186
|
-
// If at least one org was found, propagate that
|
|
187
|
-
if (initialOrganizationId) {
|
|
188
|
-
SessionService.buildFreshSession(freshIdentity, initialOrganizationId, initialStoryId);
|
|
189
|
-
onAuthenticated(initialOrganizationId, initialStoryId);
|
|
190
|
-
|
|
191
|
-
if (this.state.blockRender) {
|
|
192
|
-
this.setState({ blockRender: false });
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// If not, show the no-orgs interface
|
|
196
|
-
} else {
|
|
197
|
-
this.setState({ restrictAccess: true, blockRender: false });
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
/*
|
|
202
|
-
Bust cached creds if exist, invoke auth failure handler
|
|
203
|
-
*/
|
|
204
|
-
private handleCheckSessionFailure = (e: Error): void => {
|
|
205
|
-
if (this.props.storyId) {
|
|
206
|
-
SessionService.cacheStoryId(this.props.storyId);
|
|
207
|
-
} else {
|
|
208
|
-
SessionService.clearCachedStoryId();
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (this.props.organizationId) {
|
|
212
|
-
SessionService.cacheOrgId(this.props.organizationId);
|
|
213
|
-
} else {
|
|
214
|
-
SessionService.clearCachedOrgId();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
this.props.clearCachedAuth();
|
|
218
|
-
this.props.onAuthenticationFailure(e);
|
|
219
170
|
};
|
|
220
171
|
|
|
221
172
|
/*
|
|
222
173
|
Check auth0 session, pull Imposium access creds on success and initialize app-wrapper
|
|
223
174
|
*/
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if (blockRender) {
|
|
228
|
-
this.setState({ blockRender: true });
|
|
175
|
+
const doCheckSession = async (doBlockRender: boolean = false) => {
|
|
176
|
+
if (doBlockRender) {
|
|
177
|
+
setBlockRender(true);
|
|
229
178
|
}
|
|
230
|
-
AuthService.checkSession()
|
|
231
|
-
.then((freshIdentity: IIdentity) => {
|
|
232
|
-
const orgId = this.props.organizationId
|
|
233
|
-
? this.props.organizationId
|
|
234
|
-
: SessionService.getCachedOrgId();
|
|
235
|
-
SessionService.getAccessData(freshIdentity.accessToken, baseUrl, false, orgId)
|
|
236
|
-
.then((freshAccess: any) => {
|
|
237
|
-
this.props.setAccessData(freshAccess);
|
|
238
|
-
this.props.login(freshIdentity);
|
|
239
|
-
this.propagateCreds(freshAccess, freshIdentity);
|
|
240
|
-
})
|
|
241
|
-
.catch((e: Error) => {
|
|
242
|
-
this.setState({ restrictAccess: true, blockRender: false });
|
|
243
|
-
});
|
|
244
|
-
})
|
|
245
|
-
.catch((e: Error) => {
|
|
246
|
-
this.handleCheckSessionFailure(e);
|
|
247
|
-
});
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
public render = (): JSX.Element => {
|
|
251
|
-
const { blockRender, restrictAccess } = this.state;
|
|
252
|
-
const { children, showRequestAccess, allowUnauthenticatedRender } = this.props;
|
|
253
179
|
|
|
254
|
-
|
|
180
|
+
// If we're authenticated, get the access token, pull the access data, and propagate back to the parent component
|
|
181
|
+
if (isAuthenticated) {
|
|
182
|
+
try {
|
|
183
|
+
await getAccessTokenSilently();
|
|
184
|
+
} catch (e) {
|
|
185
|
+
// Trigger a logout if we can't get the access token
|
|
186
|
+
onLogout();
|
|
187
|
+
}
|
|
255
188
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
);
|
|
272
|
-
innerContent = [
|
|
273
|
-
typeof children[0] === 'object' && children[0].type === Header && children[0],
|
|
274
|
-
errorIndicator
|
|
275
|
-
];
|
|
189
|
+
const orgId = organizationId ? organizationId : null;
|
|
190
|
+
api.init(baseUrl, getAccessTokenSilently, orgId);
|
|
191
|
+
api.getAccessData(false)
|
|
192
|
+
.then((freshAccess: any) => {
|
|
193
|
+
props.setAccessData(freshAccess);
|
|
194
|
+
propagateCreds(freshAccess);
|
|
195
|
+
})
|
|
196
|
+
.catch((e: Error) => {
|
|
197
|
+
setErrorState(APP_WRAPPER_ERROR_STATES.UNAUTHORIZED_ORG);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// If we're not loading, and we're not authenticated, call login, and cache story + org ID from URL if it's there
|
|
201
|
+
} else if (!isLoading && !isAuthenticated) {
|
|
202
|
+
void loginWithRedirect({
|
|
203
|
+
appState: { returnTo: window.location.href }
|
|
204
|
+
});
|
|
276
205
|
}
|
|
206
|
+
};
|
|
277
207
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
208
|
+
const onLogout = () => {
|
|
209
|
+
setBlockRender(true);
|
|
210
|
+
void logout({ logoutParams: { returnTo: window.location.origin } });
|
|
211
|
+
};
|
|
281
212
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
213
|
+
let innerContent: any;
|
|
214
|
+
|
|
215
|
+
if (errorState) {
|
|
216
|
+
innerContent = (
|
|
217
|
+
<AppWrapperErrors
|
|
218
|
+
error={errorState}
|
|
219
|
+
email={user.userEmail}
|
|
220
|
+
/>
|
|
289
221
|
);
|
|
290
|
-
}
|
|
291
|
-
|
|
222
|
+
} else if (!blockRender) {
|
|
223
|
+
innerContent = children;
|
|
224
|
+
}
|
|
292
225
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
226
|
+
return (
|
|
227
|
+
<div
|
|
228
|
+
id='app'
|
|
229
|
+
className='app'>
|
|
230
|
+
<Header
|
|
231
|
+
errorState={errorState}
|
|
232
|
+
saveStory={saveStory}
|
|
233
|
+
onLogout={onLogout}
|
|
234
|
+
activeServiceId={serviceId}
|
|
235
|
+
baseUrl={baseUrl}
|
|
236
|
+
api={api}
|
|
237
|
+
unsavedChanges={unsavedChanges}
|
|
238
|
+
activeOrganization={organizationId}
|
|
239
|
+
activeStory={storyId}
|
|
240
|
+
hideStoryPicker={hideStoryPicker}
|
|
241
|
+
hideDocs={hideDocs}
|
|
242
|
+
showFTLogo={false}
|
|
243
|
+
hideOrgPicker={hideOrgPicker}
|
|
244
|
+
CrMLink={CrMLink}
|
|
245
|
+
/>
|
|
246
|
+
{innerContent}
|
|
247
|
+
<ConfirmModal />
|
|
248
|
+
</div>
|
|
301
249
|
);
|
|
302
250
|
};
|
|
303
251
|
|
|
304
|
-
const
|
|
305
|
-
|
|
252
|
+
export const ERROR_HEADINGS = {
|
|
253
|
+
[APP_WRAPPER_ERROR_STATES.UNAUTHORIZED_ORG]: 'Organization Not Found',
|
|
254
|
+
[APP_WRAPPER_ERROR_STATES.NO_ORGS_FOUND]: 'No Organizations Found',
|
|
255
|
+
[APP_WRAPPER_ERROR_STATES.UNAUTHORIZED_APP]: 'Service Not Found',
|
|
256
|
+
[APP_WRAPPER_ERROR_STATES.NO_STORIES]: 'No Projects Found',
|
|
257
|
+
[APP_WRAPPER_ERROR_STATES.STORY_NOT_FOUND]: 'Project Not Found'
|
|
306
258
|
};
|
|
307
259
|
|
|
308
|
-
export
|
|
260
|
+
export const ERROR_DESCRIPTIONS = {
|
|
261
|
+
[APP_WRAPPER_ERROR_STATES.UNAUTHORIZED_ORG]:
|
|
262
|
+
'Your user "[email]" does not have access to this organization. Please request access from an admin already on the organization.',
|
|
263
|
+
[APP_WRAPPER_ERROR_STATES.NO_ORGS_FOUND]:
|
|
264
|
+
'Your user "[email]" has not been added to any organizations. Please request access from an admin.',
|
|
265
|
+
[APP_WRAPPER_ERROR_STATES.UNAUTHORIZED_APP]:
|
|
266
|
+
'Your user "[email]" does not have access to this serivce. Please request access from an admin.',
|
|
267
|
+
[APP_WRAPPER_ERROR_STATES.NO_STORIES]: 'There are no projects on this organization.',
|
|
268
|
+
[APP_WRAPPER_ERROR_STATES.STORY_NOT_FOUND]:
|
|
269
|
+
'The Project cound not be found. Please check the URL and try again.'
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
export interface AppWrappeErrorProps {
|
|
273
|
+
error: string;
|
|
274
|
+
email: string;
|
|
275
|
+
onCreateStory?: () => void;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export const AppWrapperErrors: React.FC<AppWrappeErrorProps> = ({
|
|
279
|
+
error,
|
|
280
|
+
email,
|
|
281
|
+
onCreateStory
|
|
282
|
+
}) => {
|
|
283
|
+
return (
|
|
284
|
+
<div className='no-access'>
|
|
285
|
+
<FontAwesomeIcon
|
|
286
|
+
icon={faExclamationTriangle}
|
|
287
|
+
size='6x'
|
|
288
|
+
/>
|
|
289
|
+
|
|
290
|
+
<div className='no-access-copy'>
|
|
291
|
+
<h1 className='no-access-heading'>{ERROR_HEADINGS[error]}</h1>
|
|
292
|
+
<p>{ERROR_DESCRIPTIONS[error].replace('[email]', email)}</p>
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
295
|
+
);
|
|
296
|
+
};
|
|
@@ -1,40 +1,24 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import TextField from '../text-field/TextField';
|
|
3
|
-
import { connect } from 'react-redux';
|
|
4
|
-
import { bindActionCreators } from 'redux';
|
|
5
|
-
import { updateStoryFilter } from '../../redux/actions/story-filter';
|
|
6
3
|
|
|
7
4
|
interface IStoryTableNameFilterProps {
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
filter: any;
|
|
6
|
+
updateFilter: (filters: any) => any;
|
|
10
7
|
}
|
|
11
8
|
|
|
12
9
|
class StoryTableNameFilter extends React.PureComponent<IStoryTableNameFilterProps> {
|
|
13
10
|
public render = (): JSX.Element => {
|
|
14
|
-
const {
|
|
11
|
+
const { filter } = this.props;
|
|
15
12
|
|
|
16
13
|
return (
|
|
17
14
|
<TextField
|
|
18
15
|
className='story-name'
|
|
19
16
|
focusOnMount
|
|
20
|
-
value={
|
|
21
|
-
onChange={(n) => this.props.
|
|
17
|
+
value={filter}
|
|
18
|
+
onChange={(n) => this.props.updateFilter({ name: n })}
|
|
22
19
|
/>
|
|
23
20
|
);
|
|
24
21
|
};
|
|
25
22
|
}
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
return bindActionCreators({ updateStoryFilter }, dispatch);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const mapStateToProps = (state): any => {
|
|
32
|
-
return { storyFilter: state.storyFilter.name };
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const StoryTableNameFilterMemoized = connect(
|
|
36
|
-
mapStateToProps,
|
|
37
|
-
mapDispatchToProps
|
|
38
|
-
)(React.memo(StoryTableNameFilter));
|
|
39
|
-
|
|
40
|
-
export default StoryTableNameFilterMemoized;
|
|
24
|
+
export default StoryTableNameFilter;
|