ui-soxo-bootstrap-core 2.4.25-dev.9 → 2.4.25
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/.github/workflows/npm-publish.yml +15 -37
- package/core/components/extra-info/extra-info-details.js +126 -109
- package/core/components/landing-api/landing-api.js +30 -22
- package/core/lib/Store.js +18 -20
- package/core/lib/components/index.js +1 -4
- package/core/lib/components/sidemenu/sidemenu.js +256 -153
- package/core/lib/components/sidemenu/sidemenu.scss +26 -39
- package/core/lib/elements/basic/rangepicker/rangepicker.js +29 -118
- package/core/lib/hooks/index.js +12 -2
- package/core/lib/pages/login/login.js +139 -255
- package/core/lib/pages/login/login.scss +32 -140
- package/core/models/dashboard/dashboard.js +0 -14
- package/core/models/menus/components/menu-add/menu-add.js +268 -230
- package/core/models/menus/components/menu-lists/menu-lists.js +89 -126
- package/core/models/menus/components/menu-lists/menu-lists.scss +0 -9
- package/core/models/menus/menus.js +267 -247
- package/core/models/roles/components/role-add/role-add.js +227 -269
- package/core/models/roles/components/role-list/role-list.js +6 -8
- package/core/models/roles/roles.js +174 -182
- package/core/models/users/components/user-add/user-add.js +1 -69
- package/core/models/users/users.js +0 -57
- package/core/modules/index.js +13 -23
- package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +1 -1
- package/package.json +2 -2
- package/core/lib/hooks/use-otp-timer.js +0 -99
- package/core/models/staff/components/staff-add/staff-add.js +0 -352
- package/core/models/staff/components/staff-add/staff-add.scss +0 -0
- package/core/modules/steps/action-buttons.js +0 -79
- package/core/modules/steps/steps.js +0 -553
- package/core/modules/steps/steps.scss +0 -158
- package/core/modules/steps/timeline.js +0 -49
|
@@ -11,45 +11,23 @@ jobs:
|
|
|
11
11
|
build:
|
|
12
12
|
runs-on: ubuntu-latest
|
|
13
13
|
steps:
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
|
|
14
|
+
- uses: actions/checkout@v3
|
|
15
|
+
- uses: actions/setup-node@v3
|
|
16
|
+
with:
|
|
17
|
+
node-version: 16
|
|
18
|
+
- run: npm i
|
|
19
|
+
# - run: npm test
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
publish-npm:
|
|
22
|
+
needs: build
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v3
|
|
26
|
+
- uses: actions/setup-node@v3
|
|
21
27
|
with:
|
|
22
28
|
node-version: 16
|
|
23
29
|
registry-url: https://registry.npmjs.org/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- name: Install Dependencies
|
|
27
|
-
run: npm ci
|
|
28
|
-
|
|
29
|
-
# 4. Verify tag matches package.json version
|
|
30
|
-
- name: Verify Tag Matches Version
|
|
31
|
-
run: |
|
|
32
|
-
TAG=${GITHUB_REF#refs/tags/}
|
|
33
|
-
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
|
34
|
-
echo "Release Tag: $TAG"
|
|
35
|
-
echo "Package Version: $PACKAGE_VERSION"
|
|
36
|
-
|
|
37
|
-
if [[ "$TAG" != "v$PACKAGE_VERSION"* ]]; then
|
|
38
|
-
echo "Error: Tag does not match package.json version"
|
|
39
|
-
exit 1
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
# 5. Publish the package
|
|
43
|
-
- name: Publish Package
|
|
44
|
-
run: |
|
|
45
|
-
TAG_NAME=${GITHUB_REF#refs/tags/}
|
|
46
|
-
|
|
47
|
-
if [[ "$TAG_NAME" == *"dev"* ]]; then
|
|
48
|
-
echo "Publishing development package with 'dev' tag"
|
|
49
|
-
npm publish --tag dev
|
|
50
|
-
else
|
|
51
|
-
echo "Publishing stable package"
|
|
52
|
-
npm publish
|
|
53
|
-
fi
|
|
30
|
+
- run: npm i
|
|
31
|
+
- run: npm publish
|
|
54
32
|
env:
|
|
55
|
-
NODE_AUTH_TOKEN: ${{
|
|
33
|
+
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ExtraInfoDetail component contains the button and the data for corresponding to script mode and will open extrainfo
|
|
2
|
+
* ExtraInfoDetail component contains the button and the data for corresponding to script mode and will open extrainfo
|
|
3
3
|
*
|
|
4
|
-
* @description
|
|
4
|
+
* @description
|
|
5
5
|
* @author Sneha T
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -21,135 +21,152 @@ import ExtraInfo from './extra-info';
|
|
|
21
21
|
|
|
22
22
|
const { TabPane } = Tabs;
|
|
23
23
|
|
|
24
|
-
export default function ExtraInfoDetail({ modeValue, icon, title, tabPosition
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
export default function ExtraInfoDetail({ modeValue, icon, title, tabPosition='left',showDrawerData,dbPtr,callback,...record}) {
|
|
25
|
+
// State to control drawer
|
|
26
|
+
const [open, setOpen] = useState(false);
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
// To set extra info data
|
|
29
|
+
const [info, setInfo] = useState([]);
|
|
30
|
+
//Setting active key for tabs
|
|
31
|
+
const [activeKey, setActiveKey] = useState(null);
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
// To strore selected item
|
|
34
|
+
const [selectedItem, setSelectedItem] = useState(null);
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
const [loading, setLoading] = useState(true);
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
setActiveKey(null); // Reset activeKey before fetching new info
|
|
38
|
+
/**
|
|
39
|
+
* Show Drawer
|
|
40
|
+
*/
|
|
41
|
+
const showDrawer = () => {
|
|
43
42
|
|
|
44
|
-
|
|
43
|
+
setActiveKey(null); // Reset activeKey before fetching new info
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
};
|
|
45
|
+
getExtraInfo();
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
* Function to close
|
|
51
|
-
*/
|
|
52
|
-
const onClose = () => {
|
|
53
|
-
if (typeof callback === 'function') {
|
|
54
|
-
// Only call if it exists
|
|
55
|
-
callback(false);
|
|
56
|
-
}
|
|
57
|
-
setOpen(false);
|
|
58
|
-
};
|
|
47
|
+
setOpen(true);
|
|
59
48
|
|
|
60
|
-
|
|
61
|
-
* Function to get Info
|
|
62
|
-
*/
|
|
63
|
-
async function getExtraInfo() {
|
|
64
|
-
setSelectedItem();
|
|
49
|
+
};
|
|
65
50
|
|
|
66
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Function to close
|
|
53
|
+
*/
|
|
54
|
+
const onClose = () => {
|
|
55
|
+
if (typeof callback === 'function') {
|
|
56
|
+
// Only call if it exists
|
|
57
|
+
callback(false);
|
|
58
|
+
}
|
|
59
|
+
setOpen(false);
|
|
60
|
+
};
|
|
67
61
|
|
|
68
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Function to get Info
|
|
64
|
+
*/
|
|
65
|
+
async function getExtraInfo() {
|
|
69
66
|
|
|
70
|
-
|
|
67
|
+
setSelectedItem()
|
|
71
68
|
|
|
72
|
-
|
|
69
|
+
setLoading(true);
|
|
73
70
|
|
|
74
|
-
|
|
71
|
+
let mode = modeValue
|
|
75
72
|
|
|
76
|
-
|
|
73
|
+
const result = await Dashboard.getExtraInfo(mode);
|
|
77
74
|
|
|
78
|
-
|
|
79
|
-
}
|
|
75
|
+
setInfo(result);
|
|
80
76
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
setSelectedItem(result[0])
|
|
78
|
+
|
|
79
|
+
setActiveKey(result[0].id.toString()); // Set activeKey to the first item's id
|
|
80
|
+
|
|
81
|
+
setLoading(false);
|
|
85
82
|
}
|
|
86
|
-
}, [showDrawerData]);
|
|
87
83
|
|
|
88
|
-
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
// If showDrawerData is true then call showDrawer function
|
|
86
|
+
if (showDrawerData) {
|
|
87
|
+
showDrawer();
|
|
88
|
+
}
|
|
89
|
+
}, [showDrawerData]);
|
|
90
|
+
|
|
91
|
+
/**
|
|
89
92
|
* Function to render icon or button
|
|
90
93
|
*/
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
<>
|
|
108
|
-
{/* {loading ? (
|
|
94
|
+
const renderIconOrButton = () => {
|
|
95
|
+
switch (icon) {
|
|
96
|
+
case 'InfoCircleFilled':
|
|
97
|
+
return <InfoCircleFilled onClick={showDrawer} />;
|
|
98
|
+
case 'Button':
|
|
99
|
+
return <Button size="small" onClick={showDrawer}>Show Info</Button>;
|
|
100
|
+
default:
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<>
|
|
109
|
+
{/* {loading ? (
|
|
109
110
|
<>
|
|
110
111
|
<Skeleton active />
|
|
111
112
|
</>
|
|
112
113
|
) : ( */}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
114
|
+
<>
|
|
115
|
+
{/* */}
|
|
116
|
+
{/* <Button onClick={showDrawer}> */}
|
|
117
|
+
|
|
118
|
+
{/* <InfoCircleFilled onMouseEnter={showDrawer} /> */}
|
|
119
|
+
|
|
120
|
+
{renderIconOrButton()}
|
|
121
|
+
{/* </Button> */}
|
|
122
|
+
{/* */}
|
|
123
|
+
|
|
124
|
+
{/* */}
|
|
125
|
+
<Drawer
|
|
126
|
+
|
|
127
|
+
width={'85%'}
|
|
128
|
+
|
|
129
|
+
title={title} onClose={onClose} open={open}>
|
|
130
|
+
|
|
131
|
+
<div className="main-drawer-content">
|
|
132
|
+
|
|
133
|
+
<div className="drawer-container">
|
|
134
|
+
|
|
135
|
+
<div className="drawer-click"> {/* Flexbox approach */}
|
|
136
|
+
<Tabs
|
|
137
|
+
tabPosition={tabPosition}
|
|
138
|
+
|
|
139
|
+
activeKey={activeKey} // Set activeKey to control the active tab
|
|
140
|
+
|
|
141
|
+
onChange={(key) => {
|
|
142
|
+
|
|
143
|
+
const selectedItem = info.find(item => item.id.toString() === key);
|
|
144
|
+
|
|
145
|
+
setSelectedItem(selectedItem);
|
|
146
|
+
|
|
147
|
+
setActiveKey(key);
|
|
148
|
+
}}
|
|
149
|
+
>
|
|
150
|
+
{info.map(item => (
|
|
151
|
+
<TabPane tab={item.caption} key={item.id.toString()} />
|
|
152
|
+
))}
|
|
153
|
+
</Tabs>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<div className="right-drawer">
|
|
157
|
+
|
|
158
|
+
{selectedItem && !loading ? <ExtraInfo item={selectedItem} record={record} dbPtr={dbPtr}/> : null}
|
|
159
|
+
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
</Drawer>
|
|
167
|
+
|
|
168
|
+
</>
|
|
169
|
+
{/* )} */}
|
|
170
|
+
</>
|
|
171
|
+
);
|
|
155
172
|
}
|
|
@@ -96,6 +96,7 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
96
96
|
* @param reports
|
|
97
97
|
*/
|
|
98
98
|
async function loadMenus(reports) {
|
|
99
|
+
|
|
99
100
|
setLoader(true);
|
|
100
101
|
|
|
101
102
|
// setReports(report)
|
|
@@ -105,12 +106,16 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
105
106
|
// console.log(result);
|
|
106
107
|
|
|
107
108
|
if (result && Array.isArray(result.result) && result.result.length) {
|
|
109
|
+
|
|
108
110
|
// setModules(result.result);
|
|
111
|
+
|
|
109
112
|
// result.result.map((ele) => {
|
|
110
113
|
// let languageString = JSON.parse(ele.attributes)
|
|
111
114
|
// console.log('language_string', languageString);
|
|
112
115
|
// if (languageString && languageString.languages) {
|
|
116
|
+
|
|
113
117
|
// const language = i18n.language;
|
|
118
|
+
|
|
114
119
|
// i18n.addResourceBundle(language, 'translation', languageString.languages[i18n.language]);
|
|
115
120
|
// }
|
|
116
121
|
// })
|
|
@@ -121,6 +126,7 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
121
126
|
dispatch({ type: 'settings', payload: result.result.settings });
|
|
122
127
|
}
|
|
123
128
|
|
|
129
|
+
|
|
124
130
|
// Reports length
|
|
125
131
|
if (reports.length) {
|
|
126
132
|
reportMenus = [
|
|
@@ -147,25 +153,30 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
147
153
|
|
|
148
154
|
/**If there is roles assigned to the user */
|
|
149
155
|
// for matria
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
} else {
|
|
155
|
-
//If there is no roles assigned to the user
|
|
156
|
-
setAllModules([...coreModules]);
|
|
157
|
-
}
|
|
156
|
+
const useCoreMenus= process.env.REACT_APP_USE_CORE_MENUS === 'true';
|
|
157
|
+
if(useCoreMenus){
|
|
158
|
+
if (result && result.result && reportMenus) {
|
|
159
|
+
setAllModules([...result.result, ...reportMenus, ...coreModules]);
|
|
158
160
|
} else {
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
setAllModules([...result.result.menus, ...reportMenus, ...coreModules]);
|
|
162
|
-
} else {
|
|
163
|
-
//If there is no roles assigned to the user
|
|
164
|
-
setAllModules([...coreModules]);
|
|
165
|
-
}
|
|
161
|
+
//If there is no roles assigned to the user
|
|
162
|
+
setAllModules([...coreModules]);
|
|
166
163
|
}
|
|
167
|
-
|
|
164
|
+
|
|
165
|
+
} else{
|
|
166
|
+
// for nura
|
|
167
|
+
if (result && result.result.menus && reportMenus) {
|
|
168
|
+
setAllModules([...result.result.menus, ...reportMenus, ...coreModules]);
|
|
169
|
+
} else {
|
|
170
|
+
//If there is no roles assigned to the user
|
|
171
|
+
setAllModules([...coreModules]);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
|
|
168
175
|
}
|
|
176
|
+
setLoader(false);
|
|
177
|
+
|
|
178
|
+
}
|
|
179
|
+
|
|
169
180
|
|
|
170
181
|
/**
|
|
171
182
|
* Load the scripts
|
|
@@ -246,12 +257,6 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
246
257
|
|
|
247
258
|
<Route exact key={'profile'} path={'/profile'} render={(props) => <Profile {...props} />} />
|
|
248
259
|
|
|
249
|
-
{/* More specific routes should come before general/dynamic routes */}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
<Route path={'/reports/:id'} render={(props) => <ReportingDashboard CustomComponents={CustomComponents} {...props} />} />
|
|
253
|
-
|
|
254
|
-
|
|
255
260
|
<Route path={'/menus/:id'} render={() => <ModuleRoutes model={MenusAPI} />} />
|
|
256
261
|
|
|
257
262
|
{/* <Switch> */}
|
|
@@ -268,6 +273,9 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
268
273
|
}}
|
|
269
274
|
/>
|
|
270
275
|
|
|
276
|
+
{/* <Route path={'/users'} render={() => <ModuleRoutes model={UsersAPI} />} /> */}
|
|
277
|
+
|
|
278
|
+
<Route path={'/reports/:id'} render={(props) => <ReportingDashboard CustomComponents={CustomComponents} {...props} />} />
|
|
271
279
|
|
|
272
280
|
<Route exact key={'change-password'} path={'/change-password'} render={(props) => <ChangePassword {...props} />} />
|
|
273
281
|
|
package/core/lib/Store.js
CHANGED
|
@@ -48,25 +48,25 @@ import { ConfigProvider, theme } from 'antd';
|
|
|
48
48
|
const initialTheme = () => {
|
|
49
49
|
try {
|
|
50
50
|
// manage theme with env
|
|
51
|
-
|
|
51
|
+
const isEnvThemeTrue = process.env.REACT_APP_THEME;
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
console.log('REACT_APP_THEME:', isEnvThemeTrue);
|
|
54
|
+
const matchedTheme = themes.find(t => t.name === isEnvThemeTrue);
|
|
55
55
|
|
|
56
56
|
if (matchedTheme) return matchedTheme;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
|
|
58
|
+
// Check saved theme
|
|
59
|
+
const savedTheme = localStorage.getItem('selectedTheme');
|
|
60
|
+
if (savedTheme) {
|
|
61
|
+
return JSON.parse(savedTheme);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Fallback to default
|
|
65
|
+
return themes[0];
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.error('Error loading theme:', e);
|
|
68
|
+
return themes[0];
|
|
62
69
|
}
|
|
63
|
-
|
|
64
|
-
// Fallback to default
|
|
65
|
-
return themes[0];
|
|
66
|
-
} catch (e) {
|
|
67
|
-
console.error('Error loading theme:', e);
|
|
68
|
-
return themes[0];
|
|
69
|
-
}
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
const initialState = {
|
|
@@ -87,7 +87,7 @@ let app = {};
|
|
|
87
87
|
* @param {*} param0
|
|
88
88
|
* @returns
|
|
89
89
|
*/
|
|
90
|
-
export const GlobalProvider = ({ children, CustomModels,
|
|
90
|
+
export const GlobalProvider = ({ children, CustomModels, appSettings: settings }) => {
|
|
91
91
|
// console.log("Setting up store");
|
|
92
92
|
|
|
93
93
|
const [branches, setBranches] = useState([]);
|
|
@@ -226,14 +226,13 @@ export const GlobalProvider = ({ children, CustomModels,CustomComponents, appSet
|
|
|
226
226
|
let store = {
|
|
227
227
|
app: app,
|
|
228
228
|
user: state.user,
|
|
229
|
-
settings:
|
|
229
|
+
settings:state.settings,
|
|
230
230
|
dispatch: dispatch,
|
|
231
231
|
twilio: state.twilio,
|
|
232
232
|
isMobile,
|
|
233
233
|
branches,
|
|
234
234
|
defaultBranch: state.defaultBranch,
|
|
235
235
|
CustomModels: CustomModels,
|
|
236
|
-
CustomComponents:CustomComponents,
|
|
237
236
|
selectedBranch: state.selectedBranch,
|
|
238
237
|
kiosk: state.kiosk,
|
|
239
238
|
state,
|
|
@@ -315,8 +314,7 @@ export const AppReducer = (state, action) => {
|
|
|
315
314
|
|
|
316
315
|
case 'CustomModels':
|
|
317
316
|
return { ...state, CustomModels: action.CustomModels };
|
|
318
|
-
|
|
319
|
-
return { ...state, CustomComponents: action.CustomComponents };
|
|
317
|
+
|
|
320
318
|
// # TODO Below Variable might be removed
|
|
321
319
|
case 'selectedLocation':
|
|
322
320
|
localStorage.selectedLocation = JSON.stringify(action.payload);
|
|
@@ -109,8 +109,6 @@ import ConsentComponent from './consent/consent'
|
|
|
109
109
|
import TaskOverviewLegacy from './../models/process/components/task-overview-legacy/task-overview-legacy'
|
|
110
110
|
|
|
111
111
|
import ReportingDashboard from '../../modules/reporting/components/reporting-dashboard/reporting-dashboard';
|
|
112
|
-
|
|
113
|
-
import ProcessStepsPage from '../../modules/steps/steps'
|
|
114
112
|
export {
|
|
115
113
|
|
|
116
114
|
// Bootstrap Components
|
|
@@ -199,8 +197,7 @@ export {
|
|
|
199
197
|
// WebCamera,
|
|
200
198
|
ConsentComponent,
|
|
201
199
|
|
|
202
|
-
ReportingDashboard
|
|
203
|
-
ProcessStepsPage
|
|
200
|
+
ReportingDashboard
|
|
204
201
|
|
|
205
202
|
|
|
206
203
|
}
|