ui-soxo-bootstrap-core 2.6.0 → 2.6.1-dev.10

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.
Files changed (57) hide show
  1. package/.github/workflows/npm-publish.yml +49 -19
  2. package/core/components/extra-info/extra-info-details.js +2 -2
  3. package/core/components/menu-template-api/menu-template-api.js +2 -2
  4. package/core/lib/Store.js +3 -3
  5. package/core/lib/components/global-header/global-header.js +2 -2
  6. package/core/lib/components/sidemenu/sidemenu.js +19 -13
  7. package/core/lib/elements/basic/country-phone-input/country-phone-input.js +35 -60
  8. package/core/lib/elements/basic/country-phone-input/phone-input.scss +14 -0
  9. package/core/lib/elements/basic/dragabble-wrapper/draggable-wrapper.js +1 -1
  10. package/core/lib/elements/basic/menu-tree/menu-tree.js +26 -13
  11. package/core/lib/models/forms/components/form-creator/form-creator.js +468 -502
  12. package/core/lib/models/forms/components/form-creator/form-creator.scss +5 -4
  13. package/core/lib/models/menus/components/menu-list/menu-list.js +424 -467
  14. package/core/lib/pages/change-password/change-password.js +17 -24
  15. package/core/lib/pages/change-password/change-password.scss +45 -48
  16. package/core/lib/pages/login/commnication-mode-selection.js +46 -0
  17. package/core/lib/pages/login/communication-mode-selection.scss +60 -0
  18. package/core/lib/pages/login/login.js +153 -24
  19. package/core/lib/pages/login/login.scss +229 -334
  20. package/core/lib/pages/login/reset-password.js +124 -0
  21. package/core/lib/pages/login/reset-password.scss +31 -0
  22. package/core/lib/pages/profile/themes.json +4 -4
  23. package/core/lib/utils/api/api.utils.js +71 -48
  24. package/core/lib/utils/common/common.utils.js +109 -0
  25. package/core/lib/utils/http/http.utils.js +1 -0
  26. package/core/lib/utils/index.js +25 -28
  27. package/core/models/base/base.js +7 -3
  28. package/core/models/core-scripts/core-scripts.js +9 -0
  29. package/core/models/doctor/components/doctor-add/doctor-add.js +9 -4
  30. package/core/models/menus/components/menu-add/menu-add.js +1 -1
  31. package/core/models/menus/components/menu-lists/menu-lists.js +5 -9
  32. package/core/models/menus/menus.js +21 -2
  33. package/core/models/roles/components/role-add/role-add.js +92 -59
  34. package/core/models/roles/components/role-list/role-list.js +1 -1
  35. package/core/models/roles/roles.js +9 -0
  36. package/core/models/staff/components/staff-add/staff-add.js +20 -32
  37. package/core/models/users/components/assign-role/assign-role.js +145 -50
  38. package/core/models/users/components/assign-role/assign-role.scss +209 -45
  39. package/core/models/users/components/assign-role/avatar-props.js +45 -0
  40. package/core/models/users/components/user-add/user-add.js +47 -56
  41. package/core/models/users/components/user-add/user-edit.js +25 -4
  42. package/core/models/users/users.js +34 -8
  43. package/core/modules/dashboard/components/dashboard-card/menu-dashboard-card.js +1 -1
  44. package/core/modules/reporting/components/reporting-dashboard/README.md +316 -0
  45. package/core/modules/reporting/components/reporting-dashboard/adavance-search/advance-search.js +120 -0
  46. package/core/modules/reporting/components/reporting-dashboard/display-columns/build-display-columns.js +75 -0
  47. package/core/modules/reporting/components/reporting-dashboard/display-columns/build-display-columns.test.js +74 -0
  48. package/core/modules/reporting/components/reporting-dashboard/display-columns/display-cell-renderer.js +252 -0
  49. package/core/modules/reporting/components/reporting-dashboard/display-columns/display-cell-renderer.test.js +126 -0
  50. package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +222 -376
  51. package/core/modules/steps/action-buttons.js +47 -45
  52. package/core/modules/steps/action-buttons.scss +35 -6
  53. package/core/modules/steps/steps.js +12 -10
  54. package/core/modules/steps/steps.scss +229 -31
  55. package/core/modules/steps/timeline.js +21 -19
  56. package/package.json +3 -2
  57. package/core/components/external-window/DEVELOPER_GUIDE.md +0 -705
