@eohjsc/react-native-smart-city 0.3.53 → 0.3.54
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 -1
- package/src/Images/Common/loading-circle.json +1 -0
- package/src/commons/ActionGroup/index.js +6 -2
- package/src/commons/ButtonPopup/index.js +2 -0
- package/src/commons/DevMode/EmptyComponent.js +2 -2
- package/src/commons/Device/WaterQualitySensor/ListQualityIndicator.js +9 -6
- package/src/commons/FullLoading/__test__/index.test.js +43 -0
- package/src/commons/FullLoading/index.js +13 -3
- package/src/commons/Header/HeaderCustom.js +6 -1
- package/src/commons/Header/Styles/HeaderCustomStyles.js +4 -1
- package/src/commons/Processing/index.js +20 -18
- package/src/commons/Processing/styles.js +4 -3
- package/src/commons/StatusBox/index.js +23 -5
- package/src/commons/StatusBox/styles.js +7 -6
- package/src/configs/API.js +1 -1
- package/src/configs/AccessibilityLabel.js +1 -1
- package/src/configs/Colors.js +2 -0
- package/src/hooks/IoT/__test__/useRemoteControl.test.js +22 -21
- package/src/hooks/IoT/useRemoteControl.js +8 -7
- package/src/iot/RemoteControl/Bluetooth.js +1 -1
- package/src/navigations/Main.js +3 -1
- package/src/screens/AddNewGateway/ConnectingModbusDevice.js +16 -19
- package/src/screens/AddNewGateway/ConnectingWifiGuide.js +139 -75
- package/src/screens/AddNewGateway/ConnectingWifiGuideStyles.js +8 -7
- package/src/screens/AddNewGateway/RenameNewDevices.js +147 -70
- package/src/screens/AddNewGateway/RenameNewDevicesStyles.js +35 -16
- package/src/screens/AddNewGateway/ShareWifiPassword.js +176 -107
- package/src/screens/AddNewGateway/ShareWifiPasswordStyles.js +14 -1
- package/src/screens/AddNewGateway/__test__/ConnectingWifiGuide.test.js +53 -7
- package/src/screens/AddNewGateway/__test__/RenameNewDevices.test.js +44 -10
- package/src/screens/AddNewGateway/hooks/__Tests__/useStateAlertRename.test.js +57 -0
- package/src/screens/AddNewGateway/hooks/__Tests__/useWifiManage.test.js +22 -0
- package/src/screens/AddNewGateway/hooks/useWifiManage.js +29 -0
- package/src/screens/Device/__test__/detail.test.js +7 -1
- package/src/screens/Device/components/SensorDisplayItem.js +10 -2
- package/src/screens/Gateway/GatewayInfo/__test__/index.test.js +1 -1
- package/src/screens/Gateway/__test__/index.test.js +1 -1
- package/src/screens/Gateway/components/GatewayItem/index.js +1 -1
- package/src/screens/Gateway/components/GatewayItem/styles.js +4 -0
- package/src/screens/Gateway/components/Information/__test__/index.test.js +1 -1
- package/src/screens/Gateway/components/Information/index.js +5 -3
- package/src/screens/Gateway/components/Information/styles.js +3 -0
- package/src/screens/Gateway/components/TabPaneCT/index.js +31 -27
- package/src/screens/Gateway/components/TabPaneCT/styles.js +7 -1
- package/src/screens/Gateway/index.js +10 -10
- package/src/screens/Gateway/styles.js +3 -1
- package/src/screens/Notification/__test__/Notification.test.js +9 -1
- package/src/screens/Notification/index.js +7 -4
- package/src/screens/Template/EditTemplate.js +1 -1
- package/src/screens/Template/Styles/indexStyles.js +1 -1
- package/src/screens/Template/detail.js +26 -2
- package/src/screens/Template/index.js +1 -1
- package/src/screens/Unit/MoreMenu.js +56 -58
- package/src/screens/Unit/__test__/MoreMenu.test.js +59 -0
- package/src/screens/Unit/hook/useUnitConnectRemoteDevices.js +6 -3
- package/src/screens/UnitSummary/components/RunningDevices/__test__/index.test.js +7 -1
- package/src/utils/I18n/translations/en.json +8 -8
- package/src/utils/I18n/translations/vi.json +8 -7
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { memo, useMemo, useState, useCallback, useEffect } from 'react';
|
|
2
2
|
import { View, TouchableOpacity } from 'react-native';
|
|
3
3
|
import { Icon } from '@ant-design/react-native';
|
|
4
|
+
import { useFocusEffect } from '@react-navigation/native';
|
|
4
5
|
|
|
5
6
|
import styles from './styles/indexStyles';
|
|
6
7
|
import { API, Colors } from '../../configs';
|
|
@@ -59,10 +60,12 @@ const Notification = memo(() => {
|
|
|
59
60
|
}
|
|
60
61
|
}, []);
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
useFocusEffect(
|
|
64
|
+
useCallback(() => {
|
|
65
|
+
fetchNotifications(1);
|
|
66
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
67
|
+
}, [])
|
|
68
|
+
);
|
|
66
69
|
|
|
67
70
|
const handleOnLoadMore = useCallback(() => {
|
|
68
71
|
page += 1;
|
|
@@ -19,6 +19,7 @@ import t from '../../hooks/Common/useTranslations';
|
|
|
19
19
|
import Routes from '../../utils/Route';
|
|
20
20
|
import { SensorDisplayItem } from '../Device/components/SensorDisplayItem';
|
|
21
21
|
import { axiosGet } from '../../utils/Apis/axios';
|
|
22
|
+
import { watchMultiConfigs } from '../../iot/Monitor';
|
|
22
23
|
|
|
23
24
|
const TemplateDetail = () => {
|
|
24
25
|
const refMenuAction = useRef();
|
|
@@ -30,6 +31,23 @@ const TemplateDetail = () => {
|
|
|
30
31
|
const [data, setData] = useState([]);
|
|
31
32
|
const [isLoading, setIsLoading] = useState(true);
|
|
32
33
|
|
|
34
|
+
const listIds = useMemo(() => {
|
|
35
|
+
const configIds = [];
|
|
36
|
+
// eslint-disable-next-line no-shadow
|
|
37
|
+
data.forEach((item) => {
|
|
38
|
+
switch (item.type) {
|
|
39
|
+
case 'value':
|
|
40
|
+
(item?.configuration?.configs || []).forEach((config) => {
|
|
41
|
+
configIds.push(config.id);
|
|
42
|
+
});
|
|
43
|
+
break;
|
|
44
|
+
default:
|
|
45
|
+
configIds.push(item?.configuration?.configuration?.config);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
return configIds;
|
|
49
|
+
}, [data]);
|
|
50
|
+
|
|
33
51
|
// eslint-disable-next-line no-shadow
|
|
34
52
|
const onItemClick = useCallback((item) => {
|
|
35
53
|
item.doAction();
|
|
@@ -67,7 +85,7 @@ const TemplateDetail = () => {
|
|
|
67
85
|
const listMenuItem = useMemo(
|
|
68
86
|
() => [
|
|
69
87
|
{
|
|
70
|
-
text: t('
|
|
88
|
+
text: t('edit_dashboard'),
|
|
71
89
|
doAction: goToDetail(Routes.EditTemplate, { setData, data }),
|
|
72
90
|
},
|
|
73
91
|
{
|
|
@@ -79,7 +97,7 @@ const TemplateDetail = () => {
|
|
|
79
97
|
doAction: goToDetail(Routes.GatewayList),
|
|
80
98
|
},
|
|
81
99
|
{
|
|
82
|
-
text: t('
|
|
100
|
+
text: t('delete_dashboard'),
|
|
83
101
|
doAction: goToDetail(Routes.GatewayList),
|
|
84
102
|
textStyle: { color: Colors.Red },
|
|
85
103
|
},
|
|
@@ -114,6 +132,10 @@ const TemplateDetail = () => {
|
|
|
114
132
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
115
133
|
}, []);
|
|
116
134
|
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
listIds.length && watchMultiConfigs(listIds);
|
|
137
|
+
}, [listIds]);
|
|
138
|
+
|
|
117
139
|
return (
|
|
118
140
|
<View style={styles.wrap}>
|
|
119
141
|
<WrapHeaderScrollable
|
|
@@ -121,6 +143,7 @@ const TemplateDetail = () => {
|
|
|
121
143
|
headerAniStyle={styles.headerAniStyle}
|
|
122
144
|
rightComponent={rightComponent}
|
|
123
145
|
onGoBack={goBack}
|
|
146
|
+
onRefresh={getWidgets}
|
|
124
147
|
>
|
|
125
148
|
{!isLoading && !data?.length
|
|
126
149
|
? renderEmpty
|
|
@@ -133,6 +156,7 @@ const TemplateDetail = () => {
|
|
|
133
156
|
offsetTitle={'offsetTitle'}
|
|
134
157
|
setOffsetTitle={'setOffsetTitle'}
|
|
135
158
|
maxValue={100}
|
|
159
|
+
sensor={item}
|
|
136
160
|
/>
|
|
137
161
|
);
|
|
138
162
|
})}
|
|
@@ -71,7 +71,7 @@ const Template = () => {
|
|
|
71
71
|
return (
|
|
72
72
|
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
|
|
73
73
|
<View style={styles.wrap}>
|
|
74
|
-
<Label name={t('
|
|
74
|
+
<Label name={t('dashboard')} />
|
|
75
75
|
<Search onSearch={onSearch} />
|
|
76
76
|
<FlatList
|
|
77
77
|
contentContainerStyle={styles.contentContainerStyle}
|
|
@@ -4,65 +4,63 @@ import Routes from '../../utils/Route';
|
|
|
4
4
|
import { useNavigation } from '@react-navigation/native';
|
|
5
5
|
import { MenuActionMore } from '../../commons';
|
|
6
6
|
|
|
7
|
-
const MoreMenu =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const navigation = useNavigation();
|
|
7
|
+
const MoreMenu = ({
|
|
8
|
+
unit,
|
|
9
|
+
isOwner,
|
|
10
|
+
hidePopover,
|
|
11
|
+
childRef,
|
|
12
|
+
showingPopover,
|
|
13
|
+
idLabelPopover,
|
|
14
|
+
idLabelScrollView,
|
|
15
|
+
idLabelItem,
|
|
16
|
+
}) => {
|
|
17
|
+
const t = useTranslations();
|
|
18
|
+
const navigation = useNavigation();
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
const onItemClick = useCallback(
|
|
21
|
+
({ route: routeName, data }) => {
|
|
22
|
+
hidePopover();
|
|
23
|
+
routeName && navigation.navigate(routeName, data);
|
|
24
|
+
},
|
|
25
|
+
[hidePopover, navigation]
|
|
26
|
+
);
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
28
|
+
const listMenuItem = useMemo(() => {
|
|
29
|
+
const RouteManageUnit = {
|
|
30
|
+
id: 'mange-unit',
|
|
31
|
+
route: Routes.ManageUnit,
|
|
32
|
+
text: t('manage_unit'),
|
|
33
|
+
data: { unitId: unit?.id, unit },
|
|
34
|
+
};
|
|
35
|
+
const RouteUnitMemberList = {
|
|
36
|
+
id: 'unit-member',
|
|
37
|
+
route: Routes.UnitMemberList,
|
|
38
|
+
text: t('members'),
|
|
39
|
+
data: { unitId: unit?.id, unit },
|
|
40
|
+
};
|
|
41
|
+
const ListSmartAccount = {
|
|
42
|
+
id: 'smart-account',
|
|
43
|
+
route: Routes.ListSmartAccount,
|
|
44
|
+
text: t('smart_account'),
|
|
45
|
+
data: { unitId: unit?.id, unit },
|
|
46
|
+
};
|
|
47
|
+
return isOwner
|
|
48
|
+
? [RouteManageUnit, RouteUnitMemberList, ListSmartAccount]
|
|
49
|
+
: [RouteUnitMemberList];
|
|
50
|
+
}, [t, unit, isOwner]);
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
);
|
|
52
|
+
return (
|
|
53
|
+
<MenuActionMore
|
|
54
|
+
isVisible={showingPopover}
|
|
55
|
+
hideMore={hidePopover}
|
|
56
|
+
listMenuItem={listMenuItem}
|
|
57
|
+
childRef={childRef}
|
|
58
|
+
onItemClick={onItemClick}
|
|
59
|
+
idLabelPopover={idLabelPopover}
|
|
60
|
+
idLabelScrollView={idLabelScrollView}
|
|
61
|
+
idLabelItem={idLabelItem}
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
67
65
|
|
|
68
|
-
export default MoreMenu;
|
|
66
|
+
export default memo(MoreMenu);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { act, create } from 'react-test-renderer';
|
|
3
|
+
import { MenuActionMore } from '../../../commons';
|
|
4
|
+
import { SCProvider } from '../../../context';
|
|
5
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
6
|
+
import MoreMenu from '../MoreMenu';
|
|
7
|
+
|
|
8
|
+
const mockHidePopover = jest.fn();
|
|
9
|
+
|
|
10
|
+
const mockNavigate = jest.fn();
|
|
11
|
+
jest.mock('@react-navigation/native', () => {
|
|
12
|
+
return {
|
|
13
|
+
...jest.requireActual('@react-navigation/native'),
|
|
14
|
+
useNavigation: () => ({
|
|
15
|
+
navigate: mockNavigate,
|
|
16
|
+
}),
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const wrapComponent = (showingPopover) => (
|
|
21
|
+
<SCProvider initState={mockSCStore({})}>
|
|
22
|
+
<MoreMenu showingPopover={showingPopover} hidePopover={mockHidePopover} />
|
|
23
|
+
</SCProvider>
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
describe('Test MoreMenu', () => {
|
|
27
|
+
let tree;
|
|
28
|
+
|
|
29
|
+
it('Test render', async () => {
|
|
30
|
+
await act(async () => {
|
|
31
|
+
tree = await create(wrapComponent());
|
|
32
|
+
});
|
|
33
|
+
const menuActionMore = tree.root.findByType(MenuActionMore);
|
|
34
|
+
expect(menuActionMore.props.isVisible).toBeFalsy();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('Test show menu then hide it', async () => {
|
|
38
|
+
await act(async () => {
|
|
39
|
+
tree = await create(wrapComponent(true));
|
|
40
|
+
});
|
|
41
|
+
const menuActionMore = tree.root.findByType(MenuActionMore);
|
|
42
|
+
await act(async () => {
|
|
43
|
+
await menuActionMore.props.hideMore();
|
|
44
|
+
});
|
|
45
|
+
expect(mockHidePopover).toBeCalled();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('Test onItemClick', async () => {
|
|
49
|
+
await act(async () => {
|
|
50
|
+
tree = await create(wrapComponent(true));
|
|
51
|
+
});
|
|
52
|
+
const menuActionMore = tree.root.findByType(MenuActionMore);
|
|
53
|
+
await act(async () => {
|
|
54
|
+
await menuActionMore.props.onItemClick({ route: 'DeviceDetail' });
|
|
55
|
+
});
|
|
56
|
+
expect(mockHidePopover).toBeCalled();
|
|
57
|
+
expect(mockNavigate).toBeCalledWith('DeviceDetail', undefined);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -43,14 +43,17 @@ export const useUnitConnectRemoteDevices = (unit) => {
|
|
|
43
43
|
);
|
|
44
44
|
|
|
45
45
|
useEffect(() => {
|
|
46
|
-
if (unit?.remote_control_options?.bluetooth && isBluetoothEnabled) {
|
|
46
|
+
if (unit?.remote_control_options?.bluetooth?.length && isBluetoothEnabled) {
|
|
47
47
|
bluetoothScanDevices(unit.remote_control_options.bluetooth);
|
|
48
48
|
}
|
|
49
49
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
50
50
|
}, [unit, isBluetoothEnabled, bluetoothPermGranted]);
|
|
51
51
|
|
|
52
52
|
useEffect(() => {
|
|
53
|
-
if (
|
|
53
|
+
if (
|
|
54
|
+
unit?.remote_control_options?.googlehome?.length &&
|
|
55
|
+
isNetworkConnected
|
|
56
|
+
) {
|
|
54
57
|
(async () => {
|
|
55
58
|
await connectHomeAssistant(unit.remote_control_options.googlehome);
|
|
56
59
|
})();
|
|
@@ -59,7 +62,7 @@ export const useUnitConnectRemoteDevices = (unit) => {
|
|
|
59
62
|
}, [unit, isNetworkConnected]);
|
|
60
63
|
|
|
61
64
|
useEffect(() => {
|
|
62
|
-
if (unit?.remote_control_options?.lg_thinq) {
|
|
65
|
+
if (unit?.remote_control_options?.lg_thinq?.length) {
|
|
63
66
|
(async () => {
|
|
64
67
|
await handleLgThinqConnect(unit.remote_control_options.lg_thinq);
|
|
65
68
|
})();
|
|
@@ -684,7 +684,7 @@
|
|
|
684
684
|
"text_notification_content_member_leave_unit": "**member_name** has left **unit_name**.",
|
|
685
685
|
"text_notification_content_rename_unit": "Unit **old_unit_name** has been renamed to **new_unit_name** by **owner_name**.",
|
|
686
686
|
"text_notification_content_divice_disconnect": "**device_name** at **unit_name**: **sub_unit_name** has been disconnected. Please check and reconnect.",
|
|
687
|
-
"text_notification_content_rename_sub_unit": "Sub-unit **old_sub_unit_name**: **unit_name** has been renamed to **new_sub_unit_name** by **
|
|
687
|
+
"text_notification_content_rename_sub_unit": "Sub-unit **old_sub_unit_name**: **unit_name** has been renamed to **new_sub_unit_name** by **unit_owner_name**.",
|
|
688
688
|
"text_notification_content_remove_sub_unit": "Sub-unit **sub_unit_name** has been removed from **unit_name** by **unit_owner_name**.",
|
|
689
689
|
"text_notification_content_remove_device": "Device **device_name** has been removed from **unit_name** by **unit_owner_name**.",
|
|
690
690
|
"text_notification_content_update_address": "New address of **unit_name** has been updated by **unit_owner_name** to **unit_address**.",
|
|
@@ -991,7 +991,7 @@
|
|
|
991
991
|
"create_contact_success": "Create contact success!",
|
|
992
992
|
"can_not_login_to_current_ssid":"Can't login to current SSID",
|
|
993
993
|
"confirm_password_not_match": "Confirm password does not match",
|
|
994
|
-
"
|
|
994
|
+
"dashboard": "Dashboard",
|
|
995
995
|
"template": "Template",
|
|
996
996
|
"gateways": "Gateways",
|
|
997
997
|
"help": "Help",
|
|
@@ -999,20 +999,20 @@
|
|
|
999
999
|
"exit_dev_mode": "Exit developer mode",
|
|
1000
1000
|
"developer_mode": "Developer Mode",
|
|
1001
1001
|
"what_are_you_looking_for": "What are you looking for?",
|
|
1002
|
-
"
|
|
1003
|
-
"
|
|
1004
|
-
"
|
|
1002
|
+
"no_dashboard_yet": "No Dashboard yet",
|
|
1003
|
+
"add_your_dashboard": "Add your dashboard at web app",
|
|
1004
|
+
"edit_dashboard": "Edit dashboard",
|
|
1005
1005
|
"no_gateway_yet": "No Gateway yet",
|
|
1006
1006
|
"you_dont_have_any_gateway": "You don't have any gateway",
|
|
1007
1007
|
"gateway_information": "Gateway information",
|
|
1008
1008
|
"reboot": "Reboot",
|
|
1009
1009
|
"information": "Information",
|
|
1010
1010
|
"gateway_list": "Gateway list",
|
|
1011
|
-
"
|
|
1012
|
-
"
|
|
1011
|
+
"delete_dashboard": "Delete dashboard",
|
|
1012
|
+
"dashboard_name": "Dashboard name",
|
|
1013
1013
|
"add_widget": "Add widget",
|
|
1014
1014
|
"no_widgets": "No Widgets",
|
|
1015
|
-
"add_your_widget": "Add your widget in dashboard
|
|
1015
|
+
"add_your_widget": "Add your widget in dashboard",
|
|
1016
1016
|
"label": "Label",
|
|
1017
1017
|
"choose_type_of_device": "Choose Type of Device",
|
|
1018
1018
|
"central_controller": "Central controller",
|
|
@@ -699,7 +699,7 @@
|
|
|
699
699
|
"text_notification_content_member_leave_unit": "**member_name** vừa rời khỏi **unit_name**.",
|
|
700
700
|
"text_notification_content_rename_unit": "Địa điểm **old_unit_name** vừa được đổi tên thành **new_unit_name** bởi **owner_name**.",
|
|
701
701
|
"text_notification_content_divice_disconnect": "**device_name** tại **unit_name**: **sub_unit_name** vừa bị mất kết nối. Vui lòng kiểm tra và kết nối lại.",
|
|
702
|
-
"text_notification_content_rename_sub_unit": "Khu vực **old_sub_unit_name**: **unit_name** vừa được đổi tên thành **new_sub_unit_name** bởi **
|
|
702
|
+
"text_notification_content_rename_sub_unit": "Khu vực **old_sub_unit_name**: **unit_name** vừa được đổi tên thành **new_sub_unit_name** bởi **unit_owner_name**.",
|
|
703
703
|
"text_notification_content_remove_sub_unit": "Khu vực **sub_unit_name** vừa được xoá khỏi **%unit_name** bởi **unit_owner_name**.",
|
|
704
704
|
"text_notification_content_remove_device": "Thiết bị **device_name** vừa được xoá khỏi **unit_name** bởi **unit_owner_name**.",
|
|
705
705
|
"text_notification_content_update_address": "Địa chỉ mới của **unit_name** vừa được cập nhật bởi **unit_owner_name** thành **unit_address**.",
|
|
@@ -990,7 +990,7 @@
|
|
|
990
990
|
"create_contact_success": "Tạo liên hệ thành công!",
|
|
991
991
|
"can_not_login_to_current_ssid":"Không thể đăng nhập vào SSID hiện tại",
|
|
992
992
|
"confirm_password_not_match": "Mật khẩu xác nhận không trùng khớp",
|
|
993
|
-
"
|
|
993
|
+
"dashboard": "Bảng điều khiển",
|
|
994
994
|
"template": "Mẫu",
|
|
995
995
|
"gateways": "Cổng vào",
|
|
996
996
|
"help": "Hỗ trợ",
|
|
@@ -998,18 +998,19 @@
|
|
|
998
998
|
"exit_dev_mode": "Thoát khỏi chế độ nhà phát triển",
|
|
999
999
|
"developer_mode": "Chế độ nhà phát triển",
|
|
1000
1000
|
"what_are_you_looking_for": "Bạn đang tìm kiếm cái gì?",
|
|
1001
|
-
"
|
|
1002
|
-
"
|
|
1003
|
-
"
|
|
1001
|
+
"no_dashboard_yet": "Chưa có bảng điều khiển nào",
|
|
1002
|
+
"add_your_dashboard": "Thêm bảng điều khiển của bạn trên web",
|
|
1003
|
+
"edit_dashboard": "Chỉnh sửa bảng điều khiển",
|
|
1004
1004
|
"no_gateway_yet": "Chưa có cổng nào",
|
|
1005
1005
|
"you_dont_have_any_gateway": "Bạn không có bất kỳ cổng nào",
|
|
1006
1006
|
"gateway_information": "Thông tin cổng",
|
|
1007
1007
|
"reboot": "Khởi động lại",
|
|
1008
1008
|
"information": "Thông tin",
|
|
1009
1009
|
"gateway_list": "Danh sách cổng vào",
|
|
1010
|
-
"
|
|
1010
|
+
"delete_dashboard": "Xóa bảng điều khiển",
|
|
1011
|
+
"dashboard_name": "Dashboard name",
|
|
1011
1012
|
"add_widget": "Thêm tiện ích con",
|
|
1012
|
-
"add_your_widget": "Thêm tiện ích của bạn vào
|
|
1013
|
+
"add_your_widget": "Thêm tiện ích của bạn vào ba",
|
|
1013
1014
|
"label": "Nhãn",
|
|
1014
1015
|
"choose_type_of_device": "Chọn Loại Thiết bị",
|
|
1015
1016
|
"central_controller": "Bộ điều khiển trung tâm",
|