Merge pull request #127 from SaraVieira/logs-improvements
UX improvements for the log page
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -3,6 +3,7 @@ node_modules | |||||||
| /build | /build | ||||||
| /.svelte-kit | /.svelte-kit | ||||||
| /package | /package | ||||||
|  | /yarn.lock | ||||||
|  |  | ||||||
| .env | .env | ||||||
| .env.prod | .env.prod | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| 	export let buildId; | 	export let buildId; | ||||||
|  | 	export let followingBuild; | ||||||
|  |  | ||||||
| 	import { createEventDispatcher, onDestroy, onMount } from 'svelte'; | 	import { createEventDispatcher, onDestroy, onMount } from 'svelte'; | ||||||
| 	const dispatch = createEventDispatcher(); | 	const dispatch = createEventDispatcher(); | ||||||
| @@ -18,13 +19,15 @@ | |||||||
|  |  | ||||||
| 	const { id } = $page.params; | 	const { id } = $page.params; | ||||||
|  |  | ||||||
|  | 	const cleanAnsiCodes = (str: string) => str.replace(/\x1B\[(\d+)m/g, ''); | ||||||
|  |  | ||||||
| 	async function streamLogs(sequence = 0) { | 	async function streamLogs(sequence = 0) { | ||||||
| 		try { | 		try { | ||||||
| 			let { logs: responseLogs, status } = await get( | 			let { logs: responseLogs, status } = await get( | ||||||
| 				`/applications/${id}/logs/build/build.json?buildId=${buildId}&sequence=${sequence}` | 				`/applications/${id}/logs/build/build.json?buildId=${buildId}&sequence=${sequence}` | ||||||
| 			); | 			); | ||||||
| 			currentStatus = status; | 			currentStatus = status; | ||||||
| 			logs = logs.concat(responseLogs); | 			logs = logs.concat(responseLogs.map((log) => ({ ...log, line: cleanAnsiCodes(log.line) }))); | ||||||
| 			loading = false; | 			loading = false; | ||||||
| 			streamInterval = setInterval(async () => { | 			streamInterval = setInterval(async () => { | ||||||
| 				if (status !== 'running') { | 				if (status !== 'running') { | ||||||
| @@ -38,8 +41,13 @@ | |||||||
| 					); | 					); | ||||||
| 					status = data.status; | 					status = data.status; | ||||||
| 					currentStatus = status; | 					currentStatus = status; | ||||||
| 					logs = logs.concat(data.logs); |  | ||||||
|  | 					logs = logs.concat(data.logs.map((log) => ({ ...log, line: cleanAnsiCodes(log.line) }))); | ||||||
| 					dispatch('updateBuildStatus', { status }); | 					dispatch('updateBuildStatus', { status }); | ||||||
|  | 					if (followingBuild) { | ||||||
|  | 						const logEl = document.getElementById('logs'); | ||||||
|  | 						logEl.scrollTop = logEl.scrollHeight; | ||||||
|  | 					} | ||||||
| 				} catch ({ error }) { | 				} catch ({ error }) { | ||||||
| 					return errorNotification(error); | 					return errorNotification(error); | ||||||
| 				} | 				} | ||||||
| @@ -60,12 +68,13 @@ | |||||||
| {#if loading} | {#if loading} | ||||||
| 	<Loading /> | 	<Loading /> | ||||||
| {:else} | {:else} | ||||||
| 	<div class="relative"> | 	<div class="relative "> | ||||||
| 		{#if currentStatus === 'running'} | 		{#if currentStatus === 'running'} | ||||||
| 			<LoadingLogs /> | 			<LoadingLogs /> | ||||||
| 		{/if} | 		{/if} | ||||||
| 		<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" | 			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" | ||||||
| 		> | 		> | ||||||
| 			{#each logs as log} | 			{#each logs as log} | ||||||
| 				<div>{log.line + '\n'}</div> | 				<div>{log.line + '\n'}</div> | ||||||
|   | |||||||
| @@ -33,6 +33,7 @@ | |||||||
| 	export let buildCount; | 	export let buildCount; | ||||||
|  |  | ||||||
| 	let buildId; | 	let buildId; | ||||||
|  | 	let followingBuild; | ||||||
| 	$: buildId; | 	$: buildId; | ||||||
|  |  | ||||||
| 	let skip = 0; | 	let skip = 0; | ||||||
| @@ -85,6 +86,15 @@ | |||||||
| 		buildId = build; | 		buildId = build; | ||||||
| 		goto(`/applications/${id}/logs/build?buildId=${buildId}`); | 		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> | </script> | ||||||
|  |  | ||||||
| <div class="flex space-x-1 p-6 font-bold"> | <div class="flex space-x-1 p-6 font-bold"> | ||||||
| @@ -92,48 +102,75 @@ | |||||||
| 		Build logs of <a href={application.fqdn} target="_blank">{getDomain(application.fqdn)}</a> | 		Build logs of <a href={application.fqdn} target="_blank">{getDomain(application.fqdn)}</a> | ||||||
| 	</div> | 	</div> | ||||||
| </div> | </div> | ||||||
| <div class="flex flex-row justify-start space-x-2 px-10 pt-6 "> | <div class="block flex-row justify-start space-x-2 px-5 pt-6 sm:px-10 md:flex"> | ||||||
| 	<div class="min-w-[16rem] space-y-2"> | 	<div class="mb-4 min-w-[16rem] space-y-2 md:mb-0 "> | ||||||
| 		{#each builds as build (build.id)} | 		<div class="top-4 md:sticky"> | ||||||
| 			<div | 			{#each builds as build (build.id)} | ||||||
| 				data-tooltip={new Intl.DateTimeFormat('default', dateOptions).format( | 				<div | ||||||
| 					new Date(build.createdAt) | 					data-tooltip={new Intl.DateTimeFormat('default', dateOptions).format( | ||||||
| 				) + `\n${build.status}`} | 						new Date(build.createdAt) | ||||||
| 				on:click={() => loadBuild(build.id)} | 					) + `\n${build.status}`} | ||||||
| 				class="tooltip-top flex cursor-pointer items-center justify-center rounded-r border-l-2 border-transparent py-4 no-underline transition-all duration-100 hover:bg-coolgray-400 hover:shadow-xl" | 					on:click={() => loadBuild(build.id)} | ||||||
| 				class:bg-coolgray-400={buildId === build.id} | 					class="tooltip-top flex cursor-pointer items-center justify-center rounded-r border-l-2 border-transparent py-4 no-underline transition-all duration-100 hover:bg-coolgray-400 hover:shadow-xl " | ||||||
| 				class:border-red-500={build.status === 'failed'} | 					class:bg-coolgray-400={buildId === build.id} | ||||||
| 				class:border-green-500={build.status === 'success'} | 					class:border-red-500={build.status === 'failed'} | ||||||
| 				class:border-yellow-500={build.status === 'inprogress'} | 					class:border-green-500={build.status === 'success'} | ||||||
| 			> | 					class:border-yellow-500={build.status === 'inprogress'} | ||||||
| 				<div class="flex-col px-2"> | 				> | ||||||
| 					<div class="text-sm font-bold"> | 					<div class="flex-col px-2"> | ||||||
| 						{application.branch} | 						<div class="text-sm font-bold"> | ||||||
|  | 							{application.branch} | ||||||
|  | 						</div> | ||||||
|  | 						<div class="text-xs"> | ||||||
|  | 							{build.type} | ||||||
|  | 						</div> | ||||||
| 					</div> | 					</div> | ||||||
| 					<div class="text-xs"> | 					<div class="flex-1" /> | ||||||
| 						{build.type} |  | ||||||
| 					</div> |  | ||||||
| 				</div> |  | ||||||
| 				<div class="flex-1" /> |  | ||||||
|  |  | ||||||
| 				<div class="w-48 text-center text-xs"> | 					<div class="w-48 text-center text-xs"> | ||||||
| 					{#if build.status === 'running'} | 						{#if build.status === 'running'} | ||||||
| 						<div class="font-bold">Running</div> | 							<div class="font-bold">Running</div> | ||||||
| 					{:else} | 						{:else} | ||||||
| 						<div>{build.since}</div> | 							<div>{build.since}</div> | ||||||
| 						<div>Finished in <span class="font-bold">{build.took}s</span></div> | 							<div>Finished in <span class="font-bold">{build.took}s</span></div> | ||||||
| 					{/if} | 						{/if} | ||||||
|  | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			{/each} | ||||||
| 		{/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" | ||||||
|  | 			> | ||||||
|  | 				<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} | 		{#if buildCount > 0 && !noMoreBuilds} | ||||||
| 			<button class="w-full" on:click={loadMoreBuilds}>Load More</button> | 			<button class="w-full" on:click={loadMoreBuilds}>Load More</button> | ||||||
| 		{/if} | 		{/if} | ||||||
| 	</div> | 	</div> | ||||||
| 	<div class="w-96 flex-1"> | 	<div class="flex-1 md:w-96"> | ||||||
| 		{#if buildId} | 		{#if buildId} | ||||||
| 			{#key buildId} | 			{#key buildId} | ||||||
| 				<svelte:component this={BuildLog} {buildId} on:updateBuildStatus={updateBuildStatus} /> | 				<svelte:component | ||||||
|  | 					this={BuildLog} | ||||||
|  | 					{buildId} | ||||||
|  | 					{followingBuild} | ||||||
|  | 					on:updateBuildStatus={updateBuildStatus} | ||||||
|  | 				/> | ||||||
| 			{/key} | 			{/key} | ||||||
| 		{/if} | 		{/if} | ||||||
| 	</div> | 	</div> | ||||||
|   | |||||||
| @@ -69,7 +69,7 @@ a { | |||||||
| } | } | ||||||
|  |  | ||||||
| .nav-side { | .nav-side { | ||||||
| 	@apply absolute right-0 top-0 z-50 m-5 flex items-center justify-end space-x-2 bg-coolblack/40 text-white; | 	@apply relative right-0 top-0 z-50 m-5 flex flex-wrap items-center justify-end space-x-2 bg-coolblack/40 text-white sm:absolute; | ||||||
| } | } | ||||||
|  |  | ||||||
| .add-icon { | .add-icon { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Andras Bacsai
					Andras Bacsai