@@ -1,33 +1,63 @@
1
1
  # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2
2
  # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
3
3
 
4
- name: Node.js Package
4
+ name: Publish Node Package (OIDC)
5
5
 
6
6
  on:
7
7
  release:
8
8
  types: [created]
9
9
 
10
+ permissions:
11
+ contents: read
12
+ id-token: write # REQUIRED for OIDC
13
+
10
14
  jobs:
11
- build:
15
+ publish:
12
16
  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
17
 
21
- publish-npm:
22
- needs: build
23
- runs-on: ubuntu-latest
24
18
  steps:
25
- - uses: actions/checkout@v3
26
- - uses: actions/setup-node@v3
19
+ # 1. Checkout the exact commit the release was created from
20
+ - name: Checkout repository
21
+ uses: actions/checkout@v4
22
+
23
+ # 2. Setup Node.js
24
+ # Node 22 = current LTS
25
+ - name: Setup Node.js
26
+ uses: actions/setup-node@v4
27
27
  with:
28
- node-version: 16
28
+ node-version: 22
29
29
  registry-url: https://registry.npmjs.org/
30
- - run: npm i
31
- - run: npm publish
32
- env:
33
- NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
30
+ cache: npm
31
+
32
+ # 3. Install dependencies deterministically
33
+ - name: Install dependencies
34
+ run: npm ci
35
+
36
+ # 4. Verify git tag matches package.json version
37
+ # This prevents publishing the wrong version
38
+ - name: Verify tag matches package.json version
39
+ run: |
40
+ TAG="${{ github.event.release.tag_name }}"
41
+ VERSION=$(node -p "require('./package.json').version")
42
+
43
+ echo "Release tag: $TAG"
44
+ echo "Package version: $VERSION"
45
+
46
+ if [[ "$TAG" != "v$VERSION"* ]]; then
47
+ echo "::error::Release tag does not match package.json version"
48
+ exit 1
49
+ fi
50
+
51
+ # 5. Publish using OIDC (NO TOKEN)
52
+ # --provenance triggers GitHub → npm identity verification
53
+ - name: Publish to npm (OIDC)
54
+ run: |
55
+ TAG="${{ github.event.release.tag_name }}"
56
+
57
+ if [[ "$TAG" == *"dev"* ]]; then
58
+ echo "Publishing dev release"
59
+ npm publish --tag dev --provenance
60
+ else
61
+ echo "Publishing stable release"
62
+ npm publish --provenance
63
+ fi
@@ -21,7 +21,7 @@ import ExtraInfo from './extra-info';
21
21
 
22
22
  const { TabPane } = Tabs;
23
23
 
