varminer-app-header 2.6.2 → 2.6.4

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/index.js CHANGED
@@ -34,6 +34,40 @@ function _interopNamespaceDefault(e) {
34
34
 
35
35
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
36
36
 
37
+ const tenantFallbackCss = "/* ================================================================\r\n TENANT MODULE CSS — varminer-app-header-npm-fe\r\n Auto-generated by generate-tenant-css.js\r\n Branch scanned: Development\r\n Covers: CSS var() references, SCSS $variables, and hardcoded\r\n brand values detected in component files.\r\n ================================================================ */\r\n\r\n\r\n\n/* ── FONT FACES: local dev fallback (generate-tenant-css) ────────────── */\n/* @font-face rules for local dev fallback. In production the CDN\n tenant.css @font-face declarations (built by generate-tenant-all.js)\n load via injectTenantCss() and override these automatically.\n To change the local font path, update LOCAL_FONT_BASE_URL above. */\n@font-face {\n font-family: \"OpenSans-Light\";\n src: url(\"/asset/font/OpenSans-Light.ttf\") format(\"truetype\");\n font-weight: 300;\n font-style: normal;\n font-display: swap;\n}\n@font-face {\n font-family: \"OpenSans-LightItalic\";\n src: url(\"/asset/font/OpenSans-LightItalic.ttf\") format(\"truetype\");\n font-weight: 300;\n font-style: italic;\n font-display: swap;\n}\n@font-face {\n font-family: \"OpenSans-Regular\";\n src: url(\"/asset/font/OpenSans-Regular.ttf\") format(\"truetype\");\n font-weight: 400;\n font-style: normal;\n font-display: swap;\n}\n@font-face {\n font-family: \"OpenSans-Italic\";\n src: url(\"/asset/font/OpenSans-Italic.ttf\") format(\"truetype\");\n font-weight: 400;\n font-style: italic;\n font-display: swap;\n}\n@font-face {\n font-family: \"OpenSans-Medium\";\n src: url(\"/asset/font/OpenSans-Medium.ttf\") format(\"truetype\");\n font-weight: 500;\n font-style: normal;\n font-display: swap;\n}\n@font-face {\n font-family: \"OpenSans-MediumItalic\";\n src: url(\"/asset/font/OpenSans-MediumItalic.ttf\") format(\"truetype\");\n font-weight: 500;\n font-style: italic;\n font-display: swap;\n}\n@font-face {\n font-family: \"OpenSans-SemiBold\";\n src: url(\"/asset/font/OpenSans-SemiBold.ttf\") format(\"truetype\");\n font-weight: 600;\n font-style: normal;\n font-display: swap;\n}\n@font-face {\n font-family: \"OpenSans-SemiBoldItalic\";\n src: url(\"/asset/font/OpenSans-SemiBoldItalic.ttf\") format(\"truetype\");\n font-weight: 600;\n font-style: italic;\n font-display: swap;\n}\n@font-face {\n font-family: \"OpenSans-Bold\";\n src: url(\"/asset/font/OpenSans-Bold.ttf\") format(\"truetype\");\n font-weight: 700;\n font-style: normal;\n font-display: swap;\n}\n@font-face {\n font-family: \"OpenSans-BoldItalic\";\n src: url(\"/asset/font/OpenSans-BoldItalic.ttf\") format(\"truetype\");\n font-weight: 700;\n font-style: italic;\n font-display: swap;\n}\n@font-face {\n font-family: \"OpenSans-ExtraBold\";\n src: url(\"/asset/font/OpenSans-ExtraBold.ttf\") format(\"truetype\");\n font-weight: 800;\n font-style: normal;\n font-display: swap;\n}\n@font-face {\n font-family: \"OpenSans-ExtraBoldItalic\";\n src: url(\"/asset/font/OpenSans-ExtraBoldItalic.ttf\") format(\"truetype\");\n font-weight: 800;\n font-style: italic;\n font-display: swap;\n}\n/* ── END FONT FACES ── */\n\n/* ── FONT FACES: local dev fallback (generate-tenant-css) ────────────── */\r\n/* @font-face rules for local dev fallback. In production the CDN\r\n tenant.css @font-face declarations (built by generate-tenant-all.js)\r\n load via injectTenantCss() and override these automatically.\r\n To change the local font path, update LOCAL_FONT_BASE_URL above. */\r\n@font-face {\r\n font-family: \"OpenSans-Light\";\r\n src: url(\"/asset/font/OpenSans-Light.ttf\") format(\"truetype\");\r\n font-weight: 300;\r\n font-style: normal;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: \"OpenSans-LightItalic\";\r\n src: url(\"/asset/font/OpenSans-LightItalic.ttf\") format(\"truetype\");\r\n font-weight: 300;\r\n font-style: italic;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: \"OpenSans-Regular\";\r\n src: url(\"/asset/font/OpenSans-Regular.ttf\") format(\"truetype\");\r\n font-weight: 400;\r\n font-style: normal;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: \"OpenSans-Italic\";\r\n src: url(\"/asset/font/OpenSans-Italic.ttf\") format(\"truetype\");\r\n font-weight: 400;\r\n font-style: italic;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: \"OpenSans-Medium\";\r\n src: url(\"/asset/font/OpenSans-Medium.ttf\") format(\"truetype\");\r\n font-weight: 500;\r\n font-style: normal;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: \"OpenSans-MediumItalic\";\r\n src: url(\"/asset/font/OpenSans-MediumItalic.ttf\") format(\"truetype\");\r\n font-weight: 500;\r\n font-style: italic;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: \"OpenSans-SemiBold\";\r\n src: url(\"/asset/font/OpenSans-SemiBold.ttf\") format(\"truetype\");\r\n font-weight: 600;\r\n font-style: normal;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: \"OpenSans-SemiBoldItalic\";\r\n src: url(\"/asset/font/OpenSans-SemiBoldItalic.ttf\") format(\"truetype\");\r\n font-weight: 600;\r\n font-style: italic;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: \"OpenSans-Bold\";\r\n src: url(\"/asset/font/OpenSans-Bold.ttf\") format(\"truetype\");\r\n font-weight: 700;\r\n font-style: normal;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: \"OpenSans-BoldItalic\";\r\n src: url(\"/asset/font/OpenSans-BoldItalic.ttf\") format(\"truetype\");\r\n font-weight: 700;\r\n font-style: italic;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: \"OpenSans-ExtraBold\";\r\n src: url(\"/asset/font/OpenSans-ExtraBold.ttf\") format(\"truetype\");\r\n font-weight: 800;\r\n font-style: normal;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: \"OpenSans-ExtraBoldItalic\";\r\n src: url(\"/asset/font/OpenSans-ExtraBoldItalic.ttf\") format(\"truetype\");\r\n font-weight: 800;\r\n font-style: italic;\r\n font-display: swap;\r\n}\r\n/* ── END FONT FACES ── */\r\n\r\n/* ═══════════════════════════════════════════════════════════════\r\n MODULE: app-header (varminer-app-header-npm-fe)\r\n CSS custom-properties consumed by this micro-frontend.\r\n These are default / fallback values overridden by tenant.css.\r\n ═══════════════════════════════════════════════════════════════ */\r\n:root {\r\n --color-border-header: #e5e9eb;\r\n --color-brand-accent: #1aa7ee;\r\n --color-brand-deep-navy: #0f1e75;\r\n --color-brand-primary: #1e2f97;\r\n --color-brand-primary-hover-bg: rgba(30, 47, 151, 0.04);\r\n --color-header-bg: #ffffff;\r\n --color-menu-bg-gradient: linear-gradient(180deg, #fff, #ddf7ff, #ddf7ff);\r\n --color-menu-bg-gradient-end: #ddf7ff;\r\n --color-menu-shadow: rgba(0,0,0,0.32);\r\n --color-menu-text: #000;\r\n --color-profile-email: rgba(0, 0, 0, 0.6);\r\n --color-profile-name: #1e2f97;\r\n --color-profile-role: rgba(0, 0, 0, 0.38);\r\n --color-status-offline: #808080;\r\n --color-status-online: #44b700;\r\n --font-brand-regular: OpenSans-Regular, Roboto, sans-serif;\r\n --font-brand-semibold: OpenSans-SemiBold, Roboto, sans-serif;\r\n --image-logo-svg: url(\"asset/logo.svg\");\r\n --size-header-height: 65px;\r\n --size-header-zindex: 200;\r\n --size-menu-width: 280px;\r\n\n /* ── Auto-discovered on 2026-03-17 ── */\n --color-white: #fff;\n --color-hex-aacccc: #acc;\n --color-selected-row: #ddf7ff;\n --color-black: #000;\n --color-text-secondary-alpha: rgba(0, 0, 0, 0.6);\n --color-text-muted-alpha: rgba(0, 0, 0, 0.38);\n --color-brand-primary-dark: #0b1659;\n --color-primary-dark: #111c56;\n --color-brand-navy-header: #13257b;\n --color-brand-accent-hover: #0a8bcc;\n --color-brand-switch: #657bfd;\n --color-brand-secondary: #3f8cff;\n --color-igv-gradient-start: #1e3c72;\n --color-igv-gradient-end: #2a5298;\n --color-bg-page: #f5f9ff;\n --color-bg-title-section: #e6f2ff;\n --color-bg-dialog: #f7fbff;\n --color-bg-panel: #e3f4fd;\n --color-bg-side-menu-hover: #e3f2fd;\n --color-bg-subtle: #f5f5f5;\n --color-bg-scrollbar-track: #f1f1f1;\n --Grey-50: #ebeff5;\n --color-border-blue: #b5e6ff;\n --color-border-default: #dadada;\n --color-border-sky-blue-300: #4fc4ff;\n --color-border-light: #e4e4e4;\n --color-border-chip: #bdbdbd;\n --color-text-heading: #27323d;\n --color-text-dark: #0f172a;\n --color-text-input: #0a0a0a;\n --color-text-muted-slate: #64748b;\n --Grey-600: #586d81;\n --Grey-400: #7c8fa3;\n --color-status-success: #4caf50;\n --color-status-success-dark: #2e7d32;\n --color-status-warning: #ef6c00;\n --color-status-error: #d32f2f;\n --color-scrollbar-thumb: #1976d2;\n --color-scrollbar-track: #e3edf7;\n --color-side-menu-active-bg: #1565c0;\n --color-column-rows-even: #edfbff;\n --color-bg-error-row: #fcefef;\n --color-bg-error-row-hover: #f9e0e0;\n --color-border-error-row: #e78e8e;\n --color-bg-warning-row: #fff5ed;\n --color-bg-warning-row-hover: #ffe8d6;\n --color-border-warning-row: #e8a87c;\n --color-bg-success-row: #eff5ef;\n --color-bg-success-row-hover: #e5ede5;\n --color-shadow-dark: #b3b3b3;\n --color-bg-success-toast: #edf7ed;\n --color-bg-error-toast: #ffebee;\n --color-text-success-toast: #1e4620;\n --color-text-error-toast: #c62828;\n --color-gene-type-uncertain: #5034ee;\n --color-gene-type-candidate: #ff9800;\n --color-gene-type-known: #2196f3;\n --color-border-disabled: #ccc;\n --color-scrollbar-handle: #888;\n --color-text-placeholder: #666;\n --color-scrollbar-handle-dark: #555;\n --color-text-dark-secondary: #333;\n --color-text-near-black: #222;\n --color-hex-e0e0e0: #e0e0e0;\n --color-hex-c0c0c0: #c0c0c0;\n --color-hex-f8f9fa: #f8f9fa;\n --color-brand-primary-active-bg: rgba(30, 47, 151, 0.08);\n --color-chip-background: rgba(30, 47, 151, 0.12);\n --color-border-brand-muted: rgba(30, 47, 151, 0.23);\n --color-accent-hover-subtle: rgba(26, 167, 238, 0.04);\n --color-accent-hover-bg: rgba(26, 167, 238, 0.08);\n --color-accent-selected: rgba(26, 167, 238, 0.12);\n --color-accent-selected-dark: rgba(26, 167, 238, 0.16);\n --color-accent-light: rgba(26, 167, 238, 0.34);\n --color-accent-border: rgba(26, 167, 238, 0.54);\n --color-shadow-dialog: rgba(8, 37, 68, 0.18);\n --color-shadow-card: rgba(10, 33, 62, 0.08);\n --color-shadow-card-hover: rgba(10, 33, 62, 0.16);\n --color-deep-navy-hover-bg: rgba(15, 30, 117, 0.08);\n --color-shadow-body: rgba(15, 23, 42, 0.08);\n --color-white-overlay: rgba(255, 255, 255, 0.1);\n --color-action-hover-bg: rgba(0, 0, 0, 0.04);\n --color-overlay-subtle: rgba(0, 0, 0, 0.10);\n --color-divider: rgba(0, 0, 0, 0.12);\n --color-overlay-medium: rgba(0, 0, 0, 0.14);\n --color-shadow-light: rgba(0, 0, 0, 0.15);\n --color-shadow-medium: rgba(0, 0, 0, 0.20);\n --color-border-outline: rgba(0, 0, 0, 0.26);\n --color-border-medium: rgba(0, 0, 0, 0.5);\n --color-icon-default: rgba(0, 0, 0, 0.54);\n --color-action-active: rgba(0, 0, 0, 0.56);\n --color-border-dark: rgba(0, 0, 0, 0.7);\n --color-text-primary-alpha: rgba(0, 0, 0, 0.87);\n\n /* ── Auto-discovered on 2026-03-17 ── */\n --color-header-accent: #aacccc;\n --color-error-pink: #dc004e;\n --color-text-disabled: #999999;\n --color-overlay-40: rgba(0, 0, 0, 0.4);\n --color-white-70: rgba(255, 255, 255, 0.7);\n --color-white-90: rgba(255, 255, 255, 0.9);\n --color-white-95: rgba(255, 255, 255, 0.95);\n --color-success-90: rgba(76, 175, 80, 0.9);\n --color-error-solid: rgba(211, 47, 47, 1);\n --color-error-50: rgba(211, 47, 47, 0.5);\n --color-rgba-000000: rgb(0,0,0);\n}\n";
38
+
39
+ const TENANT_FALLBACK_STYLE_ID = "tenant-fallback-css";
40
+ function rewriteFallbackAssetUrls(cssText) {
41
+ const baseUrl = undefined?.BASE_URL ?? "/";
42
+ const normalizedBaseUrl = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
43
+ return cssText.replace(/url\((["']?)\/asset\//g, `url($1${normalizedBaseUrl}asset/`);
44
+ }
45
+ function injectTenantFallbackCss(cssText) {
46
+ if (typeof document === "undefined")
47
+ return;
48
+ const rewrittenCss = rewriteFallbackAssetUrls(cssText);
49
+ const existingStyle = document.getElementById(TENANT_FALLBACK_STYLE_ID);
50
+ if (existingStyle) {
51
+ if (existingStyle.textContent?.includes(rewrittenCss))
52
+ return;
53
+ existingStyle.textContent = existingStyle.textContent
54
+ ? `${existingStyle.textContent}\n\n${rewrittenCss}`
55
+ : rewrittenCss;
56
+ return;
57
+ }
58
+ const style = document.createElement("style");
59
+ style.id = TENANT_FALLBACK_STYLE_ID;
60
+ style.textContent = rewrittenCss;
61
+ const tenantCssLink = document.querySelector('link[rel="stylesheet"][href*="tenant.css"]');
62
+ if (tenantCssLink) {
63
+ document.head.insertBefore(style, tenantCssLink);
64
+ return;
65
+ }
66
+ document.head.appendChild(style);
67
+ }
68
+
69
+ injectTenantFallbackCss(tenantFallbackCss);
70
+
37
71
  const DrawerContext = React__namespace.createContext({
38
72
  isDrawerOpen: false,
39
73
  openDrawer: () => { },
@@ -94,21 +128,79 @@ function setHeaderAuth(auth) {
94
128
  }
95
129
  }
96
130
  /**
97
- * User display data: from IAM only (linn-i-am-userDetails). No dependency on persist:userdb.
131
+ * User display data: prefers linn-i-am-userDetails (IAM), falls back to
132
+ * persist:userdb → profileInformation.userDetails, then authDetails.auth.user.
98
133
  */
99
134
  const getUserDataFromStorage = () => {
135
+ // Primary source: IAM app sets this after OTP verification
100
136
  const iamUser = getStoredUserDetails();
101
- if (!iamUser)
102
- return null;
103
- const name = [iamUser.firstName, iamUser.lastName].filter(Boolean).join(" ").trim();
104
- const role = iamUser.roles?.length ? iamUser.roles[0] : iamUser.workInfo?.jobTitle ?? "";
105
- return {
106
- name: name || "",
107
- email: iamUser.email || "",
108
- role: role || "",
109
- avatar: undefined,
110
- initials: name ? name.split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase() : undefined,
111
- };
137
+ if (iamUser) {
138
+ const name = [iamUser.firstName, iamUser.lastName].filter(Boolean).join(" ").trim();
139
+ const role = iamUser.roles?.length ? iamUser.roles[0] : iamUser.workInfo?.jobTitle ?? "";
140
+ return {
141
+ name: name || "",
142
+ email: iamUser.email || "",
143
+ role: role || "",
144
+ avatar: undefined,
145
+ initials: name ? name.split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase() : undefined,
146
+ };
147
+ }
148
+ // Fallback: read from persist:userdb which is written by the IAM/login app
149
+ try {
150
+ const raw = localStorage.getItem("persist:userdb");
151
+ if (!raw)
152
+ return null;
153
+ const outer = JSON.parse(raw);
154
+ const parseNested = (v) => {
155
+ if (typeof v === "string") {
156
+ try {
157
+ return JSON.parse(v);
158
+ }
159
+ catch {
160
+ return v;
161
+ }
162
+ }
163
+ return v;
164
+ };
165
+ // profileInformation.userDetails has firstName, lastName, email, roles[]
166
+ const profileInfo = parseNested(outer.profileInformation);
167
+ const userDetails = profileInfo?.userDetails;
168
+ if (userDetails && (userDetails.firstName || userDetails.lastName || userDetails.email)) {
169
+ const first = userDetails.firstName || "";
170
+ const last = userDetails.lastName || "";
171
+ const name = [first, last].filter(Boolean).join(" ").trim();
172
+ const roles = userDetails.roles;
173
+ const role = roles?.length ? roles[0] : userDetails.jobTitle ?? "";
174
+ return {
175
+ name,
176
+ email: userDetails.email || "",
177
+ role: role || "",
178
+ avatar: undefined,
179
+ initials: name ? name.split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase() : undefined,
180
+ };
181
+ }
182
+ // authDetails.auth.user has firstname/lastname (lowercase n) + activeRole
183
+ const authDetailsRaw = parseNested(outer.authDetails);
184
+ const auth = authDetailsRaw?.auth;
185
+ const userObj = auth?.user;
186
+ if (auth && (userObj?.firstname || userObj?.lastname)) {
187
+ const first = userObj?.firstname || "";
188
+ const last = userObj?.lastname || "";
189
+ const name = [first, last].filter(Boolean).join(" ").trim();
190
+ const role = auth.activeRole || "";
191
+ return {
192
+ name,
193
+ email: "",
194
+ role,
195
+ avatar: undefined,
196
+ initials: name ? name.split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase() : undefined,
197
+ };
198
+ }
199
+ }
200
+ catch {
201
+ // ignore parse errors
202
+ }
203
+ return null;
112
204
  };
113
205
  const getNotificationCountFromStorage = () => {
114
206
  const userDbString = localStorage.getItem("persist:userdb");