ui-soxo-bootstrap-core 2.6.32-dev.5 → 2.6.33
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 +21 -47
- package/DEVELOPER_GUIDE.md +9 -38
- package/core/components/index.js +11 -2
- package/core/components/landing-api/landing-api.js +5 -165
- package/core/lib/components/global-header/global-header.js +77 -18
- package/core/lib/components/index.js +2 -2
- package/core/lib/elements/complex/qrscanner/qrscanner.js +1 -1
- package/core/models/core-scripts/core-scripts.js +1 -14
- package/core/models/menus/menus.js +1 -29
- package/core/models/users/components/user-add/user-add.js +3 -2
- package/core/modules/reporting/components/reporting-dashboard/display-columns/display-cell-renderer.js +5 -202
- package/core/modules/reporting/components/reporting-dashboard/display-columns/display-cell-renderer.test.js +0 -73
- package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +527 -143
- package/package.json +1 -1
- package/core/components/license-management/license-alert.js +0 -97
- package/core/modules/reporting/components/reporting-dashboard/reporting-table.js +0 -519
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
|
|
3
|
+
|
|
1
4
|
name: Node.js Package
|
|
2
5
|
|
|
3
6
|
on:
|
|
@@ -5,55 +8,26 @@ on:
|
|
|
5
8
|
types: [created]
|
|
6
9
|
|
|
7
10
|
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
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
|
|
20
|
+
|
|
8
21
|
publish-npm:
|
|
22
|
+
needs: build
|
|
9
23
|
runs-on: ubuntu-latest
|
|
10
|
-
permissions:
|
|
11
|
-
contents: read
|
|
12
|
-
id-token: write
|
|
13
24
|
steps:
|
|
14
|
-
- uses: actions/checkout@
|
|
15
|
-
- uses: actions/setup-node@
|
|
25
|
+
- uses: actions/checkout@v3
|
|
26
|
+
- uses: actions/setup-node@v3
|
|
16
27
|
with:
|
|
17
|
-
node-version:
|
|
28
|
+
node-version: 16
|
|
18
29
|
registry-url: https://registry.npmjs.org/
|
|
19
|
-
- run: npm
|
|
20
|
-
- run: npm
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
id: dist_tag
|
|
24
|
-
shell: bash
|
|
25
|
-
run: |
|
|
26
|
-
VERSION=$(node -p "require('./package.json').version")
|
|
27
|
-
echo "package.json version: $VERSION"
|
|
28
|
-
echo "release tag: ${GITHUB_REF_NAME}"
|
|
29
|
-
if [[ "v${VERSION}" != "${GITHUB_REF_NAME}" ]]; then
|
|
30
|
-
echo "::error::Release tag '${GITHUB_REF_NAME}' does not match package.json version 'v${VERSION}'."
|
|
31
|
-
echo "::error::Bump the version with 'npm version' and re-create the release."
|
|
32
|
-
exit 1
|
|
33
|
-
fi
|
|
34
|
-
if [[ "$VERSION" == *-dev* ]]; then
|
|
35
|
-
echo "tag=dev" >> "$GITHUB_OUTPUT"
|
|
36
|
-
echo "Will publish with dist-tag: dev"
|
|
37
|
-
else
|
|
38
|
-
echo "tag=latest" >> "$GITHUB_OUTPUT"
|
|
39
|
-
echo "Will publish with dist-tag: latest"
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
- name: Diagnose npm + OIDC environment
|
|
43
|
-
shell: bash
|
|
44
|
-
run: |
|
|
45
|
-
echo "--- versions ---"
|
|
46
|
-
node --version
|
|
47
|
-
npm --version
|
|
48
|
-
echo "--- OIDC env presence (must both be 'yes' for trusted publishing) ---"
|
|
49
|
-
echo "ACTIONS_ID_TOKEN_REQUEST_URL set: ${ACTIONS_ID_TOKEN_REQUEST_URL:+yes}"
|
|
50
|
-
echo "ACTIONS_ID_TOKEN_REQUEST_TOKEN set: ${ACTIONS_ID_TOKEN_REQUEST_TOKEN:+yes}"
|
|
51
|
-
echo "--- effective .npmrc (user) ---"
|
|
52
|
-
cat ~/.npmrc 2>/dev/null || echo "(none)"
|
|
53
|
-
echo "--- effective .npmrc (project) ---"
|
|
54
|
-
cat .npmrc 2>/dev/null || echo "(none)"
|
|
55
|
-
echo "--- npm config (auth-related) ---"
|
|
56
|
-
npm config get registry
|
|
57
|
-
npm config get //registry.npmjs.org/:_authToken || true
|
|
58
|
-
|
|
59
|
-
- run: npm publish --provenance --access public --tag ${{ steps.dist_tag.outputs.tag }} --loglevel=verbose
|
|
30
|
+
- run: npm i
|
|
31
|
+
- run: npm publish
|
|
32
|
+
env:
|
|
33
|
+
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
package/DEVELOPER_GUIDE.md
CHANGED
|
@@ -17,7 +17,6 @@ Incorrect versioning or incorrect tags will break the publish pipeline — follo
|
|
|
17
17
|
- Publishing via GitHub Release UI
|
|
18
18
|
- How GitHub Action Detects Release Type
|
|
19
19
|
- Summary Table
|
|
20
|
-
- CI/CD Authentication (Trusted Publishing)
|
|
21
20
|
- Common Mistakes & Fixes
|
|
22
21
|
|
|
23
22
|
---
|
|
@@ -256,14 +255,17 @@ npm publish --tag dev
|
|
|
256
255
|
|
|
257
256
|
# ⚙️ How GitHub Action Detects Release Type
|
|
258
257
|
|
|
259
|
-
|
|
258
|
+
If version contains `dev`:
|
|
260
259
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
| Version has no `-dev` suffix | `npm publish --provenance --access public --tag latest` | Publishes to the `latest` dist-tag |
|
|
260
|
+
```
|
|
261
|
+
npm publish --tag dev
|
|
262
|
+
```
|
|
265
263
|
|
|
266
|
-
|
|
264
|
+
Otherwise:
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
npm publish
|
|
268
|
+
```
|
|
267
269
|
|
|
268
270
|
---
|
|
269
271
|
|
|
@@ -281,37 +283,6 @@ The workflow also enforces that the GitHub release tag matches `v<version>` from
|
|
|
281
283
|
|
|
282
284
|
---
|
|
283
285
|
|
|
284
|
-
# 🔐 CI/CD Authentication (Trusted Publishing)
|
|
285
|
-
|
|
286
|
-
As of npm's 2025 policy changes, classic automation tokens (`NPM_TOKEN`) are deprecated. This repo now authenticates to npm via **OIDC Trusted Publishing** — GitHub Actions exchanges a short-lived OIDC token for a publish token at run time, so **no secret is stored in the repository**.
|
|
287
|
-
|
|
288
|
-
## What this means for developers
|
|
289
|
-
|
|
290
|
-
Nothing. You still follow the same flow: `npm version` → push tag → create GitHub Release. The auth happens transparently in CI.
|
|
291
|
-
|
|
292
|
-
## What this means for maintainers
|
|
293
|
-
|
|
294
|
-
The first-time setup on npmjs.com must be done once per package:
|
|
295
|
-
|
|
296
|
-
1. Log in to [npmjs.com](https://www.npmjs.com) → open the package (`ui-soxo-bootstrap-core`) → **Settings**.
|
|
297
|
-
2. Under **Trusted Publisher**, click **Add trusted publisher** and fill in:
|
|
298
|
-
- Publisher: **GitHub Actions**
|
|
299
|
-
- Organization or user: `soxo-tech`
|
|
300
|
-
- Repository: `bootstrap-core`
|
|
301
|
-
- Workflow filename: `npm-publish.yml`
|
|
302
|
-
- Environment name: *(leave blank)*
|
|
303
|
-
3. Save. Any old `NPM_TOKEN` repository secret can be removed.
|
|
304
|
-
|
|
305
|
-
## Runtime requirements
|
|
306
|
-
|
|
307
|
-
The workflow runs on Node 20 and upgrades npm to the latest CLI (`npm install -g npm@latest`) because OIDC trusted publishing requires **npm ≥ 11.5.1**. The `--provenance` flag attaches a verifiable build attestation to every published version, visible on the npmjs.com package page.
|
|
308
|
-
|
|
309
|
-
## If publish fails with `403 Forbidden` or `ENEEDAUTH`
|
|
310
|
-
|
|
311
|
-
The trusted publisher config on npmjs.com no longer matches the workflow. Check that org, repo, and workflow filename match exactly — including case.
|
|
312
|
-
|
|
313
|
-
---
|
|
314
|
-
|
|
315
286
|
# ⚠️ Common Mistakes & Fixes
|
|
316
287
|
|
|
317
288
|
| Mistake | Issue | Fix |
|
package/core/components/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
1
5
|
import LandingAPI from './landing-api/landing-api';
|
|
2
6
|
|
|
3
7
|
import ExtraInfoDetail from './extra-info/extra-info-details';
|
|
@@ -7,6 +11,11 @@ import RootApplicationAPI from './root-application-api/root-application-api';
|
|
|
7
11
|
import { HomePageAPI } from '../modules';
|
|
8
12
|
|
|
9
13
|
import { ExternalWindow } from './external-window/external-window';
|
|
10
|
-
import LicenseAlert from './license-management/license-alert';
|
|
11
14
|
|
|
12
|
-
export {
|
|
15
|
+
export {
|
|
16
|
+
LandingAPI,
|
|
17
|
+
RootApplicationAPI,
|
|
18
|
+
ExtraInfoDetail,
|
|
19
|
+
HomePageAPI,
|
|
20
|
+
ExternalWindow
|
|
21
|
+
}
|
|
@@ -2,20 +2,9 @@ import { useContext, useEffect, useRef, useState } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { Route, Switch } from 'react-router-dom';
|
|
4
4
|
|
|
5
|
-
import { Skeleton
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
GlobalHeader,
|
|
9
|
-
ChangePassword,
|
|
10
|
-
useTranslation,
|
|
11
|
-
GlobalContext,
|
|
12
|
-
ModuleRoutes,
|
|
13
|
-
SpotlightSearch,
|
|
14
|
-
SettingsUtil,
|
|
15
|
-
Profile,
|
|
16
|
-
Card,
|
|
17
|
-
safeJSON,
|
|
18
|
-
} from '../../lib';
|
|
5
|
+
import { Skeleton } from 'antd';
|
|
6
|
+
|
|
7
|
+
import { Card, ChangePassword, GlobalContext, GlobalHeader, ModuleRoutes, Profile, SettingsUtil, SpotlightSearch, useTranslation } from '../../lib';
|
|
19
8
|
|
|
20
9
|
import './landing-api.scss';
|
|
21
10
|
|
|
@@ -57,6 +46,7 @@ function getRandomMessage(previousMessage = '') {
|
|
|
57
46
|
*/
|
|
58
47
|
export default function LandingApi({ history, CustomComponents, CustomModels, appSettings, transitionPending = false, onHomeReady, ...props }) {
|
|
59
48
|
const [loader, setLoader] = useState(false);
|
|
49
|
+
|
|
60
50
|
// const [modules, setModules] = useState([]);
|
|
61
51
|
|
|
62
52
|
const [connected] = useState();
|
|
@@ -69,31 +59,11 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
69
59
|
|
|
70
60
|
const [meta, setMeta] = useState({});
|
|
71
61
|
const [loadingMessage, setLoadingMessage] = useState('');
|
|
72
|
-
const [licenseData, setLicenseData] = useState(null);
|
|
73
|
-
|
|
74
|
-
const [licAlert, setLicAlert] = useState(false);
|
|
75
|
-
// License data state
|
|
76
62
|
|
|
77
63
|
// const [reports, setReports] = useState([]);
|
|
78
64
|
|
|
79
65
|
var config = {};
|
|
80
66
|
|
|
81
|
-
//fetch license summary
|
|
82
|
-
// const fetchSummary = async () => {
|
|
83
|
-
// try {
|
|
84
|
-
// const res = await MenusAPI.getSummary();
|
|
85
|
-
// if (res?.data) {
|
|
86
|
-
// setLicenseData(res?.data);
|
|
87
|
-
// setLicAlert(true);
|
|
88
|
-
// } else {
|
|
89
|
-
// setLicenseData(null);
|
|
90
|
-
// setLicAlert(false);
|
|
91
|
-
// }
|
|
92
|
-
// } catch (err) {
|
|
93
|
-
// console.error(err);
|
|
94
|
-
// }
|
|
95
|
-
// };
|
|
96
|
-
|
|
97
67
|
// Variable decides the control of homepage
|
|
98
68
|
// #TODO This is a temporary fix - Homemage
|
|
99
69
|
|
|
@@ -103,70 +73,6 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
103
73
|
disableHomepage = JSON.parse(process.env.REACT_APP_DISABLEHOMEPAGE);
|
|
104
74
|
}
|
|
105
75
|
|
|
106
|
-
/**
|
|
107
|
-
* Normalizes the user's branch access list from `organization_details`.
|
|
108
|
-
*
|
|
109
|
-
* The API can return `organization_details` as a JSON string, so we always
|
|
110
|
-
* parse it through `safeJSON` before reading the branch collection.
|
|
111
|
-
*
|
|
112
|
-
* @returns {Array} List of branches the current user can access.
|
|
113
|
-
*/
|
|
114
|
-
const getAccessibleBranches = () => {
|
|
115
|
-
const orgDetails = safeJSON(user?.organization_details);
|
|
116
|
-
return Array.isArray(orgDetails?.branch) ? orgDetails.branch : [];
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Resolves the currently selected branch record using the persisted db pointer.
|
|
121
|
-
*
|
|
122
|
-
* @param {Array} branches
|
|
123
|
-
* @returns {Object|null}
|
|
124
|
-
*/
|
|
125
|
-
const getCurrentBranchRecord = (branches) => {
|
|
126
|
-
const currentDbPtr = localStorage.getItem('db_ptr');
|
|
127
|
-
return branches.find((branch) => String(branch.dbPtr) === String(currentDbPtr)) || null;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Resolves the target branch from the URL `index` query parameter.
|
|
132
|
-
*
|
|
133
|
-
* @param {Array} branches
|
|
134
|
-
* @param {string|null} branchId
|
|
135
|
-
* @returns {Object|null}
|
|
136
|
-
*/
|
|
137
|
-
const getBranchRecordById = (branches, branchId) => {
|
|
138
|
-
return branches.find((branch) => String(branch.branch_id) === String(branchId)) || null;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Persists branch-specific auth data after a successful switch.
|
|
143
|
-
*
|
|
144
|
-
* @param {Object} tokenBundle
|
|
145
|
-
* @param {string} dbPtr
|
|
146
|
-
*/
|
|
147
|
-
const persistBranchSession = (tokenBundle, dbPtr) => {
|
|
148
|
-
const accessToken = tokenBundle?.access_token;
|
|
149
|
-
const refreshToken = tokenBundle?.refresh_token;
|
|
150
|
-
|
|
151
|
-
if (accessToken) localStorage.setItem('access_token', accessToken);
|
|
152
|
-
if (refreshToken) localStorage.setItem('refresh_token', refreshToken);
|
|
153
|
-
if (dbPtr) localStorage.setItem('db_ptr', dbPtr);
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const fetchSummary = async () => {
|
|
157
|
-
try {
|
|
158
|
-
const res = await MenusAPI.getSummary();
|
|
159
|
-
if (res?.data) {
|
|
160
|
-
setLicenseData(res?.data);
|
|
161
|
-
setLicAlert(true);
|
|
162
|
-
} else {
|
|
163
|
-
setLicenseData(null);
|
|
164
|
-
setLicAlert(false);
|
|
165
|
-
}
|
|
166
|
-
} catch (err) {
|
|
167
|
-
console.error(err);
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
76
|
// useEffect(() => {
|
|
171
77
|
|
|
172
78
|
// // Initialize the menus for the logged in user
|
|
@@ -182,67 +88,6 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
182
88
|
// }
|
|
183
89
|
// }, [loader]);
|
|
184
90
|
|
|
185
|
-
/**
|
|
186
|
-
* Synchronizes the active branch with the `index` query parameter.
|
|
187
|
-
*
|
|
188
|
-
* Flow:
|
|
189
|
-
* 1. Read the target branch id from the URL.
|
|
190
|
-
* 2. Compare it against the branch represented by the current `db_ptr`.
|
|
191
|
-
* 3. Switch branch only when the user has access and the branch actually differs.
|
|
192
|
-
* 4. Refresh auth/profile state and reload menus for the new branch context.
|
|
193
|
-
*/
|
|
194
|
-
useEffect(() => {
|
|
195
|
-
const handleUrlBranchSwitch = async () => {
|
|
196
|
-
const searchParams = new URLSearchParams(history.location.search);
|
|
197
|
-
const urlDbPtr = searchParams.get('index');
|
|
198
|
-
if (!urlDbPtr) return;
|
|
199
|
-
|
|
200
|
-
const accessibleBranches = getAccessibleBranches();
|
|
201
|
-
const currentBranch = getCurrentBranchRecord(accessibleBranches);
|
|
202
|
-
const targetBranch = getBranchRecordById(accessibleBranches, urlDbPtr);
|
|
203
|
-
|
|
204
|
-
if (!targetBranch || String(currentBranch?.branch_id) === String(urlDbPtr)) return;
|
|
205
|
-
|
|
206
|
-
setLoader(true);
|
|
207
|
-
|
|
208
|
-
try {
|
|
209
|
-
const switchResult = await MenusAPI.switchBranch(
|
|
210
|
-
{
|
|
211
|
-
firm_id: targetBranch.firm_ptr,
|
|
212
|
-
branch_id: targetBranch.branch_id,
|
|
213
|
-
},
|
|
214
|
-
targetBranch.dbPtr
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
if (!switchResult?.success) {
|
|
218
|
-
Modal.error({
|
|
219
|
-
title: 'Branch Switch Failed',
|
|
220
|
-
content: switchResult?.message || 'An error occurred while attempting to switch branches.',
|
|
221
|
-
});
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
persistBranchSession(switchResult?.token, targetBranch.dbPtr);
|
|
226
|
-
window.dispatchEvent(new CustomEvent('branchChanged', { detail: targetBranch.dbPtr }));
|
|
227
|
-
|
|
228
|
-
const accessToken = switchResult?.token?.access_token;
|
|
229
|
-
const profileResult = await MenusAPI.getProfile(accessToken);
|
|
230
|
-
const updatedUser = { ...profileResult, loggedCheckDone: true };
|
|
231
|
-
|
|
232
|
-
dispatch({ type: 'user', payload: updatedUser });
|
|
233
|
-
localStorage.setItem('userInfo', JSON.stringify(updatedUser));
|
|
234
|
-
|
|
235
|
-
await initializeUserMenus();
|
|
236
|
-
} catch (error) {
|
|
237
|
-
console.error('Auto branch switch failed:', error);
|
|
238
|
-
} finally {
|
|
239
|
-
setLoader(false);
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
if (user?.id && history?.location) handleUrlBranchSwitch();
|
|
244
|
-
}, [history?.location?.search, user?.id]);
|
|
245
|
-
|
|
246
91
|
useEffect(() => {
|
|
247
92
|
// Initialize the menus for the logged in user
|
|
248
93
|
initializeUserMenus();
|
|
@@ -293,12 +138,9 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
293
138
|
*/
|
|
294
139
|
async function initializeUserMenus() {
|
|
295
140
|
// need to find what implement, with a login who has the respective value ("wug_custreportids")
|
|
296
|
-
|
|
297
141
|
const report = await loadScripts(user);
|
|
298
142
|
|
|
299
143
|
await loadMenus(report);
|
|
300
|
-
// fetch license summary
|
|
301
|
-
fetchSummary();
|
|
302
144
|
}
|
|
303
145
|
|
|
304
146
|
// const keyMap = {
|
|
@@ -320,7 +162,7 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
320
162
|
setLoader(true);
|
|
321
163
|
|
|
322
164
|
// setReports(report)
|
|
323
|
-
|
|
165
|
+
|
|
324
166
|
const result = await MenusAPI.getMenus(user);
|
|
325
167
|
|
|
326
168
|
// console.log(result);
|
|
@@ -450,8 +292,6 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
|
|
|
450
292
|
modules={allModules}
|
|
451
293
|
user={user}
|
|
452
294
|
history={history}
|
|
453
|
-
licenseData={licenseData}
|
|
454
|
-
licAlert={licAlert}
|
|
455
295
|
>
|
|
456
296
|
{loader ? (
|
|
457
297
|
<Card className="skeleton-card">
|
|
@@ -2,91 +2,136 @@
|
|
|
2
2
|
*
|
|
3
3
|
* Global header component
|
|
4
4
|
*/
|
|
5
|
+
|
|
5
6
|
import { useContext, useEffect, useRef, useState } from 'react';
|
|
7
|
+
|
|
6
8
|
import { motion, useAnimation } from 'framer-motion';
|
|
9
|
+
|
|
7
10
|
import { boxVariants } from './animations';
|
|
11
|
+
|
|
8
12
|
import { GlobalContext, GlobalProvider } from './../../Store';
|
|
13
|
+
|
|
9
14
|
import { Link, useLocation } from 'react-router-dom';
|
|
15
|
+
|
|
10
16
|
import { Avatar, Input, Tooltip, Typography } from 'antd';
|
|
17
|
+
|
|
11
18
|
import ProgressBar from '../progress-bar/progress-bar'; // Adjust the path as needed
|
|
19
|
+
|
|
12
20
|
import { Button } from '../../elements';
|
|
21
|
+
|
|
13
22
|
import GenericHeader from '../header/generic-header';
|
|
23
|
+
|
|
24
|
+
|
|
14
25
|
import { CustomerServiceOutlined, MenuOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
|
|
26
|
+
|
|
15
27
|
import { Drawer } from 'antd';
|
|
28
|
+
|
|
16
29
|
import { ReloadOutlined, SearchOutlined } from '@ant-design/icons';
|
|
30
|
+
|
|
17
31
|
import SideMenu from './../sidemenu/sidemenu';
|
|
32
|
+
|
|
18
33
|
import './global-header.scss';
|
|
34
|
+
|
|
19
35
|
import LanguageSwitcher from '../language-switcher/language-switcher';
|
|
36
|
+
|
|
20
37
|
import { useTranslation } from 'react-i18next';
|
|
38
|
+
|
|
21
39
|
import SettingsUtil from '../../../utils/settings.utils';
|
|
22
40
|
import SpotlightSearch from '../spotlight-search/spotlight-search.component';
|
|
23
|
-
|
|
41
|
+
|
|
24
42
|
const { Title } = Typography;
|
|
25
|
-
|
|
26
|
-
|
|
43
|
+
|
|
44
|
+
function GlobalHeaderContent({ loading, appSettings, children, isConnected, history, modules = [], sidemenu = [], reload, meta = {}, ...props }) {
|
|
27
45
|
let location = useLocation();
|
|
28
46
|
// let location = {};
|
|
47
|
+
|
|
29
48
|
const { isMobile, user = { locations: [] }, kiosk, state, settings } = useContext(GlobalContext);
|
|
49
|
+
|
|
30
50
|
const [visible, setVisible] = useState(false);
|
|
31
51
|
const helpDeskSetting = settings?.HELPATR || {};
|
|
52
|
+
|
|
32
53
|
// Variable to handle toggling of menu
|
|
33
54
|
const [collapsed, setCollapsed] = useState(false);
|
|
34
55
|
// varibale handle branch switcher
|
|
56
|
+
|
|
35
57
|
// const [searchModalVisible, setSearchModalVisible] = useState(false);
|
|
58
|
+
|
|
36
59
|
const { globalCustomerHeader = () => {} } = appSettings;
|
|
60
|
+
|
|
37
61
|
const { t, i18n } = useTranslation();
|
|
62
|
+
|
|
38
63
|
const spotlightRef = useRef();
|
|
64
|
+
|
|
39
65
|
useEffect(() => {
|
|
40
66
|
setTimeout(() => {
|
|
41
67
|
i18n.changeLanguage(localStorage.selectedLanguage);
|
|
42
68
|
}, 0);
|
|
43
69
|
}, []);
|
|
70
|
+
|
|
44
71
|
/**
|
|
45
72
|
* Function to handle toggling of menu
|
|
46
73
|
*/
|
|
74
|
+
|
|
47
75
|
const toggleCollapsed = () => {
|
|
48
76
|
setVisible(true);
|
|
77
|
+
|
|
49
78
|
collapsed === true ? setCollapsed(false) : setCollapsed(true);
|
|
50
79
|
};
|
|
80
|
+
|
|
51
81
|
const openSearchModal = () => {
|
|
52
82
|
// input to avoid typing
|
|
53
83
|
SettingsUtil.openSpotlightModal();
|
|
54
84
|
};
|
|
85
|
+
|
|
55
86
|
/**
|
|
56
87
|
* Function to remove toggling on mobile view
|
|
57
88
|
*/
|
|
58
89
|
const hideToggle = () => {
|
|
59
90
|
setVisible(true);
|
|
91
|
+
|
|
60
92
|
setCollapsed(false);
|
|
61
93
|
};
|
|
94
|
+
|
|
62
95
|
/**
|
|
63
96
|
* onClose Function
|
|
64
97
|
*/
|
|
98
|
+
|
|
65
99
|
const onClose = () => {
|
|
66
100
|
setVisible(false);
|
|
67
101
|
};
|
|
102
|
+
|
|
68
103
|
// const { model = {} } = menu;
|
|
104
|
+
|
|
69
105
|
const { model: BaseModel = {}, menu = {} } = meta;
|
|
106
|
+
|
|
70
107
|
const { model = {} } = menu;
|
|
108
|
+
|
|
71
109
|
//Animations//
|
|
72
110
|
const boxControls = useAnimation();
|
|
111
|
+
|
|
73
112
|
async function animate() {
|
|
74
113
|
await boxControls.start('entered');
|
|
114
|
+
|
|
75
115
|
//await boxControls.start("show");
|
|
76
116
|
}
|
|
117
|
+
|
|
77
118
|
useEffect(() => {
|
|
78
119
|
animate();
|
|
79
120
|
}, []);
|
|
121
|
+
|
|
80
122
|
useEffect(() => {}, [state.theme]);
|
|
123
|
+
|
|
81
124
|
return (
|
|
82
125
|
<div
|
|
83
126
|
className={`global-header ${process.env.REACT_APP_THEME} ${isConnected && !kiosk ? 'connected' : ''}`}
|
|
84
127
|
style={{
|
|
85
128
|
// background: state.theme.colors.bodyBackground,
|
|
86
|
-
|
|
129
|
+
|
|
130
|
+
height: 10,
|
|
87
131
|
}}
|
|
88
132
|
>
|
|
89
133
|
{/* <MenuOutlined style={{left:'1%',top:'1%', fontSize:18, position:'absolute', zIndex:999}} onClick={showSidebar}/> */}
|
|
134
|
+
|
|
90
135
|
<div className="layout-content">
|
|
91
136
|
<div
|
|
92
137
|
//whileHover="hover"
|
|
@@ -129,6 +174,7 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
|
|
|
129
174
|
</Drawer>
|
|
130
175
|
)}
|
|
131
176
|
</div>
|
|
177
|
+
|
|
132
178
|
{/* Right Section of the Component Loader */}
|
|
133
179
|
<div
|
|
134
180
|
className={`right-section ${!collapsed ? 'open' : 'close'} ${kiosk ? 'kioskon' : ''}`}
|
|
@@ -143,9 +189,11 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
|
|
|
143
189
|
{/* */}
|
|
144
190
|
<div className="page-header-name">
|
|
145
191
|
<ProgressBar isLoading={loading} />
|
|
192
|
+
|
|
146
193
|
<span type onClick={!isMobile ? toggleCollapsed : hideToggle} className="toggle-box toggle-menu">
|
|
147
194
|
<MenuOutlined />
|
|
148
195
|
</span>
|
|
196
|
+
|
|
149
197
|
{/* Back Button */}
|
|
150
198
|
{location.pathname !== '/' ? (
|
|
151
199
|
<span
|
|
@@ -158,30 +206,39 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
|
|
|
158
206
|
</span>
|
|
159
207
|
) : null}
|
|
160
208
|
{/* Back Button Ends */}
|
|
209
|
+
|
|
161
210
|
{location.pathname !== '/' ? (
|
|
162
211
|
<h4 className="menu-caption header-caption" style={{ color: state.theme.colors.headerColor }}>
|
|
163
212
|
{menu.caption}
|
|
164
213
|
</h4>
|
|
165
214
|
) : null}
|
|
166
215
|
</div>
|
|
216
|
+
|
|
167
217
|
{/* Page Menu Actions */}
|
|
218
|
+
|
|
168
219
|
{user.role || user.id ? (
|
|
169
220
|
<div className="page-menu">
|
|
170
221
|
{/* Search Input in header start */}
|
|
171
222
|
{!isMobile && (
|
|
172
223
|
<div>
|
|
173
224
|
<Input placeholder="Search (Shift + F)" prefix={<SearchOutlined />} onClick={openSearchModal} readOnly style={{ width: 250 }} />
|
|
225
|
+
|
|
174
226
|
<SpotlightSearch ref={(elem) => SettingsUtil.registerModal(elem)} props={props} />
|
|
175
227
|
</div>
|
|
176
228
|
)}
|
|
177
229
|
{/* Search Input in header start */}
|
|
230
|
+
|
|
178
231
|
{/** branchswitcher Option */}
|
|
179
232
|
{/* branch switcher controlled with env for matria and nura */}
|
|
180
233
|
{!process.env.REACT_APP_SHOW_BRANCH_SWITCHER ? <div className="branch-switcher">{globalCustomerHeader()}</div> : null}
|
|
181
234
|
{/* <div className="branch-switcher">{globalCustomerHeader()}</div> */}
|
|
235
|
+
|
|
182
236
|
{/* Search Option */}
|
|
237
|
+
|
|
183
238
|
{/* <ModalSearch /> */}
|
|
239
|
+
|
|
184
240
|
{/* Search Option Ends */}
|
|
241
|
+
|
|
185
242
|
{/* Configurator Actions */}
|
|
186
243
|
{user.isAdmin ? (
|
|
187
244
|
<>
|
|
@@ -195,9 +252,13 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
|
|
|
195
252
|
</>
|
|
196
253
|
) : null}
|
|
197
254
|
{/* Configurator Actions Ends */}
|
|
255
|
+
|
|
198
256
|
{/* Reload Button */}
|
|
257
|
+
|
|
199
258
|
<Button onClick={reload} icon={<ReloadOutlined />} type="default" size={'small'}></Button>
|
|
259
|
+
|
|
200
260
|
{/* Reload Button Ends */}
|
|
261
|
+
|
|
201
262
|
{/* Help-desk-btn */}
|
|
202
263
|
{helpDeskSetting?.showSupportBtn
|
|
203
264
|
? (() => {
|
|
@@ -216,9 +277,11 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
|
|
|
216
277
|
);
|
|
217
278
|
})()
|
|
218
279
|
: null}
|
|
280
|
+
|
|
219
281
|
{/** Switch Languages starts */}
|
|
220
282
|
{process.env.REACT_APP_ENABLE_LANGUAGE_SWITCHER ? <LanguageSwitcher /> : null}
|
|
221
283
|
{/** Switch Languages ends */}
|
|
284
|
+
|
|
222
285
|
{/* User Profile */}
|
|
223
286
|
<div style={{ padding: '10px' }}>
|
|
224
287
|
<ProfileAvatar />
|
|
@@ -227,49 +290,44 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
|
|
|
227
290
|
{/* User Profile Ends */}
|
|
228
291
|
</div>
|
|
229
292
|
) : null}
|
|
293
|
+
|
|
230
294
|
{/* Page Menu Actions Ends */}
|
|
231
295
|
</div>
|
|
232
296
|
) : null}
|
|
297
|
+
|
|
233
298
|
{/* The children is rendered */}
|
|
234
299
|
{children}
|
|
235
300
|
{/* The children is rendered */}
|
|
236
301
|
</div>
|
|
237
302
|
{/* Right Section of the Component Loader Ends */}
|
|
238
303
|
</div>
|
|
239
|
-
{licAlert && licenseData && (
|
|
240
|
-
<div
|
|
241
|
-
style={{
|
|
242
|
-
top: 0,
|
|
243
|
-
marginTop: '3rem',
|
|
244
|
-
right: '2%',
|
|
245
|
-
position: 'absolute',
|
|
246
|
-
zIndex: 1008,
|
|
247
|
-
}}
|
|
248
|
-
>
|
|
249
|
-
<LicenseAlert data={licenseData} />
|
|
250
|
-
</div>
|
|
251
|
-
)}
|
|
252
304
|
</div>
|
|
253
305
|
);
|
|
254
306
|
}
|
|
307
|
+
|
|
255
308
|
export default function GlobalHeader(props) {
|
|
256
309
|
const context = useContext(GlobalContext);
|
|
310
|
+
|
|
257
311
|
if (context.dispatch) {
|
|
258
312
|
return <GlobalHeaderContent {...props} />;
|
|
259
313
|
}
|
|
314
|
+
|
|
260
315
|
return (
|
|
261
316
|
<GlobalProvider {...props} appSettings={props.appSettings}>
|
|
262
317
|
<GlobalHeaderContent {...props} />
|
|
263
318
|
</GlobalProvider>
|
|
264
319
|
);
|
|
265
320
|
}
|
|
321
|
+
|
|
266
322
|
/**
|
|
267
323
|
*
|
|
268
324
|
* @returns
|
|
269
325
|
*/
|
|
270
326
|
function ProfileAvatar() {
|
|
271
327
|
const { user = { locations: [] } } = useContext(GlobalContext);
|
|
328
|
+
|
|
272
329
|
useEffect(() => {}, []);
|
|
330
|
+
|
|
273
331
|
return (
|
|
274
332
|
<Link className="profile-avatar" to="/profile">
|
|
275
333
|
{user.photograph ? (
|
|
@@ -279,7 +337,8 @@ function ProfileAvatar() {
|
|
|
279
337
|
) : (
|
|
280
338
|
<Avatar shape="square" size="small" icon={<UserOutlined />} />
|
|
281
339
|
)}
|
|
340
|
+
|
|
282
341
|
{/* {user.name} */}
|
|
283
342
|
</Link>
|
|
284
343
|
);
|
|
285
|
-
}
|
|
344
|
+
}
|