Automation.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import { useEffect, useState } from "react";
  2. import { Button, Drawer, Icon, Steps, Typography } from "tiny-ui";
  3. import { useLocalStorage } from "lib/state";
  4. import { isBlank } from "lib/utils";
  5. const { Step } = Steps;
  6. const { Heading, Paragraph, Text } = Typography;
  7. const Automation = ({
  8. automation,
  9. presets,
  10. clients,
  11. names,
  12. onPreset,
  13. onSync,
  14. onPower,
  15. ...props
  16. }) => {
  17. const [current, setCurrent] = useLocalStorage(-1);
  18. const [total, setTotal] = useState();
  19. const [visible, setVisible] = useState(false);
  20. const getTitle = (indx) => presets?.[indx]?.name || indx;
  21. const getName = (v) => {
  22. let indx = clients?.findIndex((o) => o === v);
  23. return indx > -1 ? names?.[indx] : v;
  24. };
  25. const getDescription = (indx) => {
  26. return (
  27. (automation?.[indx] &&
  28. Object.keys(automation?.[indx])
  29. ?.map((o) => getName(o))
  30. ?.join(", ")) ||
  31. null
  32. );
  33. };
  34. const handleChange = (indx) => {
  35. let keys = Object.keys(automation?.[indx]);
  36. let preset = { clients: keys || [], value: indx };
  37. let power = { on: [], off: [] };
  38. let sync = { enable: [], disable: [] };
  39. // loop the keys and determine what to do
  40. for (let key of keys) {
  41. if (automation?.[indx]?.[key]?.on === true) power.on.push(key);
  42. else power.off.push(key);
  43. if (automation?.[indx]?.[key]?.sync === true) sync.enable.push(key);
  44. else sync.disable.push(key);
  45. }
  46. if (!isBlank(power?.on)) onPower({ clients: power?.on, value: "on" }); // power on
  47. if (!isBlank(power?.off)) onPower({ clients: power?.off, value: "off" }); // power off
  48. if (!isBlank(sync?.enable))
  49. onSync({ clients: sync?.enable, value: "enable" }); // enable sync
  50. if (!isBlank(sync?.disable))
  51. onSync({ clients: sync?.disable, value: "disable" }); // disable sync
  52. onPreset(preset); // apply the preset
  53. };
  54. useEffect(() => {
  55. setTotal((automation && Object.keys(automation)) || 0);
  56. }, [automation]);
  57. useEffect(() => {
  58. if (current > -1 && current < total) handleChange(current + 1);
  59. }, [current]);
  60. let steps = Object.keys(automation).map((o, i) => {
  61. return (
  62. <Step
  63. key={i}
  64. title={
  65. <>
  66. {getTitle(o)}
  67. {current === o - 1 ? (
  68. <div style={{ float: "right" }}>
  69. <Button
  70. title="Reapply"
  71. round
  72. icon={<Icon name="loader-circle" />}
  73. onClick={() => {
  74. handleChange(o);
  75. }}
  76. />
  77. </div>
  78. ) : null}
  79. </>
  80. }
  81. description={getDescription(o)}
  82. ></Step>
  83. );
  84. });
  85. return (
  86. <>
  87. <div style={{ position: "sticky", top: "60px", marginBottom: "2rem" }}>
  88. <Button.Group size="lg" round>
  89. <Button
  90. title="Previous"
  91. icon={<Icon name="arrow-left" />}
  92. onClick={() => {
  93. let next = current - 1;
  94. if (next < 0) next = 0;
  95. setCurrent(next);
  96. }}
  97. />
  98. <Button
  99. title="Reapply"
  100. icon={<Icon name="loader-circle" />}
  101. onClick={() => {
  102. handleChange(current);
  103. }}
  104. />
  105. <Button
  106. title="Next"
  107. icon={<Icon name="arrow-right" />}
  108. onClick={() => {
  109. let next = current + 1;
  110. if (next > total) next = 0;
  111. setCurrent(next);
  112. }}
  113. />
  114. </Button.Group>
  115. <Button.Group size="lg" round>
  116. <Button
  117. title="Help"
  118. icon={<Icon name="question-fill" />}
  119. onClick={() => {
  120. setVisible(true);
  121. }}
  122. />
  123. </Button.Group>
  124. </div>
  125. <Steps
  126. current={current}
  127. direction="vertical"
  128. onChange={(v) => setCurrent(v)}
  129. >
  130. {steps}
  131. </Steps>
  132. <Drawer
  133. header="Introduction"
  134. placement="right"
  135. size={480}
  136. onClose={() => setVisible(false)}
  137. visible={visible}
  138. >
  139. <>
  140. <Paragraph>
  141. Select one of the presets from the left to start applying preset
  142. automation.
  143. </Paragraph>
  144. <Paragraph>
  145. You can use the navigation buttons above to advance forward{" "}
  146. <Icon name="arrow-right" size={16} /> and backward{" "}
  147. <Icon name="arrow-left" size={16} /> through the preset list.
  148. </Paragraph>
  149. <Paragraph>
  150. If a preset fails to apply to all of the intended WLED instances
  151. then use the Reapply button <Icon name="loader-circle" size={16} />{" "}
  152. within the navigation menu bar or within the target step.
  153. </Paragraph>
  154. </>
  155. </Drawer>
  156. </>
  157. );
  158. };
  159. export default Automation;