@controleonline/ui-common 1.2.96 → 1.2.98
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/.release/rc-manifest.json +7 -7
- package/package.json +1 -1
- package/src/react/components/BottomNavigationBar.js +4 -14
- package/src/react/components/DefaultProvider.styles.js +0 -3
- package/src/react/components/DefaultProvider.web.js +3 -7
- package/src/react/components/RuntimeBottomNavigationBar.js +0 -2
- package/src/react/components/RuntimeInfoFooter.js +2 -8
- package/src/react/components/UserAvatar.js +1 -3
- package/src/react/utils/runtimeFooter.js +24 -3
- package/src/tests/react/utils/runtimeFooter.test.js +26 -0
- package/docs/homepage-1056.md +0 -14
- package/src/react/components/BottomNavigationBar.soft.styles.js +0 -28
- package/src/react/components/RuntimeInfoFooter.home.spacing.js +0 -5
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.2.
|
|
3
|
-
"rc":
|
|
4
|
-
"branch": "rc/1.2.
|
|
5
|
-
"baseMaster": "
|
|
6
|
-
"tasks": [
|
|
7
|
-
"repositories": { "ControleOnline/ui-common": "
|
|
8
|
-
"compositionNotes": ["
|
|
2
|
+
"version": "1.2.98",
|
|
3
|
+
"rc": 2,
|
|
4
|
+
"branch": "rc/1.2.98-rc.2",
|
|
5
|
+
"baseMaster": "aa5ad406d201d23bb88023bc4b7a7d4f9b11fd0a",
|
|
6
|
+
"tasks": [88],
|
|
7
|
+
"repositories": { "ControleOnline/ui-common": "0c96fc6ebac3af856cfba103fa0694171f590ce1" },
|
|
8
|
+
"compositionNotes": ["Task 88: rodapé mostra …últimos 2 blocos quando o identificador não é IPv4. rc.2 inclui bump de versão 1.2.98 para publicação npm; supersedes rc.1."],
|
|
9
9
|
"frozen": true
|
|
10
10
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import React, {useLayoutEffect, useMemo} from 'react';
|
|
2
2
|
import {Pressable, Text, View} from 'react-native';
|
|
3
|
-
import
|
|
4
|
-
import HomeIcon from '@controleonline/../../src/components/HomeIcon';
|
|
3
|
+
import Icon from 'react-native-vector-icons/Feather';
|
|
5
4
|
import {useTheme} from './DefaultProvider';
|
|
6
5
|
import RuntimeInfoFooter from './RuntimeInfoFooter';
|
|
7
6
|
import {resolveMenuRouteParams} from '../utils/menuNavigation';
|
|
8
7
|
import createStyles from './BottomNavigationBar.styles';
|
|
9
|
-
import softenStyles from './BottomNavigationBar.soft.styles';
|
|
10
|
-
import {resolveHomepagePalette} from '@controleonline/../../src/styles/homepagePalette';
|
|
11
8
|
|
|
12
9
|
const BottomNavigationBar = ({
|
|
13
10
|
navigation,
|
|
@@ -17,10 +14,7 @@ const BottomNavigationBar = ({
|
|
|
17
14
|
colors = {},
|
|
18
15
|
testID = 'bottom-navigation',
|
|
19
16
|
useModernWebChromeProps = false,
|
|
20
|
-
appearance = 'legacy',
|
|
21
17
|
}) => {
|
|
22
|
-
const Icon = appearance === 'soft' ? HomeIcon : LegacyIcon;
|
|
23
|
-
colors = appearance === 'soft' ? resolveHomepagePalette(colors) : colors;
|
|
24
18
|
const theme = useTheme?.() || {};
|
|
25
19
|
const runtimeFooter = theme?.runtimeFooter || null;
|
|
26
20
|
const registerBottomNavigation =
|
|
@@ -37,14 +31,14 @@ const BottomNavigationBar = ({
|
|
|
37
31
|
|
|
38
32
|
const styles = useMemo(
|
|
39
33
|
() =>
|
|
40
|
-
|
|
34
|
+
createStyles({
|
|
41
35
|
activeBackground,
|
|
42
36
|
dockBackground,
|
|
43
37
|
dockBorder,
|
|
44
38
|
dockShadow,
|
|
45
39
|
activeBorder,
|
|
46
40
|
useModernWebChromeProps,
|
|
47
|
-
}),
|
|
41
|
+
}),
|
|
48
42
|
[
|
|
49
43
|
activeBackground,
|
|
50
44
|
activeBorder,
|
|
@@ -52,7 +46,6 @@ const BottomNavigationBar = ({
|
|
|
52
46
|
dockBorder,
|
|
53
47
|
dockShadow,
|
|
54
48
|
useModernWebChromeProps,
|
|
55
|
-
appearance,
|
|
56
49
|
],
|
|
57
50
|
);
|
|
58
51
|
|
|
@@ -123,11 +116,8 @@ const BottomNavigationBar = ({
|
|
|
123
116
|
? [styles.host, styles.hostPointerEventsBoxNone]
|
|
124
117
|
: styles.host;
|
|
125
118
|
const footerProps = {
|
|
126
|
-
appearance,
|
|
127
119
|
appVersion: runtimeFooter?.appVersion,
|
|
128
|
-
colors:
|
|
129
|
-
? {...runtimeFooter?.colors, footerBackground: colors.footerBackground, footerText: colors.footerText}
|
|
130
|
-
: runtimeFooter?.colors || {},
|
|
120
|
+
colors: runtimeFooter?.colors || {},
|
|
131
121
|
mainCompany: runtimeFooter?.mainCompany,
|
|
132
122
|
device: runtimeFooter?.device,
|
|
133
123
|
useModernWebChromeProps,
|
|
@@ -395,19 +395,15 @@ export const DefaultProvider = ({
|
|
|
395
395
|
|
|
396
396
|
useWebThemePalette({resolveDomainThemeColors, baseThemeColors, mainCompany, resolveThemePalette, runtimeColors, applyPaletteToRuntimeColors, applyThemeCssVariables, actions, currentCompany, isShopClientApp});
|
|
397
397
|
|
|
398
|
-
|
|
398
|
+
if (requiresTranslateBootstrap && !isTranslateBootstrapReady) {
|
|
399
|
+
return <View style={providerStyles.loadingContainer} />;
|
|
400
|
+
}
|
|
399
401
|
|
|
400
402
|
return (
|
|
401
403
|
<ThemeContext.Provider value={themeContextValue}>
|
|
402
404
|
<View
|
|
403
|
-
pointerEvents={translationPending ? 'none' : 'auto'}
|
|
404
|
-
accessibilityElementsHidden={translationPending}
|
|
405
|
-
importantForAccessibility={translationPending ? 'no-hide-descendants' : 'auto'}
|
|
406
405
|
style={[
|
|
407
406
|
providerStyles.shell,
|
|
408
|
-
// Keep navigation mounted while translations load. Unmounting it
|
|
409
|
-
// resets the login route and repeatedly registers the bottom bar.
|
|
410
|
-
translationPending && providerStyles.translationPending,
|
|
411
407
|
{
|
|
412
408
|
backgroundColor: colors?.background || runtimeColors.background,
|
|
413
409
|
},
|
|
@@ -19,7 +19,6 @@ const {
|
|
|
19
19
|
} = require('@controleonline/ui-common/src/react/utils/bottomNavigationToolbar');
|
|
20
20
|
|
|
21
21
|
const RuntimeBottomNavigationBar = ({
|
|
22
|
-
appearance = 'legacy',
|
|
23
22
|
activeRouteName: activeRouteNameProp,
|
|
24
23
|
colors: colorsOverride,
|
|
25
24
|
disabled: disabledOverride,
|
|
@@ -160,7 +159,6 @@ const RuntimeBottomNavigationBar = ({
|
|
|
160
159
|
|
|
161
160
|
return (
|
|
162
161
|
<BottomNavigationBar
|
|
163
|
-
appearance={appearance}
|
|
164
162
|
activeRouteName={effectiveActiveRoute}
|
|
165
163
|
colors={colors}
|
|
166
164
|
disabled={isDisabled}
|
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
} from '@controleonline/ui-common/src/react/utils/runtimeFooter';
|
|
23
23
|
import styles from './RuntimeInfoFooter.styles';
|
|
24
24
|
import RuntimeFooterMarqueeText from './RuntimeFooterMarqueeText';
|
|
25
|
-
import resolveHomeFooterSpacing from './RuntimeInfoFooter.home.spacing';
|
|
26
25
|
|
|
27
26
|
const ROTATION_INTERVAL_MS = 4000;
|
|
28
27
|
const COMPACT_BREAKPOINT = 720;
|
|
@@ -67,7 +66,6 @@ const RuntimeInfoFooter = ({
|
|
|
67
66
|
device,
|
|
68
67
|
colors,
|
|
69
68
|
useModernWebChromeProps = false,
|
|
70
|
-
appearance = 'legacy',
|
|
71
69
|
}) => {
|
|
72
70
|
const {width} = useWindowDimensions();
|
|
73
71
|
const insets = useSafeAreaInsets();
|
|
@@ -260,7 +258,6 @@ const RuntimeInfoFooter = ({
|
|
|
260
258
|
: inlineText
|
|
261
259
|
) || primaryText || device?.id || '';
|
|
262
260
|
const backgroundColor = colors?.footerBackground;
|
|
263
|
-
const homeSpacing = resolveHomeFooterSpacing(appearance, Platform.OS, insets.bottom);
|
|
264
261
|
const borderColor = colors?.footerBorder;
|
|
265
262
|
const textColor = resolveVisibleFooterTextColor(colors);
|
|
266
263
|
const loadingColor = colors?.footerLink || colors?.primary || textColor;
|
|
@@ -270,9 +267,7 @@ const RuntimeInfoFooter = ({
|
|
|
270
267
|
: styles.shell;
|
|
271
268
|
|
|
272
269
|
return (
|
|
273
|
-
<View {...shellProps} style={
|
|
274
|
-
paddingBottom: homeSpacing.safeAreaBottom, backgroundColor,
|
|
275
|
-
}]}>
|
|
270
|
+
<View {...shellProps} style={shellStyle}>
|
|
276
271
|
<View
|
|
277
272
|
testID="runtime-info-footer"
|
|
278
273
|
style={[
|
|
@@ -281,8 +276,7 @@ const RuntimeInfoFooter = ({
|
|
|
281
276
|
{
|
|
282
277
|
backgroundColor,
|
|
283
278
|
borderTopColor: borderColor,
|
|
284
|
-
paddingBottom:
|
|
285
|
-
...(homeSpacing && !showDebugInfo ? {paddingTop: homeSpacing.contentPadding} : {}),
|
|
279
|
+
paddingBottom: bottomInset,
|
|
286
280
|
},
|
|
287
281
|
]}>
|
|
288
282
|
<View style={styles.primaryRow}>
|
|
@@ -156,7 +156,6 @@ const useDisplayUri = uri => {
|
|
|
156
156
|
|
|
157
157
|
const UserAvatar = ({
|
|
158
158
|
imageUrl,
|
|
159
|
-
imageHeaders,
|
|
160
159
|
email,
|
|
161
160
|
name,
|
|
162
161
|
size = 40,
|
|
@@ -216,8 +215,7 @@ const UserAvatar = ({
|
|
|
216
215
|
<View style={containerStyle}>
|
|
217
216
|
{displayUri ? (
|
|
218
217
|
<Image
|
|
219
|
-
source={
|
|
220
|
-
? {uri: displayUri, headers: imageHeaders} : {uri: displayUri}}
|
|
218
|
+
source={{uri: displayUri}}
|
|
221
219
|
style={styles.image}
|
|
222
220
|
onError={() => setSourceIndex(index => index + 1)}
|
|
223
221
|
/>
|
|
@@ -128,6 +128,26 @@ const formatRuntimeFooterVersion = version => {
|
|
|
128
128
|
return normalizedVersion ? `v${normalizedVersion}` : '';
|
|
129
129
|
};
|
|
130
130
|
|
|
131
|
+
const IPV4_PATTERN = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
132
|
+
|
|
133
|
+
// IPv4 is shown in full; other ':'-separated ids (IPv6/MAC-like) are shortened
|
|
134
|
+
// to an ellipsis plus the last two blocks, e.g. "…46f4:eb0b".
|
|
135
|
+
const formatRuntimeFooterIdentifier = value => {
|
|
136
|
+
const identifier = safeTrim(value);
|
|
137
|
+
|
|
138
|
+
if (!identifier || IPV4_PATTERN.test(identifier) || !identifier.includes(':')) {
|
|
139
|
+
return identifier;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const blocks = identifier.split(':').filter(Boolean);
|
|
143
|
+
|
|
144
|
+
if (blocks.length <= 2) {
|
|
145
|
+
return identifier;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return `…${blocks.slice(-2).join(':')}`;
|
|
149
|
+
};
|
|
150
|
+
|
|
131
151
|
const getRuntimeFooterWebHost = () => {
|
|
132
152
|
const hostname = safeTrim(globalThis?.location?.hostname);
|
|
133
153
|
|
|
@@ -364,9 +384,9 @@ const getRuntimeFooterDebugInfo = ({device, appVersion, deviceConfig}) => {
|
|
|
364
384
|
const nativeIdentifier = nativeIdentifierCandidates[0]?.value || '';
|
|
365
385
|
const runtimeDetail = operationModeLabel
|
|
366
386
|
? operationModeLabel
|
|
367
|
-
:
|
|
368
|
-
? webIdentifier
|
|
369
|
-
|
|
387
|
+
: formatRuntimeFooterIdentifier(
|
|
388
|
+
isWebRuntime ? webIdentifier : nativeIdentifier,
|
|
389
|
+
);
|
|
370
390
|
const runtimeDetailSource = operationModeLabel
|
|
371
391
|
? 'device_config.configs.pos-operation-mode'
|
|
372
392
|
: isWebRuntime
|
|
@@ -444,6 +464,7 @@ module.exports = {
|
|
|
444
464
|
getRuntimeFooterStoredVersion,
|
|
445
465
|
getRuntimeFooterTextLines,
|
|
446
466
|
getRuntimeFooterVersionCandidates,
|
|
467
|
+
formatRuntimeFooterIdentifier,
|
|
447
468
|
getRuntimeFooterWebIdentifierCandidates,
|
|
448
469
|
getRuntimeFooterText,
|
|
449
470
|
getRuntimeFooterWebHost,
|
|
@@ -2,6 +2,7 @@ const assert = require('node:assert/strict')
|
|
|
2
2
|
const {after, before, test} = require('node:test')
|
|
3
3
|
|
|
4
4
|
const {
|
|
5
|
+
formatRuntimeFooterIdentifier,
|
|
5
6
|
getRuntimeFooterDebugInfo,
|
|
6
7
|
getRuntimeFooterNativeIdentifierCandidates,
|
|
7
8
|
getRuntimeFooterPrimaryText,
|
|
@@ -487,3 +488,28 @@ test('hides runtime device information on the customer paylist only', () => {
|
|
|
487
488
|
assert.equal(shouldShowRuntimeFooter('LoginPage'), true)
|
|
488
489
|
assert.equal(shouldShowRuntimeFooter('WalletsPage'), true)
|
|
489
490
|
})
|
|
491
|
+
|
|
492
|
+
test('formats runtime identifier: IPv4 full, non-IPv4 shortened to last two blocks', () => {
|
|
493
|
+
assert.equal(formatRuntimeFooterIdentifier('179.110.95.138'), '179.110.95.138')
|
|
494
|
+
assert.equal(
|
|
495
|
+
formatRuntimeFooterIdentifier('2804:18:1119:f433:54b4:a587:46f4:eb0b'),
|
|
496
|
+
'…46f4:eb0b',
|
|
497
|
+
)
|
|
498
|
+
assert.equal(formatRuntimeFooterIdentifier('aa:bb:cc:dd:ee:ff'), '…ee:ff')
|
|
499
|
+
assert.equal(formatRuntimeFooterIdentifier('::1'), '::1')
|
|
500
|
+
assert.equal(formatRuntimeFooterIdentifier('abc'), 'abc')
|
|
501
|
+
assert.equal(formatRuntimeFooterIdentifier(''), '')
|
|
502
|
+
assert.equal(formatRuntimeFooterIdentifier(null), '')
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
test('primary text shortens IPv6 public ip', () => {
|
|
506
|
+
const text = getRuntimeFooterPrimaryText({
|
|
507
|
+
device: {
|
|
508
|
+
type: 'PDV',
|
|
509
|
+
systemName: 'web',
|
|
510
|
+
metadata: {network: {publicIp: '2804:18:1119:f433:54b4:a587:46f4:eb0b'}},
|
|
511
|
+
},
|
|
512
|
+
appVersion: '1.10.68',
|
|
513
|
+
})
|
|
514
|
+
assert.ok(text.includes('(…46f4:eb0b)'), text)
|
|
515
|
+
})
|
package/docs/homepage-1056.md
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Homepage ADMIN/MANAGER — app-community#1056
|
|
2
|
-
|
|
3
|
-
Soft appearance is opt-in for HomePage only. Existing menu routes/parameters, permissions, stores and translations are preserved. App-provided homepage colors and components are used only in this appearance. Default consumers retain their current behavior.
|
|
4
|
-
|
|
5
|
-
Source: https://github.com/ControleOnline/app-community/issues/1056
|
|
6
|
-
Local evidence: 40 homepage tests and 34 runtime footer/zoom tests passed. No production authorization.
|
|
7
|
-
|
|
8
|
-
## Web login translation bootstrap
|
|
9
|
-
|
|
10
|
-
Keep the navigation tree mounted while translations initialize. Hide the shell and disable pointer/accessibility interaction until the existing translation readiness contract succeeds. Unmounting navigation during login resets its route and repeatedly mounts/registers the bottom bar, causing React maximum update depth. No route, permission, translation source, theme or zoom changes. Native behavior is unchanged.
|
|
11
|
-
|
|
12
|
-
Regression evidence: app-community homepage bootstrapNavigation.test.js reproduced maximum update depth before the fix, then passed after it. 44 tests across 9 homepage suites passed. Runtime Dev reproduced the unfixed bug; new runtime verification is required after consuming ui-common 1.2.96.
|
|
13
|
-
|
|
14
|
-
Release 1.2.96 uses the task-only c91510d source plus version metadata. The integration merge into dev preserves independent team work, but those changes are excluded from this homepage package. Publication uses the existing tag-triggered trusted publishing workflow.
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import {Platform} from 'react-native';
|
|
2
|
-
|
|
3
|
-
// Only the homepage opts into this chrome; preserve all default navigation styles.
|
|
4
|
-
export default (styles, colors, appearance) => appearance !== 'soft' ? styles : {
|
|
5
|
-
...styles,
|
|
6
|
-
dock: [styles.dock, {
|
|
7
|
-
paddingHorizontal: 0,
|
|
8
|
-
paddingTop: 0,
|
|
9
|
-
paddingBottom: 0,
|
|
10
|
-
borderWidth: 0,
|
|
11
|
-
borderTopWidth: 1,
|
|
12
|
-
borderColor: colors.navigationBorder,
|
|
13
|
-
borderTopLeftRadius: 0,
|
|
14
|
-
borderTopRightRadius: 0,
|
|
15
|
-
elevation: 0,
|
|
16
|
-
shadowOpacity: 0,
|
|
17
|
-
...(Platform.OS === 'web' ? {boxShadow: 'none'} : {}),
|
|
18
|
-
}],
|
|
19
|
-
itemsRow: [styles.itemsRow, {minHeight: 64, paddingHorizontal: 12, paddingVertical: 5}],
|
|
20
|
-
item: [styles.item, {minHeight: 54, borderRadius: 12}],
|
|
21
|
-
itemLabel: [styles.itemLabel, {fontSize: 11, fontWeight: '400'}],
|
|
22
|
-
footerSlot: [styles.footerSlot, {
|
|
23
|
-
borderTopWidth: 1,
|
|
24
|
-
borderColor: colors.navigationBorder,
|
|
25
|
-
paddingHorizontal: 0,
|
|
26
|
-
minHeight: 28,
|
|
27
|
-
}],
|
|
28
|
-
};
|