Brock_Stones

Untitled

Jun 17th, 2025 (edited)
46
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.89 KB | None | 0 0
  1. <!DOCTYPE html>
  2.  
  3. <html lang="en">
  4. <head>
  5. <meta charset="utf-8"/>
  6. <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
  7. <title>Epic Downtime Utility</title>
  8. <style>
  9. body {
  10. font-family: 'Josefin Sans', sans-serif;
  11. background: url(./mountain-6191719.png);
  12. background-attachment: fixed;
  13. background-position: center;
  14. background-repeat: no-repeat;
  15. background-size: cover;
  16. display: flex;
  17. justify-content: center;
  18. min-height: 100vh;
  19. margin: 0;
  20. overflow-y: auto;
  21. }
  22. .wrapper {
  23. background: linear-gradient(45deg, #3459ff5e, #ffffff54, #3459ff5e);
  24. border-radius: 2rem;
  25. padding: 2rem;
  26. max-width: 1440px;
  27. width: 90%;
  28. display: flex;
  29. flex-direction: column;
  30. align-items: center;
  31. }
  32. h1 {
  33. font-family: 'Poppins', sans-serif;
  34. color: red;
  35. font-size: 4rem;
  36. font-style: italic;
  37. letter-spacing: -0.4rem;
  38. margin: 0.5rem 0;
  39. text-align: center;
  40. }
  41. h2 {
  42. font-size: 2rem;
  43. color: #fff;
  44. font-family: 'Poppins', sans-serif;
  45. font-weight: 600;
  46. text-shadow: 0px 1px 0px rgb(255 255 255 / 30%), 0px -1px 0px rgb(0 0 0);
  47. text-align: center;
  48. margin-top: 2rem;
  49. }
  50. #epicStatus h3 {
  51. margin-top: 0;
  52. color: #000;
  53. }
  54. #systemStatus {
  55. display: flex;
  56. flex-wrap: wrap;
  57. gap: 1rem;
  58. margin-top: 1rem;
  59. justify-content: center;
  60. }
  61. .system {
  62. background: #fff8;
  63. padding: 0.5rem;
  64. border-radius: 1rem;
  65. display: flex;
  66. flex-direction: column;
  67. align-items: center;
  68. }
  69. #timeInputs {
  70. margin-top: 1rem;
  71. display: flex;
  72. justify-content: center;
  73. gap: 1rem;
  74. }
  75. #buttons {
  76. display: flex;
  77. justify-content: center;
  78. margin-top: 1rem;
  79. flex-wrap: wrap;
  80. gap: 0.5rem;
  81. }
  82. button {
  83. padding: 0.5rem 1rem;
  84. border: none;
  85. border-radius: 0.5rem;
  86. background-color: #6465ed;
  87. color: #fff;
  88. cursor: pointer;
  89. font-weight: bold;
  90. min-width: 200px;
  91. }
  92. #subjectOutput {
  93. width: 100%;
  94. }
  95. #output {
  96. width: 100%;
  97. height: 300px;
  98. margin-top: 1rem;
  99. padding: 0.5rem;
  100. font-family: monospace;
  101. white-space: pre-wrap;
  102. box-sizing: border-box;
  103. }
  104. </style>
  105. </head>
  106. <body>
  107. <div class="wrapper">
  108. <h1>Epic Downtime Utility</h1>
  109. <!-- Epic Status -->
  110. <div id="epicStatus">
  111.   <h3 style="text-align: center;">Epic System Status</h3>
  112.   <div class="epic-status-options">
  113.    
  114.    
  115.    
  116.   </div>
  117. <div class="epic-status-options"><label><input checked="" name="EpicStatus" type="radio" value="UP"/> UP</label><label><input name="EpicStatus" type="radio" value="TRANSPARENT_PAUSE"/> TRANSPARENT PAUSE</label><label><input name="EpicStatus" type="radio" value="FULLY_DOWN"/> FULLY DOWN</label></div></div>
  118. <h2>System Status</h2>
  119. <div id="systemStatus">
  120. <div class="system" data-name="WellSky">
  121. <div>WellSky</div>
  122. <label><input checked="" name="WellSky" type="radio" value="UP"/> UP</label>
  123. <label><input name="WellSky" type="radio" value="DOWN"/> DOWN</label>
  124. </div>
  125. <div class="system" data-name="Data Innovation">
  126. <div>Data Innovation</div>
  127. <label><input checked="" name="Data Innovation" type="radio" value="UP"/> UP</label>
  128. <label><input name="Data Innovation" type="radio" value="DOWN"/> DOWN</label>
  129. </div>
  130. <div class="system" data-name="Capsule">
  131. <div>Capsule</div>
  132. <label><input checked="" name="Capsule" type="radio" value="UP"/> UP</label>
  133. <label><input name="Capsule" type="radio" value="DOWN"/> DOWN</label>
  134. </div>
  135. <div class="system" data-name="Onbase">
  136. <div>Onbase</div>
  137. <label><input checked="" name="Onbase" type="radio" value="UP"/> UP</label>
  138. <label><input name="Onbase" type="radio" value="DOWN"/> DOWN</label>
  139. </div>
  140. <div class="system" data-name="Forward Advantage">
  141. <div>Forward Advantage</div>
  142. <label><input checked="" name="Forward Advantage" type="radio" value="UP"/> UP</label>
  143. <label><input name="Forward Advantage" type="radio" value="DOWN"/> DOWN</label>
  144. </div>
  145. <div class="system" data-name="Orpheus">
  146. <div>Orpheus</div>
  147. <label><input checked="" name="Orpheus" type="radio" value="UP"/> UP</label>
  148. <label><input name="Orpheus" type="radio" value="DOWN"/> DOWN</label>
  149. </div>
  150. <div class="system" data-name="Cloverleaf">
  151. <div>Cloverleaf</div>
  152. <label><input checked="" name="Cloverleaf" type="radio" value="UP"/> UP</label>
  153. <label><input name="Cloverleaf" type="radio" value="DOWN"/> DOWN</label>
  154. </div>
  155. </div>
  156. <div id="timeInputs">
  157. <label>Downtime Start: <input id="startTime" type="text" value="3:00am"/></label>
  158. <label>Downtime End: <input id="endTime" type="text" value="3:30am"/></label>
  159. </div>
  160. <div id="buttons">
  161. <button id="reminderBtn">Downtime Reminder</button><button id="statusBtn">Third party status message</button><button id="completeBtn">Downtime Complete</button></div>
  162. <label for="subjectOutput">Subject:</label><textarea id="subjectOutput" oninput="this.style.height = ''; this.style.height = this.scrollHeight + 'px'" readonly="True" style="overflow:hidden; resize:none;"></textarea><textarea id="output" readonly=""></textarea>
  163. <script>
  164. // Systems data
  165. const systems = [
  166. {
  167. name: "WellSky",
  168. upMsg: "Transfusion Medicine (Wellsky) is Up and Online",
  169. downMsg: "Transfusion Medicine (Wellsky) is down. Use downtime processes for blood product administration. Ordering via Epic is not impacted."
  170. },
  171. {
  172. name: "Data Innovation",
  173. upMsg: "Laboratory Specimen Reporting (Data Innovations) is Up and Online",
  174. downMsg: "Laboratory Specimen Reporting (Data Innovations) is down. Expect slower turnaround times for lab result reporting."
  175. },
  176. {
  177. name: "Capsule",
  178. upMsg: "Integrated medical devices (Capsule) are Up and Online",
  179. downMsg: "Integrated medical devices (Capsule) such as vital signs monitors, dialysis machines, CRRT machines, ventilators, anesthetic gas machines, patient central station systems, aortic balloon pumps etc. may not receive the most up to date information from Epic."
  180. },
  181. {
  182. name: "Onbase",
  183. upMsg: "Document retrieval and scanning in Media Manager are Up and Online",
  184. downMsg: "Document retrieval and scanning in Media Manager is down. Clinical users and health records will be impacted."
  185. },
  186. {
  187. name: "Forward Advantage",
  188. upMsg: "Faxing via Epic is Up and Online",
  189. downMsg: "Faxing via Epic is delayed and will be queued and sent when services are restored."
  190. },
  191. {
  192. name: "Orpheus",
  193. upMsg: "Endoscopy images (Orpheus) via Epic is Up and Online",
  194. downMsg: "New endoscopy images (Orpheus) will not be available in Epic for resulting. Images will upload once Orpheus is restored."
  195. },
  196. {
  197. name: "Cloverleaf",
  198. upMsg: "Results and orders to Epic from external systems are flowing and updating properly.",
  199. downMsg: "Results and orders to Epic from external systems will not be updated until services are restored.\nExamples of external systems include:\n- Ontario Health services such as OLIS, eCHN, and Clinical Viewer\n- Local site applications such as PACS, pharmacy applications, and dietary systems."
  200. }
  201. ];
  202.  
  203. const output = document.getElementById('output');
  204.  
  205. function getSelectedRadio(groupName) {
  206. const radios = document.getElementsByName(groupName);
  207. for (const r of radios) {
  208. if (r.checked) return r.value;
  209. }
  210. return null;
  211. }
  212.  
  213. function analyzeThirdPartyStatus() {
  214. let allUp = true;
  215. let allDown = true;
  216. for (const s of systems) {
  217. const radios = document.getElementsByName(s.name);
  218. let status = "UP";
  219. for (const r of radios) {
  220. if (r.checked && r.value === "DOWN") {
  221. status = "DOWN";
  222. break;
  223. }
  224. }
  225. if (status !== "UP") {
  226. allUp = false;
  227. }
  228. if (status !== "DOWN") {
  229. allDown = false;
  230. }
  231. }
  232. if (allDown) return "ALL_DOWN";
  233. if (allUp) return "ALL_UP";
  234. return "SOME_DOWN";
  235. }
  236.  
  237. // "Third party status message"
  238. document.getElementById('statusBtn').addEventListener('click', () => {
  239.   const epicStatus = getSelectedRadio('EpicStatus');
  240.   const start = document.getElementById('startTime').value;
  241.   const end = document.getElementById('endTime').value;
  242.  
  243.   let message = "Planned Service Interruption Update\n\n";
  244.  
  245.   if (epicStatus === 'TRANSPARENT_PAUSE') {
  246.     message += `Epic will be paused for up to 5 minutes between ${start} and ${end}.\n`;
  247.   } else if (epicStatus === 'FULLY_DOWN') {
  248.     message += `Epic is down. Please leverage your SRO during this time.\n`;
  249.   } else if (epicStatus === 'UP') {
  250.     message += `Epic is Up and Available.\n`;
  251.   } else {
  252.     message += `A reminder that Epic will be down during this time.\n`;
  253.   }
  254.  
  255.   if (message.startsWith("Subject: ")) {
  256. const subjectEnd = message.indexOf("\n");
  257. if (subjectEnd !== -1) {
  258. subjectOutput.value = message.substring(8, subjectEnd).trim();
  259. output.value = message.substring(subjectEnd + 1).trim();
  260. } else {
  261. subjectOutput.value = message.substring(8).trim();
  262. output.value = "";
  263. }
  264. } else {
  265. subjectOutput.value = "";
  266. output.value = message;
  267. }
  268.  
  269.   for (const s of systems) {
  270.     const radios = document.getElementsByName(s.name);
  271.     let status = "UP";
  272.     for (const r of radios) {
  273.       if (r.checked && r.value === "DOWN") {
  274.         status = "DOWN";
  275.         break;
  276.       }
  277.     }
  278.     output.value += "- " + (status === "UP" ? s.upMsg : s.downMsg) + "\n";
  279.   }
  280. });
  281.  
  282. // "Downtime Reminder"
  283. document.getElementById('reminderBtn').addEventListener('click', () => {
  284.   const start = document.getElementById('startTime').value;
  285.   const end = document.getElementById('endTime').value;
  286.   const thirdPartyStatus = analyzeThirdPartyStatus();
  287.   const epicStatus = getSelectedRadio('EpicStatus');
  288.  
  289.   if (thirdPartyStatus === 'ALL_UP' && epicStatus === 'UP') {
  290.     output.value = "Nothing is down. Please select third party or Epic to be down.";
  291.     return;
  292.   }
  293.  
  294.   const header = "Reminder: Planned Service Interruption\n\n";
  295.   let message = header;
  296.  
  297.   if (epicStatus === 'TRANSPARENT_PAUSE') {
  298.     message += `A reminder that Epic will be paused for up to 5 minutes between ${start} and ${end}.\n`;
  299.   } else if (epicStatus === 'FULLY_DOWN') {
  300.     message += `A reminder that Epic will be down. Please leverage your SRO during this time.\n`;
  301.   } else if (epicStatus === 'UP') {
  302.     message += `A reminder that Epic will be Up and Available between ${start} and ${end}.\n`;
  303.   } else {
  304.     message += `A reminder that Epic will be down between ${start} and ${end}.\n`;
  305.   }
  306.  
  307.   // Handle the third-party impact message
  308.   if (thirdPartyStatus === 'ALL_DOWN') {
  309.     message += "All Third Party Systems will be down.\n";
  310.   } else if (thirdPartyStatus === 'SOME_DOWN') {
  311.     message += "Some third-party systems will be down.\n";
  312.   } else {
  313.     message += "All third-party systems will be up.\n";
  314.   }
  315.  
  316.   if (message.startsWith("Subject: ")) {
  317. const subjectEnd = message.indexOf("\n");
  318. if (subjectEnd !== -1) {
  319. subjectOutput.value = message.substring(8, subjectEnd).trim();
  320. output.value = message.substring(subjectEnd + 1).trim();
  321. } else {
  322. subjectOutput.value = message.substring(8).trim();
  323. output.value = "";
  324. }
  325. } else {
  326. subjectOutput.value = "";
  327. output.value = message;
  328. }
  329. });
  330.  
  331.  
  332. // "Downtime Complete"
  333. document.getElementById('completeBtn').addEventListener('click', () => {
  334. const end = document.getElementById('endTime').value;
  335. const epicStatus = getSelectedRadio('EpicStatus');
  336. const thirdPartyStatus = analyzeThirdPartyStatus();
  337.  
  338. if (epicStatus !== 'UP' || thirdPartyStatus !== 'ALL_UP') {
  339. output.value = "Not everything is up. Please select all systems to be up.";
  340. } else {
  341. subjectOutput.value = "Planned Service Interruption Completed.";
  342. output.value = `Please note that Epic and third-party systems are now available as of ${end}. An Email Notification will be released shortly.`;
  343. }
  344. });
  345. </script>
  346. </div>
  347. </body>
  348. </html>
Advertisement
Add Comment
Please, Sign In to add comment