feat: Follow logs
This commit is contained in:
		| @@ -1,6 +1,5 @@ | ||||
| <script lang="ts"> | ||||
| 	export let buildId; | ||||
| 	export let followingBuild; | ||||
|  | ||||
| 	import { createEventDispatcher, onDestroy, onMount } from 'svelte'; | ||||
| 	const dispatch = createEventDispatcher(); | ||||
| @@ -16,11 +15,25 @@ | ||||
| 	let loading = true; | ||||
| 	let currentStatus; | ||||
| 	let streamInterval; | ||||
| 	let followingBuild; | ||||
| 	let followingInterval; | ||||
| 	let logsEl; | ||||
|  | ||||
| 	const { id } = $page.params; | ||||
|  | ||||
| 	const cleanAnsiCodes = (str: string) => str.replace(/\x1B\[(\d+)m/g, ''); | ||||
|  | ||||
| 	function followBuild() { | ||||
| 		followingBuild = !followingBuild; | ||||
| 		if (followingBuild) { | ||||
| 			followingInterval = setInterval(() => { | ||||
| 				logsEl.scrollTop = logsEl.scrollHeight; | ||||
| 				window.scrollTo(0, document.body.scrollHeight); | ||||
| 			}, 100); | ||||
| 		} else { | ||||
| 			window.clearInterval(followingInterval); | ||||
| 		} | ||||
| 	} | ||||
| 	async function streamLogs(sequence = 0) { | ||||
| 		try { | ||||
| 			let { logs: responseLogs, status } = await get( | ||||
| @@ -57,7 +70,8 @@ | ||||
| 		} | ||||
| 	} | ||||
| 	onDestroy(() => { | ||||
| 		clearInterval(streamInterval); | ||||
| 		window.clearInterval(streamInterval); | ||||
| 		window.clearInterval(followingInterval); | ||||
| 	}); | ||||
| 	onMount(async () => { | ||||
| 		window.scrollTo(0, 0); | ||||
| @@ -72,9 +86,33 @@ | ||||
| 		{#if currentStatus === 'running'} | ||||
| 			<LoadingLogs /> | ||||
| 		{/if} | ||||
| 		<div class="flex justify-end sticky top-0 p-2"> | ||||
| 			<button | ||||
| 				on:click={followBuild} | ||||
| 				data-tooltip="Follow logs" | ||||
| 				class:text-green-500={followingBuild} | ||||
| 			> | ||||
| 				<svg | ||||
| 					xmlns="http://www.w3.org/2000/svg" | ||||
| 					class="w-6 h-6" | ||||
| 					viewBox="0 0 24 24" | ||||
| 					stroke-width="1.5" | ||||
| 					stroke="currentColor" | ||||
| 					fill="none" | ||||
| 					stroke-linecap="round" | ||||
| 					stroke-linejoin="round" | ||||
| 				> | ||||
| 					<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | ||||
| 					<circle cx="12" cy="12" r="9" /> | ||||
| 					<line x1="8" y1="12" x2="12" y2="16" /> | ||||
| 					<line x1="12" y1="8" x2="12" y2="16" /> | ||||
| 					<line x1="16" y1="12" x2="12" y2="16" /> | ||||
| 				</svg> | ||||
| 			</button> | ||||
| 		</div> | ||||
| 		<div | ||||
| 			class="font-mono leading-6 text-left text-md tracking-tighter rounded bg-coolgray-200 py-5 px-6 whitespace-pre-wrap break-words overflow-auto max-h-[80vh]" | ||||
| 			id="logs" | ||||
| 			class="font-mono leading-6 text-left text-md tracking-tighter rounded bg-coolgray-200 py-5 px-6 whitespace-pre-wrap break-words overflow-auto max-h-[80vh] -mt-12" | ||||
| 			bind:this={logsEl} | ||||
| 		> | ||||
| 			{#each logs as log} | ||||
| 				<div>{log.line + '\n'}</div> | ||||
|   | ||||
| @@ -33,8 +33,6 @@ | ||||
| 	export let buildCount; | ||||
|  | ||||
| 	let buildId; | ||||
| 	let followingBuild; | ||||
| 	$: buildId; | ||||
|  | ||||
| 	let skip = 0; | ||||
| 	let noMoreBuilds = buildCount < 5 || buildCount <= skip; | ||||
| @@ -86,15 +84,6 @@ | ||||
| 		buildId = build; | ||||
| 		goto(`/applications/${id}/logs/build?buildId=${buildId}`); | ||||
| 	} | ||||
|  | ||||
| 	function followBuild() { | ||||
| 		followingBuild = !followingBuild; | ||||
| 		if (followingBuild) { | ||||
| 			const logEl = document.getElementById('logs'); | ||||
| 			logEl.scrollTop = logEl.scrollHeight; | ||||
| 			window.scrollTo(0, document.body.scrollHeight); | ||||
| 		} | ||||
| 	} | ||||
| </script> | ||||
|  | ||||
| <div class="flex space-x-1 p-6 font-bold"> | ||||
| @@ -138,39 +127,16 @@ | ||||
| 				</div> | ||||
| 			{/each} | ||||
| 		</div> | ||||
| 		<button | ||||
| 			on:click={followBuild} | ||||
| 			data-tooltip="Follow logs" | ||||
| 			class={followingBuild && 'text-green-500'} | ||||
| 		> | ||||
| 			<svg | ||||
| 				xmlns="http://www.w3.org/2000/svg" | ||||
| 				class="h-6 w-6" | ||||
| 				fill="none" | ||||
| 				viewBox="0 0 24 24" | ||||
| 				stroke="currentColor" | ||||
| 		<div class="flex space-x-2"> | ||||
| 			<button disabled={buildCount > 0 && !noMoreBuilds} class="w-full" on:click={loadMoreBuilds} | ||||
| 				>Load More</button | ||||
| 			> | ||||
| 				<path | ||||
| 					stroke-linecap="round" | ||||
| 					stroke-linejoin="round" | ||||
| 					stroke-width="2" | ||||
| 					d="M15 13l-3 3m0 0l-3-3m3 3V8m0 13a9 9 0 110-18 9 9 0 010 18z" | ||||
| 				/> | ||||
| 			</svg> | ||||
| 		</button> | ||||
| 		{#if buildCount > 0 && !noMoreBuilds} | ||||
| 			<button class="w-full" on:click={loadMoreBuilds}>Load More</button> | ||||
| 		{/if} | ||||
| 		</div> | ||||
| 	</div> | ||||
| 	<div class="flex-1 md:w-96"> | ||||
| 		{#if buildId} | ||||
| 			{#key buildId} | ||||
| 				<svelte:component | ||||
| 					this={BuildLog} | ||||
| 					{buildId} | ||||
| 					{followingBuild} | ||||
| 					on:updateBuildStatus={updateBuildStatus} | ||||
| 				/> | ||||
| 				<svelte:component this={BuildLog} {buildId} on:updateBuildStatus={updateBuildStatus} /> | ||||
| 			{/key} | ||||
| 		{/if} | ||||
| 	</div> | ||||
|   | ||||
| @@ -27,19 +27,23 @@ | ||||
| 	import { getDomain } from '$lib/components/common'; | ||||
| 	import { get } from '$lib/api'; | ||||
| 	import { errorNotification } from '$lib/form'; | ||||
|  | ||||
| 	let loadLogsInterval = null; | ||||
| 	let logs = []; | ||||
| 	let followingBuild; | ||||
| 	let followingInterval; | ||||
| 	let logsEl; | ||||
|  | ||||
| 	const { id } = $page.params; | ||||
|  | ||||
| 	onMount(async () => { | ||||
| 		loadLogs(); | ||||
| 		loadLogsInterval = setInterval(() => { | ||||
| 			loadLogs(); | ||||
| 		}, 3000); | ||||
| 		}, 1000); | ||||
| 	}); | ||||
| 	onDestroy(() => { | ||||
| 		clearInterval(loadLogsInterval); | ||||
| 		window.clearInterval(loadLogsInterval); | ||||
| 		window.clearInterval(followingInterval); | ||||
| 	}); | ||||
| 	async function loadLogs() { | ||||
| 		try { | ||||
| @@ -50,6 +54,18 @@ | ||||
| 			return errorNotification(error); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	function followBuild() { | ||||
| 		followingBuild = !followingBuild; | ||||
| 		if (followingBuild) { | ||||
| 			followingInterval = setInterval(() => { | ||||
| 				logsEl.scrollTop = logsEl.scrollHeight; | ||||
| 				window.scrollTo(0, document.body.scrollHeight); | ||||
| 			}, 100); | ||||
| 		} else { | ||||
| 			window.clearInterval(followingInterval); | ||||
| 		} | ||||
| 	} | ||||
| </script> | ||||
|  | ||||
| <div class="flex space-x-1 p-6 font-bold"> | ||||
| @@ -63,8 +79,33 @@ | ||||
| 	{:else} | ||||
| 		<div class="relative w-full"> | ||||
| 			<LoadingLogs /> | ||||
| 			<div class="flex justify-end sticky top-0 p-2"> | ||||
| 				<button | ||||
| 					on:click={followBuild} | ||||
| 					data-tooltip="Follow logs" | ||||
| 					class:text-green-500={followingBuild} | ||||
| 				> | ||||
| 					<svg | ||||
| 						xmlns="http://www.w3.org/2000/svg" | ||||
| 						class="w-6 h-6" | ||||
| 						viewBox="0 0 24 24" | ||||
| 						stroke-width="1.5" | ||||
| 						stroke="currentColor" | ||||
| 						fill="none" | ||||
| 						stroke-linecap="round" | ||||
| 						stroke-linejoin="round" | ||||
| 					> | ||||
| 						<path stroke="none" d="M0 0h24v24H0z" fill="none" /> | ||||
| 						<circle cx="12" cy="12" r="9" /> | ||||
| 						<line x1="8" y1="12" x2="12" y2="16" /> | ||||
| 						<line x1="12" y1="8" x2="12" y2="16" /> | ||||
| 						<line x1="16" y1="12" x2="12" y2="16" /> | ||||
| 					</svg> | ||||
| 				</button> | ||||
| 			</div> | ||||
| 			<div | ||||
| 				class="font-mono leading-6 text-left text-md tracking-tighter rounded bg-coolgray-200 p-6 whitespace-pre-wrap break-words w-full" | ||||
| 				class="font-mono leading-6 text-left text-md tracking-tighter rounded bg-coolgray-200 p-6 whitespace-pre-wrap break-words w-full mb-10 -mt-12" | ||||
| 				bind:this={logsEl} | ||||
| 			> | ||||
| 				{#each logs as log} | ||||
| 					{log + '\n'} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Andras Bacsai
					Andras Bacsai