mirror of
				https://github.com/tormachris/cf-workers-status-page.git
				synced 2025-11-04 04:46:24 +01:00 
			
		
		
		
	refactor: switch css framework to tailwind
This commit is contained in:
		@@ -9,7 +9,9 @@ const apiToken = process.env.CF_API_TOKEN
 | 
			
		||||
const kvPrefix = 's_'
 | 
			
		||||
 | 
			
		||||
if (!accountId || !namespaceId || !apiToken) {
 | 
			
		||||
  console.error("Missing required environment variables: CF_ACCOUNT_ID, KV_NAMESPACE_ID, CF_API_TOKEN")
 | 
			
		||||
  console.error(
 | 
			
		||||
    'Missing required environment variables: CF_ACCOUNT_ID, KV_NAMESPACE_ID, CF_API_TOKEN',
 | 
			
		||||
  )
 | 
			
		||||
  process.exit(0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -51,24 +53,26 @@ function loadConfig() {
 | 
			
		||||
  return JSON.parse(config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
getKvMonitors(kvPrefix).then(async kvMonitors => {
 | 
			
		||||
  const config = loadConfig()
 | 
			
		||||
  const monitors = config.monitors.map(key => {
 | 
			
		||||
    return key.id
 | 
			
		||||
  })
 | 
			
		||||
  const kvState = kvMonitors.map(key => {
 | 
			
		||||
    return key.name
 | 
			
		||||
  })
 | 
			
		||||
  const keysForRemoval = kvState.filter(
 | 
			
		||||
    x => !monitors.includes(x.replace(kvPrefix, '')),
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  if (keysForRemoval.length > 0) {
 | 
			
		||||
    console.log(
 | 
			
		||||
      `Removing following keys from KV storage as they are no longer in the config: ${keysForRemoval.join(
 | 
			
		||||
        ', ',
 | 
			
		||||
      )}`,
 | 
			
		||||
getKvMonitors(kvPrefix)
 | 
			
		||||
  .then(async (kvMonitors) => {
 | 
			
		||||
    const config = loadConfig()
 | 
			
		||||
    const monitors = config.monitors.map((key) => {
 | 
			
		||||
      return key.id
 | 
			
		||||
    })
 | 
			
		||||
    const kvState = kvMonitors.map((key) => {
 | 
			
		||||
      return key.name
 | 
			
		||||
    })
 | 
			
		||||
    const keysForRemoval = kvState.filter(
 | 
			
		||||
      (x) => !monitors.includes(x.replace(kvPrefix, '')),
 | 
			
		||||
    )
 | 
			
		||||
    await deleteKvBulk(keysForRemoval)
 | 
			
		||||
  }
 | 
			
		||||
}).catch(e => console.log(e))
 | 
			
		||||
 | 
			
		||||
    if (keysForRemoval.length > 0) {
 | 
			
		||||
      console.log(
 | 
			
		||||
        `Removing following keys from KV storage as they are no longer in the config: ${keysForRemoval.join(
 | 
			
		||||
          ', ',
 | 
			
		||||
        )}`,
 | 
			
		||||
      )
 | 
			
		||||
      await deleteKvBulk(keysForRemoval)
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  .catch((e) => console.log(e))
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								src/components/monitorCard.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/components/monitorCard.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
import config from '../../config.yaml'
 | 
			
		||||
import MonitorStatusLabel from './monitorStatusLabel'
 | 
			
		||||
import MonitorHistogram from './monitorHistogram'
 | 
			
		||||
 | 
			
		||||
const infoIcon = (
 | 
			
		||||
  <svg
 | 
			
		||||
    xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
    viewBox="0 0 20 20"
 | 
			
		||||
    fill="currentColor"
 | 
			
		||||
    className="h-5 mr-2 mx-auto text-blue-500 dark:text-blue-400"
 | 
			
		||||
  >
 | 
			
		||||
    <path
 | 
			
		||||
      fillRule="evenodd"
 | 
			
		||||
      d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
 | 
			
		||||
      clipRule="evenodd"
 | 
			
		||||
    />
 | 
			
		||||
  </svg>
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
export default function MonitorCard({ key, monitor, data }) {
 | 
			
		||||
  return (
 | 
			
		||||
    <div key={key} className="card">
 | 
			
		||||
      <div className="flex flex-row justify-between items-center mb-2">
 | 
			
		||||
        <div className="flex flex-row items-center align-center">
 | 
			
		||||
          {monitor.description && (
 | 
			
		||||
            <div className="tooltip">
 | 
			
		||||
              {infoIcon}
 | 
			
		||||
              <div className="content text-center transform -translate-y-1/2 top-1/2 ml-8 w-72 text-sm object-left">
 | 
			
		||||
                {monitor.description}
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          )}
 | 
			
		||||
          <div className="text-xl">{monitor.name}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <MonitorStatusLabel kvMonitor={data} />
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <MonitorHistogram monitorId={monitor.id} kvMonitor={data} />
 | 
			
		||||
 | 
			
		||||
      <div className="flex flex-row justify-between items-center text-gray-400 text-sm">
 | 
			
		||||
        <div>{config.settings.daysInHistogram} days ago</div>
 | 
			
		||||
        <div>Today</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,21 @@
 | 
			
		||||
import config from '../../config.yaml'
 | 
			
		||||
import { useState } from 'react'
 | 
			
		||||
 | 
			
		||||
const searchIcon = (
 | 
			
		||||
  <svg
 | 
			
		||||
    xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
    viewBox="0 0 20 20"
 | 
			
		||||
    className="h-7 mx-auto text-gray-300 dark:text-gray-600"
 | 
			
		||||
    fill="currentColor"
 | 
			
		||||
  >
 | 
			
		||||
    <path d="M9 9a2 2 0 114 0 2 2 0 01-4 0z" />
 | 
			
		||||
    <path
 | 
			
		||||
      fillRule="evenodd"
 | 
			
		||||
      d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-13a4 4 0 00-3.446 6.032l-2.261 2.26a1 1 0 101.414 1.415l2.261-2.261A4 4 0 1011 5z"
 | 
			
		||||
      clipRule="evenodd"
 | 
			
		||||
    />
 | 
			
		||||
  </svg>
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
export default function MonitorFilter({ active, callback }) {
 | 
			
		||||
  const [input, setInput] = useState('')
 | 
			
		||||
 | 
			
		||||
@@ -21,21 +36,19 @@ export default function MonitorFilter({ active, callback }) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="ui search">
 | 
			
		||||
      <div className="ui icon input">
 | 
			
		||||
        <input
 | 
			
		||||
          className="prompt"
 | 
			
		||||
          type="text"
 | 
			
		||||
          value={input}
 | 
			
		||||
          onInput={handleInput}
 | 
			
		||||
          onKeyDown={handleKeyDown}
 | 
			
		||||
          placeholder="Tap '/' to search"
 | 
			
		||||
          tabIndex={0}
 | 
			
		||||
          ref={
 | 
			
		||||
            (e) => e && active && e.focus()
 | 
			
		||||
          }
 | 
			
		||||
        />
 | 
			
		||||
        <i className="search icon"></i>
 | 
			
		||||
    <div className="col-span-6 sm:col-span-3 relative">
 | 
			
		||||
      <input
 | 
			
		||||
        className="block w-full py-2 px-3 border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-700 rounded-full shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
 | 
			
		||||
        type="text"
 | 
			
		||||
        value={input}
 | 
			
		||||
        onInput={handleInput}
 | 
			
		||||
        onKeyDown={handleKeyDown}
 | 
			
		||||
        placeholder="Tap '/' to search"
 | 
			
		||||
        tabIndex={0}
 | 
			
		||||
        ref={(e) => e && active && e.focus()}
 | 
			
		||||
      />
 | 
			
		||||
      <div className="absolute inset-y-1 right-1 flex z-1 items-center">
 | 
			
		||||
        {searchIcon}
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
 
 | 
			
		||||
@@ -1,56 +1,54 @@
 | 
			
		||||
import config from '../../config.yaml'
 | 
			
		||||
 | 
			
		||||
export default function MonitorHistogram({
 | 
			
		||||
  monitorId,
 | 
			
		||||
  kvMonitor,
 | 
			
		||||
}) {
 | 
			
		||||
export default function MonitorHistogram({ monitorId, kvMonitor }) {
 | 
			
		||||
  // create date and set date - daysInHistogram for the first day of the histogram
 | 
			
		||||
  let date = new Date()
 | 
			
		||||
  date.setDate(date.getDate() - config.settings.daysInHistogram)
 | 
			
		||||
 | 
			
		||||
  let content = null
 | 
			
		||||
 | 
			
		||||
  if (typeof window !== 'undefined') {
 | 
			
		||||
    return (
 | 
			
		||||
      <div
 | 
			
		||||
        key={`${monitorId}-histogram`}
 | 
			
		||||
        className="horizontal flex histogram"
 | 
			
		||||
      >
 | 
			
		||||
        {Array.from(Array(config.settings.daysInHistogram).keys()).map(key => {
 | 
			
		||||
          date.setDate(date.getDate() + 1)
 | 
			
		||||
          const dayInHistogram = date.toISOString().split('T')[0]
 | 
			
		||||
    content = Array.from(Array(config.settings.daysInHistogram).keys()).map(
 | 
			
		||||
      (key) => {
 | 
			
		||||
        date.setDate(date.getDate() + 1)
 | 
			
		||||
        const dayInHistogram = date.toISOString().split('T')[0]
 | 
			
		||||
 | 
			
		||||
          let bg = ''
 | 
			
		||||
          let dayInHistogramLabel = config.settings.dayInHistogramNoData
 | 
			
		||||
        let bg = ''
 | 
			
		||||
        let dayInHistogramLabel = config.settings.dayInHistogramNoData
 | 
			
		||||
 | 
			
		||||
          // filter all dates before first check, check the rest
 | 
			
		||||
          if (kvMonitor && kvMonitor.firstCheck <= dayInHistogram) {
 | 
			
		||||
            if (!kvMonitor.failedDays.includes(dayInHistogram)) {
 | 
			
		||||
              bg = 'green'
 | 
			
		||||
              dayInHistogramLabel = config.settings.dayInHistogramOperational
 | 
			
		||||
            } else {
 | 
			
		||||
              bg = 'orange'
 | 
			
		||||
              dayInHistogramLabel = config.settings.dayInHistogramNotOperational
 | 
			
		||||
            }
 | 
			
		||||
        // filter all dates before first check, check the rest
 | 
			
		||||
        if (kvMonitor && kvMonitor.firstCheck <= dayInHistogram) {
 | 
			
		||||
          if (!kvMonitor.failedDays.includes(dayInHistogram)) {
 | 
			
		||||
            bg = 'green'
 | 
			
		||||
            dayInHistogramLabel = config.settings.dayInHistogramOperational
 | 
			
		||||
          } else {
 | 
			
		||||
            bg = 'yellow'
 | 
			
		||||
            dayInHistogramLabel = config.settings.dayInHistogramNotOperational
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
          return (
 | 
			
		||||
            <div key={key} className="hitbox">
 | 
			
		||||
              <div
 | 
			
		||||
                className={`${bg} bar`}
 | 
			
		||||
                data-tooltip={`${dayInHistogram} - ${dayInHistogramLabel}`}
 | 
			
		||||
              />
 | 
			
		||||
        return (
 | 
			
		||||
          <div key={key} className="hitbox tooltip">
 | 
			
		||||
            <div className={`${bg} bar`} />
 | 
			
		||||
            <div className="content text-center py-1 px-2 mt-2 left-1/2 -ml-20 w-40 text-xs">
 | 
			
		||||
              {dayInHistogram}
 | 
			
		||||
              <br />
 | 
			
		||||
              <span className="font-semibold text-sm">
 | 
			
		||||
                {dayInHistogramLabel}
 | 
			
		||||
              </span>
 | 
			
		||||
            </div>
 | 
			
		||||
          )
 | 
			
		||||
        })}
 | 
			
		||||
      </div>
 | 
			
		||||
    )
 | 
			
		||||
  } else {
 | 
			
		||||
    return (
 | 
			
		||||
      <div
 | 
			
		||||
        key={`${monitorId}-histogram`}
 | 
			
		||||
        className="horizontal flex histogram"
 | 
			
		||||
      >
 | 
			
		||||
        <div className="grey-text">Loading histogram ...</div>
 | 
			
		||||
      </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        )
 | 
			
		||||
      },
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
      key={`${monitorId}-histogram`}
 | 
			
		||||
      className="flex flex-row items-center histogram"
 | 
			
		||||
    >
 | 
			
		||||
      {content}
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +1,34 @@
 | 
			
		||||
import config from '../../config.yaml'
 | 
			
		||||
 | 
			
		||||
export default function MonitorStatusHeader({kvMonitorsMetadata}) {
 | 
			
		||||
  let backgroundColor = 'green'
 | 
			
		||||
  let headerText = config.settings.allmonitorsOperational
 | 
			
		||||
  let textColor = 'black'
 | 
			
		||||
const classes = {
 | 
			
		||||
  green:
 | 
			
		||||
    'bg-green-200 text-green-700 dark:bg-green-700 dark:text-green-200 border-green-300 dark:border-green-600',
 | 
			
		||||
  yellow:
 | 
			
		||||
    'bg-yellow-200 text-yellow-700 dark:bg-yellow-700 dark:text-yellow-200 border-yellow-300 dark:border-yellow-600',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function MonitorStatusHeader({ kvMonitorsMetadata }) {
 | 
			
		||||
  let color = 'green'
 | 
			
		||||
  let text = config.settings.allmonitorsOperational
 | 
			
		||||
 | 
			
		||||
  if (!kvMonitorsMetadata.monitorsOperational) {
 | 
			
		||||
    backgroundColor = 'yellow'
 | 
			
		||||
    headerText = config.settings.notAllmonitorsOperational
 | 
			
		||||
    color = 'yellow'
 | 
			
		||||
    text = config.settings.notAllmonitorsOperational
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={`ui inverted segment ${backgroundColor}`}>
 | 
			
		||||
      <div className="horizontal flex between">
 | 
			
		||||
        <div className={`ui marginless header ${textColor}-text`}>
 | 
			
		||||
          {headerText}
 | 
			
		||||
        </div>
 | 
			
		||||
        {
 | 
			
		||||
          kvMonitorsMetadata.lastUpdate && typeof window !== 'undefined' && (
 | 
			
		||||
          <div className={`${textColor}-text`}>
 | 
			
		||||
            checked {Math.round((Date.now() - kvMonitorsMetadata.lastUpdate.time) / 1000)} sec ago (from {kvMonitorsMetadata.lastUpdate.loc})
 | 
			
		||||
    <div className={`card mb-4 font-semibold ${classes[color]}`}>
 | 
			
		||||
      <div className="flex flex-row justify-between items-center">
 | 
			
		||||
        <div>{text}</div>
 | 
			
		||||
        {kvMonitorsMetadata.lastUpdate && typeof window !== 'undefined' && (
 | 
			
		||||
          <div className="text-xs font-light">
 | 
			
		||||
            checked{' '}
 | 
			
		||||
            {Math.round(
 | 
			
		||||
              (Date.now() - kvMonitorsMetadata.lastUpdate.time) / 1000,
 | 
			
		||||
            )}{' '}
 | 
			
		||||
            sec ago (from {kvMonitorsMetadata.lastUpdate.loc})
 | 
			
		||||
          </div>
 | 
			
		||||
          )
 | 
			
		||||
        }
 | 
			
		||||
        )}
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  )
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,25 @@
 | 
			
		||||
import config from '../../config.yaml'
 | 
			
		||||
 | 
			
		||||
const classes = {
 | 
			
		||||
  gray: 'bg-gray-200 text-gray-800 dark:bg-gray-800 dark:text-gray-200',
 | 
			
		||||
  green: 'bg-green-200 text-green-800 dark:bg-green-800 dark:text-green-200',
 | 
			
		||||
  yellow:
 | 
			
		||||
    'bg-yellow-200 text-yellow-800 dark:bg-yellow-800 dark:text-yellow-200',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function MonitorStatusLabel({ kvMonitor }) {
 | 
			
		||||
  let labelColor = 'grey'
 | 
			
		||||
  let labelText = 'No data'
 | 
			
		||||
  let color = 'gray'
 | 
			
		||||
  let text = 'No data'
 | 
			
		||||
 | 
			
		||||
  if (typeof kvMonitor !== 'undefined') {
 | 
			
		||||
    if (kvMonitor.operational) {
 | 
			
		||||
      labelColor = 'green'
 | 
			
		||||
      labelText = config.settings.monitorLabelOperational
 | 
			
		||||
      color = 'green'
 | 
			
		||||
      text = config.settings.monitorLabelOperational
 | 
			
		||||
    } else {
 | 
			
		||||
      labelColor = 'orange'
 | 
			
		||||
      labelText = config.settings.monitorLabelNotOperational
 | 
			
		||||
      color = 'yellow'
 | 
			
		||||
      text = config.settings.monitorLabelNotOperational
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return <div className={`ui ${labelColor} horizontal label`}>{labelText}</div>
 | 
			
		||||
  return <div className={`pill leading-5 ${classes[color]}`}>{text}</div>
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								src/components/themeSwitcher.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/components/themeSwitcher.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
import { useEffect, useState } from 'react'
 | 
			
		||||
 | 
			
		||||
const moonIcon = (
 | 
			
		||||
  <svg
 | 
			
		||||
    xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
    fill="none"
 | 
			
		||||
    viewBox="0 0 24 24"
 | 
			
		||||
    stroke="currentColor"
 | 
			
		||||
    className="h-5 mx-auto"
 | 
			
		||||
  >
 | 
			
		||||
    <path
 | 
			
		||||
      strokeLinecap="round"
 | 
			
		||||
      strokeLinejoin="round"
 | 
			
		||||
      strokeWidth={2}
 | 
			
		||||
      d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
 | 
			
		||||
    />
 | 
			
		||||
  </svg>
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const sunIcon = (
 | 
			
		||||
  <svg
 | 
			
		||||
    xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
    fill="none"
 | 
			
		||||
    viewBox="0 0 24 24"
 | 
			
		||||
    stroke="currentColor"
 | 
			
		||||
    className="h-5 mx-auto"
 | 
			
		||||
  >
 | 
			
		||||
    <path
 | 
			
		||||
      strokeLinecap="round"
 | 
			
		||||
      strokeLinejoin="round"
 | 
			
		||||
      strokeWidth={2}
 | 
			
		||||
      d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"
 | 
			
		||||
    />
 | 
			
		||||
  </svg>
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
export default function ThemeSwitcher() {
 | 
			
		||||
  const [darkmode, setDark] = useState(localStorage.getItem('theme') === 'dark')
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    setTheme(darkmode ? 'dark' : 'light')
 | 
			
		||||
  }, [darkmode])
 | 
			
		||||
 | 
			
		||||
  const changeTheme = () => {
 | 
			
		||||
    setDark(!darkmode)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const buttonColor = darkmode ? 'bg-gray-700' : 'bg-gray-200'
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <button
 | 
			
		||||
      className={`${buttonColor} rounded-full h-7 w-7 mr-4`}
 | 
			
		||||
      onClick={changeTheme}
 | 
			
		||||
    >
 | 
			
		||||
      {darkmode ? sunIcon : moonIcon}
 | 
			
		||||
    </button>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
@@ -1,10 +1,6 @@
 | 
			
		||||
import config from '../../config.yaml'
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  setKV,
 | 
			
		||||
  getKVWithMetadata,
 | 
			
		||||
  notifySlack,
 | 
			
		||||
} from './helpers'
 | 
			
		||||
import { setKV, getKVWithMetadata, notifySlack } from './helpers'
 | 
			
		||||
 | 
			
		||||
function getDate() {
 | 
			
		||||
  return new Date().toISOString().split('T')[0]
 | 
			
		||||
@@ -12,7 +8,10 @@ function getDate() {
 | 
			
		||||
 | 
			
		||||
export async function processCronTrigger(event) {
 | 
			
		||||
  // Get monitors state from KV
 | 
			
		||||
  let {value: monitorsState, metadata: monitorsStateMetadata} = await getKVWithMetadata('monitors_data', 'json')
 | 
			
		||||
  let {
 | 
			
		||||
    value: monitorsState,
 | 
			
		||||
    metadata: monitorsStateMetadata,
 | 
			
		||||
  } = await getKVWithMetadata('monitors_data', 'json')
 | 
			
		||||
 | 
			
		||||
  // Create empty state objects if not exists in KV storage yet
 | 
			
		||||
  if (!monitorsState) {
 | 
			
		||||
@@ -28,7 +27,7 @@ export async function processCronTrigger(event) {
 | 
			
		||||
  for (const monitor of config.monitors) {
 | 
			
		||||
    // Create default monitor state if does not exist yet
 | 
			
		||||
    if (typeof monitorsState[monitor.id] === 'undefined') {
 | 
			
		||||
      monitorsState[monitor.id] = {failedDays: []}
 | 
			
		||||
      monitorsState[monitor.id] = { failedDays: [] }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    console.log(`Checking ${monitor.name} ...`)
 | 
			
		||||
@@ -43,15 +42,22 @@ export async function processCronTrigger(event) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const checkResponse = await fetch(monitor.url, init)
 | 
			
		||||
    const monitorOperational = checkResponse.status === (monitor.expectStatus || 200)
 | 
			
		||||
    const monitorOperational =
 | 
			
		||||
      checkResponse.status === (monitor.expectStatus || 200)
 | 
			
		||||
 | 
			
		||||
    // Send Slack message on monitor change
 | 
			
		||||
    if (monitorsState[monitor.id].operational !== monitorOperational && typeof SECRET_SLACK_WEBHOOK_URL !== 'undefined' && SECRET_SLACK_WEBHOOK_URL !== 'default-gh-action-secret') {
 | 
			
		||||
        event.waitUntil(notifySlack(monitor, monitorOperational))
 | 
			
		||||
    if (
 | 
			
		||||
      monitorsState[monitor.id].operational !== monitorOperational &&
 | 
			
		||||
      typeof SECRET_SLACK_WEBHOOK_URL !== 'undefined' &&
 | 
			
		||||
      SECRET_SLACK_WEBHOOK_URL !== 'default-gh-action-secret'
 | 
			
		||||
    ) {
 | 
			
		||||
      event.waitUntil(notifySlack(monitor, monitorOperational))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    monitorsState[monitor.id].operational = checkResponse.status === (monitor.expectStatus || 200)
 | 
			
		||||
    monitorsState[monitor.id].firstCheck = monitorsState[monitor.id].firstCheck || getDate()
 | 
			
		||||
    monitorsState[monitor.id].operational =
 | 
			
		||||
      checkResponse.status === (monitor.expectStatus || 200)
 | 
			
		||||
    monitorsState[monitor.id].firstCheck =
 | 
			
		||||
      monitorsState[monitor.id].firstCheck || getDate()
 | 
			
		||||
 | 
			
		||||
    // Set monitorsOperational and push current day to failedDays
 | 
			
		||||
    if (!monitorOperational) {
 | 
			
		||||
@@ -72,11 +78,15 @@ export async function processCronTrigger(event) {
 | 
			
		||||
  const loc = res.headers.get('cf-ray').split('-')[1]
 | 
			
		||||
  monitorsStateMetadata.lastUpdate = {
 | 
			
		||||
    loc,
 | 
			
		||||
    time: Date.now()
 | 
			
		||||
    time: Date.now(),
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Save monitorsState and monitorsStateMetadata to KV storage
 | 
			
		||||
  await setKV('monitors_data', JSON.stringify(monitorsState), monitorsStateMetadata)
 | 
			
		||||
  await setKV(
 | 
			
		||||
    'monitors_data',
 | 
			
		||||
    JSON.stringify(monitorsState),
 | 
			
		||||
    monitorsStateMetadata,
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  return new Response('OK')
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
import config from '../../config.yaml'
 | 
			
		||||
import {useEffect, useState} from 'react'
 | 
			
		||||
import { useEffect, useState } from 'react'
 | 
			
		||||
 | 
			
		||||
export async function getMonitors() {
 | 
			
		||||
  return await getKVWithMetadata('monitors_data', "json")
 | 
			
		||||
  return await getKVWithMetadata('monitors_data', 'json')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function setKV(key, value, metadata, expirationTtl) {
 | 
			
		||||
@@ -23,11 +23,10 @@ export async function notifySlack(monitor, operational) {
 | 
			
		||||
            type: 'section',
 | 
			
		||||
            text: {
 | 
			
		||||
              type: 'mrkdwn',
 | 
			
		||||
              text: `Monitor *${monitor.name}* changed status to *${
 | 
			
		||||
                operational
 | 
			
		||||
              text: `Monitor *${monitor.name}* changed status to *${operational
 | 
			
		||||
                  ? config.settings.monitorLabelOperational
 | 
			
		||||
                  : config.settings.monitorLabelNotOperational
 | 
			
		||||
              }*`,
 | 
			
		||||
                }*`,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
@@ -35,11 +34,9 @@ export async function notifySlack(monitor, operational) {
 | 
			
		||||
            elements: [
 | 
			
		||||
              {
 | 
			
		||||
                type: 'mrkdwn',
 | 
			
		||||
                text: `${
 | 
			
		||||
                  operational ? ':white_check_mark:' : ':x:'
 | 
			
		||||
                } \`${monitor.method ? monitor.method : "GET"} ${monitor.url}\` - :eyes: <${
 | 
			
		||||
                  config.settings.url
 | 
			
		||||
                }|Status Page>`,
 | 
			
		||||
                text: `${operational ? ':white_check_mark:' : ':x:'} \`${monitor.method ? monitor.method : 'GET'
 | 
			
		||||
                  } ${monitor.url}\` - :eyes: <${config.settings.url
 | 
			
		||||
                  }|Status Page>`,
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
@@ -59,24 +56,24 @@ export function useKeyPress(targetKey) {
 | 
			
		||||
 | 
			
		||||
  function downHandler({ key }) {
 | 
			
		||||
    if (key === targetKey) {
 | 
			
		||||
      setKeyPressed(true);
 | 
			
		||||
      setKeyPressed(true)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const upHandler = ({ key }) => {
 | 
			
		||||
    if (key === targetKey) {
 | 
			
		||||
      setKeyPressed(false);
 | 
			
		||||
      setKeyPressed(false)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    window.addEventListener('keydown', downHandler);
 | 
			
		||||
    window.addEventListener('keyup', upHandler);
 | 
			
		||||
    window.addEventListener('keydown', downHandler)
 | 
			
		||||
    window.addEventListener('keyup', upHandler)
 | 
			
		||||
 | 
			
		||||
    return () => {
 | 
			
		||||
      window.removeEventListener('keydown', downHandler);
 | 
			
		||||
      window.removeEventListener('keyup', upHandler);
 | 
			
		||||
    };
 | 
			
		||||
      window.removeEventListener('keydown', downHandler)
 | 
			
		||||
      window.removeEventListener('keyup', upHandler)
 | 
			
		||||
    }
 | 
			
		||||
  }, [])
 | 
			
		||||
 | 
			
		||||
  return keyPressed
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user