windmill-components 1.430.5 → 1.433.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package/components/AppConnectInner.svelte +27 -2
- package/package/components/ConfirmButton.svelte +31 -0
- package/package/components/ConfirmButton.svelte.d.ts +20 -0
- package/package/components/DiffEditor.svelte +0 -6
- package/package/components/FlowStatusViewerInner.svelte +8 -4
- package/package/components/InstanceSettings.svelte +20 -1
- package/package/components/Login.svelte +31 -6
- package/package/components/ServiceLogsInner.svelte +365 -337
- package/package/components/apps/components/buttons/AppSchemaForm.svelte +1 -1
- package/package/components/apps/components/display/AppNavbarItem.svelte +1 -1
- package/package/components/apps/components/helpers/RunnableComponent.svelte +2 -2
- package/package/components/apps/components/inputs/AppS3FileInput.svelte +1 -1
- package/package/components/apps/editor/AppEditor.svelte +18 -8
- package/package/components/apps/editor/AppEditor.svelte.d.ts +5 -0
- package/package/components/apps/editor/AppEditorHeader.svelte +58 -58
- package/package/components/apps/editor/AppEditorHeader.svelte.d.ts +2 -0
- package/package/components/apps/editor/AppPreview.svelte +6 -1
- package/package/components/apps/editor/AppReportsDrawer.svelte +3 -613
- package/package/components/apps/editor/AppReportsDrawerInner.svelte +622 -0
- package/package/components/apps/editor/AppReportsDrawerInner.svelte.d.ts +17 -0
- package/package/components/apps/editor/component/components.d.ts +79 -79
- package/package/components/apps/editor/inlineScriptsPanel/EmptyInlineScript.svelte +1 -1
- package/package/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte +1 -1
- package/package/components/apps/editor/settingsPanel/GridNavbar.svelte +1 -1
- package/package/components/apps/types.d.ts +1 -1
- package/package/components/splitPanes/SplitPanesOrColumnOnMobile.svelte +34 -0
- package/package/components/splitPanes/SplitPanesOrColumnOnMobile.svelte.d.ts +23 -0
- package/package/components/wizards/AppPicker.svelte +4 -4
- package/package/gen/core/OpenAPI.js +1 -1
- package/package/gen/schemas.gen.d.ts +2 -2
- package/package/gen/schemas.gen.js +2 -2
- package/package/gen/services.gen.d.ts +0 -1
- package/package/gen/services.gen.js +0 -2
- package/package/gen/types.gen.d.ts +2 -4
- package/package.json +5 -5
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script>import { IndexSearchService, ServiceLogsService } from '../gen';
|
|
2
|
-
import { Pane, Splitpanes } from 'svelte-splitpanes';
|
|
3
2
|
import ManuelDatePicker from './runs/ManuelDatePicker.svelte';
|
|
4
3
|
import CalendarPicker from './common/calendarPicker/CalendarPicker.svelte';
|
|
5
4
|
import LogViewer from './LogViewer.svelte';
|
|
@@ -13,7 +12,7 @@ import { Button, Drawer, DrawerContent } from './common';
|
|
|
13
12
|
import ClipboardCopy from 'lucide-svelte/icons/clipboard-copy';
|
|
14
13
|
import AnsiUp from 'ansi_up';
|
|
15
14
|
import { scroll_into_view_if_needed_polyfill } from './multiselect/utils';
|
|
16
|
-
import
|
|
15
|
+
import SplitPanesOrColumnOnMobile from './splitPanes/SplitPanesOrColumnOnMobile.svelte';
|
|
17
16
|
export let searchTerm;
|
|
18
17
|
export let queryParseErrors = [];
|
|
19
18
|
let minTs = undefined;
|
|
@@ -238,11 +237,13 @@ const debouncePeriod = 400;
|
|
|
238
237
|
let loadingLogs = false;
|
|
239
238
|
let loadingLogCounts = false;
|
|
240
239
|
let countsPerHost;
|
|
240
|
+
let sumOtherDocCount = 0;
|
|
241
241
|
async function searchLogs(searchTerm, selected, minTs, maxTs, allLogs) {
|
|
242
242
|
if (searchTerm.trim() === '') {
|
|
243
243
|
debounceTimeout && clearTimeout(debounceTimeout);
|
|
244
244
|
logs = undefined;
|
|
245
245
|
countsPerHost = undefined;
|
|
246
|
+
sumOtherDocCount = 0;
|
|
246
247
|
loadingLogs = false;
|
|
247
248
|
loadingLogCounts = false;
|
|
248
249
|
return;
|
|
@@ -258,7 +259,9 @@ async function searchLogs(searchTerm, selected, minTs, maxTs, allLogs) {
|
|
|
258
259
|
minTs,
|
|
259
260
|
maxTs
|
|
260
261
|
});
|
|
261
|
-
const
|
|
262
|
+
const res = countLogsResponse.count_per_host['count_per_host'];
|
|
263
|
+
const buckets = res['buckets'];
|
|
264
|
+
sumOtherDocCount = res['sum_other_doc_count'];
|
|
262
265
|
countsPerHost = new Map(buckets.map(({ key, doc_count }) => [key, doc_count]));
|
|
263
266
|
countsPerHost = buckets.reduce((acc, { key, doc_count }) => {
|
|
264
267
|
acc[key] = { doc_count };
|
|
@@ -297,6 +300,26 @@ async function seeLogContext(lineNumber, path, hostname, jsonFmt) {
|
|
|
297
300
|
scroll_into_view_if_needed_polyfill(el, false);
|
|
298
301
|
}
|
|
299
302
|
$: searchLogs(searchTerm, selected, minTsManual, maxTsManual, allLogs);
|
|
303
|
+
function allLogsOrQueryResults(allLogs, countsPerHost) {
|
|
304
|
+
if (countsPerHost == undefined) {
|
|
305
|
+
return allLogs;
|
|
306
|
+
}
|
|
307
|
+
let ret = {};
|
|
308
|
+
for (const hk of Object.keys(countsPerHost)) {
|
|
309
|
+
let u = hk.split(",");
|
|
310
|
+
let [mode, wg, hn] = [u[0], u[1], u[2]];
|
|
311
|
+
if (!ret[mode]) {
|
|
312
|
+
ret[mode] = {};
|
|
313
|
+
}
|
|
314
|
+
if (!ret[mode][wg]) {
|
|
315
|
+
ret[mode][wg] = {};
|
|
316
|
+
}
|
|
317
|
+
if (!ret[mode][wg][hn]) {
|
|
318
|
+
ret[mode][wg][hn] = [];
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return ret;
|
|
322
|
+
}
|
|
300
323
|
</script>
|
|
301
324
|
|
|
302
325
|
<Drawer bind:this={logDrawer} bind:open={logDrawerOpen} size="1400px">
|
|
@@ -325,366 +348,371 @@ $: searchLogs(searchTerm, selected, minTsManual, maxTsManual, allLogs);
|
|
|
325
348
|
</DrawerContent>
|
|
326
349
|
</Drawer>
|
|
327
350
|
|
|
328
|
-
<
|
|
329
|
-
<
|
|
330
|
-
<
|
|
331
|
-
<div
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
>
|
|
336
|
-
<
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
on:change={({ detail }) => {
|
|
353
|
-
minTs = undefined
|
|
354
|
-
maxTs = undefined
|
|
355
|
-
allLogs = undefined
|
|
356
|
-
minTsManual = detail
|
|
357
|
-
getAllLogs(minTsManual, maxTsManual)
|
|
358
|
-
}}
|
|
359
|
-
/>
|
|
360
|
-
</div>
|
|
361
|
-
<ManuelDatePicker
|
|
362
|
-
bind:minTs={minTsManual}
|
|
363
|
-
bind:maxTs={maxTsManual}
|
|
364
|
-
bind:this={manualPicker}
|
|
365
|
-
{loading}
|
|
366
|
-
on:loadJobs={() => {
|
|
351
|
+
<SplitPanesOrColumnOnMobile>
|
|
352
|
+
<svelte:fragment slot="left-pane">
|
|
353
|
+
<div class="p-1">
|
|
354
|
+
<div
|
|
355
|
+
class="flex flex-col lg:flex-row gap-y-1 justify-between w-full relative pb-4 gap-x-0.5"
|
|
356
|
+
id="service-logs-date-pickers"
|
|
357
|
+
>
|
|
358
|
+
<div class="flex relative">
|
|
359
|
+
<input
|
|
360
|
+
type="text"
|
|
361
|
+
value={minTsManual
|
|
362
|
+
? new Date(minTsManual).toLocaleTimeString([], {
|
|
363
|
+
day: '2-digit',
|
|
364
|
+
month: '2-digit',
|
|
365
|
+
hour: '2-digit',
|
|
366
|
+
minute: '2-digit'
|
|
367
|
+
})
|
|
368
|
+
: 'min datetime'}
|
|
369
|
+
disabled
|
|
370
|
+
/>
|
|
371
|
+
<CalendarPicker
|
|
372
|
+
label="min datetime"
|
|
373
|
+
date={minTsManual}
|
|
374
|
+
on:change={({ detail }) => {
|
|
367
375
|
minTs = undefined
|
|
368
376
|
maxTs = undefined
|
|
369
377
|
allLogs = undefined
|
|
378
|
+
minTsManual = detail
|
|
370
379
|
getAllLogs(minTsManual, maxTsManual)
|
|
371
380
|
}}
|
|
372
|
-
|
|
373
|
-
loadText={searchTerm === '' ? 'Last 1000 logfiles' : 'All time'}
|
|
381
|
+
placement="top-start"
|
|
374
382
|
/>
|
|
375
|
-
<div class="flex relative">
|
|
376
|
-
<input
|
|
377
|
-
type="text"
|
|
378
|
-
value={maxTsManual
|
|
379
|
-
? new Date(maxTsManual).toLocaleTimeString([], {
|
|
380
|
-
day: '2-digit',
|
|
381
|
-
month: '2-digit',
|
|
382
|
-
hour: '2-digit',
|
|
383
|
-
minute: '2-digit'
|
|
384
|
-
})
|
|
385
|
-
: 'max datetime'}
|
|
386
|
-
disabled
|
|
387
|
-
/>
|
|
388
|
-
<CalendarPicker
|
|
389
|
-
label="max datetime"
|
|
390
|
-
date={maxTsManual}
|
|
391
|
-
on:change={({ detail }) => {
|
|
392
|
-
minTs = undefined
|
|
393
|
-
maxTs = undefined
|
|
394
|
-
allLogs = undefined
|
|
395
|
-
maxTsManual = detail
|
|
396
|
-
getAllLogs(minTsManual, maxTsManual)
|
|
397
|
-
}}
|
|
398
|
-
/>
|
|
399
|
-
</div>
|
|
400
383
|
</div>
|
|
401
|
-
<
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
384
|
+
<ManuelDatePicker
|
|
385
|
+
bind:minTs={minTsManual}
|
|
386
|
+
bind:maxTs={maxTsManual}
|
|
387
|
+
bind:this={manualPicker}
|
|
388
|
+
{loading}
|
|
389
|
+
on:loadJobs={() => {
|
|
390
|
+
minTs = undefined
|
|
391
|
+
maxTs = undefined
|
|
392
|
+
allLogs = undefined
|
|
393
|
+
getAllLogs(minTsManual, maxTsManual)
|
|
394
|
+
}}
|
|
395
|
+
serviceLogsChoices
|
|
396
|
+
loadText={searchTerm === '' ? 'Last 1000 logfiles' : 'All time'}
|
|
397
|
+
/>
|
|
398
|
+
<div class="flex relative">
|
|
399
|
+
<input
|
|
400
|
+
type="text"
|
|
401
|
+
value={maxTsManual
|
|
402
|
+
? new Date(maxTsManual).toLocaleTimeString([], {
|
|
403
|
+
day: '2-digit',
|
|
404
|
+
month: '2-digit',
|
|
405
|
+
hour: '2-digit',
|
|
406
|
+
minute: '2-digit'
|
|
407
|
+
})
|
|
408
|
+
: 'max datetime'}
|
|
409
|
+
disabled
|
|
410
|
+
/>
|
|
411
|
+
<CalendarPicker
|
|
412
|
+
label="max datetime"
|
|
413
|
+
date={maxTsManual}
|
|
414
|
+
on:change={({ detail }) => {
|
|
415
|
+
minTs = undefined
|
|
416
|
+
maxTs = undefined
|
|
407
417
|
allLogs = undefined
|
|
408
|
-
|
|
418
|
+
maxTsManual = detail
|
|
419
|
+
getAllLogs(minTsManual, maxTsManual)
|
|
409
420
|
}}
|
|
410
421
|
/>
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
422
|
+
</div>
|
|
423
|
+
</div>
|
|
424
|
+
<div class="flex w-full flex-row-reverse pb-4 -mt-2 gap-2"
|
|
425
|
+
><Toggle
|
|
426
|
+
size="xs"
|
|
427
|
+
bind:checked={withError}
|
|
428
|
+
options={{ right: 'errors > 0' }}
|
|
429
|
+
on:change={() => {
|
|
430
|
+
allLogs = undefined
|
|
431
|
+
getAllLogs(minTs, maxTs)
|
|
432
|
+
}}
|
|
433
|
+
/>
|
|
434
|
+
<Toggle
|
|
435
|
+
size="xs"
|
|
436
|
+
bind:checked={autoRefresh}
|
|
437
|
+
disabled={searchTerm != ''}
|
|
438
|
+
on:change={(e) => {
|
|
439
|
+
if (e.detail) {
|
|
440
|
+
getAllLogs(maxTs, undefined)
|
|
441
|
+
} else {
|
|
442
|
+
timeout && clearTimeout(timeout)
|
|
443
|
+
}
|
|
444
|
+
}}
|
|
445
|
+
options={{ right: 'auto-refresh' }}
|
|
446
|
+
/></div
|
|
447
|
+
>
|
|
448
|
+
{#if allLogs == undefined}
|
|
449
|
+
<div class="text-center pb-2"><Loader2 class="animate-spin" /></div>
|
|
450
|
+
{:else if Object.keys(allLogs).length == 0}
|
|
451
|
+
<div class="flex justify-center items-center h-full">No logs</div>
|
|
452
|
+
{:else if minTs && maxTs}
|
|
453
|
+
{@const minTsN = new Date(minTs).getTime()}
|
|
454
|
+
{@const maxTsN = new Date(maxTs).getTime()}
|
|
455
|
+
{@const diff = maxTsN - minTsN}
|
|
456
|
+
{#if searchTerm === ''}
|
|
457
|
+
<div class="flex w-full text-2xs text-tertiary pb-6">
|
|
458
|
+
<div style="width: 60px;" />
|
|
436
459
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
return true
|
|
468
|
-
}
|
|
469
|
-
const hostKey = `${mode},${wg},${hn}`
|
|
470
|
-
if (countsPerHost && (countsPerHost[hostKey] == undefined || countsPerHost[hostKey].doc_count === 0)) {
|
|
471
|
-
return false
|
|
472
|
-
}
|
|
460
|
+
<div class="flex justify-between w-full"
|
|
461
|
+
><div
|
|
462
|
+
>{new Date(minTs).toLocaleTimeString([], {
|
|
463
|
+
day: '2-digit',
|
|
464
|
+
month: '2-digit',
|
|
465
|
+
hour: '2-digit',
|
|
466
|
+
minute: '2-digit'
|
|
467
|
+
})}</div
|
|
468
|
+
><div
|
|
469
|
+
>{new Date(maxTs).toLocaleTimeString([], {
|
|
470
|
+
day: '2-digit',
|
|
471
|
+
month: '2-digit',
|
|
472
|
+
hour: '2-digit',
|
|
473
|
+
minute: '2-digit'
|
|
474
|
+
})}</div
|
|
475
|
+
></div
|
|
476
|
+
>
|
|
477
|
+
</div>
|
|
478
|
+
{/if}
|
|
479
|
+
{#each Object.entries(allLogsOrQueryResults(allLogs, countsPerHost)) as [mode, o1]}
|
|
480
|
+
<div class="w-full pb-8">
|
|
481
|
+
<h2 class="pb-2 text-2xl">{mode}s</h2>
|
|
482
|
+
{#each Object.entries(o1) as [wg, o2]}
|
|
483
|
+
<div class="w-full px-1">
|
|
484
|
+
{#if wg && wg != ''}
|
|
485
|
+
<h4 class="pt-4">{wg}</h4>
|
|
486
|
+
{/if}
|
|
487
|
+
<div class="divide-y flex flex-col">
|
|
488
|
+
{#each Object.entries(o2).filter(([hn, files]) => {
|
|
489
|
+
if (selected && selected[0] === mode && selected[1] === wg && selected[2] === hn) {
|
|
473
490
|
return true
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
491
|
+
}
|
|
492
|
+
const hostKey = `${mode},${wg},${hn}`
|
|
493
|
+
if (countsPerHost && (countsPerHost[hostKey] == undefined || countsPerHost[hostKey].doc_count === 0)) {
|
|
494
|
+
return false
|
|
495
|
+
}
|
|
496
|
+
return true
|
|
497
|
+
}) as [hn, files]}
|
|
498
|
+
{@const hostKey = `${mode},${wg},${hn}`}
|
|
499
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
500
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
501
|
+
<div
|
|
502
|
+
class="w-full flex items-baseline justify-between rounded px-1 hover:bg-surface-hover cursor-pointer {selected &&
|
|
503
|
+
selected[0] == mode &&
|
|
504
|
+
selected[1] == wg &&
|
|
505
|
+
selected[2] == hn
|
|
506
|
+
? 'bg-surface-secondary'
|
|
507
|
+
: ''}"
|
|
508
|
+
on:click={() => {
|
|
509
|
+
selected = [mode, wg, hn]
|
|
510
|
+
upToIsLatest = true
|
|
511
|
+
upTo = getLatestUpTo(selected)
|
|
512
|
+
scrollToBottom()
|
|
513
|
+
}}
|
|
514
|
+
>
|
|
478
515
|
<div
|
|
479
|
-
class="
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
selected[2] == hn
|
|
483
|
-
? 'bg-surface-secondary'
|
|
484
|
-
: ''}"
|
|
485
|
-
on:click={() => {
|
|
486
|
-
selected = [mode, wg, hn]
|
|
487
|
-
upToIsLatest = true
|
|
488
|
-
upTo = getLatestUpTo(selected)
|
|
489
|
-
scrollToBottom()
|
|
490
|
-
}}
|
|
516
|
+
class="text-sm pt-2 pl-0.5 whitespace-nowrap"
|
|
517
|
+
title={hn}
|
|
518
|
+
style="width: 90px;">{truncateRev(hn, 8)}</div
|
|
491
519
|
>
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
{
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
/>
|
|
519
|
-
{/each}
|
|
520
|
-
</div>
|
|
521
|
-
{/if}
|
|
522
|
-
</div>
|
|
523
|
-
{/each}
|
|
524
|
-
</div>
|
|
525
|
-
</div>
|
|
526
|
-
{/each}
|
|
527
|
-
</div>
|
|
528
|
-
{/each}
|
|
529
|
-
{/if}
|
|
530
|
-
</div>
|
|
531
|
-
</Pane>
|
|
532
|
-
<Pane size={70} minSize={25}
|
|
533
|
-
><div class="relative h-full flex flex-col gap-1"
|
|
534
|
-
><div class="w-full bg-surface-primary-inverse text-tertiary text-xs text-center"
|
|
535
|
-
>1 min delay: logs are compacted before being available</div
|
|
536
|
-
>
|
|
537
|
-
{#if selected}
|
|
538
|
-
<div class="grow overflow-auto" id="logviewer">
|
|
539
|
-
{#if loadingLogs}
|
|
540
|
-
<div class="flex w-full justify-center items-center h-48">
|
|
541
|
-
<div class="text-tertiary text-center">
|
|
542
|
-
<Loader2 size={34} class="animate-spin" />
|
|
520
|
+
{#if loadingLogCounts}
|
|
521
|
+
<Loader2 size={15} class="animate-spin" />
|
|
522
|
+
{:else if countsPerHost}
|
|
523
|
+
<div class="text-tertiary text-xs">
|
|
524
|
+
{countsPerHost[hostKey]?.doc_count ?? 0} matches
|
|
525
|
+
</div>
|
|
526
|
+
{:else}
|
|
527
|
+
<div class="relative grow h-8 mr-2">
|
|
528
|
+
{#each files as file}
|
|
529
|
+
{@const okHeight = 100.0 * ((file.ok_lines * 1.0) / (max_lines ?? 1))}
|
|
530
|
+
{@const errHeight = 100.0 * ((file.err_lines * 1.0) / (max_lines ?? 1))}
|
|
531
|
+
<div
|
|
532
|
+
class=" w-2 bg-red-400 absolute"
|
|
533
|
+
style="left: {((file.ts - minTsN) / diff) *
|
|
534
|
+
100}%; height: {errHeight}%; bottom: {okHeight}%;"
|
|
535
|
+
/>
|
|
536
|
+
<div
|
|
537
|
+
class="w-2 bg-surface-secondary-inverse absolute bottom-0"
|
|
538
|
+
style="left: {((file.ts - minTsN) / diff) *
|
|
539
|
+
100}%; height: {okHeight}%"
|
|
540
|
+
/>
|
|
541
|
+
{/each}
|
|
542
|
+
</div>
|
|
543
|
+
{/if}
|
|
544
|
+
</div>
|
|
545
|
+
{/each}
|
|
543
546
|
</div>
|
|
544
547
|
</div>
|
|
545
|
-
{
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
{
|
|
569
|
-
<div class="py-20" />
|
|
548
|
+
{/each}
|
|
549
|
+
</div>
|
|
550
|
+
{/each}
|
|
551
|
+
{#if !loadingLogCounts && sumOtherDocCount != 0}
|
|
552
|
+
<div class="text-tertiary italic text-sm">
|
|
553
|
+
Note: {sumOtherDocCount} additional matches weren't grouped into any of the above hosts.
|
|
554
|
+
</div>
|
|
555
|
+
{/if}
|
|
556
|
+
{/if}
|
|
557
|
+
</div>
|
|
558
|
+
</svelte:fragment>
|
|
559
|
+
<svelte:fragment slot="right-pane">
|
|
560
|
+
<div class="relative h-full flex flex-col gap-1 pb-2">
|
|
561
|
+
{#if selected}
|
|
562
|
+
{#if !loadingLogs && logs == undefined}
|
|
563
|
+
<div class="w-full bg-surface-primary-inverse text-tertiary text-xs text-center">
|
|
564
|
+
1 min delay: logs are compacted before being available
|
|
565
|
+
</div>
|
|
566
|
+
{/if}
|
|
567
|
+
<div class="grow overflow-auto" id="logviewer">
|
|
568
|
+
{#if loadingLogs}
|
|
569
|
+
<div class="flex w-full justify-center items-center h-48">
|
|
570
|
+
<div class="text-tertiary text-center">
|
|
571
|
+
<Loader2 size={34} class="animate-spin" />
|
|
570
572
|
</div>
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
573
|
+
</div>
|
|
574
|
+
{:else if logs != undefined}
|
|
575
|
+
<div class="flex flex-col min-w-full w-fit">
|
|
576
|
+
{#each logs.hits as { snippet_fragment, snippet_highlighted, document }}
|
|
577
|
+
<LogSnippetViewer
|
|
578
|
+
content={snippet_fragment || document.logs[0]}
|
|
579
|
+
highlighted={snippet_highlighted}
|
|
580
|
+
on:click={() => {
|
|
581
|
+
let logLineNumber = document.line_number[0]
|
|
582
|
+
let logFile = document.file_name[0]
|
|
583
|
+
let host = document.host[0]
|
|
584
|
+
let jsonFmt = document.json_fmt[0]
|
|
585
|
+
seeLogContext(logLineNumber, logFile, host, jsonFmt)
|
|
586
|
+
}}
|
|
587
|
+
/>
|
|
588
|
+
{/each}
|
|
589
|
+
{#if logs.hits.length === 0}
|
|
590
|
+
<div class="text-center py-20 text-bold text-xl text-tertiary"> No logs </div>
|
|
591
|
+
{/if}
|
|
592
|
+
{#if logs.hits.length === 1000}
|
|
593
|
+
<div class="pl-6 py-6 text-sm text-secondary">
|
|
594
|
+
Older matches were truncated from this search, try refining your filters to get
|
|
595
|
+
more precise results.
|
|
596
|
+
</div>
|
|
597
|
+
{/if}
|
|
598
|
+
<div class="py-20" />
|
|
599
|
+
</div>
|
|
600
|
+
{:else}
|
|
601
|
+
{#each getLogs(selected, upTo) as file}
|
|
602
|
+
<div
|
|
603
|
+
style="min-height: {logsContent[file.file_path]
|
|
604
|
+
? 10
|
|
605
|
+
: Math.min(file.ok_lines + file.err_lines, 30) * 16}px;"
|
|
606
|
+
>
|
|
607
|
+
<div class="bg-surface-primary-inverse text-sm font-semibold px-1"
|
|
608
|
+
>{new Date(file.ts).toLocaleTimeString([], {
|
|
609
|
+
day: '2-digit',
|
|
610
|
+
month: '2-digit',
|
|
611
|
+
hour: '2-digit',
|
|
612
|
+
minute: '2-digit'
|
|
613
|
+
})}</div
|
|
577
614
|
>
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
{:else if logsContent[file.file_path]}
|
|
591
|
-
{#if logsContent[file.file_path].error}
|
|
592
|
-
{#if logsContent[file.file_path].error?.startsWith('Not Found')}
|
|
593
|
-
<div class="text-xs pb-4 pt-2 text-secondary"
|
|
594
|
-
>Log file is missing. Log files require a shared log volume to be mounted
|
|
595
|
-
across servers and workers or to use the EE S3/object storage integration
|
|
596
|
-
for logs. To avoid mounting a shared volume, set the EE object store logs
|
|
597
|
-
in the instance settings</div
|
|
598
|
-
>
|
|
599
|
-
{:else}
|
|
600
|
-
<div class="text-xs text-red-400 pb-4"
|
|
601
|
-
>{logsContent[file.file_path].error}</div
|
|
602
|
-
>
|
|
603
|
-
{/if}
|
|
604
|
-
{:else if logsContent[file.file_path].content}
|
|
605
|
-
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
606
|
-
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
607
|
-
<div on:click|preventDefault class="pr-2"
|
|
608
|
-
><LogViewer
|
|
609
|
-
noAutoScroll
|
|
610
|
-
noMaxH
|
|
611
|
-
isLoading={false}
|
|
612
|
-
tag={undefined}
|
|
613
|
-
content={processLogWithJsonFmt(
|
|
614
|
-
logsContent[file.file_path].content,
|
|
615
|
-
file.json_fmt
|
|
616
|
-
)}
|
|
617
|
-
/></div
|
|
615
|
+
{#if logsContent[file.file_path] == undefined}
|
|
616
|
+
<div
|
|
617
|
+
class="animate-skeleton dark:bg-frost-900/50 [animation-delay:1000ms] h-full w-full"
|
|
618
|
+
/>
|
|
619
|
+
{:else if logsContent[file.file_path]}
|
|
620
|
+
{#if logsContent[file.file_path].error}
|
|
621
|
+
{#if logsContent[file.file_path].error?.startsWith('Not Found')}
|
|
622
|
+
<div class="text-xs pb-4 pt-2 text-secondary"
|
|
623
|
+
>Log file is missing. Log files require a shared log volume to be mounted
|
|
624
|
+
across servers and workers or to use the EE S3/object storage integration
|
|
625
|
+
for logs. To avoid mounting a shared volume, set the EE object store logs in
|
|
626
|
+
the instance settings</div
|
|
618
627
|
>
|
|
619
628
|
{:else}
|
|
620
|
-
<div
|
|
629
|
+
<div class="text-xs text-red-400 pb-4"
|
|
630
|
+
>{logsContent[file.file_path].error}</div
|
|
631
|
+
>
|
|
621
632
|
{/if}
|
|
633
|
+
{:else if logsContent[file.file_path].content}
|
|
634
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
635
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
636
|
+
<div on:click|preventDefault class="pr-2"
|
|
637
|
+
><LogViewer
|
|
638
|
+
noAutoScroll
|
|
639
|
+
noMaxH
|
|
640
|
+
isLoading={false}
|
|
641
|
+
tag={undefined}
|
|
642
|
+
content={processLogWithJsonFmt(
|
|
643
|
+
logsContent[file.file_path].content,
|
|
644
|
+
file.json_fmt
|
|
645
|
+
)}
|
|
646
|
+
/></div
|
|
647
|
+
>
|
|
648
|
+
{:else}
|
|
649
|
+
<div>No logs</div>
|
|
622
650
|
{/if}
|
|
623
|
-
</div>
|
|
624
|
-
{/each}
|
|
625
|
-
{/if}
|
|
626
|
-
</div>
|
|
627
|
-
{#if searchTerm == ''}
|
|
628
|
-
<div class="flex w-full items-center gap-4">
|
|
629
|
-
<div class="text-tertiary px-1 text-2xs">Last 5 log files up to:</div>
|
|
630
|
-
<div class="flex grow text-xs justify-center px-2 items-center gap-2">
|
|
631
|
-
{#if upTo}
|
|
632
|
-
<button
|
|
633
|
-
on:click={() => {
|
|
634
|
-
if (upTo) {
|
|
635
|
-
upToIsLatest = false
|
|
636
|
-
upTo = new Date(new Date(upTo).getTime() - 5 * 60 * 1000).toISOString()
|
|
637
|
-
}
|
|
638
|
-
}}>{'<'} 5m</button
|
|
639
|
-
>
|
|
640
|
-
{:else}
|
|
641
|
-
<div />
|
|
642
|
-
{/if}
|
|
643
|
-
|
|
644
|
-
<div class="flex gap-1 relative items-center"
|
|
645
|
-
><div class="flex gap-1 relative">
|
|
646
|
-
<input
|
|
647
|
-
type="text"
|
|
648
|
-
value={upTo
|
|
649
|
-
? new Date(upTo).toLocaleTimeString([], {
|
|
650
|
-
day: '2-digit',
|
|
651
|
-
month: '2-digit',
|
|
652
|
-
hour: '2-digit',
|
|
653
|
-
minute: '2-digit'
|
|
654
|
-
})
|
|
655
|
-
: ''}
|
|
656
|
-
disabled
|
|
657
|
-
/><CalendarPicker bind:date={upTo} label="Logs up to" /></div
|
|
658
|
-
></div
|
|
659
|
-
>
|
|
660
|
-
{#if upTo}
|
|
661
|
-
<button
|
|
662
|
-
on:click={() => {
|
|
663
|
-
if (upTo) {
|
|
664
|
-
upToIsLatest = false
|
|
665
|
-
upTo = new Date(new Date(upTo).getTime() + 5 * 60 * 1000).toISOString()
|
|
666
|
-
}
|
|
667
|
-
}}>5m {'>'}</button
|
|
668
|
-
>
|
|
669
|
-
{:else}
|
|
670
|
-
<div />
|
|
671
651
|
{/if}
|
|
672
652
|
</div>
|
|
673
|
-
|
|
653
|
+
{/each}
|
|
654
|
+
{/if}
|
|
655
|
+
</div>
|
|
656
|
+
{#if searchTerm == ''}
|
|
657
|
+
<div class="flex w-full items-center gap-4">
|
|
658
|
+
<div class="text-tertiary px-1 text-2xs">Last 5 log files up to:</div>
|
|
659
|
+
<div class="flex grow text-xs justify-center px-2 items-center gap-2">
|
|
660
|
+
{#if upTo}
|
|
674
661
|
<button
|
|
675
|
-
class="text-xs"
|
|
676
662
|
on:click={() => {
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
663
|
+
if (upTo) {
|
|
664
|
+
upToIsLatest = false
|
|
665
|
+
upTo = new Date(new Date(upTo).getTime() - 5 * 60 * 1000).toISOString()
|
|
666
|
+
}
|
|
667
|
+
}}>{'<'} 5m</button
|
|
680
668
|
>
|
|
681
|
-
|
|
669
|
+
{:else}
|
|
670
|
+
<div />
|
|
671
|
+
{/if}
|
|
672
|
+
|
|
673
|
+
<div class="flex gap-1 relative items-center"
|
|
674
|
+
><div class="flex gap-1 relative">
|
|
675
|
+
<input
|
|
676
|
+
type="text"
|
|
677
|
+
value={upTo
|
|
678
|
+
? new Date(upTo).toLocaleTimeString([], {
|
|
679
|
+
day: '2-digit',
|
|
680
|
+
month: '2-digit',
|
|
681
|
+
hour: '2-digit',
|
|
682
|
+
minute: '2-digit'
|
|
683
|
+
})
|
|
684
|
+
: ''}
|
|
685
|
+
disabled
|
|
686
|
+
/><CalendarPicker bind:date={upTo} label="Logs up to" /></div
|
|
687
|
+
></div
|
|
688
|
+
>
|
|
689
|
+
{#if upTo}
|
|
690
|
+
<button
|
|
691
|
+
on:click={() => {
|
|
692
|
+
if (upTo) {
|
|
693
|
+
upToIsLatest = false
|
|
694
|
+
upTo = new Date(new Date(upTo).getTime() + 5 * 60 * 1000).toISOString()
|
|
695
|
+
}
|
|
696
|
+
}}>5m {'>'}</button
|
|
697
|
+
>
|
|
698
|
+
{:else}
|
|
699
|
+
<div />
|
|
700
|
+
{/if}
|
|
682
701
|
</div>
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
702
|
+
<div>
|
|
703
|
+
<button
|
|
704
|
+
class="text-xs"
|
|
705
|
+
on:click={() => {
|
|
706
|
+
upTo = new Date().toISOString()
|
|
707
|
+
upToIsLatest = true
|
|
708
|
+
}}>now</button
|
|
709
|
+
>
|
|
710
|
+
</div>
|
|
711
|
+
</div>
|
|
712
|
+
{/if}
|
|
713
|
+
{:else}
|
|
714
|
+
<div class="flex justify-center items-center pt-8">Select a host to see its logs</div>
|
|
715
|
+
{/if}</div
|
|
688
716
|
>
|
|
689
|
-
</
|
|
690
|
-
</
|
|
717
|
+
</svelte:fragment>
|
|
718
|
+
</SplitPanesOrColumnOnMobile>
|