24
- export default function ExtraInfoDetail({ modeValue, icon, title, tabPosition = 'left', showDrawerData, dbPtr, callback, ...record }) {
24
+ export default function ExtraInfoDetail({ modeValue, icon, title, tabPosition = 'left', showDrawerData, dbPtr, callback, drawerWidth = '35%', ...record }) {
25
25
  // State to control drawer
26
26
  const [open, setOpen] = useState(false);
27
27
 
@@ -121,7 +121,7 @@ export default function ExtraInfoDetail({ modeValue, icon, title, tabPosition =
121
121
  {/* */}
122
122
 
123
123
  {/* */}
124
- <Drawer width={'35%'} title={title} onClose={onClose} open={open}>
124
+ <Drawer width={drawerWidth} title={title} onClose={onClose} open={open}>
125
125
  <div className="main-drawer-content">
126
126
  <div className="drawer-container">
127
127
  <div className="drawer-click">
@@ -99,9 +99,9 @@ export default class MenuTemplateAPI extends Component {
99
99
  }
100
100
 
101
101
 
102
- if (menu && menu.model_id) {
102
+ if (menu && menu?.model_id) {
103
103
 
104
- if (menu.model_id && allModels[menu.model.name]) {
104
+ if (menu?.model_id && allModels[menu?.model?.name]) {
105
105
 
106
106
  this.loadedModel = allModels[menu.model.name]
107
107
 
package/core/lib/Store.js CHANGED
@@ -50,7 +50,7 @@ const initialTheme = () => {
50
50
  // manage theme with env
51
51
  const isEnvThemeTrue = process.env.REACT_APP_THEME;
52
52
 
53
- console.log('REACT_APP_THEME:', isEnvThemeTrue);
53
+ // console.log('REACT_APP_THEME:', isEnvThemeTrue);
54
54
  const matchedTheme = themes.find((t) => t.name === isEnvThemeTrue);
55
55
 
56
56
  if (matchedTheme) return matchedTheme;
@@ -64,7 +64,7 @@ const initialTheme = () => {
64
64
  // Fallback to default
65
65
  return themes[0];
66
66
  } catch (e) {
67
- console.error('Error loading theme:', e);
67
+ // console.error('Error loading theme:', e);
68
68
  return themes[0];
69
69
  }
70
70
  };
@@ -94,7 +94,7 @@ export const GlobalProvider = ({ children, CustomModels,CustomComponents, appSet
94
94
 
95
95
  const [state, dispatch] = useReducer(AppReducer, initialState);
96
96
 
97
- console.log(state);
97
+ // console.log(state);
98
98
 
99
99
  const { isMobile } = useDeviceDetect();
100
100
 
@@ -49,7 +49,7 @@ import { useTranslation } from "react-i18next";
49
49
  import BorderStyle from "pdf-lib/cjs/core/annotation/BorderStyle";
50
50
 
51
51
  import SettingsUtil from "../../../utils/settings.utils";
52
- import { SpotlightSearch } from "..";
52
+ import SpotlightSearch from "../spotlight-search/spotlight-search.component";
53
53
 
54
54
 
55
55
 
@@ -410,4 +410,4 @@ function ProfileAvatar() {
410
410
  {/* {user.name} */}
411
411
  </Link>
412
412
  );
413
- }
413
+ }
@@ -39,18 +39,18 @@ function CollapsedIconMenu({ menu, collapsed, icon, caption }) {
39
39
  // Import t and i18n from useTranslation
40
40
  const { t, i18n } = useTranslation();
41
41
  const { state } = useContext(GlobalContext);
42
- const [isMobile, setIsMobile] = useState(false);
42
+ const [isMobile, setIsMobile] = useState(false);
43
43
 
44
- useEffect(() => {
45
- const handleResize = () => {
46
- setIsMobile(window.innerWidth < 768); // Common breakpoint for mobile
47
- };
44
+ useEffect(() => {
45
+ const handleResize = () => {
46
+ setIsMobile(window.innerWidth < 768); // Common breakpoint for mobile
47
+ };
48
48
 
49
- handleResize(); // Set initial value
50
- window.addEventListener('resize', handleResize);
49
+ handleResize(); // Set initial value
50
+ window.addEventListener('resize', handleResize);
51
51
 
52
- return () => window.removeEventListener('resize', handleResize);
53
- }, []);
52
+ return () => window.removeEventListener('resize', handleResize);
53
+ }, []);
54
54
 
55
55
  const menuText = t(caption);
56
56
  const menuContent = (
@@ -85,8 +85,14 @@ function CollapsedIconMenu({ menu, collapsed, icon, caption }) {
85
85
  </>
86
86
  );
87
87
 
88
- // On mobile, or when the menu is collapsed (based on original logic), don't show the popover tooltip.
89
- return isMobile || collapsed ? menuContent : <Popover content={menuText} placement="right">{menuContent}</Popover>;
88
+ // On mobile, or when the menu is collapsed (based on original logic), don't show the popover tooltip.
89
+ return isMobile || collapsed ? (
90
+ menuContent
91
+ ) : (
92
+ <Popover content={menuText} placement="right">
93
+ {menuContent}
94
+ </Popover>
95
+ );
90
96
  }
91
97
 
92
98
  export default function SideMenu({ loading, modules = [], callback, appSettings, collapsed }) {
@@ -123,7 +129,7 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
123
129
  * Logout Function
124
130
  */
125
131
  async function handleLogout() {
126
- let dbPtrValue = appSettings.headers.db_ptr;
132
+ // let dbPtrValue = appSettings.headers.db_ptr;
127
133
  const isEnvThemeTrue = process.env.REACT_APP_THEME === 'true';
128
134
 
129
135
  // Only clear localStorage if theme is not 'true'
@@ -137,7 +143,7 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
137
143
  // const result = Users.logout()
138
144
  localStorage.clear();
139
145
 
140
- localStorage.setItem('db_ptr', dbPtrValue);
146
+ // localStorage.setItem('db_ptr', dbPtrValue);
141
147
 
142
148
  let userInfo = {
143
149
  dms: {},
@@ -6,86 +6,61 @@
6
6
  * Ensure to follow a minimal standard
7
7
  */
8
8
  import React, { useState, useEffect, useRef } from 'react';
9
-
10
9
  import PhoneInput from 'react-phone-input-2';
11
-
12
10
  import 'react-phone-input-2/lib/style.css';
13
-
14
- import PropTypes from "prop-types";
15
-
11
+ import PropTypes from 'prop-types';
16
12
  import './phone-input.scss';
17
13
 
14
+ export default function CountryPhoneInput({
15
+ value,
16
+ onChange,
17
+ disabled,
18
+ disableCountryCode,
19
+ required,
20
+ defaultCountryCode,
21
+ onBlur,
22
+ className,
23
+ onKeyDown,
24
+ }) {
25
+ const inputRef = useRef();
26
+ const hasInitializedRef = useRef(false); // IMPORTANT
27
+
28
+ const [phone, setPhone] = useState('');
18
29
 
19
- export default function CountryPhoneInput({ value, onChange, disabled, disableCountryCode, required, defaultCountryCode, onBlur }) {
20
-
21
- let inputRef = useRef();
22
-
23
- const [phone, setPhone] = useState();
24
-
30
+ /**
31
+ * run ONLY ONCE when initial value has dial code
32
+ */
25
33
  useEffect(() => {
26
- if (value && value.code && value.code.dialCode !== null) {
27
- // To prepopulate phone number ,concat dialCode and phone number
34
+ if (!hasInitializedRef.current && value?.code?.dialCode && value?.value) {
28
35
  setPhone(value.code.dialCode + value.value);
29
-
30
- // In case of update , to identify the country code that is getting selected
31
- // We are setting a timeout
32
- setTimeout(() => {
33
- // Using the reference , we get the internal state of the library component
34
- let selectedCountry = null;
35
-
36
- let selectedCode = null;
37
-
38
- if (
39
- inputRef.current &&
40
- inputRef.current.state &&
41
- inputRef.current.state.selectedCountry
42
- ) {
43
- selectedCountry = inputRef.current.state.selectedCountry;
44
-
45
- // Once we get the selected country ,we format it to the form that is received for normal onChange
46
- selectedCode = {
47
- countryCode: selectedCountry.iso2,
48
- dialCode: selectedCountry.dialCode,
49
- name: selectedCountry.name,
50
- };
51
- }
52
-
53
- // Below being the format expected , we trigger the onChange to manually update the form
54
- let updatedValue = {
55
- value: value.code.dialCode + value.value,
56
- code: selectedCode,
57
- };
58
-
59
- onChange(updatedValue);
60
- }, 0);
36
+ hasInitializedRef.current = true; // 👈 mark as done
61
37
  }
62
- }, []);
38
+ }, [value]);
63
39
 
64
40
  /**
65
- * To get value in parent component
66
- * @param {*} value
41
+ * handle user input
67
42
  */
68
- function handleInput(value, code) {
69
- if (code.dialCode) {
70
- value = value.substring(code.dialCode.length);
71
- }
72
- // To get country code with phone number in parent component
73
- value = {
74
- value,
43
+ function handleInput(inputValue, code) {
44
+ if (!code?.dialCode) return;
45
+
46
+ const phoneNumber = inputValue.slice(code.dialCode.length);
47
+
48
+ // remove autofill class when user edits field (if you use it)
49
+ onChange({
50
+ value: phoneNumber,
75
51
  code,
76
- };
77
- onChange(value);
52
+ });
78
53
  }
79
54
 
80
55
  return (
81
- <div className="phone-input">
56
+ <div className={`phone-input ${className || ''}`}>
82
57
  <PhoneInput
83
58
  ref={inputRef}
84
59
  country={defaultCountryCode || 'in'}
85
60
  // country={disableCountryCode ? false : 'in'}
86
61
  value={phone}
87
62
  onChange={handleInput}
88
- inputProps={{ required: required }}
63
+ inputProps={{ required: required, onKeyDown: onKeyDown }}
89
64
  disabled={disabled}
90
65
  onBlur={onBlur}
91
66
  />
@@ -104,4 +79,4 @@ CountryPhoneInput.propTypes = {
104
79
  disableCountryCode: PropTypes.bool,
105
80
  /** A boolean indicating whether the input is required or not. This prop is optional. */
106
81
  required: PropTypes.bool,
107
- };
82
+ };
@@ -12,6 +12,20 @@
12
12
  // }
13
13
  }
14
14
 
15
+ .autofilled-field {
16
+ .react-tel-input {
17
+ .form-control {
18
+ border-color: #fa8c16 !important; // AntD warning orange
19
+ background-color: #fff7e6;
20
+ box-shadow: none;
21
+ }
22
+
23
+ .flag-dropdown {
24
+ border-color: #fa8c16 !important;
25
+ background-color: #fff7e6;
26
+ }
27
+ }
28
+ }
15
29
  // /* For tablets and smaller screens (max-width: 1024px) */
16
30
  // @media (max-width: 1024px) {
17
31
  // .phone-input {
@@ -102,7 +102,7 @@ export default function DraggableWrapper({ id, index, movePanel, item, dragEnabl
102
102
  >
103
103
  <div style={{ flex: 1 }}>
104
104
  {dragEnabled && <span style={{ marginRight: 8 }}>⋮⋮</span>}
105
- <span>{item.name}</span>
105
+ <span>{item.caption}</span>
106
106
  {dragEnabled ? (
107
107
  <span style={{ marginLeft: 8, fontSize: 11, color: '#999' }}>(Level {level})</span>
108
108
  ) : (
@@ -23,7 +23,7 @@
23
23
  */
24
24
 
25
25
  import React from 'react';
26
- import { Checkbox, Collapse } from 'antd';
26
+ import { Checkbox, Collapse, Tag } from 'antd';
27
27
 
28
28
  const { Panel } = Collapse;
29
29
 
@@ -73,11 +73,15 @@ export const MenuTree = ({ menus, selectedMenus = [], toggleMenu, parentId = nul
73
73
  background: '#fff',
74
74
  display: 'flex',
75
75
  alignItems: 'center',
76
- gap: 8,
76
+ justifyContent: 'space-between',
77
77
  }}
78
78
  >
79
- {showCheckbox && <Checkbox checked={selectedMenus.includes(menu.id)} onChange={(e) => onParentChange(e.target.checked)} />}
80
- <span>{menu.title || menu.caption}</span>
79
+ {/* Left Side */}
80
+ <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
81
+ {showCheckbox && <Checkbox checked={selectedMenus.includes(menu.id)} onChange={(e) => onParentChange(e.target.checked)} />}
82
+ <span>{menu.caption}</span>
83
+ </div>
84
+ <Tag color={menu.is_visible === true ? 'green' : 'blue'}>{menu.is_visible === true ? 'VISIBLE' : 'HIDDEN'}</Tag>{' '}
81
85
  </div>
82
86
  );
83
87
  }
@@ -91,15 +95,24 @@ export const MenuTree = ({ menus, selectedMenus = [], toggleMenu, parentId = nul
91
95
  <Panel
92
96
  key={menu.id}
93
97
  header={
94
- <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
95
- {showCheckbox && (
96
- <Checkbox
97
- checked={children.every((c) => selectedMenus.includes(c.id))}
98
- indeterminate={children.some((c) => selectedMenus.includes(c.id)) && !children.every((c) => selectedMenus.includes(c.id))}
99
- onChange={(e) => onParentChange(e.target.checked)}
100
- />
101
- )}
102
- <span>{menu.title || menu.caption}</span>
98
+ <div
99
+ style={{
100
+ display: 'flex',
101
+ alignItems: 'center',
102
+ justifyContent: 'space-between',
103
+ }}
104
+ >
105
+ <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
106
+ {showCheckbox && (
107
+ <Checkbox
108
+ checked={children.every((c) => selectedMenus.includes(c.id))}
109
+ indeterminate={children.some((c) => selectedMenus.includes(c.id)) && !children.every((c) => selectedMenus.includes(c.id))}
110
+ onChange={(e) => onParentChange(e.target.checked)}
111
+ />
112
+ )}
113
+ <span>{menu.caption}</span>
114
+ </div>
115
+ <Tag color={menu.is_visible === true ? 'green' : 'blue'}>{menu.is_visible === true ? 'VISIBLE' : 'HIDDEN'}</Tag>{' '}
103
116
  </div>
104
117
  }
105
118
  >