mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-15 10:29:47 +00:00
improved device dashboard events table
This commit is contained in:
1 parent
bb983fb4b2
commit
5c87f2f22c
5 files changed
+51
-21
No files matched your search
@@ -180,10 +180,8 @@ static size_t print_events(void (*out)(char, void *), void *ptr, va_list *ap) {
|
||||
return len;
|
||||
}
|
||||
|
||||
static void handle_events_get(struct mg_connection *c, struct mg_str query) {
|
||||
int pageno = atoi(query.ptr + 5); // query is represented by 'page=<page_id>'
|
||||
|
||||
if (pageno > MAX_EVENTS_NO / EVENTS_PER_PAGE + 1 || pageno < 1) pageno = 1;
|
||||
static void handle_events_get(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
int pageno = mg_json_get_long(hm->body, "$.page", 1);
|
||||
mg_http_reply(c, 200, s_json_header, "{%m:[%M], %m:%d}", MG_ESC("arr"),
|
||||
print_events, pageno, MG_ESC("totalCount"), MAX_EVENTS_NO);
|
||||
}
|
||||
@@ -240,7 +238,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
} else if (mg_http_match_uri(hm, "/api/stats/get")) {
|
||||
handle_stats_get(c);
|
||||
} else if (mg_http_match_uri(hm, "/api/events/get")) {
|
||||
handle_events_get(c, hm->query);
|
||||
handle_events_get(c, hm);
|
||||
} else if (mg_http_match_uri(hm, "/api/settings/get")) {
|
||||
handle_settings_get(c);
|
||||
} else if (mg_http_match_uri(hm, "/api/settings/set")) {
|
||||
|
||||
@@ -212,31 +212,28 @@ export function Pagination({ totalItems, itemsPerPage, currentPage, setPageFn })
|
||||
const greaterThanSymbol = ">";
|
||||
const whiteSpace = " ";
|
||||
|
||||
// Function to handle rendering of individual page item
|
||||
const PageItem = ({ page, isActive }) => (
|
||||
html`<a
|
||||
onClick=${() => setPageFn(page)}
|
||||
className=${`relative inline-flex items-center px-4 py-2 text-sm font-semibold ${isActive ? 'bg-blue-600 text-white' : 'text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50'} focus:z-20 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600`}
|
||||
className=${`relative inline-flex items-center px-4 py-2 text-sm font-semibold ${isActive ? 'bg-blue-600 text-white' : ' cursor-pointer text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50'} focus:z-20 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600`}
|
||||
>
|
||||
${page}
|
||||
</a>`
|
||||
);
|
||||
|
||||
return html`
|
||||
<div className="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6">
|
||||
<div className="flex items-center justify-between bg-white px-2 py-1.5">
|
||||
<div className="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between space-x-4">
|
||||
<p className="text-sm text-gray-700">
|
||||
showing entries <span className="font-medium">${(currentPage - 1) * itemsPerPage + 1}</span> - <span className="font-medium">${Math.min(currentPage * itemsPerPage, totalItems)}</span> of ${whiteSpace}
|
||||
showing <span className="font-medium">${(currentPage - 1) * itemsPerPage + 1}</span> - <span className="font-medium">${Math.min(currentPage * itemsPerPage, totalItems)}</span> of ${whiteSpace}
|
||||
<span className="font-medium">${totalItems}</span> results
|
||||
</p>
|
||||
<div>
|
||||
<nav className="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
||||
<a
|
||||
onClick=${() => setPageFn(Math.max(currentPage - 1, 1))}
|
||||
className="relative inline-flex items-center rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
|
||||
className="relative inline-flex px-4 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 ${currentPage != 1 ? 'cursor-pointer' : ''} focus:z-20 focus:outline-offset-0">
|
||||
${lessThanSymbol}
|
||||
<span className="sr-only">Previous</span>
|
||||
<ChevronLeftIcon className="h-5 w-5" aria-hidden="true" />
|
||||
</a>
|
||||
|
||||
<${PageItem} page=${1} isActive=${currentPage === 1} />
|
||||
@@ -249,10 +246,8 @@ export function Pagination({ totalItems, itemsPerPage, currentPage, setPageFn })
|
||||
|
||||
<a
|
||||
onClick=${() => setPageFn(Math.min(currentPage + 1, totalPages))}
|
||||
className="relative inline-flex items-center rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
|
||||
className="relative inline-flex px-4 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 ${currentPage != totalPages ? 'cursor-pointer' : ''} focus:z-20 focus:outline-offset-0">
|
||||
${greaterThanSymbol}
|
||||
<span className="sr-only">Next</span>
|
||||
<ChevronRightIcon className="h-5 w-5" aria-hidden="true" />
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<link href="main.css" rel="stylesheet" />
|
||||
<link href="https://rsms.me/inter/inter.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body class="min-h-screen bg-slate-100"></body>
|
||||
<body class="h-full"></body>
|
||||
<script src="history.min.js"></script>
|
||||
<script type="module" src="main.js"></script>
|
||||
</html>
|
||||
@@ -1 +1 @@
|
||||
/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter var,Helvetica,sans-serif;font-feature-settings:"cv11","ss01";font-variation-settings:"opsz" 32}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.right-auto{right:auto}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-\[48\]{z-index:48}.z-\[60\]{z-index:60}.col-span-2{grid-column:span 2/span 2}.m-4{margin:1rem}.mx-10{margin-left:2.5rem;margin-right:2.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-5{margin-top:1.25rem;margin-bottom:1.25rem}.mb-1{margin-bottom:.25rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-2{margin-right:.5rem}.mt-1{margin-top:.25rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.mt-7{margin-top:1.75rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-0{width:0}.w-11{width:2.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-72{width:18rem}.w-96{width:24rem}.w-full{width:100%}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow-0{flex-grow:0}.basis-\[30px\]{flex-basis:30px}.-translate-x-full{--tw-translate-x:-100%}.-translate-x-full,.translate-x-0{transLine truncated
|
||||
/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter var,Helvetica,sans-serif;font-feature-settings:"cv11","ss01";font-variation-settings:"opsz" 32}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.right-auto{right:auto}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-\[48\]{z-index:48}.z-\[60\]{z-index:60}.col-span-2{grid-column:span 2/span 2}.m-4{margin:1rem}.m-8{margin:2rem}.mx-10{margin-left:2.5rem;margin-right:2.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-5{margin-top:1.25rem;margin-bottom:1.25rem}.mb-1{margin-bottom:.25rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-2{margin-right:.5rem}.mr-4{margin-right:1rem}.mt-1{margin-top:.25rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.mt-7{margin-top:1.75rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-0{width:0}.w-11{width:2.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-72{width:18rem}.w-96{width:24rem}.w-full{width:100%}.min-w-full{min-width:100%}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow-0{flex-grow:0}.basis-\[30px\]{flex-basis:30px}.border-separLine truncated
|
||||
@@ -54,7 +54,19 @@ function Events({}) {
|
||||
const [events, setEvents] = useState([]);
|
||||
const [page, setPage] = useState(1);
|
||||
|
||||
const refresh = () => fetch(`api/events/get?page=${page}`).then(r => r.json()).then(r => {console.log(r); setEvents(r)}).catch(e => console.log(e));
|
||||
const refresh = () =>
|
||||
fetch('/api/events/get',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
page: page
|
||||
}),
|
||||
}).then(r => r.json())
|
||||
.then(r => setEvents(r));
|
||||
|
||||
useEffect(refresh, [page]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -81,7 +93,32 @@ function Events({}) {
|
||||
<${Td} text=${e.text} />
|
||||
<//>`;
|
||||
|
||||
return html`
|
||||
return html`
|
||||
<div class="m-8 divide-y divide-gray-200 overflow-auto rounded bg-white">
|
||||
<div class="font-semibold flex items-center text-gray-600 px-3 justify-between">
|
||||
<div class="font-semibold flex items-center text-gray-600">
|
||||
<div class="mr-4">EVENT LOG</div>
|
||||
</div>
|
||||
<${Pagination} currentPage=${page} setPageFn=${setPage} totalItems=400 itemsPerPage=20 />
|
||||
<//>
|
||||
<div class="inline-block min-w-full align-middle" style="max-height: 82vh; overflow: auto;">
|
||||
<table class="min-w-full border-separate border-spacing-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<${Th} title="Type" />
|
||||
<${Th} title="Prio" />
|
||||
<${Th} title="Time" />
|
||||
<${Th} title="Description" />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${(events.arr ? events.arr : []).map(e => h(Event, {e}))}
|
||||
</tbody>
|
||||
</table>
|
||||
<//>
|
||||
<//>`
|
||||
|
||||
/*return html`
|
||||
<div class="divide-y divide-gray-200 overflow-x-auto shadow-xl rounded-xl bg-white dark:bg-gray-700 my-3 mx-10">
|
||||
<div class="font-light flex items-center text-slate-600 px-4 py-2 justify-between">
|
||||
EVENT LOG
|
||||
@@ -102,7 +139,7 @@ function Events({}) {
|
||||
</tbody>
|
||||
</table>
|
||||
<//>
|
||||
<//>`;
|
||||
<//>`;*/
|
||||
};
|
||||
|
||||
function Chart({data}) {
|
||||
@@ -247,7 +284,7 @@ const App = function({}) {
|
||||
<${Router} onChange=${ev => setUrl(ev.url)} history=${History.createHashHistory()} >
|
||||
<${Main} default=${true} />
|
||||
<${Settings} path="settings" />
|
||||
<${Events} path="events">
|
||||
<${Events} path="events" />
|
||||
<//>
|
||||
<//>
|
||||
<//>`;
|
||||
|
||||
Reference in new issue
Block a user