mirror of
https://github.com/tormachris/cf-workers-status-page.git
synced 2024-11-23 22:45:43 +01:00
Merge pull request #8 from aexvir/aexvir/monitor-filter
feat: add monitor filter field
This commit is contained in:
commit
3dddea4f45
@ -13,6 +13,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"flareact": "^0.7.1",
|
"flareact": "^0.7.1",
|
||||||
|
"laco": "^1.2.1",
|
||||||
|
"laco-react": "^1.1.0",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1"
|
"react-dom": "^16.13.1"
|
||||||
},
|
},
|
||||||
|
@ -5,11 +5,28 @@ import {
|
|||||||
getLastUpdate,
|
getLastUpdate,
|
||||||
getMonitors,
|
getMonitors,
|
||||||
getMonitorsHistory,
|
getMonitorsHistory,
|
||||||
|
useKeyPress,
|
||||||
} from '../src/functions/helpers'
|
} from '../src/functions/helpers'
|
||||||
|
|
||||||
import config from '../config.yaml'
|
import config from '../config.yaml'
|
||||||
import MonitorStatusLabel from '../src/components/monitorStatusLabel'
|
import MonitorStatusLabel from '../src/components/monitorStatusLabel'
|
||||||
import MonitorStatusHeader from '../src/components/monitorStatusHeader'
|
import MonitorStatusHeader from '../src/components/monitorStatusHeader'
|
||||||
|
import MonitorFilter from '../src/components/monitorFilter'
|
||||||
|
|
||||||
|
import { Store } from 'laco'
|
||||||
|
import { useStore } from 'laco-react'
|
||||||
|
|
||||||
|
const MonitorStore = new Store(
|
||||||
|
{
|
||||||
|
monitors: config.monitors,
|
||||||
|
visible: config.monitors,
|
||||||
|
activeFilter: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const filterByTerm = (term) => MonitorStore.set(
|
||||||
|
state => ({ visible: state.monitors.filter((monitor) => monitor.name.toLowerCase().includes(term)) })
|
||||||
|
)
|
||||||
|
|
||||||
export async function getEdgeProps() {
|
export async function getEdgeProps() {
|
||||||
// get KV data
|
// get KV data
|
||||||
@ -50,6 +67,9 @@ export default function Index({
|
|||||||
monitorsOperational,
|
monitorsOperational,
|
||||||
kvLastUpdate,
|
kvLastUpdate,
|
||||||
}) {
|
}) {
|
||||||
|
const state = useStore(MonitorStore)
|
||||||
|
const slash = useKeyPress('/')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Head>
|
<Head>
|
||||||
@ -62,18 +82,24 @@ export default function Index({
|
|||||||
<link rel="stylesheet" href="./main.css" />
|
<link rel="stylesheet" href="./main.css" />
|
||||||
</Head>
|
</Head>
|
||||||
<div className="ui basic segment container">
|
<div className="ui basic segment container">
|
||||||
<h1 className="ui huge title header">
|
<div className="horizontal flex between">
|
||||||
<img
|
<h1 className="ui huge marginless title header">
|
||||||
className="ui middle aligned tiny image"
|
<img
|
||||||
src={config.settings.logo}
|
className="ui middle aligned tiny image"
|
||||||
|
src={config.settings.logo}
|
||||||
|
/>
|
||||||
|
{config.settings.title}
|
||||||
|
</h1>
|
||||||
|
<MonitorFilter
|
||||||
|
active={slash}
|
||||||
|
callback={filterByTerm}
|
||||||
/>
|
/>
|
||||||
{config.settings.title}
|
</div>
|
||||||
</h1>
|
|
||||||
<MonitorStatusHeader
|
<MonitorStatusHeader
|
||||||
operational={monitorsOperational}
|
operational={monitorsOperational}
|
||||||
lastUpdate={kvLastUpdate}
|
lastUpdate={kvLastUpdate}
|
||||||
/>
|
/>
|
||||||
{config.monitors.map((monitor, key) => {
|
{state.visible.map((monitor, key) => {
|
||||||
return (
|
return (
|
||||||
<div key={key} className="ui segment">
|
<div key={key} className="ui segment">
|
||||||
<div
|
<div
|
||||||
|
42
src/components/monitorFilter.js
Normal file
42
src/components/monitorFilter.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import config from '../../config.yaml'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
export default function MonitorFilter({ active, callback }) {
|
||||||
|
const [input, setInput] = useState('')
|
||||||
|
|
||||||
|
const handleInput = (event) => {
|
||||||
|
// ignore focus trigger
|
||||||
|
if (event.target.value === '/') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setInput(event.target.value)
|
||||||
|
callback(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKeyDown = (event) => {
|
||||||
|
// blur input field on escape
|
||||||
|
if (event.keyCode === 27) {
|
||||||
|
event.target.blur()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import config from '../../config.yaml'
|
import config from '../../config.yaml'
|
||||||
|
import {useEffect, useState} from 'react'
|
||||||
|
|
||||||
export async function getMonitors() {
|
export async function getMonitors() {
|
||||||
const monitors = await listKV('s_')
|
const monitors = await listKV('s_')
|
||||||
@ -115,3 +116,31 @@ export async function notifySlack(monitor, newMetadata) {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useKeyPress(targetKey) {
|
||||||
|
const [keyPressed, setKeyPressed] = useState(false)
|
||||||
|
|
||||||
|
function downHandler({ key }) {
|
||||||
|
if (key === targetKey) {
|
||||||
|
setKeyPressed(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const upHandler = ({ key }) => {
|
||||||
|
if (key === targetKey) {
|
||||||
|
setKeyPressed(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener('keydown', downHandler);
|
||||||
|
window.addEventListener('keyup', upHandler);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('keydown', downHandler);
|
||||||
|
window.removeEventListener('keyup', upHandler);
|
||||||
|
};
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return keyPressed
|
||||||
|
}
|
||||||
|
10
yarn.lock
10
yarn.lock
@ -3902,6 +3902,16 @@ kind-of@^6.0.0, kind-of@^6.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
|
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
|
||||||
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
||||||
|
|
||||||
|
laco-react@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/laco-react/-/laco-react-1.1.0.tgz#8572117aabd245e9ff0000aab534c0f817da8238"
|
||||||
|
integrity sha512-RbN7dFUH7RsNpRMB46gWSjEMXo7WDhgkKl8HXpxn1o/bJItHj7FT0VsIWF963mrvORncIgI7bnZJ6KPcHV8fvA==
|
||||||
|
|
||||||
|
laco@^1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/laco/-/laco-1.2.1.tgz#4acf24ab4ea7b2983d10c2fd982208e96a315158"
|
||||||
|
integrity sha512-fw3vWTR1L/u/XTReyBQt3bnhylMLMqp+YoIFEr52bb9NqRnwPcvTQuFH0TRMyvg0Zucbx+eRViO4wxoij6xzDg==
|
||||||
|
|
||||||
last-call-webpack-plugin@^3.0.0:
|
last-call-webpack-plugin@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555"
|
resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555"
|
||||||
|
Loading…
Reference in New Issue
Block a user