@eohjsc/react-native-smart-city 0.5.0 → 0.5.1
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/package.json +2 -2
- package/src/commons/ActionGroup/OnOffTemplate/OnOffButtonTemplateStyle.js +0 -1
- package/src/commons/ActionGroup/OnOffTemplate/SwitchButtonTemplate.js +60 -48
- package/src/commons/ActionGroup/OnOffTemplate/index.js +1 -2
- package/src/commons/ActionGroup/SliderRangeTemplate.js +53 -64
- package/src/commons/ActionGroup/SliderRangeTemplateStyles.js +2 -4
- package/src/commons/ActionGroup/TerminalBoxTemplate.js +6 -6
- package/src/commons/ActionGroup/TextBoxTemplate.js +2 -2
- package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +69 -17
- package/src/commons/ActionGroup/__test__/SwitchButtonTemplate.test.js +33 -25
- package/src/commons/ActionGroup/__test__/TextBoxTemplate.test.js +19 -0
- package/src/commons/Device/RainningSensor/CurrentRainSensor.js +50 -45
- package/src/commons/Form/TextInput.js +2 -0
- package/src/commons/Header/Styles/HeaderCustomStyles.js +1 -1
- package/src/commons/HeaderAni/index.js +1 -1
- package/src/commons/Sharing/WrapHeaderScrollable.js +1 -2
- package/src/screens/Automate/AddNewAction/SetupScriptDelay.js +1 -1
- package/src/screens/Automate/Components/InputName.js +8 -2
- package/src/screens/Automate/EditActionsList/index.js +5 -5
- package/src/screens/Automate/OneTap/__test__/AddNewOneTap.test.js +17 -3
- package/src/screens/Device/components/SensorDisplayItem.js +7 -3
- package/src/screens/Device/detail.js +1 -1
- package/src/screens/Unit/ManageUnitStyles.js +1 -1
- package/src/utils/I18n/translations/en.js +2 -0
- package/src/utils/I18n/translations/vi.js +2 -0
- package/src/commons/ActionGroup/OnOffTemplate/styles.js +0 -7
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eohjsc/react-native-smart-city",
|
|
3
3
|
"title": "React Native Smart Home",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.01",
|
|
5
5
|
"description": "TODO",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
"react-native-toast-message": "^2.1.1",
|
|
199
199
|
"react-native-udp": "4.1.3",
|
|
200
200
|
"react-native-version-check": "^3.4.2",
|
|
201
|
-
"react-native-vlc-media-player": "^1.0.
|
|
201
|
+
"react-native-vlc-media-player": "^1.0.67",
|
|
202
202
|
"react-native-webview": "11.22.7",
|
|
203
203
|
"react-native-wheel-color-picker": "^1.2.0",
|
|
204
204
|
"react-native-wheel-scrollview-picker": "^1.2.2",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { memo, useCallback, useEffect, useState } from 'react';
|
|
1
|
+
import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
2
|
import { Switch, View } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import Text from '../../Text';
|
|
@@ -7,10 +7,9 @@ import styles from './OnOffButtonTemplateStyle';
|
|
|
7
7
|
import AccessibilityLabel from '../../../configs/AccessibilityLabel';
|
|
8
8
|
import { useConfigGlobalState } from '../../../iot/states';
|
|
9
9
|
|
|
10
|
-
const SwitchButtonTemplate = memo(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const {
|
|
10
|
+
const SwitchButtonTemplate = memo(({ item, doAction }) => {
|
|
11
|
+
const {
|
|
12
|
+
configuration: {
|
|
14
13
|
action_off_data,
|
|
15
14
|
action_on_data,
|
|
16
15
|
text_on,
|
|
@@ -18,54 +17,67 @@ const SwitchButtonTemplate = memo(
|
|
|
18
17
|
color_on,
|
|
19
18
|
color_off,
|
|
20
19
|
config,
|
|
21
|
-
|
|
20
|
+
is_on_value,
|
|
21
|
+
} = {},
|
|
22
|
+
id,
|
|
23
|
+
} = item;
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
const [configValues] = useConfigGlobalState('configValues');
|
|
26
|
+
const configValue = configValues[config]?.value;
|
|
27
|
+
const [isOn, setIsOn] = useState();
|
|
28
|
+
const getIsOnValue = useCallback(() => {
|
|
29
|
+
if (is_on_value && is_on_value.length > 0) {
|
|
30
|
+
return is_on_value.includes(configValue);
|
|
31
|
+
}
|
|
32
|
+
return !!configValue;
|
|
33
|
+
}, [configValue, is_on_value]);
|
|
26
34
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
setIsOn(getIsOnValue());
|
|
37
|
+
}, [getIsOnValue]);
|
|
38
|
+
|
|
39
|
+
const onValueChange = useCallback(() => {
|
|
40
|
+
setIsOn((prevIsOn) => {
|
|
41
|
+
const newState = !prevIsOn;
|
|
42
|
+
if (newState) {
|
|
43
|
+
doAction(action_on_data, null);
|
|
44
|
+
} else {
|
|
30
45
|
doAction(action_off_data, null);
|
|
31
|
-
return;
|
|
32
46
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
configValue && setIsOn(configValue?.value);
|
|
39
|
-
}, [configValue]);
|
|
47
|
+
return newState;
|
|
48
|
+
});
|
|
49
|
+
}, [action_off_data, action_on_data, doAction]);
|
|
40
50
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
/>
|
|
50
|
-
<Text
|
|
51
|
-
style={[
|
|
52
|
-
styles.textBig,
|
|
53
|
-
{ color: _isOn ? Colors.Gray8 : Colors.Gray6 },
|
|
54
|
-
]}
|
|
55
|
-
accessibilityLabel={`${AccessibilityLabel.SENSOR_STATUS}-${id}`}
|
|
56
|
-
>
|
|
57
|
-
{_isOn ? text_on : text_off}
|
|
58
|
-
</Text>
|
|
59
|
-
</View>
|
|
51
|
+
const trackColor = useMemo(
|
|
52
|
+
() => ({ false: color_off, true: color_on }),
|
|
53
|
+
[color_off, color_on]
|
|
54
|
+
);
|
|
55
|
+
const backgroundColor = useMemo(
|
|
56
|
+
() => (isOn ? color_on : color_off),
|
|
57
|
+
[color_off, color_on, isOn]
|
|
58
|
+
);
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
return (
|
|
61
|
+
<>
|
|
62
|
+
<View style={styles.barrierControlContainer}>
|
|
63
|
+
<Switch
|
|
64
|
+
trackColor={trackColor}
|
|
65
|
+
ios_backgroundColor={backgroundColor}
|
|
66
|
+
onValueChange={onValueChange}
|
|
67
|
+
value={isOn}
|
|
68
|
+
/>
|
|
69
|
+
<Text
|
|
70
|
+
style={[
|
|
71
|
+
styles.textBig,
|
|
72
|
+
{ color: isOn ? Colors.Gray8 : Colors.Gray6 },
|
|
73
|
+
]}
|
|
74
|
+
accessibilityLabel={`${AccessibilityLabel.SENSOR_STATUS}-${id}`}
|
|
75
|
+
>
|
|
76
|
+
{isOn ? text_on : text_off}
|
|
77
|
+
</Text>
|
|
78
|
+
</View>
|
|
79
|
+
</>
|
|
80
|
+
);
|
|
81
|
+
});
|
|
70
82
|
|
|
71
83
|
export default SwitchButtonTemplate;
|
|
@@ -7,7 +7,6 @@ import { useConfigGlobalState } from '../../../iot/states';
|
|
|
7
7
|
import { useUnwatchLGDeviceConfigControl } from '../../../hooks/IoT';
|
|
8
8
|
import OnOffButtonTemplate from './OnOffButtonTemplate';
|
|
9
9
|
import OnOffSimpleTemplate from './OnOffSimpleTemplate';
|
|
10
|
-
import styles from './styles';
|
|
11
10
|
|
|
12
11
|
const getComponent = (template) => {
|
|
13
12
|
switch (template) {
|
|
@@ -97,7 +96,7 @@ const OnOffTemplate = memo(({ item = {}, doAction, sensor = {} }) => {
|
|
|
97
96
|
}, [item.template]);
|
|
98
97
|
|
|
99
98
|
return (
|
|
100
|
-
<View
|
|
99
|
+
<View>
|
|
101
100
|
<Component
|
|
102
101
|
isOn={isOn}
|
|
103
102
|
triggerAction={triggerAction}
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
memo,
|
|
3
|
-
useCallback,
|
|
4
|
-
useState,
|
|
5
|
-
useEffect,
|
|
6
|
-
useMemo,
|
|
7
|
-
useRef,
|
|
8
|
-
} from 'react';
|
|
1
|
+
import React, { memo, useCallback, useState, useEffect } from 'react';
|
|
9
2
|
import { Slider } from '@miblanchard/react-native-slider';
|
|
10
3
|
|
|
11
4
|
import { View } from 'react-native';
|
|
12
|
-
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
13
5
|
import styles from './SliderRangeTemplateStyles';
|
|
14
6
|
import Text from '../Text';
|
|
15
7
|
import { Colors } from '../../configs';
|
|
@@ -18,101 +10,98 @@ import { DEVICE_TYPE } from '../../configs/Constants';
|
|
|
18
10
|
import _TextInput from '../Form/TextInput';
|
|
19
11
|
|
|
20
12
|
const SliderRangeTemplate = memo(
|
|
21
|
-
({ item
|
|
22
|
-
const
|
|
23
|
-
const { configuration = {}, title, label } = item;
|
|
13
|
+
({ item, doAction, sensor, isWidgetOrder }) => {
|
|
14
|
+
const { configuration, label = 'Slider range' } = item;
|
|
24
15
|
const [configValues] = useConfigGlobalState('configValues');
|
|
25
|
-
const {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
max_value = 100,
|
|
29
|
-
action_data,
|
|
30
|
-
} = configuration;
|
|
31
|
-
const timeout = useRef(null);
|
|
16
|
+
const { config, min_value, max_value, action_data } = configuration;
|
|
17
|
+
const [value, setValue] = useState();
|
|
18
|
+
const [processing, setProcessing] = useState(false);
|
|
32
19
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
}, [
|
|
20
|
+
const onSlidingStart = useCallback(() => {
|
|
21
|
+
setProcessing(true);
|
|
22
|
+
}, []);
|
|
36
23
|
|
|
37
|
-
const
|
|
24
|
+
const onSlidingChange = useCallback(async (number) => {
|
|
25
|
+
setValue(number[0]);
|
|
26
|
+
}, []);
|
|
38
27
|
|
|
39
|
-
const
|
|
40
|
-
async (
|
|
41
|
-
const value_brness = value[0];
|
|
28
|
+
const onSlidingComplete = useCallback(
|
|
29
|
+
async (number) => {
|
|
42
30
|
await doAction(
|
|
43
31
|
action_data,
|
|
44
|
-
JSON.stringify({ value_brness:
|
|
32
|
+
JSON.stringify({ value_brness: number[0], value: number[0] })
|
|
45
33
|
);
|
|
34
|
+
setProcessing(false);
|
|
46
35
|
},
|
|
47
36
|
[action_data, doAction]
|
|
48
37
|
);
|
|
49
38
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
setValueBrightness(value);
|
|
54
|
-
}
|
|
55
|
-
}, [config, configValues, sensor?.device_type]);
|
|
39
|
+
const onFocus = useCallback(() => {
|
|
40
|
+
setProcessing(true);
|
|
41
|
+
}, []);
|
|
56
42
|
|
|
57
|
-
const
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
43
|
+
const onEndEditing = useCallback(async () => {
|
|
44
|
+
if (value) {
|
|
45
|
+
const data = parseInt(value, 10);
|
|
46
|
+
await doAction(
|
|
47
|
+
action_data,
|
|
48
|
+
JSON.stringify({
|
|
49
|
+
value_brness: data,
|
|
50
|
+
value: data,
|
|
51
|
+
})
|
|
52
|
+
);
|
|
61
53
|
}
|
|
54
|
+
setProcessing(false);
|
|
55
|
+
}, [action_data, doAction, value]);
|
|
62
56
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (!processing) {
|
|
59
|
+
if (sensor?.device_type !== DEVICE_TYPE.LG_THINQ) {
|
|
60
|
+
const configValue = configValues[config]?.value || 0;
|
|
61
|
+
setValue(configValue);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}, [config, configValues, processing, sensor?.device_type]);
|
|
67
65
|
|
|
68
|
-
const onInputChange = (
|
|
69
|
-
if (isNaN(
|
|
66
|
+
const onInputChange = (text) => {
|
|
67
|
+
if (text === '' || isNaN(text)) {
|
|
68
|
+
setValue(min_value);
|
|
70
69
|
return;
|
|
71
70
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
clearTimeout(timeout.current);
|
|
76
|
-
}
|
|
77
|
-
if (value !== '') {
|
|
78
|
-
timeout.current = setTimeout(() => {
|
|
79
|
-
doAction(
|
|
80
|
-
action_data,
|
|
81
|
-
JSON.stringify({
|
|
82
|
-
value_brness: parseInt(value, 10),
|
|
83
|
-
value: parseInt(value, 10),
|
|
84
|
-
})
|
|
85
|
-
);
|
|
86
|
-
}, 300);
|
|
87
|
-
}
|
|
71
|
+
|
|
72
|
+
const numericValue = Number(text);
|
|
73
|
+
setValue(Math.min(max_value, Math.max(min_value, numericValue)));
|
|
88
74
|
};
|
|
89
75
|
|
|
90
76
|
return (
|
|
91
77
|
<View
|
|
92
78
|
style={(isWidgetOrder && styles.wrapOrderItem) || styles.viewBrightness}
|
|
93
79
|
>
|
|
94
|
-
<Text type="H4">{
|
|
80
|
+
<Text type="H4">{label}</Text>
|
|
95
81
|
<View style={styles.wrap}>
|
|
96
82
|
<Slider
|
|
97
83
|
step={1}
|
|
98
84
|
minimumValue={min_value}
|
|
99
85
|
maximumValue={max_value}
|
|
100
|
-
value={
|
|
101
|
-
onValueChange={onValueChange}
|
|
102
|
-
onSlidingComplete={onChangeBrightness}
|
|
86
|
+
value={value}
|
|
103
87
|
minimumTrackTintColor={Colors.Primary}
|
|
104
88
|
maximumTrackTintColor={Colors.Gray3}
|
|
105
89
|
trackStyle={styles.trackSlider}
|
|
106
90
|
thumbStyle={styles.thumbSlider}
|
|
107
91
|
containerStyle={styles.slider}
|
|
92
|
+
onSlidingStart={onSlidingStart}
|
|
93
|
+
onValueChange={onSlidingChange}
|
|
94
|
+
onSlidingComplete={onSlidingComplete}
|
|
108
95
|
/>
|
|
109
96
|
<_TextInput
|
|
110
97
|
keyboardType="numeric"
|
|
111
98
|
style={styles.text}
|
|
112
99
|
wrapStyle={styles.wrapInputStyle}
|
|
113
100
|
textInputStyle={styles.textInputStyle}
|
|
114
|
-
value={
|
|
101
|
+
value={String(value)}
|
|
102
|
+
onFocus={onFocus}
|
|
115
103
|
onChange={onInputChange}
|
|
104
|
+
onEndEditing={onEndEditing}
|
|
116
105
|
/>
|
|
117
106
|
</View>
|
|
118
107
|
</View>
|
|
@@ -29,11 +29,11 @@ export default StyleSheet.create({
|
|
|
29
29
|
marginTop: 8,
|
|
30
30
|
},
|
|
31
31
|
slider: {
|
|
32
|
-
width: '
|
|
32
|
+
width: '75%',
|
|
33
33
|
},
|
|
34
34
|
wrapInputStyle: {
|
|
35
35
|
marginTop: 0,
|
|
36
|
-
width: '
|
|
36
|
+
width: '25%',
|
|
37
37
|
},
|
|
38
38
|
textInputStyle: {
|
|
39
39
|
marginTop: 0,
|
|
@@ -41,8 +41,6 @@ export default StyleSheet.create({
|
|
|
41
41
|
borderRadius: 4,
|
|
42
42
|
paddingTop: 5,
|
|
43
43
|
paddingBottom: 5,
|
|
44
|
-
paddingHorizontal: 20,
|
|
45
|
-
|
|
46
44
|
shadowColor: Colors.Gray13,
|
|
47
45
|
borderColor: Colors.Gray5,
|
|
48
46
|
borderWidth: 1,
|
|
@@ -96,8 +96,8 @@ const TerminalBoxTemplate = ({ item, doAction, isWidgetOrder }) => {
|
|
|
96
96
|
const type = configMessage.id === from_config.id ? 'from' : 'to';
|
|
97
97
|
messages = [
|
|
98
98
|
...messages,
|
|
99
|
-
...configMessage.data.map((
|
|
100
|
-
return { x:
|
|
99
|
+
...configMessage.data.map((object) => {
|
|
100
|
+
return { x: object.x, y: object.y, type };
|
|
101
101
|
}),
|
|
102
102
|
];
|
|
103
103
|
});
|
|
@@ -147,14 +147,14 @@ const TerminalBoxTemplate = ({ item, doAction, isWidgetOrder }) => {
|
|
|
147
147
|
}
|
|
148
148
|
style={styles.scrollView}
|
|
149
149
|
>
|
|
150
|
-
{allMessages.map((
|
|
150
|
+
{allMessages.map((object, index) => {
|
|
151
151
|
return (
|
|
152
152
|
<View
|
|
153
153
|
key={index}
|
|
154
|
-
style={
|
|
154
|
+
style={object.type === 'to' ? styles.to : styles.from}
|
|
155
155
|
>
|
|
156
|
-
<Text>{
|
|
157
|
-
<Text>{moment(
|
|
156
|
+
<Text>{object.y}</Text>
|
|
157
|
+
<Text>{moment(object.x).format('DD/MM/YYYY HH:mm:ss')}</Text>
|
|
158
158
|
</View>
|
|
159
159
|
);
|
|
160
160
|
})}
|
|
@@ -30,8 +30,8 @@ const TextBoxTemplate = ({ item, doAction, isWidgetOrder }) => {
|
|
|
30
30
|
setValue(e);
|
|
31
31
|
};
|
|
32
32
|
const valueText = useMemo(() => {
|
|
33
|
-
return configValues[config
|
|
34
|
-
}, [config
|
|
33
|
+
return configValues[config?.id]?.value || ''; // config undefined when is_configuration_ready = False
|
|
34
|
+
}, [config?.id, configValues]);
|
|
35
35
|
|
|
36
36
|
return (
|
|
37
37
|
<View style={(isWidgetOrder && styles.wrapOrderItem) || styles.wrap}>
|
|
@@ -7,6 +7,7 @@ import { mockSCStore } from '../../../context/mockStore';
|
|
|
7
7
|
import { useConfigGlobalState } from '../../../iot/states';
|
|
8
8
|
import { Slider } from '@miblanchard/react-native-slider';
|
|
9
9
|
import _TextInput from '../../Form/TextInput';
|
|
10
|
+
import { DEVICE_TYPE } from '../../../configs/Constants';
|
|
10
11
|
|
|
11
12
|
jest.mock('../../../iot/Monitor');
|
|
12
13
|
const mockDoAction = jest.fn();
|
|
@@ -14,9 +15,14 @@ jest.mock('../../../iot/states', () => ({
|
|
|
14
15
|
useConfigGlobalState: jest.fn(),
|
|
15
16
|
}));
|
|
16
17
|
|
|
17
|
-
const wrapComponent = (item, doAction, sensor) => (
|
|
18
|
+
const wrapComponent = (item, doAction, sensor, isWidgetOrder = false) => (
|
|
18
19
|
<SCProvider initState={mockSCStore({})}>
|
|
19
|
-
<SliderRangeTemplate
|
|
20
|
+
<SliderRangeTemplate
|
|
21
|
+
item={item}
|
|
22
|
+
doAction={doAction}
|
|
23
|
+
sensor={sensor}
|
|
24
|
+
isWidgetOrder={isWidgetOrder}
|
|
25
|
+
/>
|
|
20
26
|
</SCProvider>
|
|
21
27
|
);
|
|
22
28
|
|
|
@@ -37,12 +43,15 @@ describe('Test SliderRangeTemplate', () => {
|
|
|
37
43
|
watchMultiConfigs.mockClear();
|
|
38
44
|
mockDoAction.mockClear();
|
|
39
45
|
displayItem = {
|
|
40
|
-
template: '
|
|
46
|
+
template: 'slider_range_template',
|
|
47
|
+
is_configuration_ready: true,
|
|
41
48
|
configuration: {
|
|
42
49
|
config: 5,
|
|
43
50
|
action_data: actionData,
|
|
51
|
+
min_value: 0,
|
|
52
|
+
max_value: 100,
|
|
44
53
|
},
|
|
45
|
-
|
|
54
|
+
label: '',
|
|
46
55
|
};
|
|
47
56
|
});
|
|
48
57
|
|
|
@@ -53,10 +62,16 @@ describe('Test SliderRangeTemplate', () => {
|
|
|
53
62
|
wrapper = await create(wrapComponent(displayItem, mockDoAction, sensor));
|
|
54
63
|
});
|
|
55
64
|
const instance = wrapper.root;
|
|
56
|
-
const
|
|
57
|
-
expect(
|
|
65
|
+
const sliderRange = instance.findByType(Slider);
|
|
66
|
+
expect(sliderRange.props.value).toBe(0);
|
|
58
67
|
await act(async () => {
|
|
59
|
-
await
|
|
68
|
+
await sliderRange.props.onSlidingStart();
|
|
69
|
+
});
|
|
70
|
+
await act(async () => {
|
|
71
|
+
await sliderRange.props.onValueChange([50]);
|
|
72
|
+
});
|
|
73
|
+
await act(async () => {
|
|
74
|
+
await sliderRange.props.onSlidingComplete([50]);
|
|
60
75
|
});
|
|
61
76
|
expect(mockDoAction).toHaveBeenCalledWith(
|
|
62
77
|
actionData,
|
|
@@ -78,8 +93,8 @@ describe('Test SliderRangeTemplate', () => {
|
|
|
78
93
|
wrapper = await create(wrapComponent(displayItem, mockDoAction, sensor));
|
|
79
94
|
});
|
|
80
95
|
const instance = wrapper.root;
|
|
81
|
-
const
|
|
82
|
-
expect(
|
|
96
|
+
const sliderRange = instance.findByType(Slider);
|
|
97
|
+
expect(sliderRange.props.value).toBe(50);
|
|
83
98
|
});
|
|
84
99
|
|
|
85
100
|
it('test change input invalid number', async () => {
|
|
@@ -91,22 +106,24 @@ describe('Test SliderRangeTemplate', () => {
|
|
|
91
106
|
},
|
|
92
107
|
jest.fn(),
|
|
93
108
|
]);
|
|
94
|
-
const sensor = { is_managed_by_backend: true, name: 'Sensor' };
|
|
95
109
|
|
|
96
110
|
await act(async () => {
|
|
97
|
-
wrapper = await create(wrapComponent(displayItem, mockDoAction
|
|
111
|
+
wrapper = await create(wrapComponent(displayItem, mockDoAction));
|
|
98
112
|
});
|
|
99
113
|
const instance = wrapper.root;
|
|
100
114
|
const textInput = instance.findByType(_TextInput);
|
|
101
115
|
expect(textInput.props.value).toEqual('50');
|
|
102
116
|
|
|
103
117
|
await act(async () => {
|
|
104
|
-
await textInput.props.onChange('
|
|
118
|
+
await textInput.props.onChange('');
|
|
119
|
+
});
|
|
120
|
+
await act(async () => {
|
|
121
|
+
await textInput.props.onEndEditing('');
|
|
105
122
|
});
|
|
106
123
|
expect(textInput.props.value).toEqual('50'); // not change value
|
|
107
124
|
});
|
|
108
125
|
|
|
109
|
-
it('test change input called doAction', async () => {
|
|
126
|
+
it('test change input text called doAction', async () => {
|
|
110
127
|
useConfigGlobalState.mockImplementation(() => [
|
|
111
128
|
{
|
|
112
129
|
5: {
|
|
@@ -115,24 +132,59 @@ describe('Test SliderRangeTemplate', () => {
|
|
|
115
132
|
},
|
|
116
133
|
jest.fn(),
|
|
117
134
|
]);
|
|
118
|
-
const sensor = { is_managed_by_backend: true, name: 'Sensor' };
|
|
119
135
|
|
|
120
136
|
await act(async () => {
|
|
121
|
-
wrapper = await create(wrapComponent(displayItem, mockDoAction
|
|
137
|
+
wrapper = await create(wrapComponent(displayItem, mockDoAction));
|
|
122
138
|
});
|
|
123
139
|
|
|
124
140
|
const instance = wrapper.root;
|
|
125
141
|
let textInput = instance.findByType(_TextInput);
|
|
126
|
-
|
|
142
|
+
await act(async () => {
|
|
143
|
+
await textInput.props.onFocus();
|
|
144
|
+
});
|
|
127
145
|
await act(async () => {
|
|
128
146
|
await textInput.props.onChange('60');
|
|
129
147
|
});
|
|
130
148
|
await act(async () => {
|
|
131
|
-
|
|
149
|
+
await textInput.props.onEndEditing('60');
|
|
132
150
|
});
|
|
133
151
|
expect(mockDoAction).toHaveBeenCalledWith(
|
|
134
152
|
actionData,
|
|
135
153
|
JSON.stringify({ value_brness: 60, value: 60 })
|
|
136
154
|
);
|
|
137
155
|
});
|
|
156
|
+
|
|
157
|
+
it('render template SliderRangeTemplate not ready', async () => {
|
|
158
|
+
useConfigGlobalState.mockImplementation(() => [
|
|
159
|
+
{
|
|
160
|
+
5: {
|
|
161
|
+
value: 50,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
jest.fn(),
|
|
165
|
+
]);
|
|
166
|
+
const sensor = { is_managed_by_backend: true, name: 'Sensor' };
|
|
167
|
+
displayItem.is_configuration_ready = false;
|
|
168
|
+
displayItem.configuration = {};
|
|
169
|
+
displayItem.label = undefined;
|
|
170
|
+
await act(async () => {
|
|
171
|
+
wrapper = await create(wrapComponent(displayItem, mockDoAction, sensor));
|
|
172
|
+
});
|
|
173
|
+
const instance = wrapper.root;
|
|
174
|
+
const sliderRange = instance.findByType(Slider);
|
|
175
|
+
expect(sliderRange.props.value).toBe(0);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('render template SliderRangeTemplate sensor device_type LG_THINQ and isWidgetOrder change position', async () => {
|
|
179
|
+
useConfigGlobalState.mockImplementation(() => [{}, jest.fn()]);
|
|
180
|
+
const sensor = { device_type: DEVICE_TYPE.LG_THINQ };
|
|
181
|
+
await act(async () => {
|
|
182
|
+
wrapper = await create(
|
|
183
|
+
wrapComponent(displayItem, mockDoAction, sensor, true)
|
|
184
|
+
);
|
|
185
|
+
});
|
|
186
|
+
const instance = wrapper.root;
|
|
187
|
+
const sliderRange = instance.findByType(Slider);
|
|
188
|
+
expect(sliderRange.props.value).toBe(0);
|
|
189
|
+
});
|
|
138
190
|
});
|
|
@@ -13,7 +13,7 @@ jest.mock('../../../iot/states', () => ({
|
|
|
13
13
|
|
|
14
14
|
const wrapComponent = (item, mockDoAction, isOn) => (
|
|
15
15
|
<SCProvider initState={mockSCStore({})}>
|
|
16
|
-
<SwitchButtonTemplate item={item} doAction={mockDoAction}
|
|
16
|
+
<SwitchButtonTemplate item={item} doAction={mockDoAction} />
|
|
17
17
|
</SCProvider>
|
|
18
18
|
);
|
|
19
19
|
|
|
@@ -76,7 +76,23 @@ describe('Test SwitchButtonTemplate', () => {
|
|
|
76
76
|
expect(switchButton.props.value).toEqual(state);
|
|
77
77
|
};
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
const assertActionCall = async (action_data) => {
|
|
80
|
+
const mockDoAction = jest.fn();
|
|
81
|
+
await act(async () => {
|
|
82
|
+
wrapper = await create(wrapComponent(displayItem, mockDoAction));
|
|
83
|
+
});
|
|
84
|
+
expect(mockDoAction).not.toHaveBeenCalled();
|
|
85
|
+
const root = wrapper.root;
|
|
86
|
+
|
|
87
|
+
const item = root.findByType(Switch);
|
|
88
|
+
await act(async () => {
|
|
89
|
+
item.props.onValueChange();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(mockDoAction).toHaveBeenCalledWith(action_data, null);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
it('render state on action off', async () => {
|
|
80
96
|
useConfigGlobalState.mockImplementation(() => [
|
|
81
97
|
{
|
|
82
98
|
1: {
|
|
@@ -86,9 +102,10 @@ describe('Test SwitchButtonTemplate', () => {
|
|
|
86
102
|
jest.fn(),
|
|
87
103
|
]);
|
|
88
104
|
await assertRender(true);
|
|
105
|
+
await assertActionCall(actionOffData);
|
|
89
106
|
});
|
|
90
107
|
|
|
91
|
-
it('render state off', async () => {
|
|
108
|
+
it('render state off action on', async () => {
|
|
92
109
|
useConfigGlobalState.mockImplementation(() => [
|
|
93
110
|
{
|
|
94
111
|
1: {
|
|
@@ -98,29 +115,20 @@ describe('Test SwitchButtonTemplate', () => {
|
|
|
98
115
|
jest.fn(),
|
|
99
116
|
]);
|
|
100
117
|
await assertRender(false);
|
|
118
|
+
await assertActionCall(actionOnData);
|
|
101
119
|
});
|
|
102
120
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
expect(mockDoAction).toHaveBeenCalledWith(action_data, null);
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
it('action state on', async () => {
|
|
120
|
-
await assertActionCall(true, actionOffData);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('action state off', async () => {
|
|
124
|
-
await assertActionCall(false, actionOnData);
|
|
121
|
+
it('render with is_on_value 0 action on', async () => {
|
|
122
|
+
displayItem.configuration.is_on_value = [0];
|
|
123
|
+
useConfigGlobalState.mockImplementation(() => [
|
|
124
|
+
{
|
|
125
|
+
1: {
|
|
126
|
+
value: 1,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
jest.fn(),
|
|
130
|
+
]);
|
|
131
|
+
await assertRender(false);
|
|
132
|
+
await assertActionCall(actionOnData);
|
|
125
133
|
});
|
|
126
134
|
});
|
|
@@ -120,6 +120,25 @@ describe('Test TextBoxTemplate', () => {
|
|
|
120
120
|
const instance = wrapper.root;
|
|
121
121
|
const views = instance.findAllByType(View);
|
|
122
122
|
|
|
123
|
+
expect(views[0].props.style).toEqual({
|
|
124
|
+
flex: 1,
|
|
125
|
+
flexDirection: 'row',
|
|
126
|
+
justifyContent: 'space-between',
|
|
127
|
+
padding: 16,
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
it('render template is_configuration_ready = False', async () => {
|
|
131
|
+
const mockDoAction = jest.fn();
|
|
132
|
+
displayItem = {
|
|
133
|
+
is_configuration_ready: false,
|
|
134
|
+
configuration: {},
|
|
135
|
+
};
|
|
136
|
+
await act(async () => {
|
|
137
|
+
wrapper = await create(wrapComponent(displayItem, mockDoAction, true));
|
|
138
|
+
});
|
|
139
|
+
const instance = wrapper.root;
|
|
140
|
+
const views = instance.findAllByType(View);
|
|
141
|
+
|
|
123
142
|
expect(views[0].props.style).toEqual({
|
|
124
143
|
flex: 1,
|
|
125
144
|
flexDirection: 'row',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
2
|
import { View, StyleSheet } from 'react-native';
|
|
3
3
|
import LinearGradient from 'react-native-linear-gradient';
|
|
4
4
|
|
|
@@ -8,54 +8,62 @@ import Text from '../../../commons/Text';
|
|
|
8
8
|
import IconComponent from '../../IconComponent';
|
|
9
9
|
import images from '../../../configs/Images';
|
|
10
10
|
import FImage from '../../FImage';
|
|
11
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
11
12
|
|
|
12
|
-
const CurrentRainSensor =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
25
|
-
const { text, backgroundColor, borderColor, icon, icon_kit_data } =
|
|
26
|
-
item.evaluate || {};
|
|
13
|
+
const CurrentRainSensor = ({
|
|
14
|
+
data = [],
|
|
15
|
+
isWidgetOrder,
|
|
16
|
+
size = 180,
|
|
17
|
+
textType = 'H2',
|
|
18
|
+
iconSize = 30,
|
|
19
|
+
}) => {
|
|
20
|
+
const t = useTranslations();
|
|
21
|
+
const item = useMemo(
|
|
22
|
+
() => (data.length ? data[0] : { evaluate: {} }),
|
|
23
|
+
[data]
|
|
24
|
+
);
|
|
27
25
|
|
|
26
|
+
if (!item.evaluate) {
|
|
28
27
|
return (
|
|
29
28
|
<View style={[styles.standard, isWidgetOrder && styles.marginBottomZero]}>
|
|
30
|
-
<
|
|
31
|
-
size={size}
|
|
32
|
-
backgroundColor={backgroundColor}
|
|
33
|
-
borderWidth={2}
|
|
34
|
-
borderColor={borderColor}
|
|
35
|
-
style={styles.center}
|
|
36
|
-
>
|
|
37
|
-
<LinearGradient
|
|
38
|
-
style={styles.linearView}
|
|
39
|
-
colors={[Colors.TransparentWhite, 'white']}
|
|
40
|
-
start={{ x: 1, y: 0 }}
|
|
41
|
-
end={{ x: 1, y: 1 }}
|
|
42
|
-
/>
|
|
43
|
-
{icon_kit_data?.icon || icon ? (
|
|
44
|
-
<IconComponent size={iconSize} icon={icon_kit_data?.icon || icon} />
|
|
45
|
-
) : (
|
|
46
|
-
<FImage
|
|
47
|
-
source={images.activeCurrentSensor}
|
|
48
|
-
style={styles.iconDefault}
|
|
49
|
-
/>
|
|
50
|
-
)}
|
|
51
|
-
<Text type={textType} style={styles.text}>
|
|
52
|
-
{text}
|
|
53
|
-
</Text>
|
|
54
|
-
</CircleView>
|
|
29
|
+
<Text>{t('widget_have_not_been_shared', { widget: 'Circle' })}</Text>
|
|
55
30
|
</View>
|
|
56
31
|
);
|
|
57
32
|
}
|
|
58
|
-
|
|
33
|
+
|
|
34
|
+
const { text, backgroundColor, borderColor, icon, icon_kit_data } =
|
|
35
|
+
item.evaluate;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<View style={[styles.standard, isWidgetOrder && styles.marginBottomZero]}>
|
|
39
|
+
<CircleView
|
|
40
|
+
size={size}
|
|
41
|
+
backgroundColor={backgroundColor}
|
|
42
|
+
borderWidth={2}
|
|
43
|
+
borderColor={borderColor}
|
|
44
|
+
style={styles.center}
|
|
45
|
+
>
|
|
46
|
+
<LinearGradient
|
|
47
|
+
style={styles.linearView}
|
|
48
|
+
colors={[Colors.TransparentWhite, 'white']}
|
|
49
|
+
start={{ x: 1, y: 0 }}
|
|
50
|
+
end={{ x: 1, y: 1 }}
|
|
51
|
+
/>
|
|
52
|
+
{icon_kit_data?.icon || icon ? (
|
|
53
|
+
<IconComponent size={iconSize} icon={icon_kit_data?.icon || icon} />
|
|
54
|
+
) : (
|
|
55
|
+
<FImage
|
|
56
|
+
source={images.activeCurrentSensor}
|
|
57
|
+
style={styles.iconDefault}
|
|
58
|
+
/>
|
|
59
|
+
)}
|
|
60
|
+
<Text type={textType} style={styles.text}>
|
|
61
|
+
{text}
|
|
62
|
+
</Text>
|
|
63
|
+
</CircleView>
|
|
64
|
+
</View>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
59
67
|
|
|
60
68
|
export default CurrentRainSensor;
|
|
61
69
|
|
|
@@ -68,9 +76,6 @@ const styles = StyleSheet.create({
|
|
|
68
76
|
marginBottomZero: {
|
|
69
77
|
marginBottom: 0,
|
|
70
78
|
},
|
|
71
|
-
flatlistContent: {
|
|
72
|
-
paddingHorizontal: 16,
|
|
73
|
-
},
|
|
74
79
|
center: {
|
|
75
80
|
alignItems: 'center',
|
|
76
81
|
justifyContent: 'center',
|
|
@@ -30,6 +30,7 @@ const _TextInput = ({
|
|
|
30
30
|
selection,
|
|
31
31
|
onSelectionChange,
|
|
32
32
|
accessibilityLabelError,
|
|
33
|
+
onEndEditing,
|
|
33
34
|
}) => {
|
|
34
35
|
const errorStyle = !!errorText && styles.errorWrap;
|
|
35
36
|
return (
|
|
@@ -69,6 +70,7 @@ const _TextInput = ({
|
|
|
69
70
|
{...(value ? { value } : {})}
|
|
70
71
|
selection={selection}
|
|
71
72
|
onSelectionChange={onSelectionChange}
|
|
73
|
+
onEndEditing={onEndEditing}
|
|
72
74
|
/>
|
|
73
75
|
{extraText && extraText}
|
|
74
76
|
{!!errorText && (
|
|
@@ -10,7 +10,7 @@ import { AccessibilityLabel } from '../../configs/Constants';
|
|
|
10
10
|
|
|
11
11
|
const screenHeight = Constants.height;
|
|
12
12
|
const default_height = 45;
|
|
13
|
-
const paddingIos = getStatusBarHeight() +
|
|
13
|
+
const paddingIos = getStatusBarHeight() + 20;
|
|
14
14
|
export const title_height = 44;
|
|
15
15
|
export const heightHeader = default_height + title_height + paddingIos;
|
|
16
16
|
|
|
@@ -45,7 +45,7 @@ const SetupScriptDelay = ({ route }) => {
|
|
|
45
45
|
}, [automateId, navigate, delay, t]);
|
|
46
46
|
|
|
47
47
|
const canSave = useMemo(() => {
|
|
48
|
-
const value = parseInt(delay);
|
|
48
|
+
const value = parseInt(delay, 10);
|
|
49
49
|
if (!Number.isInteger(value) || value <= 0 || value > 3600) {
|
|
50
50
|
return false;
|
|
51
51
|
}
|
|
@@ -15,8 +15,13 @@ const InputName = ({ title, placeholder }) => {
|
|
|
15
15
|
const t = useTranslations();
|
|
16
16
|
const { navigate } = useNavigation();
|
|
17
17
|
const [name, setName] = useState(automate?.name);
|
|
18
|
-
|
|
18
|
+
const [processing, setProcessing] = useState(false);
|
|
19
19
|
const handleContinue = useCallback(async () => {
|
|
20
|
+
if (processing) {
|
|
21
|
+
/* istanbul ignore next */
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
setProcessing(true);
|
|
20
25
|
Keyboard.dismiss();
|
|
21
26
|
|
|
22
27
|
const params = {
|
|
@@ -37,7 +42,8 @@ const InputName = ({ title, placeholder }) => {
|
|
|
37
42
|
},
|
|
38
43
|
});
|
|
39
44
|
}
|
|
40
|
-
|
|
45
|
+
setProcessing(false);
|
|
46
|
+
}, [processing, automate, name, navigate, closeScreen]);
|
|
41
47
|
|
|
42
48
|
return (
|
|
43
49
|
<NewActionWrapper
|
|
@@ -83,7 +83,7 @@ const EditActionsList = memo(() => {
|
|
|
83
83
|
paddedIndex,
|
|
84
84
|
icon,
|
|
85
85
|
content,
|
|
86
|
-
|
|
86
|
+
onPress,
|
|
87
87
|
isActive,
|
|
88
88
|
drag,
|
|
89
89
|
}) => (
|
|
@@ -103,7 +103,7 @@ const EditActionsList = memo(() => {
|
|
|
103
103
|
<View style={styles.contentItem}>{content}</View>
|
|
104
104
|
<TouchableOpacity
|
|
105
105
|
accessibilityLabel={AccessibilityLabel.BUTTON_REMOVE_EDIT_ACTION_LIST}
|
|
106
|
-
onPress={
|
|
106
|
+
onPress={onPress}
|
|
107
107
|
style={styles.closeButton}
|
|
108
108
|
>
|
|
109
109
|
<Close />
|
|
@@ -148,7 +148,7 @@ const EditActionsList = memo(() => {
|
|
|
148
148
|
</Text>
|
|
149
149
|
</>
|
|
150
150
|
}
|
|
151
|
-
|
|
151
|
+
onPress={() => onPressRemove(item)}
|
|
152
152
|
isActive={isActive}
|
|
153
153
|
drag={drag}
|
|
154
154
|
/>
|
|
@@ -176,7 +176,7 @@ const EditActionsList = memo(() => {
|
|
|
176
176
|
</Text>
|
|
177
177
|
</>
|
|
178
178
|
}
|
|
179
|
-
|
|
179
|
+
onPress={() => onPressRemove(item)}
|
|
180
180
|
isActive={isActive}
|
|
181
181
|
drag={drag}
|
|
182
182
|
/>
|
|
@@ -203,7 +203,7 @@ const EditActionsList = memo(() => {
|
|
|
203
203
|
</Text>
|
|
204
204
|
</>
|
|
205
205
|
}
|
|
206
|
-
|
|
206
|
+
onPress={() => onPressRemove(item)}
|
|
207
207
|
isActive={isActive}
|
|
208
208
|
drag={drag}
|
|
209
209
|
/>
|
|
@@ -38,6 +38,7 @@ describe('test OneTap', () => {
|
|
|
38
38
|
unit: { id: 1 },
|
|
39
39
|
isMultiUnits: false,
|
|
40
40
|
isAutomateTab: false,
|
|
41
|
+
closeScreen: Routes.ScriptDetail,
|
|
41
42
|
},
|
|
42
43
|
};
|
|
43
44
|
|
|
@@ -66,15 +67,28 @@ describe('test OneTap', () => {
|
|
|
66
67
|
await inputName[0].props.onChangeText('Tap to up');
|
|
67
68
|
});
|
|
68
69
|
|
|
69
|
-
const item = instance.
|
|
70
|
+
const item = instance.find(
|
|
70
71
|
(el) =>
|
|
71
72
|
el.props.accessibilityLabel === AccessibilityLabel.BOTTOM_VIEW_MAIN &&
|
|
72
73
|
el.type === TouchableOpacity
|
|
73
74
|
);
|
|
74
75
|
|
|
75
|
-
expect(item).toHaveLength(1);
|
|
76
76
|
await act(async () => {
|
|
77
|
-
await item
|
|
77
|
+
await item.props.onPress();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(mockedNavigate).toHaveBeenCalledWith({
|
|
81
|
+
merge: true,
|
|
82
|
+
name: Routes.ScriptDetail,
|
|
83
|
+
params: {
|
|
84
|
+
newAutomate: {
|
|
85
|
+
id: 1,
|
|
86
|
+
script: { id: 1, name: 'William Miller' },
|
|
87
|
+
type: 'one_tap',
|
|
88
|
+
unit: 1,
|
|
89
|
+
weekday_repeat: [],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
78
92
|
});
|
|
79
93
|
});
|
|
80
94
|
|
|
@@ -22,7 +22,11 @@ import { useEvaluateValue } from '../hooks/useEvaluateValue';
|
|
|
22
22
|
import styles from '../styles';
|
|
23
23
|
import { DetailHistoryChart } from './DetailHistoryChart';
|
|
24
24
|
import VisualChart from './VisualChart';
|
|
25
|
-
|
|
25
|
+
import { standardizeCameraScreenSize } from '../../../utils/Utils';
|
|
26
|
+
import { Device } from '../../../configs';
|
|
27
|
+
const { standardizeWidth, standardizeHeight } = standardizeCameraScreenSize(
|
|
28
|
+
Device.screenWidth - 32
|
|
29
|
+
);
|
|
26
30
|
export const SensorDisplayItem = ({
|
|
27
31
|
item = {},
|
|
28
32
|
sensor,
|
|
@@ -147,8 +151,8 @@ export const SensorDisplayItem = ({
|
|
|
147
151
|
}}
|
|
148
152
|
key={`camera-device-${id}`}
|
|
149
153
|
cameraName={name}
|
|
150
|
-
width=
|
|
151
|
-
height=
|
|
154
|
+
width={standardizeWidth}
|
|
155
|
+
height={standardizeHeight}
|
|
152
156
|
/>
|
|
153
157
|
</View>
|
|
154
158
|
);
|
|
@@ -512,7 +512,7 @@ const DeviceDetail = ({ route }) => {
|
|
|
512
512
|
const { configs, options, config, from_config, to_config } =
|
|
513
513
|
configuration;
|
|
514
514
|
|
|
515
|
-
configs?.forEach((
|
|
515
|
+
configs?.forEach((object) => configIdsSet.add(object.id));
|
|
516
516
|
options?.forEach((option) => configIdsSet.add(option.config));
|
|
517
517
|
|
|
518
518
|
if (config) {
|
|
@@ -1464,6 +1464,8 @@ export default {
|
|
|
1464
1464
|
end_devices_added: 'end devices added',
|
|
1465
1465
|
bellow_widget_is_not_configured: 'Bellow widget is not configured',
|
|
1466
1466
|
bellow_widget_is_wrongly_configured: 'Bellow widget is wrongly configured',
|
|
1467
|
+
widget_have_not_been_shared:
|
|
1468
|
+
'{widget} widget have not been shared. Please contact the owner',
|
|
1467
1469
|
'customize...': 'Customize...',
|
|
1468
1470
|
uri_invalid: 'URI invalid',
|
|
1469
1471
|
when_value_is: 'When value is',
|
|
@@ -1474,6 +1474,8 @@ export default {
|
|
|
1474
1474
|
end_devices_added: 'thiết bị được thêm vào',
|
|
1475
1475
|
bellow_widget_is_not_configured: 'Tiện ích bên dưới chưa được cấu hình',
|
|
1476
1476
|
bellow_widget_is_wrongly_configured: 'Tiện ích bên dưới được cấu hình sai',
|
|
1477
|
+
widget_have_not_been_shared:
|
|
1478
|
+
'Tiện ích {widget} chưa được chia sẽ. Vui lòng liên hệ với chủ sở hữu',
|
|
1477
1479
|
'customize...': 'Tùy chỉnh...',
|
|
1478
1480
|
uri_invalid: 'URI không hợp lệ',
|
|
1479
1481
|
when_value_is: 'Khi giá trị là',
|