@iobroker/adapter-react-v5 7.0.1 → 7.1.0

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 (314) hide show
  1. package/Components/404.d.ts +3 -2
  2. package/Components/404.js +16 -15
  3. package/Components/ColorPicker.d.ts +22 -8
  4. package/Components/ColorPicker.js +34 -17
  5. package/Components/ComplexCron.js +24 -24
  6. package/Components/CopyToClipboard.d.ts +10 -1
  7. package/Components/CopyToClipboard.js +17 -8
  8. package/Components/CustomModal.d.ts +1 -1
  9. package/Components/CustomModal.js +8 -8
  10. package/Components/FileBrowser.d.ts +11 -11
  11. package/Components/FileBrowser.js +173 -164
  12. package/Components/FileViewer.js +34 -23
  13. package/Components/Icon.d.ts +16 -2
  14. package/Components/Icon.js +19 -8
  15. package/Components/IconPicker.js +10 -14
  16. package/Components/IconSelector.d.ts +1 -1
  17. package/Components/IconSelector.js +64 -74
  18. package/Components/Image.d.ts +8 -4
  19. package/Components/Image.js +13 -32
  20. package/Components/Loader.d.ts +2 -2
  21. package/Components/Loader.js +244 -241
  22. package/Components/Loaders/MV.d.ts +6 -1
  23. package/Components/Loaders/MV.js +23 -7
  24. package/Components/Loaders/PT.d.ts +7 -2
  25. package/Components/Loaders/PT.js +123 -110
  26. package/Components/Loaders/Vendor.d.ts +2 -2
  27. package/Components/Loaders/Vendor.js +22 -14
  28. package/Components/Logo.js +16 -18
  29. package/Components/MDUtils.d.ts +1 -1
  30. package/Components/MDUtils.js +8 -4
  31. package/Components/ObjectBrowser.d.ts +49 -38
  32. package/Components/ObjectBrowser.js +757 -494
  33. package/Components/Router.d.ts +1 -3
  34. package/Components/Router.js +3 -1
  35. package/Components/SaveCloseButtons.d.ts +3 -3
  36. package/Components/SaveCloseButtons.js +3 -3
  37. package/Components/Schedule.d.ts +15 -15
  38. package/Components/Schedule.js +177 -154
  39. package/Components/SelectWithIcon.d.ts +2 -2
  40. package/Components/SelectWithIcon.js +45 -34
  41. package/Components/SimpleCron/index.js +83 -43
  42. package/Components/TabContainer.js +2 -2
  43. package/Components/TabContent.js +1 -1
  44. package/Components/TabHeader.js +1 -1
  45. package/Components/TableResize.d.ts +2 -2
  46. package/Components/TableResize.js +5 -5
  47. package/Components/TextWithIcon.d.ts +1 -1
  48. package/Components/TextWithIcon.js +10 -8
  49. package/Components/ToggleThemeMenu.d.ts +2 -2
  50. package/Components/ToggleThemeMenu.js +3 -3
  51. package/Components/TreeTable.d.ts +18 -18
  52. package/Components/TreeTable.js +76 -72
  53. package/Components/UploadImage.d.ts +2 -2
  54. package/Components/UploadImage.js +330 -326
  55. package/Components/Utils.d.ts +42 -22
  56. package/Components/Utils.js +66 -65
  57. package/Components/withWidth.d.ts +2 -2
  58. package/Components/withWidth.js +10 -6
  59. package/Dialogs/ComplexCron.d.ts +2 -2
  60. package/Dialogs/ComplexCron.js +3 -3
  61. package/Dialogs/Confirm.d.ts +4 -4
  62. package/Dialogs/Confirm.js +18 -8
  63. package/Dialogs/Cron.d.ts +3 -3
  64. package/Dialogs/Cron.js +21 -17
  65. package/Dialogs/Error.d.ts +3 -3
  66. package/Dialogs/Error.js +6 -4
  67. package/Dialogs/Message.d.ts +3 -3
  68. package/Dialogs/Message.js +6 -4
  69. package/Dialogs/SelectFile.d.ts +4 -4
  70. package/Dialogs/SelectFile.js +6 -4
  71. package/Dialogs/SelectID.d.ts +12 -10
  72. package/Dialogs/SelectID.js +12 -8
  73. package/Dialogs/SimpleCron.d.ts +2 -2
  74. package/Dialogs/SimpleCron.js +2 -2
  75. package/Dialogs/TextInput.d.ts +2 -2
  76. package/Dialogs/TextInput.js +3 -3
  77. package/GenericApp.d.ts +19 -13
  78. package/GenericApp.js +177 -134
  79. package/LICENSE +22 -22
  80. package/LegacyConnection.d.ts +240 -248
  81. package/LegacyConnection.js +500 -525
  82. package/Prompt.js +7 -7
  83. package/README.md +1239 -1166
  84. package/Theme.d.ts +1 -1
  85. package/Theme.js +9 -12
  86. package/assets/devices.json +1 -0
  87. package/assets/lamp_ceiling.svg +8 -8
  88. package/assets/lamp_table.svg +7 -7
  89. package/assets/no_icon.svg +9 -9
  90. package/assets/rooms.json +1 -0
  91. package/craco-module-federation.js +62 -71
  92. package/i18n/de.json +434 -431
  93. package/i18n/en.json +434 -431
  94. package/i18n/es.json +434 -431
  95. package/i18n/fr.json +434 -431
  96. package/i18n/it.json +434 -431
  97. package/i18n/nl.json +434 -431
  98. package/i18n/pl.json +434 -431
  99. package/i18n/pt.json +434 -431
  100. package/i18n/ru.json +434 -431
  101. package/i18n/uk.json +434 -431
  102. package/i18n/zh-cn.json +434 -431
  103. package/i18n.d.ts +26 -19
  104. package/i18n.js +28 -22
  105. package/icons/IconAdapter.js +2 -2
  106. package/icons/IconAlias.js +2 -2
  107. package/icons/IconChannel.js +2 -2
  108. package/icons/IconClearFilter.js +2 -2
  109. package/icons/IconClosed.js +2 -2
  110. package/icons/IconCopy.js +2 -2
  111. package/icons/IconDevice.js +2 -2
  112. package/icons/IconDocument.js +2 -2
  113. package/icons/IconDocumentReadOnly.js +2 -2
  114. package/icons/IconExpert.js +2 -2
  115. package/icons/IconFx.js +2 -2
  116. package/icons/IconInstance.js +2 -2
  117. package/icons/IconLogout.js +2 -2
  118. package/icons/IconNoIcon.js +2 -2
  119. package/icons/IconOpen.d.ts +2 -2
  120. package/icons/IconOpen.js +2 -2
  121. package/icons/IconProps.d.ts +4 -3
  122. package/icons/IconState.d.ts +2 -2
  123. package/icons/IconState.js +2 -2
  124. package/index.css +56 -55
  125. package/modulefederation.admin.config.js +31 -31
  126. package/package.json +5 -5
  127. package/src/AdminConnection.tsx +3 -3
  128. package/src/Components/404.tsx +122 -121
  129. package/src/Components/ColorPicker.tsx +343 -315
  130. package/src/Components/ComplexCron.tsx +544 -507
  131. package/src/Components/CopyToClipboard.tsx +178 -165
  132. package/src/Components/CustomModal.tsx +170 -163
  133. package/src/Components/FileBrowser.tsx +2550 -2414
  134. package/src/Components/FileViewer.tsx +412 -393
  135. package/src/Components/Icon.tsx +238 -210
  136. package/src/Components/IconPicker.tsx +165 -149
  137. package/src/Components/IconSelector.tsx +2220 -2202
  138. package/src/Components/Image.tsx +193 -176
  139. package/src/Components/Loader.tsx +328 -304
  140. package/src/Components/Logo.tsx +176 -166
  141. package/src/Components/MDUtils.tsx +104 -100
  142. package/src/Components/ObjectBrowser.tsx +8935 -8032
  143. package/src/Components/Router.tsx +90 -90
  144. package/src/Components/SaveCloseButtons.tsx +117 -113
  145. package/src/Components/Schedule.tsx +1962 -1724
  146. package/src/Components/SelectWithIcon.tsx +239 -197
  147. package/src/Components/TabContainer.tsx +57 -55
  148. package/src/Components/TabContent.tsx +38 -37
  149. package/src/Components/TabHeader.tsx +20 -19
  150. package/src/Components/TableResize.tsx +274 -259
  151. package/src/Components/TextWithIcon.tsx +159 -148
  152. package/src/Components/ToggleThemeMenu.tsx +52 -34
  153. package/src/Components/TreeTable.tsx +1002 -919
  154. package/src/Components/UploadImage.tsx +631 -599
  155. package/src/Components/Utils.tsx +1802 -1794
  156. package/src/Components/loader.css +231 -222
  157. package/src/Components/withWidth.tsx +32 -21
  158. package/src/Connection.tsx +5 -7
  159. package/src/Dialogs/ComplexCron.tsx +123 -129
  160. package/src/Dialogs/Confirm.tsx +185 -162
  161. package/src/Dialogs/Cron.tsx +192 -182
  162. package/src/Dialogs/Error.tsx +67 -72
  163. package/src/Dialogs/Message.tsx +73 -71
  164. package/src/Dialogs/SelectFile.tsx +280 -270
  165. package/src/Dialogs/SelectID.tsx +310 -298
  166. package/src/Dialogs/SimpleCron.tsx +100 -100
  167. package/src/Dialogs/TextInput.tsx +99 -107
  168. package/src/GenericApp.tsx +1076 -976
  169. package/src/LegacyConnection.tsx +3719 -3589
  170. package/src/Prompt.tsx +22 -20
  171. package/src/Theme.tsx +472 -479
  172. package/src/icons/IconAdapter.tsx +22 -20
  173. package/src/icons/IconAlias.tsx +22 -20
  174. package/src/icons/IconChannel.tsx +60 -21
  175. package/src/icons/IconClearFilter.tsx +24 -22
  176. package/src/icons/IconClosed.tsx +22 -17
  177. package/src/icons/IconCopy.tsx +21 -16
  178. package/src/icons/IconDevice.tsx +126 -27
  179. package/src/icons/IconDocument.tsx +22 -17
  180. package/src/icons/IconDocumentReadOnly.tsx +27 -18
  181. package/src/icons/IconExpert.tsx +26 -18
  182. package/src/icons/IconFx.tsx +38 -36
  183. package/src/icons/IconInstance.tsx +22 -20
  184. package/src/icons/IconLogout.tsx +32 -30
  185. package/src/icons/IconNoIcon.tsx +21 -19
  186. package/src/icons/IconOpen.tsx +22 -17
  187. package/src/icons/IconProps.tsx +16 -15
  188. package/src/icons/IconState.tsx +38 -17
  189. package/src/index.css +56 -55
  190. package/tasks.js +91 -0
  191. package/types.d.ts +141 -134
  192. package/Components/Loaders/PT.css +0 -109
  193. package/Components/Loaders/Vendor.css +0 -13
  194. package/Components/loader.css +0 -222
  195. package/Components/types.d.ts +0 -82
  196. package/assets/devices/Alarm Systems.svg +0 -19
  197. package/assets/devices/Amplifier.svg +0 -22
  198. package/assets/devices/Awnings.svg +0 -5
  199. package/assets/devices/Battery Status.svg +0 -5
  200. package/assets/devices/Ceiling Spotlights.svg +0 -16
  201. package/assets/devices/Chandelier.svg +0 -7
  202. package/assets/devices/Climate.svg +0 -12
  203. package/assets/devices/Coffee Makers.svg +0 -6
  204. package/assets/devices/Cold Water.svg +0 -31
  205. package/assets/devices/Computer.svg +0 -21
  206. package/assets/devices/Consumption.svg +0 -8
  207. package/assets/devices/Curtains.svg +0 -43
  208. package/assets/devices/Dishwashers.svg +0 -12
  209. package/assets/devices/Doors.svg +0 -6
  210. package/assets/devices/Doorstep.svg +0 -35
  211. package/assets/devices/Dryer.svg +0 -14
  212. package/assets/devices/Fan.svg +0 -20
  213. package/assets/devices/Floor Lamps.svg +0 -5
  214. package/assets/devices/Garage Doors.svg +0 -9
  215. package/assets/devices/Gates.svg +0 -32
  216. package/assets/devices/Hairdryer.svg +0 -23
  217. package/assets/devices/Handle.svg +0 -6
  218. package/assets/devices/Hanging Lamps.svg +0 -9
  219. package/assets/devices/Heater.svg +0 -44
  220. package/assets/devices/Hoods.svg +0 -12
  221. package/assets/devices/Hot Water.svg +0 -10
  222. package/assets/devices/Humidity.svg +0 -41
  223. package/assets/devices/Iron.svg +0 -5
  224. package/assets/devices/Irrigation.svg +0 -23
  225. package/assets/devices/Led Strip.svg +0 -31
  226. package/assets/devices/Light.svg +0 -30
  227. package/assets/devices/Lightings.svg +0 -46
  228. package/assets/devices/Lock.svg +0 -19
  229. package/assets/devices/Louvre.svg +0 -7
  230. package/assets/devices/Mowing Machine.svg +0 -9
  231. package/assets/devices/Music.svg +0 -13
  232. package/assets/devices/Outdoor Blinds.svg +0 -7
  233. package/assets/devices/People.svg +0 -19
  234. package/assets/devices/Pool.svg +0 -8
  235. package/assets/devices/Power Consumption.svg +0 -13
  236. package/assets/devices/Printer.svg +0 -10
  237. package/assets/devices/Pump.svg +0 -10
  238. package/assets/devices/Receiver.svg +0 -19
  239. package/assets/devices/Sconces.svg +0 -10
  240. package/assets/devices/Security.svg +0 -34
  241. package/assets/devices/Shading.svg +0 -5
  242. package/assets/devices/Shutters.svg +0 -11
  243. package/assets/devices/SmokeDetector.svg +0 -13
  244. package/assets/devices/Sockets.svg +0 -13
  245. package/assets/devices/Speaker.svg +0 -35
  246. package/assets/devices/Stove.svg +0 -12
  247. package/assets/devices/Table Lamps.svg +0 -12
  248. package/assets/devices/Temperature Sensors.svg +0 -28
  249. package/assets/devices/Tv.svg +0 -8
  250. package/assets/devices/Vacuum Cleaner.svg +0 -16
  251. package/assets/devices/Ventilation.svg +0 -12
  252. package/assets/devices/Washing Machines.svg +0 -16
  253. package/assets/devices/Water Consumption.svg +0 -6
  254. package/assets/devices/Water Heater.svg +0 -8
  255. package/assets/devices/Water.svg +0 -40
  256. package/assets/devices/Weather.svg +0 -28
  257. package/assets/devices/Window.svg +0 -8
  258. package/assets/rooms/Anteroom.svg +0 -53
  259. package/assets/rooms/Attic.svg +0 -21
  260. package/assets/rooms/Balcony.svg +0 -13
  261. package/assets/rooms/Barn.svg +0 -6
  262. package/assets/rooms/Basement.svg +0 -5
  263. package/assets/rooms/Bathroom.svg +0 -38
  264. package/assets/rooms/Bedroom.svg +0 -5
  265. package/assets/rooms/Boiler Room.svg +0 -13
  266. package/assets/rooms/Carport.svg +0 -17
  267. package/assets/rooms/Cellar.svg +0 -89
  268. package/assets/rooms/Chamber.svg +0 -9
  269. package/assets/rooms/Corridor.svg +0 -53
  270. package/assets/rooms/Dining Area.svg +0 -37
  271. package/assets/rooms/Dining Room.svg +0 -37
  272. package/assets/rooms/Dining.svg +0 -37
  273. package/assets/rooms/Dressing Room.svg +0 -5
  274. package/assets/rooms/Driveway.svg +0 -15
  275. package/assets/rooms/Entrance.svg +0 -44
  276. package/assets/rooms/Equipment Room.svg +0 -15
  277. package/assets/rooms/Front Yard.svg +0 -64
  278. package/assets/rooms/Gallery.svg +0 -14
  279. package/assets/rooms/Garage.svg +0 -20
  280. package/assets/rooms/Garden.svg +0 -13
  281. package/assets/rooms/Ground Floor.svg +0 -95
  282. package/assets/rooms/Guest Bathroom.svg +0 -33
  283. package/assets/rooms/Guest Room.svg +0 -5
  284. package/assets/rooms/Gym.svg +0 -5
  285. package/assets/rooms/Hall.svg +0 -19
  286. package/assets/rooms/Home Theater.svg +0 -8
  287. package/assets/rooms/Kitchen.svg +0 -18
  288. package/assets/rooms/Laundry Room.svg +0 -12
  289. package/assets/rooms/Living Area.svg +0 -11
  290. package/assets/rooms/Living Room.svg +0 -10
  291. package/assets/rooms/Locker Room.svg +0 -17
  292. package/assets/rooms/Nursery.svg +0 -5
  293. package/assets/rooms/Office.svg +0 -8
  294. package/assets/rooms/Outdoors.svg +0 -7
  295. package/assets/rooms/Playroom.svg +0 -6
  296. package/assets/rooms/Pool.svg +0 -8
  297. package/assets/rooms/Rear Wall.svg +0 -30
  298. package/assets/rooms/Second Floor.svg +0 -95
  299. package/assets/rooms/Shed.svg +0 -16
  300. package/assets/rooms/Sleeping Area.svg +0 -22
  301. package/assets/rooms/Stairway.svg +0 -5
  302. package/assets/rooms/Stairwell.svg +0 -15
  303. package/assets/rooms/Storeroom.svg +0 -5
  304. package/assets/rooms/Summer House.svg +0 -27
  305. package/assets/rooms/Swimming Pool.svg +0 -21
  306. package/assets/rooms/Terrace.svg +0 -7
  307. package/assets/rooms/Toilet.svg +0 -10
  308. package/assets/rooms/Upstairs.svg +0 -6
  309. package/assets/rooms/Wardrobe.svg +0 -60
  310. package/assets/rooms/Washroom.svg +0 -20
  311. package/assets/rooms/Wc.svg +0 -10
  312. package/assets/rooms/Windscreen.svg +0 -60
  313. package/assets/rooms/Workshop.svg +0 -23
  314. package/assets/rooms/Workspace.svg +0 -8
