diff --git a/package.json b/package.json index ee42e4b..5bb2a67 100644 --- a/package.json +++ b/package.json @@ -35,5 +35,8 @@ "typescript": "~5.7.3", "valid-url": "^1.0.9" }, - "type": "module" + "type": "module", + "dependencies": { + "prismjs": "^1.29.0" + } } diff --git a/src/lib/api/index.js b/src/lib/api/index.js index af09ed2..de6035f 100644 --- a/src/lib/api/index.js +++ b/src/lib/api/index.js @@ -48,6 +48,27 @@ async function invoke (fn, args, fetch) { return body } +/** + * @template T + * @param {string} indexId + * @param {string} fn + * @param {Object} args + * @param {fetch} fetch + * @returns {Promise>} + */ +async function invokeLog (indexId, fn, args, fetch) { + const url = `${indexId}${fn ? ('/' + fn) : ''}${args ? ('?' + args) : ''}` + const resp = await fetch(`${endpoint}/log/${encodeURIComponent(url)}`, { + method: 'POST', + headers: { + 'content-type': 'application/json' + } + }) + + const body = await resp.json() + return body +} + /** * @param {Function} callback */ @@ -90,6 +111,7 @@ function intervalInvalidate (callback, interval) { export default { invoke, + invokeLog, setOnUnauth, invalidate: wrapInvalidate, intervalInvalidate diff --git a/src/lib/format/index.js b/src/lib/format/index.js index 60ea0cc..ae151fc 100644 --- a/src/lib/format/index.js +++ b/src/lib/format/index.js @@ -56,6 +56,17 @@ export function datetime (v) { return dayjs(v).format('YYYY-MM-DD HH:mm:ss') } +/** + * @param {string} v + * @returns {number} + */ +export function unixDatetime (v) { + if (!v) { + return 0 + } + return dayjs(v).unix() +} + /** * @param {string} project * @param {string} name diff --git a/src/lib/use-action/clickAway.js b/src/lib/use-action/clickAway.js new file mode 100644 index 0000000..eea6017 --- /dev/null +++ b/src/lib/use-action/clickAway.js @@ -0,0 +1,15 @@ +export default function clickAway (node) { + const handleClick = (event) => { + if (node && !node.contains(event.target) && !event.defaultPrevented) { + node.dispatchEvent(new CustomEvent('clickAway')) + } + } + + document.addEventListener('click', handleClick, true) + + return { + destroy () { + document.removeEventListener('click', handleClick, true) + } + } +} diff --git a/src/routes/(auth)/(project)/log/+page.js b/src/routes/(auth)/(project)/log/+page.js new file mode 100644 index 0000000..0fb0d15 --- /dev/null +++ b/src/routes/(auth)/(project)/log/+page.js @@ -0,0 +1,17 @@ +export async function load ({ url }) { + const duration = url.searchParams.get('duration') || '' + const startDate = url.searchParams.get('startDate') || '' + const endDate = url.searchParams.get('endDate') || '' + const query = url.searchParams.get('query') || '' + const indexId = url.searchParams.get('indexId') || '' + const endpoint = url.searchParams.get('endpoint') || '' + + return { + duration, + startDate, + endDate, + query, + indexId, + endpoint + } +} diff --git a/src/routes/(auth)/(project)/log/+page.svelte b/src/routes/(auth)/(project)/log/+page.svelte new file mode 100644 index 0000000..86ad53d --- /dev/null +++ b/src/routes/(auth)/(project)/log/+page.svelte @@ -0,0 +1,356 @@ + + + + + + + + + +
+
Log
+ {#if initLoading} + + {:else} +
+
+
+ + {#if indexId && endpoint} +
+
+ { show.fields = !show.fields } } + aria-hidden="true" + > + +
+
+ {/if} +
+
+
+
+ {#if filter.startDate && indexId && endpoint} +
+ { format.datetime(String(Number(filter.startDate) * 1000)) } to { format.datetime(String(Number(filter.endDate) * 1000)) } +
+ {/if} +
+
+ +
+
+
+ +
+
+ per Page +
+
+ {#if indexId && endpoint } + + {/if} +
+
+
+ +
+
+
+ {#if indexId && endpoint} +
+
+ API URL: +
{ endpoint }/api/v1/{ indexId }/search?{createQueryString()}
+ copy(`${endpoint}/api/v1/${indexId}/search?${createQueryString()}`) } + aria-hidden="true" + > +
+ { result.total.toLocaleString() } hits found in { result.elapsedTime } seconds +
+ {#if loading} + + {:else} + {#if result.list.length} + + {/if} +
+ {#each result.list as item, idx} + {@const identity = `${item['logger.name']}-${item.timestamp}`} + {@const open = show.result.includes(identity)} +
+ { show.result = open ? show.result.filter(r => r !== identity) : [...show.result, identity] } } + aria-hidden="true" + > +
+
+ { show.result = open ? show.result.filter(r => r !== identity) : [...show.result, identity] } } + aria-hidden="true" + > + + { format.datetime(item.timestamp) } + + {#if open} +
{ JSON.stringify(item, null, 2) }
+ {:else} +
{ JSON.stringify(item) }
+ {/if} +
+
+
+ {:else} + No Data + {/each} +
+ {#if result.list.length} + + {/if} + {/if} + {/if} +
+
+ {/if} +
+ + diff --git a/src/routes/(auth)/(project)/log/_components/Fields.svelte b/src/routes/(auth)/(project)/log/_components/Fields.svelte new file mode 100644 index 0000000..6ab0883 --- /dev/null +++ b/src/routes/(auth)/(project)/log/_components/Fields.svelte @@ -0,0 +1,32 @@ + + +
+ { show = !show } } + aria-hidden="true" + > + Fields + + {#if show} +
+ {#each list as item} +
+
{ item.type }
+ { item.name } +
+ {/each} +
+ {/if} +
diff --git a/src/routes/(auth)/(project)/log/_components/Input.svelte b/src/routes/(auth)/(project)/log/_components/Input.svelte new file mode 100644 index 0000000..986cd51 --- /dev/null +++ b/src/routes/(auth)/(project)/log/_components/Input.svelte @@ -0,0 +1,79 @@ + + +
+
+ {#if !show} +
+ Endpoint URL: + { valueEndpoint } + Index ID: + { valueIndexId } +
+ + {:else} +
+
+ +
+
+ +
+ +
+ {/if} +
+
diff --git a/src/routes/(auth)/(project)/log/_components/Pagination.svelte b/src/routes/(auth)/(project)/log/_components/Pagination.svelte new file mode 100644 index 0000000..ee9788b --- /dev/null +++ b/src/routes/(auth)/(project)/log/_components/Pagination.svelte @@ -0,0 +1,40 @@ + + +
+
+
+
+ + + +
+
+
diff --git a/src/routes/(auth)/(project)/log/_components/TimeFilter.svelte b/src/routes/(auth)/(project)/log/_components/TimeFilter.svelte new file mode 100644 index 0000000..3d2acfa --- /dev/null +++ b/src/routes/(auth)/(project)/log/_components/TimeFilter.svelte @@ -0,0 +1,301 @@ + + + + +
{ show = false } } + aria-hidden="true" +> +
{ show = false } } + > + +

Select a period

+
+
+ + + + + + + + + +
+ {#if showCustom} +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + +
+
+ {/if} +
+
+
+ + diff --git a/src/routes/(auth)/+layout.svelte b/src/routes/(auth)/+layout.svelte index c1fdc8a..8cf990c 100644 --- a/src/routes/(auth)/+layout.svelte +++ b/src/routes/(auth)/+layout.svelte @@ -88,7 +88,9 @@ padding-left: calc(var(--width-sidebar) + var(--content-sidegap)); padding-right: 2rem; padding-bottom: 2rem; - + min-height: 100dvh; + display: flex; + flex-direction: column; } @media screen and (max-width: 1023px) { diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 60b4f05..fc9ceed 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,7 +1,8 @@