@@ -1,507 +1,544 @@
1
- import React, { Component } from 'react';
2
-
3
- import {
4
- Checkbox,
5
- Button,
6
- MenuItem,
7
- Select,
8
- FormControlLabel,
9
- AppBar,
10
- Tabs,
11
- Tab,
12
- TextField, Box,
13
- } from '@mui/material';
14
-
15
- import I18n from '../i18n';
16
- import convertCronToText from './SimpleCron/cronText';
17
-
18
- const styles: Record<string, React.CSSProperties> = {
19
- mainDiv: {
20
- width: '100%',
21
- height: '100%',
22
- },
23
- periodSelect: {
24
- // margin: '0 10px 60px 10px',
25
- display: 'block',
26
- width: 200,
27
- },
28
- slider: {
29
- marginTop: 20,
30
- display: 'block',
31
- width: '100%',
32
- },
33
- tabContent: {
34
- padding: 20,
35
- height: 'calc(100% - 240px)',
36
- overflow: 'auto',
37
- },
38
- numberButton: {
39
- padding: 4,
40
- minWidth: 40,
41
- margin: 5,
42
- },
43
- numberButtonBreak: {
44
- display: 'block',
45
- },
46
- appBar: {
47
- color: 'white',
48
- },
49
- };
50
-
51
- const WEEKDAYS = [
52
- 'Sunday',
53
- 'Monday',
54
- 'Tuesday',
55
- 'Wednesday',
56
- 'Thursday',
57
- 'Friday',
58
- 'Saturday',
59
- 'Sunday',
60
- ];
61
- const MONTHS = [
62
- 'January',
63
- 'February',
64
- 'March',
65
- 'April',
66
- 'May',
67
- 'June',
68
- 'July',
69
- 'August',
70
- 'September',
71
- 'October',
72
- 'November',
73
- 'December',
74
- ];
75
-
76
- // 5-7,9-11 => [5,6,7,9,10,11]
77
- function convertMinusIntoArray(value: string | false | undefined, max: number): number[] {
78
- const result: number[] = [];
79
-
80
- if (value === '*') {
81
- if (max === 24 || max === 60 || max === 7) {
82
- for (let i = 0; i < max; i++) {
83
- result.push(i);
84
- }
85
- } else {
86
- for (let i = 1; i <= max; i++) {
87
- result.push(i);
88
- }
89
- }
90
- return result; // array with entries max
91
- }
92
-
93
- const parts = (value || '').toString().split(',');
94
-
95
- for (let p = 0; p < parts.length; p++) {
96
- if (!parts[p].trim().length) {
97
- continue;
98
- }
99
- const items = parts[p].trim().split('-');
100
- if (items.length > 1) {
101
- const iMax = parseInt(items[1], 10);
102
- for (let i = parseInt(items[0], 10); i <= iMax; i++) {
103
- result.push(i);
104
- }
105
- } else {
106
- result.push(parseInt(parts[p], 10));
107
- }
108
- }
109
-
110
- result.sort();
111
-
112
- // remove double entries
113
- for (let p = result.length - 1; p >= 0; p--) {
114
- if (result[p] === result[p + 1]) {
115
- result.splice(p + 1, 1);
116
- }
117
- }
118
-
119
- return result;
120
- }
121
-
122
- // [5,6,7,9,10,11] => 5-7,9-11
123
- function convertArrayIntoMinus(value: number | number [], max: number): string {
124
- if (typeof value !== 'object') {
125
- value = [value];
126
- }
127
- if (value.length === max) {
128
- return '*';
129
- }
130
- const newParts = [];
131
- if (!value.length) {
132
- return '-';
133
- }
134
- value = value.map(a => parseInt(a as any as string, 10));
135
-
136
- value.sort((a, b) => a - b);
137
-
138
- let start = value[0];
139
- let end = value[0];
140
- for (let p = 1; p < value.length; p++) {
141
- if (value[p] - 1 !== parseInt(value[p - 1] as any as string, 10)) {
142
- if (start === end) {
143
- newParts.push(start);
144
- } else if (end - 1 === start) {
145
- newParts.push(`${start},${end}`);
146
- } else {
147
- newParts.push(`${start}-${end}`);
148
- }
149
- start = value[p];
150
- }
151
- end = value[p];
152
- }
153
-
154
- if (start === end) {
155
- newParts.push(start);
156
- } else if (end - 1 === start) {
157
- newParts.push(`${start},${end}`);
158
- } else {
159
- newParts.push(`${start}-${end}`);
160
- }
161
-
162
- return newParts.join(',');
163
- }
164
-
165
- type CronNames = 'seconds' | 'minutes' | 'hours' | 'dates' | 'months' | 'dow';
166
-
167
- interface CronProps {
168
- seconds: string | false | null;
169
- minutes: string | null;
170
- hours: string | null;
171
- dates: string | null;
172
- months: string | null;
173
- dow: string | null;
174
- }
175
-
176
- interface ComplexCronProps {
177
- cronExpression: string;
178
- onChange: (cron: string) => void;
179
- language: ioBroker.Languages;
180
- }
181
-
182
- // type CronModes = 'every' | 'everyN' | 'specific';
183
-
184
- interface ComplexCronState {
185
- extended: boolean;
186
- tab: number;
187
- cron: string;
188
- seconds?: string | false;
189
- minutes?: string;
190
- hours?: string;
191
- dates?: string;
192
- months?: string;
193
- dow?: string;
194
- modes: CronProps;
195
- }
196
-
197
- class ComplexCron extends Component<ComplexCronProps, ComplexCronState> {
198
- constructor(props: ComplexCronProps) {
199
- super(props);
200
- let cron = typeof this.props.cronExpression === 'string' ?
201
- this.props.cronExpression.replace(/^["']/, '').replace(/["']\n?$/, '') : '';
202
- if (cron[0] === '{') {
203
- cron = '';
204
- }
205
- const state = ComplexCron.cron2state(cron || '* * * * *');
206
-
207
- this.state = {
208
- extended: false,
209
- tab: state.seconds !== false ? 1 : 0,
210
- cron: ComplexCron.state2cron(state),
211
- modes: {
212
- seconds: null,
213
- minutes: null,
214
- hours: null,
215
- dates: null,
216
- months: null,
217
- dow: null,
218
- },
219
- };
220
- Object.assign(this.state, state);
221
- if (this.state.cron !== this.props.cronExpression) {
222
- setTimeout(() => this.props.onChange && this.props.onChange(this.state.cron), 100);
223
- }
224
- }
225
-
226
- static cron2state(cron: string): CronProps {
227
- cron = cron.replace(/['"]/g, '').trim();
228
- const cronParts = cron.split(' ').map(p => p.trim());
229
- let options: CronProps;
230
-
231
- if (cronParts.length === 6) {
232
- options = {
233
- seconds: cronParts[0] || '*',
234
- minutes: cronParts[1] || '*',
235
- hours: cronParts[2] || '*',
236
- dates: cronParts[3] || '*',
237
- months: cronParts[4] || '*',
238
- dow: cronParts[5] || '*',
239
- };
240
- } else {
241
- options = {
242
- seconds: false,
243
- minutes: cronParts[0] || '*',
244
- hours: cronParts[1] || '*',
245
- dates: cronParts[2] || '*',
246
- months: cronParts[3] || '*',
247
- dow: cronParts[4] || '*',
248
- };
249
- }
250
- return options;
251
- }
252
-
253
- static state2cron(state: ComplexCronState | CronProps): string {
254
- let text = `${state.minutes} ${state.hours} ${state.dates} ${state.months} ${state.dow}`;
255
- if (state.seconds !== false) {
256
- text = `${state.seconds} ${text}`;
257
- }
258
- return text;
259
- }
260
-
261
- recalcCron() {
262
- const cron = ComplexCron.state2cron(this.state);
263
- if (cron !== this.state.cron) {
264
- this.setState({ cron }, () =>
265
- this.props.onChange && this.props.onChange(this.state.cron));
266
- }
267
- }
268
-
269
- onToggle(i: boolean | number, type: CronNames, max: number) {
270
- if (i === true) {
271
- this.setCronAttr(type, '*');
272
- } else if (i === false) {
273
- if (max === 60 || max === 24) {
274
- this.setCronAttr(type, '0');
275
- } else {
276
- this.setCronAttr(type, '1');
277
- }
278
- } else {
279
- const nums = convertMinusIntoArray(this.state[type], max);
280
- const pos = nums.indexOf(i);
281
- if (pos !== -1) {
282
- nums.splice(pos, 1);
283
- } else {
284
- nums.push(i);
285
- nums.sort();
286
- }
287
- this.setCronAttr(type, convertArrayIntoMinus(nums, max));
288
- }
289
- }
290
-
291
- getDigitsSelector(type: CronNames, max: number) {
292
- let values = [];
293
- if (max === 7) {
294
- values = [1, 2, 3, 4, 5, 6, 0];
295
- } else if (max === 60 || max === 24) {
296
- for (let i = 0; i < max; i++) {
297
- values.push(i);
298
- }
299
- } else {
300
- for (let i = 1; i <= max; i++) {
301
- values.push(i);
302
- }
303
- }
304
-
305
- const parts = convertMinusIntoArray(this.state[type], max);
306
-
307
- return [
308
- <Button
309
- key="removeall"
310
- variant="outlined"
311
- style={styles.numberButton}
312
- // style={{paddingBottom: 20}}
313
- color="primary"
314
- onClick={() => this.onToggle(false, type, max)}
315
- >
316
- {I18n.t('ra_Deselect all')}
317
- </Button>,
318
- <Button
319
- key="addall"
320
- variant="contained"
321
- // style={{paddingBottom: 20}}
322
- style={styles.numberButton}
323
- color="secondary"
324
- onClick={() => this.onToggle(true, type, max)}
325
- >
326
- {I18n.t('ra_Select all')}
327
- </Button>,
328
- <div key="all">
329
- {values.map(i =>
330
- [((max === 7 && i === 4) ||
331
- (max === 12 && i === 7) ||
332
- (max === 31 && !((i - 1) % 10)) ||
333
- (max === 60 && i && !(i % 10)) ||
334
- (max === 24 && i && !(i % 6))) ?
335
- <div key={`allInner${i}`} style={{ width: '100%' }} /> : null,
336
- <Button
337
- key={`_${i}`}
338
- variant={parts.indexOf(i) !== -1 ? 'contained' : 'outlined'}
339
- style={styles.numberButton}
340
- color={parts.indexOf(i) !== -1 ? 'secondary' : 'primary'}
341
- onClick={() => this.onToggle(i, type, max)}
342
- >
343
- {max === 7 ? I18n.t(WEEKDAYS[i]) : (max === 12 ? MONTHS[i - 1] : i)}
344
- </Button>,
345
- ])}
346
- </div>,
347
- ];
348
- }
349
-
350
- getPeriodsTab(type: CronNames, max: number): React.JSX.Element | null {
351
- const value = this.state[type];
352
- let every = value === '*';
353
- let everyN = value === undefined || value === null ? false : value.toString().includes('/');
354
- let select;
355
- if (this.state.modes[type] === null) {
356
- select = every ? 'every' : (everyN ? 'everyN' : 'specific');
357
- const modes = JSON.parse(JSON.stringify(this.state.modes));
358
- modes[type] = select;
359
- setTimeout(() => this.setState({ modes }, () => this.recalcCron()), 100);
360
- return null;
361
- }
362
-
363
- every = this.state.modes[type] === 'every';
364
- everyN = this.state.modes[type] === 'everyN';
365
- select = this.state.modes[type];
366
-
367
- let valueNumber = 1;
368
- if (everyN && value) {
369
- valueNumber = parseInt(value.replace('*/', ''), 10) || 1;
370
- }
371
-
372
- return <div>
373
- <Select
374
- variant="standard"
375
- style={{ ...styles.periodSelect, verticalAlign: 'bottom' }}
376
- value={select}
377
- onChange={e => {
378
- const modes = JSON.parse(JSON.stringify(this.state.modes));
379
- modes[type] = e.target.value;
380
- if (e.target.value === 'every') {
381
- this.setCronAttr(type, '*', modes);
382
- } else if (e.target.value === 'everyN') {
383
- const num = parseInt((this.state[type] || '').toString().replace('*/', ''), 10) || 1;
384
- this.setCronAttr(type, `*/${num}`, modes);
385
- } else if (e.target.value === 'specific') {
386
- let num = parseInt((this.state[type] || '').toString().split(',')[0], 10) || 0;
387
- if (!num && (type === 'months' || type === 'dates')) {
388
- num = 1;
389
- }
390
- this.setCronAttr(type, convertArrayIntoMinus(num, max), modes);
391
- }
392
- }}
393
- >
394
- <MenuItem key="every" value="every">{I18n.t(`sc_every_${type}`)}</MenuItem>
395
- <MenuItem key="everyN" value="everyN">{I18n.t(`sc_everyN_${type}`)}</MenuItem>
396
- <MenuItem key="specific" value="specific">{I18n.t(`sc_specific_${type}`)}</MenuItem>
397
- </Select>
398
- {everyN && false && <span>{value}</span>}
399
- {everyN && <TextField
400
- variant="standard"
401
- key="interval"
402
- label={I18n.t(`sc_${type}`)}
403
- value={valueNumber}
404
- inputProps={{ min: 1, max }}
405
- onChange={e => {
406
- // @ts-expect-error is allowed
407
- this.setState({ [type]: `*/${e.target.value}` }, () => this.recalcCron());
408
- }}
409
- InputLabelProps={{ shrink: true }}
410
- type="number"
411
- margin="normal"
412
- />}
413
- {!every && !everyN && this.getDigitsSelector(type, max)}
414
- </div>;
415
- }
416
-
417
- static convertCronToText(cron: string, lang: ioBroker.Languages): string {
418
- if (cron.split(' ').includes('-')) {
419
- return I18n.t('ra_Invalid CRON');
420
- }
421
- return convertCronToText(cron, lang);
422
- }
423
-
424
- setCronAttr(attr: CronNames, value: string, modes?: CronProps) {
425
- if (modes) {
426
- if (attr === 'seconds') {
427
- this.setState({ seconds: value, modes }, () =>
428
- this.recalcCron());
429
- } else if (attr === 'minutes') {
430
- this.setState({ minutes: value, modes }, () =>
431
- this.recalcCron());
432
- } else if (attr === 'hours') {
433
- this.setState({ hours: value, modes }, () =>
434
- this.recalcCron());
435
- } else if (attr === 'dates') {
436
- this.setState({ dates: value, modes }, () =>
437
- this.recalcCron());
438
- } else if (attr === 'months') {
439
- this.setState({ months: value, modes }, () =>
440
- this.recalcCron());
441
- } else if (attr === 'dow') {
442
- this.setState({ dow: value, modes }, () =>
443
- this.recalcCron());
444
- } else {
445
- this.setState({ modes }, () =>
446
- this.recalcCron());
447
- }
448
- } else if (attr === 'seconds') {
449
- this.setState({ seconds: value }, () =>
450
- this.recalcCron());
451
- } else if (attr === 'minutes') {
452
- this.setState({ minutes: value }, () =>
453
- this.recalcCron());
454
- } else if (attr === 'hours') {
455
- this.setState({ hours: value }, () =>
456
- this.recalcCron());
457
- } else if (attr === 'dates') {
458
- this.setState({ dates: value }, () =>
459
- this.recalcCron());
460
- } else if (attr === 'months') {
461
- this.setState({ months: value }, () =>
462
- this.recalcCron());
463
- } else if (attr === 'dow') {
464
- this.setState({ dow: value }, () =>
465
- this.recalcCron());
466
- }
467
- }
468
-
469
- render() {
470
- const tab = this.state.seconds !== false ? this.state.tab : this.state.tab + 1;
471
- return <div style={styles.mainDiv}>
472
- <div style={{ paddingLeft: 8, width: '100%' }}><TextField variant="standard" style={{ width: '100%' }} value={this.state.cron} disabled /></div>
473
- <div style={{ paddingLeft: 8, width: '100%', height: 60 }}>{ComplexCron.convertCronToText(this.state.cron, this.props.language || 'en')}</div>
474
- <FormControlLabel
475
- control={<Checkbox
476
- checked={!!this.state.seconds}
477
- onChange={e => this.setState({ seconds: e.target.checked ? '*' : false }, () => this.recalcCron())}
478
- />}
479
- label={I18n.t('ra_use seconds')}
480
- />
481
- <AppBar position="static" sx={{ '&.MuiAppBar-root': styles.appBar }} color="secondary">
482
- <Tabs
483
- value={this.state.tab}
484
- style={styles.appBar}
485
- color="secondary"
486
- onChange={(active, _tab) =>
487
- this.setState({ tab: _tab })}
488
- >
489
- {this.state.seconds !== false && <Tab id="sc_seconds" label={I18n.t('sc_seconds')} />}
490
- <Tab id="minutes" label={I18n.t('sc_minutes')} />
491
- <Tab id="hours" label={I18n.t('sc_hours')} />
492
- <Tab id="dates" label={I18n.t('sc_dates')} />
493
- <Tab id="months" label={I18n.t('sc_months')} />
494
- <Tab id="dow" label={I18n.t('sc_dows')} />
495
- </Tabs>
496
- </AppBar>
497
- {tab === 0 && <div style={styles.tabContent}>{this.getPeriodsTab('seconds', 60)}</div>}
498
- {tab === 1 && <div style={styles.tabContent}>{this.getPeriodsTab('minutes', 60)}</div>}
499
- {tab === 2 && <div style={styles.tabContent}>{this.getPeriodsTab('hours', 24)}</div>}
500
- {tab === 3 && <div style={styles.tabContent}>{this.getPeriodsTab('dates', 31)}</div>}
501
- {tab === 4 && <div style={styles.tabContent}>{this.getPeriodsTab('months', 12)}</div>}
502
- {tab === 5 && <div style={styles.tabContent}>{this.getPeriodsTab('dow', 7)}</div>}
503
- </div>;
504
- }
505
- }
506
-
507
- export default ComplexCron;
1
+ import React, { Component } from 'react';
2
+
3
+ import { Checkbox, Button, MenuItem, Select, FormControlLabel, AppBar, Tabs, Tab, TextField } from '@mui/material';
4
+
5
+ import I18n from '../i18n';
6
+ import convertCronToText from './SimpleCron/cronText';
7
+
8
+ const styles: Record<string, React.CSSProperties> = {
9
+ mainDiv: {
10
+ width: '100%',
11
+ height: '100%',
12
+ },
13
+ periodSelect: {
14
+ // margin: '0 10px 60px 10px',
15
+ display: 'block',
16
+ width: 200,
17
+ },
18
+ slider: {
19
+ marginTop: 20,
20
+ display: 'block',
21
+ width: '100%',
22
+ },
23
+ tabContent: {
24
+ padding: 20,
25
+ height: 'calc(100% - 240px)',
26
+ overflow: 'auto',
27
+ },
28
+ numberButton: {
29
+ padding: 4,
30
+ minWidth: 40,
31
+ margin: 5,
32
+ },
33
+ numberButtonBreak: {
34
+ display: 'block',
35
+ },
36
+ appBar: {
37
+ color: 'white',
38
+ },
39
+ };
40
+
41
+ const WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
42
+ const MONTHS = [
43
+ 'January',
44
+ 'February',
45
+ 'March',
46
+ 'April',
47
+ 'May',
48
+ 'June',
49
+ 'July',
50
+ 'August',
51
+ 'September',
52
+ 'October',
53
+ 'November',
54
+ 'December',
55
+ ];
56
+
57
+ // 5-7,9-11 => [5,6,7,9,10,11]
58
+ function convertMinusIntoArray(value: string | false | undefined, max: number): number[] {
59
+ const result: number[] = [];
60
+
61
+ if (value === '*') {
62
+ if (max === 24 || max === 60 || max === 7) {
63
+ for (let i = 0; i < max; i++) {
64
+ result.push(i);
65
+ }
66
+ } else {
67
+ for (let i = 1; i <= max; i++) {
68
+ result.push(i);
69
+ }
70
+ }
71
+ return result; // array with entries max
72
+ }
73
+
74
+ const parts = (value || '').toString().split(',');
75
+
76
+ for (let p = 0; p < parts.length; p++) {
77
+ if (!parts[p].trim().length) {
78
+ continue;
79
+ }
80
+ const items = parts[p].trim().split('-');
81
+ if (items.length > 1) {
82
+ const iMax = parseInt(items[1], 10);
83
+ for (let i = parseInt(items[0], 10); i <= iMax; i++) {
84
+ result.push(i);
85
+ }
86
+ } else {
87
+ result.push(parseInt(parts[p], 10));
88
+ }
89
+ }
90
+
91
+ result.sort();
92
+
93
+ // remove double entries
94
+ for (let p = result.length - 1; p >= 0; p--) {
95
+ if (result[p] === result[p + 1]) {
96
+ result.splice(p + 1, 1);
97
+ }
98
+ }
99
+
100
+ return result;
101
+ }
102
+
103
+ // [5,6,7,9,10,11] => 5-7,9-11
104
+ function convertArrayIntoMinus(value: number | number[], max: number): string {
105
+ if (typeof value !== 'object') {
106
+ value = [value];
107
+ }
108
+ if (value.length === max) {
109
+ return '*';
110
+ }
111
+ const newParts = [];
112
+ if (!value.length) {
113
+ return '-';
114
+ }
115
+ value = value.map(a => parseInt(a as any as string, 10));
116
+
117
+ value.sort((a, b) => a - b);
118
+
119
+ let start = value[0];
120
+ let end = value[0];
121
+ for (let p = 1; p < value.length; p++) {
122
+ if (value[p] - 1 !== parseInt(value[p - 1] as any as string, 10)) {
123
+ if (start === end) {
124
+ newParts.push(start);
125
+ } else if (end - 1 === start) {
126
+ newParts.push(`${start},${end}`);
127
+ } else {
128
+ newParts.push(`${start}-${end}`);
129
+ }
130
+ start = value[p];
131
+ }
132
+ end = value[p];
133
+ }
134
+
135
+ if (start === end) {
136
+ newParts.push(start);
137
+ } else if (end - 1 === start) {
138
+ newParts.push(`${start},${end}`);
139
+ } else {
140
+ newParts.push(`${start}-${end}`);
141
+ }
142
+
143
+ return newParts.join(',');
144
+ }
145
+
146
+ type CronNames = 'seconds' | 'minutes' | 'hours' | 'dates' | 'months' | 'dow';
147
+
148
+ interface CronProps {
149
+ seconds: string | false | null;
150
+ minutes: string | null;
151
+ hours: string | null;
152
+ dates: string | null;
153
+ months: string | null;
154
+ dow: string | null;
155
+ }
156
+
157
+ interface ComplexCronProps {
158
+ cronExpression: string;
159
+ onChange: (cron: string) => void;
160
+ language: ioBroker.Languages;
161
+ }
162
+
163
+ // type CronModes = 'every' | 'everyN' | 'specific';
164
+
165
+ interface ComplexCronState {
166
+ extended: boolean;
167
+ tab: number;
168
+ cron: string;
169
+ seconds?: string | false;
170
+ minutes?: string;
171
+ hours?: string;
172
+ dates?: string;
173
+ months?: string;
174
+ dow?: string;
175
+ modes: CronProps;
176
+ }
177
+
178
+ class ComplexCron extends Component<ComplexCronProps, ComplexCronState> {
179
+ constructor(props: ComplexCronProps) {
180
+ super(props);
181
+ let cron =
182
+ typeof this.props.cronExpression === 'string'
183
+ ? this.props.cronExpression.replace(/^["']/, '').replace(/["']\n?$/, '')
184
+ : '';
185
+ if (cron[0] === '{') {
186
+ cron = '';
187
+ }
188
+ const state = ComplexCron.cron2state(cron || '* * * * *');
189
+
190
+ this.state = {
191
+ extended: false,
192
+ tab: state.seconds !== false ? 1 : 0,
193
+ cron: ComplexCron.state2cron(state),
194
+ modes: {
195
+ seconds: null,
196
+ minutes: null,
197
+ hours: null,
198
+ dates: null,
199
+ months: null,
200
+ dow: null,
201
+ },
202
+ };
203
+ Object.assign(this.state, state);
204
+ if (this.state.cron !== this.props.cronExpression) {
205
+ setTimeout(() => this.props.onChange && this.props.onChange(this.state.cron), 100);
206
+ }
207
+ }
208
+
209
+ static cron2state(cron: string): CronProps {
210
+ cron = cron.replace(/['"]/g, '').trim();
211
+ const cronParts = cron.split(' ').map(p => p.trim());
212
+ let options: CronProps;
213
+
214
+ if (cronParts.length === 6) {
215
+ options = {
216
+ seconds: cronParts[0] || '*',
217
+ minutes: cronParts[1] || '*',
218
+ hours: cronParts[2] || '*',
219
+ dates: cronParts[3] || '*',
220
+ months: cronParts[4] || '*',
221
+ dow: cronParts[5] || '*',
222
+ };
223
+ } else {
224
+ options = {
225
+ seconds: false,
226
+ minutes: cronParts[0] || '*',
227
+ hours: cronParts[1] || '*',
228
+ dates: cronParts[2] || '*',
229
+ months: cronParts[3] || '*',
230
+ dow: cronParts[4] || '*',
231
+ };
232
+ }
233
+ return options;
234
+ }
235
+
236
+ static state2cron(state: ComplexCronState | CronProps): string {
237
+ let text = `${state.minutes} ${state.hours} ${state.dates} ${state.months} ${state.dow}`;
238
+ if (state.seconds !== false) {
239
+ text = `${state.seconds} ${text}`;
240
+ }
241
+ return text;
242
+ }
243
+
244
+ recalcCron(): void {
245
+ const cron = ComplexCron.state2cron(this.state);
246
+ if (cron !== this.state.cron) {
247
+ this.setState({ cron }, () => this.props.onChange && this.props.onChange(this.state.cron));
248
+ }
249
+ }
250
+
251
+ onToggle(i: boolean | number, type: CronNames, max: number): void {
252
+ if (i === true) {
253
+ this.setCronAttr(type, '*');
254
+ } else if (i === false) {
255
+ if (max === 60 || max === 24) {
256
+ this.setCronAttr(type, '0');
257
+ } else {
258
+ this.setCronAttr(type, '1');
259
+ }
260
+ } else {
261
+ const nums = convertMinusIntoArray(this.state[type], max);
262
+ const pos = nums.indexOf(i);
263
+ if (pos !== -1) {
264
+ nums.splice(pos, 1);
265
+ } else {
266
+ nums.push(i);
267
+ nums.sort();
268
+ }
269
+ this.setCronAttr(type, convertArrayIntoMinus(nums, max));
270
+ }
271
+ }
272
+
273
+ getDigitsSelector(type: CronNames, max: number): React.JSX.Element[] {
274
+ let values = [];
275
+ if (max === 7) {
276
+ values = [1, 2, 3, 4, 5, 6, 0];
277
+ } else if (max === 60 || max === 24) {
278
+ for (let i = 0; i < max; i++) {
279
+ values.push(i);
280
+ }
281
+ } else {
282
+ for (let i = 1; i <= max; i++) {
283
+ values.push(i);
284
+ }
285
+ }
286
+
287
+ const parts = convertMinusIntoArray(this.state[type], max);
288
+
289
+ return [
290
+ <Button
291
+ key="removeall"
292
+ variant="outlined"
293
+ style={styles.numberButton}
294
+ // style={{paddingBottom: 20}}
295
+ color="primary"
296
+ onClick={() => this.onToggle(false, type, max)}
297
+ >
298
+ {I18n.t('ra_Deselect all')}
299
+ </Button>,
300
+ <Button
301
+ key="addall"
302
+ variant="contained"
303
+ // style={{paddingBottom: 20}}
304
+ style={styles.numberButton}
305
+ color="secondary"
306
+ onClick={() => this.onToggle(true, type, max)}
307
+ >
308
+ {I18n.t('ra_Select all')}
309
+ </Button>,
310
+ <div key="all">
311
+ {values.map(i => [
312
+ (max === 7 && i === 4) ||
313
+ (max === 12 && i === 7) ||
314
+ (max === 31 && !((i - 1) % 10)) ||
315
+ (max === 60 && i && !(i % 10)) ||
316
+ (max === 24 && i && !(i % 6)) ? (
317
+ <div
318
+ key={`allInner${i}`}
319
+ style={{ width: '100%' }}
320
+ />
321
+ ) : null,
322
+ <Button
323
+ key={`_${i}`}
324
+ variant={parts.indexOf(i) !== -1 ? 'contained' : 'outlined'}
325
+ style={styles.numberButton}
326
+ color={parts.indexOf(i) !== -1 ? 'secondary' : 'primary'}
327
+ onClick={() => this.onToggle(i, type, max)}
328
+ >
329
+ {max === 7 ? I18n.t(WEEKDAYS[i]) : max === 12 ? MONTHS[i - 1] : i}
330
+ </Button>,
331
+ ])}
332
+ </div>,
333
+ ];
334
+ }
335
+
336
+ getPeriodsTab(type: CronNames, max: number): React.JSX.Element | null {
337
+ const value = this.state[type];
338
+ let every = value === '*';
339
+ let everyN = value === undefined || value === null ? false : value.toString().includes('/');
340
+ let select;
341
+ if (this.state.modes[type] === null) {
342
+ select = every ? 'every' : everyN ? 'everyN' : 'specific';
343
+ const modes = JSON.parse(JSON.stringify(this.state.modes));
344
+ modes[type] = select;
345
+ setTimeout(() => this.setState({ modes }, () => this.recalcCron()), 100);
346
+ return null;
347
+ }
348
+
349
+ every = this.state.modes[type] === 'every';
350
+ everyN = this.state.modes[type] === 'everyN';
351
+ select = this.state.modes[type];
352
+
353
+ let valueNumber = 1;
354
+ if (everyN && value) {
355
+ valueNumber = parseInt(value.replace('*/', ''), 10) || 1;
356
+ }
357
+
358
+ return (
359
+ <div>
360
+ <Select
361
+ variant="standard"
362
+ style={{ ...styles.periodSelect, verticalAlign: 'bottom' }}
363
+ value={select}
364
+ onChange={e => {
365
+ const modes = JSON.parse(JSON.stringify(this.state.modes));
366
+ modes[type] = e.target.value;
367
+ if (e.target.value === 'every') {
368
+ this.setCronAttr(type, '*', modes);
369
+ } else if (e.target.value === 'everyN') {
370
+ const num = parseInt((this.state[type] || '').toString().replace('*/', ''), 10) || 1;
371
+ this.setCronAttr(type, `*/${num}`, modes);
372
+ } else if (e.target.value === 'specific') {
373
+ let num = parseInt((this.state[type] || '').toString().split(',')[0], 10) || 0;
374
+ if (!num && (type === 'months' || type === 'dates')) {
375
+ num = 1;
376
+ }
377
+ this.setCronAttr(type, convertArrayIntoMinus(num, max), modes);
378
+ }
379
+ }}
380
+ >
381
+ <MenuItem
382
+ key="every"
383
+ value="every"
384
+ >
385
+ {I18n.t(`sc_every_${type}`)}
386
+ </MenuItem>
387
+ <MenuItem
388
+ key="everyN"
389
+ value="everyN"
390
+ >
391
+ {I18n.t(`sc_everyN_${type}`)}
392
+ </MenuItem>
393
+ <MenuItem
394
+ key="specific"
395
+ value="specific"
396
+ >
397
+ {I18n.t(`sc_specific_${type}`)}
398
+ </MenuItem>
399
+ </Select>
400
+ {/* everyN && false && <span>{value}</span> */}
401
+ {everyN && (
402
+ <TextField
403
+ variant="standard"
404
+ key="interval"
405
+ label={I18n.t(`sc_${type}`)}
406
+ value={valueNumber}
407
+ slotProps={{
408
+ htmlInput: {
409
+ min: 1,
410
+ max,
411
+ },
412
+ inputLabel: {
413
+ shrink: true,
414
+ },
415
+ }}
416
+ onChange={e => {
417
+ // @ts-expect-error is allowed
418
+ this.setState({ [type]: `*/${e.target.value}` }, () => this.recalcCron());
419
+ }}
420
+ type="number"
421
+ margin="normal"
422
+ />
423
+ )}
424
+ {!every && !everyN && this.getDigitsSelector(type, max)}
425
+ </div>
426
+ );
427
+ }
428
+
429
+ static convertCronToText(cron: string, lang: ioBroker.Languages): string {
430
+ if (cron.split(' ').includes('-')) {
431
+ return I18n.t('ra_Invalid CRON');
432
+ }
433
+ return convertCronToText(cron, lang);
434
+ }
435
+
436
+ setCronAttr(attr: CronNames, value: string, modes?: CronProps): void {
437
+ if (modes) {
438
+ if (attr === 'seconds') {
439
+ this.setState({ seconds: value, modes }, () => this.recalcCron());
440
+ } else if (attr === 'minutes') {
441
+ this.setState({ minutes: value, modes }, () => this.recalcCron());
442
+ } else if (attr === 'hours') {
443
+ this.setState({ hours: value, modes }, () => this.recalcCron());
444
+ } else if (attr === 'dates') {
445
+ this.setState({ dates: value, modes }, () => this.recalcCron());
446
+ } else if (attr === 'months') {
447
+ this.setState({ months: value, modes }, () => this.recalcCron());
448
+ } else if (attr === 'dow') {
449
+ this.setState({ dow: value, modes }, () => this.recalcCron());
450
+ } else {
451
+ this.setState({ modes }, () => this.recalcCron());
452
+ }
453
+ } else if (attr === 'seconds') {
454
+ this.setState({ seconds: value }, () => this.recalcCron());
455
+ } else if (attr === 'minutes') {
456
+ this.setState({ minutes: value }, () => this.recalcCron());
457
+ } else if (attr === 'hours') {
458
+ this.setState({ hours: value }, () => this.recalcCron());
459
+ } else if (attr === 'dates') {
460
+ this.setState({ dates: value }, () => this.recalcCron());
461
+ } else if (attr === 'months') {
462
+ this.setState({ months: value }, () => this.recalcCron());
463
+ } else if (attr === 'dow') {
464
+ this.setState({ dow: value }, () => this.recalcCron());
465
+ }
466
+ }
467
+
468
+ render(): React.JSX.Element {
469
+ const tab = this.state.seconds !== false ? this.state.tab : this.state.tab + 1;
470
+ return (
471
+ <div style={styles.mainDiv}>
472
+ <div style={{ paddingLeft: 8, width: '100%' }}>
473
+ <TextField
474
+ variant="standard"
475
+ style={{ width: '100%' }}
476
+ value={this.state.cron}
477
+ disabled
478
+ />
479
+ </div>
480
+ <div style={{ paddingLeft: 8, width: '100%', height: 60 }}>
481
+ {ComplexCron.convertCronToText(this.state.cron, this.props.language || 'en')}
482
+ </div>
483
+ <FormControlLabel
484
+ control={
485
+ <Checkbox
486
+ checked={!!this.state.seconds}
487
+ onChange={e =>
488
+ this.setState({ seconds: e.target.checked ? '*' : false }, () => this.recalcCron())
489
+ }
490
+ />
491
+ }
492
+ label={I18n.t('ra_use seconds')}
493
+ />
494
+ <AppBar
495
+ position="static"
496
+ sx={{ '&.MuiAppBar-root': styles.appBar }}
497
+ color="secondary"
498
+ >
499
+ <Tabs
500
+ value={this.state.tab}
501
+ style={styles.appBar}
502
+ color="secondary"
503
+ onChange={(active, _tab) => this.setState({ tab: _tab })}
504
+ >
505
+ {this.state.seconds !== false && (
506
+ <Tab
507
+ id="sc_seconds"
508
+ label={I18n.t('sc_seconds')}
509
+ />
510
+ )}
511
+ <Tab
512
+ id="minutes"
513
+ label={I18n.t('sc_minutes')}
514
+ />
515
+ <Tab
516
+ id="hours"
517
+ label={I18n.t('sc_hours')}
518
+ />
519
+ <Tab
520
+ id="dates"
521
+ label={I18n.t('sc_dates')}
522
+ />
523
+ <Tab
524
+ id="months"
525
+ label={I18n.t('sc_months')}
526
+ />
527
+ <Tab
528
+ id="dow"
529
+ label={I18n.t('sc_dows')}
530
+ />
531
+ </Tabs>
532
+ </AppBar>
533
+ {tab === 0 && <div style={styles.tabContent}>{this.getPeriodsTab('seconds', 60)}</div>}
534
+ {tab === 1 && <div style={styles.tabContent}>{this.getPeriodsTab('minutes', 60)}</div>}
535
+ {tab === 2 && <div style={styles.tabContent}>{this.getPeriodsTab('hours', 24)}</div>}
536
+ {tab === 3 && <div style={styles.tabContent}>{this.getPeriodsTab('dates', 31)}</div>}
537
+ {tab === 4 && <div style={styles.tabContent}>{this.getPeriodsTab('months', 12)}</div>}
538
+ {tab === 5 && <div style={styles.tabContent}>{this.getPeriodsTab('dow', 7)}</div>}
539
+ </div>
540
+ );
541
+ }
542
+ }
543
+
544
+ export default ComplexCron;