feat: show elapsed time on running builds
This commit is contained in:
		@@ -6,7 +6,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	import { page } from '$app/stores';
 | 
						import { page } from '$app/stores';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	import Loading from '$lib/components/Loading.svelte';
 | 
					 | 
				
			||||||
	import { get, post } from '$lib/api';
 | 
						import { get, post } from '$lib/api';
 | 
				
			||||||
	import { t } from '$lib/translations';
 | 
						import { t } from '$lib/translations';
 | 
				
			||||||
	import LoadingLogs from '$lib/components/LoadingLogs.svelte';
 | 
						import LoadingLogs from '$lib/components/LoadingLogs.svelte';
 | 
				
			||||||
@@ -14,7 +13,6 @@
 | 
				
			|||||||
	import Tooltip from '$lib/components/Tooltip.svelte';
 | 
						import Tooltip from '$lib/components/Tooltip.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let logs: any = [];
 | 
						let logs: any = [];
 | 
				
			||||||
	let loading = true;
 | 
					 | 
				
			||||||
	let currentStatus: any;
 | 
						let currentStatus: any;
 | 
				
			||||||
	let streamInterval: any;
 | 
						let streamInterval: any;
 | 
				
			||||||
	let followingBuild: any;
 | 
						let followingBuild: any;
 | 
				
			||||||
@@ -47,7 +45,6 @@
 | 
				
			|||||||
			logs = logs.concat(
 | 
								logs = logs.concat(
 | 
				
			||||||
				responseLogs.map((log: any) => ({ ...log, line: cleanAnsiCodes(log.line) }))
 | 
									responseLogs.map((log: any) => ({ ...log, line: cleanAnsiCodes(log.line) }))
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			loading = false;
 | 
					 | 
				
			||||||
			streamInterval = setInterval(async () => {
 | 
								streamInterval = setInterval(async () => {
 | 
				
			||||||
				if (status !== 'running' && status !== 'queued') {
 | 
									if (status !== 'running' && status !== 'queued') {
 | 
				
			||||||
					clearInterval(streamInterval);
 | 
										clearInterval(streamInterval);
 | 
				
			||||||
@@ -64,7 +61,7 @@
 | 
				
			|||||||
					logs = logs.concat(
 | 
										logs = logs.concat(
 | 
				
			||||||
						data.logs.map((log: any) => ({ ...log, line: cleanAnsiCodes(log.line) }))
 | 
											data.logs.map((log: any) => ({ ...log, line: cleanAnsiCodes(log.line) }))
 | 
				
			||||||
					);
 | 
										);
 | 
				
			||||||
					dispatch('updateBuildStatus', { status });
 | 
										dispatch('updateBuildStatus', { status, took: data.took });
 | 
				
			||||||
				} catch (error) {
 | 
									} catch (error) {
 | 
				
			||||||
					return errorNotification(error);
 | 
										return errorNotification(error);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -97,86 +94,82 @@
 | 
				
			|||||||
	});
 | 
						});
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{#if loading}
 | 
					<div class="relative ">
 | 
				
			||||||
	<Loading />
 | 
						{#if currentStatus === 'running'}
 | 
				
			||||||
{:else}
 | 
							<LoadingLogs />
 | 
				
			||||||
	<div class="relative ">
 | 
						{/if}
 | 
				
			||||||
		{#if currentStatus === 'running'}
 | 
						{#if currentStatus === 'queued'}
 | 
				
			||||||
			<LoadingLogs />
 | 
							<div class="text-center font-bold text-xl">{$t('application.build.queued_waiting_exec')}</div>
 | 
				
			||||||
		{/if}
 | 
						{:else}
 | 
				
			||||||
		{#if currentStatus === 'queued'}
 | 
							<div class="flex justify-end sticky top-0 p-2 mx-1">
 | 
				
			||||||
			<div class="text-center font-bold text-xl">{$t('application.build.queued_waiting_exec')}</div>
 | 
								<button
 | 
				
			||||||
		{:else}
 | 
									id="follow"
 | 
				
			||||||
			<div class="flex justify-end sticky top-0 p-2 mx-1">
 | 
									on:click={followBuild}
 | 
				
			||||||
 | 
									class="bg-transparent btn btn-sm btn-linkhover:text-green-500 hover:bg-coolgray-500"
 | 
				
			||||||
 | 
									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>
 | 
				
			||||||
 | 
								<Tooltip triggeredBy="#follow">Follow Logs</Tooltip>
 | 
				
			||||||
 | 
								{#if currentStatus === 'running'}
 | 
				
			||||||
				<button
 | 
									<button
 | 
				
			||||||
					id="follow"
 | 
										id="cancel"
 | 
				
			||||||
					on:click={followBuild}
 | 
										on:click={cancelBuild}
 | 
				
			||||||
					class="bg-transparent btn btn-sm btn-linkhover:text-green-500 hover:bg-coolgray-500"
 | 
										class:animation-spin={cancelInprogress}
 | 
				
			||||||
					class:text-green-500={followingBuild}
 | 
										class="bg-transparent btn btn-sm btn-link hover:text-red-500 hover:bg-coolgray-500"
 | 
				
			||||||
				>
 | 
									>
 | 
				
			||||||
					<svg
 | 
										{#if cancelInprogress}
 | 
				
			||||||
						xmlns="http://www.w3.org/2000/svg"
 | 
											Cancelling...
 | 
				
			||||||
						class="w-6 h-6"
 | 
										{:else}
 | 
				
			||||||
						viewBox="0 0 24 24"
 | 
											<svg
 | 
				
			||||||
						stroke-width="1.5"
 | 
												xmlns="http://www.w3.org/2000/svg"
 | 
				
			||||||
						stroke="currentColor"
 | 
												class="w-6 h-6"
 | 
				
			||||||
						fill="none"
 | 
												viewBox="0 0 24 24"
 | 
				
			||||||
						stroke-linecap="round"
 | 
												stroke-width="1.5"
 | 
				
			||||||
						stroke-linejoin="round"
 | 
												stroke="currentColor"
 | 
				
			||||||
					>
 | 
												fill="none"
 | 
				
			||||||
						<path stroke="none" d="M0 0h24v24H0z" fill="none" />
 | 
												stroke-linecap="round"
 | 
				
			||||||
						<circle cx="12" cy="12" r="9" />
 | 
												stroke-linejoin="round"
 | 
				
			||||||
						<line x1="8" y1="12" x2="12" y2="16" />
 | 
											>
 | 
				
			||||||
						<line x1="12" y1="8" x2="12" y2="16" />
 | 
												<path stroke="none" d="M0 0h24v24H0z" fill="none" />
 | 
				
			||||||
						<line x1="16" y1="12" x2="12" y2="16" />
 | 
												<circle cx="12" cy="12" r="9" />
 | 
				
			||||||
					</svg>
 | 
												<path d="M10 10l4 4m0 -4l-4 4" />
 | 
				
			||||||
 | 
											</svg>
 | 
				
			||||||
 | 
										{/if}
 | 
				
			||||||
				</button>
 | 
									</button>
 | 
				
			||||||
				<Tooltip triggeredBy="#follow">Follow Logs</Tooltip>
 | 
									<Tooltip triggeredBy="#cancel">Cancel build</Tooltip>
 | 
				
			||||||
				{#if currentStatus === 'running'}
 | 
					 | 
				
			||||||
					<button
 | 
					 | 
				
			||||||
						id="cancel"
 | 
					 | 
				
			||||||
						on:click={cancelBuild}
 | 
					 | 
				
			||||||
						class:animation-spin={cancelInprogress}
 | 
					 | 
				
			||||||
						class="bg-transparent btn btn-sm btn-link hover:text-red-500 hover:bg-coolgray-500"
 | 
					 | 
				
			||||||
					>
 | 
					 | 
				
			||||||
						{#if cancelInprogress}
 | 
					 | 
				
			||||||
							Cancelling...
 | 
					 | 
				
			||||||
						{:else}
 | 
					 | 
				
			||||||
							<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" />
 | 
					 | 
				
			||||||
								<path d="M10 10l4 4m0 -4l-4 4" />
 | 
					 | 
				
			||||||
							</svg>
 | 
					 | 
				
			||||||
						{/if}
 | 
					 | 
				
			||||||
					</button>
 | 
					 | 
				
			||||||
					<Tooltip triggeredBy="#cancel">Cancel build</Tooltip>
 | 
					 | 
				
			||||||
				{/if}
 | 
					 | 
				
			||||||
			</div>
 | 
					 | 
				
			||||||
			{#if logs.length > 0}
 | 
					 | 
				
			||||||
				<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] -mt-12 overflow-y-scroll scrollbar-w-1 scrollbar-thumb-coollabs scrollbar-track-coolgray-200"
 | 
					 | 
				
			||||||
					bind:this={logsEl}
 | 
					 | 
				
			||||||
				>
 | 
					 | 
				
			||||||
					{#each logs as log}
 | 
					 | 
				
			||||||
						<div>{log.line + '\n'}</div>
 | 
					 | 
				
			||||||
					{/each}
 | 
					 | 
				
			||||||
				</div>
 | 
					 | 
				
			||||||
			{:else}
 | 
					 | 
				
			||||||
				<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] -mt-12 overflow-y-scroll scrollbar-w-1 scrollbar-thumb-coollabs scrollbar-track-coolgray-200"
 | 
					 | 
				
			||||||
				>
 | 
					 | 
				
			||||||
					No logs found.
 | 
					 | 
				
			||||||
				</div>
 | 
					 | 
				
			||||||
			{/if}
 | 
								{/if}
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							{#if logs.length > 0}
 | 
				
			||||||
 | 
								<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] -mt-12 overflow-y-scroll scrollbar-w-1 scrollbar-thumb-coollabs scrollbar-track-coolgray-200"
 | 
				
			||||||
 | 
									bind:this={logsEl}
 | 
				
			||||||
 | 
								>
 | 
				
			||||||
 | 
									{#each logs as log}
 | 
				
			||||||
 | 
										<div>{log.line + '\n'}</div>
 | 
				
			||||||
 | 
									{/each}
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
							{:else}
 | 
				
			||||||
 | 
								<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] -mt-12 overflow-y-scroll scrollbar-w-1 scrollbar-thumb-coollabs scrollbar-track-coolgray-200"
 | 
				
			||||||
 | 
								>
 | 
				
			||||||
 | 
									No logs found.
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
		{/if}
 | 
							{/if}
 | 
				
			||||||
	</div>
 | 
						{/if}
 | 
				
			||||||
{/if}
 | 
					</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,17 +28,20 @@
 | 
				
			|||||||
	import { get } from '$lib/api';
 | 
						import { get } from '$lib/api';
 | 
				
			||||||
	import { t } from '$lib/translations';
 | 
						import { t } from '$lib/translations';
 | 
				
			||||||
	import { changeQueryParams, dateOptions, errorNotification } from '$lib/common';
 | 
						import { changeQueryParams, dateOptions, errorNotification } from '$lib/common';
 | 
				
			||||||
 | 
						import Tooltip from '$lib/components/Tooltip.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let buildId: any;
 | 
						let buildId: any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let skip = 0;
 | 
						let skip = 0;
 | 
				
			||||||
	let noMoreBuilds = buildCount < 5 || buildCount <= skip;
 | 
						let noMoreBuilds = buildCount < 5 || buildCount <= skip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						let buildTook = 0;
 | 
				
			||||||
	const { id } = $page.params;
 | 
						const { id } = $page.params;
 | 
				
			||||||
	let preselectedBuildId = $page.url.searchParams.get('buildId');
 | 
						let preselectedBuildId = $page.url.searchParams.get('buildId');
 | 
				
			||||||
	if (preselectedBuildId) buildId = preselectedBuildId;
 | 
						if (preselectedBuildId) buildId = preselectedBuildId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	async function updateBuildStatus({ detail }: { detail: any }) {
 | 
						async function updateBuildStatus({ detail }: { detail: any }) {
 | 
				
			||||||
		const { status } = detail;
 | 
							const { status, took } = detail;
 | 
				
			||||||
		if (status !== 'running') {
 | 
							if (status !== 'running') {
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
				const data = await get(`/applications/${id}/logs/build?buildId=${buildId}`);
 | 
									const data = await get(`/applications/${id}/logs/build?buildId=${buildId}`);
 | 
				
			||||||
@@ -58,6 +61,7 @@
 | 
				
			|||||||
				if (build.id === buildId) build.status = status;
 | 
									if (build.id === buildId) build.status = status;
 | 
				
			||||||
				return build;
 | 
									return build;
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 | 
								buildTook = took;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	async function loadMoreBuilds() {
 | 
						async function loadMoreBuilds() {
 | 
				
			||||||
@@ -137,20 +141,18 @@
 | 
				
			|||||||
		<div class="top-4 md:sticky">
 | 
							<div class="top-4 md:sticky">
 | 
				
			||||||
			{#each builds as build, index (build.id)}
 | 
								{#each builds as build, index (build.id)}
 | 
				
			||||||
				<div
 | 
									<div
 | 
				
			||||||
					data-tip={new Intl.DateTimeFormat('default', dateOptions).format(
 | 
										id={`building-${build.id}`}
 | 
				
			||||||
						new Date(build.createdAt)
 | 
					 | 
				
			||||||
					) + `\n${build.status}`}
 | 
					 | 
				
			||||||
					on:click={() => loadBuild(build.id)}
 | 
										on:click={() => loadBuild(build.id)}
 | 
				
			||||||
					class:rounded-tr={index === 0}
 | 
										class:rounded-tr={index === 0}
 | 
				
			||||||
					class:rounded-br={index === builds.length - 1}
 | 
										class:rounded-br={index === builds.length - 1}
 | 
				
			||||||
					class="tooltip tooltip-primary tooltip-top flex cursor-pointer items-center justify-center border-l-2 py-4 no-underline transition-all duration-100 hover:bg-coolgray-400 hover:shadow-xl"
 | 
										class="flex cursor-pointer items-center justify-center border-l-2 py-4 no-underline transition-all duration-100 hover:bg-coolgray-400 hover:shadow-xl"
 | 
				
			||||||
					class:bg-coolgray-400={buildId === build.id}
 | 
										class:bg-coolgray-400={buildId === build.id}
 | 
				
			||||||
					class:border-red-500={build.status === 'failed'}
 | 
										class:border-red-500={build.status === 'failed'}
 | 
				
			||||||
					class:border-orange-500={build.status === 'canceled'}
 | 
										class:border-orange-500={build.status === 'canceled'}
 | 
				
			||||||
					class:border-green-500={build.status === 'success'}
 | 
										class:border-green-500={build.status === 'success'}
 | 
				
			||||||
					class:border-yellow-500={build.status === 'running'}
 | 
										class:border-yellow-500={build.status === 'running'}
 | 
				
			||||||
				>
 | 
									>
 | 
				
			||||||
					<div class="flex-col px-2">
 | 
										<div class="flex-col px-2 text-center min-w-[10rem]">
 | 
				
			||||||
						<div class="text-sm font-bold">
 | 
											<div class="text-sm font-bold">
 | 
				
			||||||
							{build.branch || application.branch}
 | 
												{build.branch || application.branch}
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
@@ -162,6 +164,10 @@
 | 
				
			|||||||
					<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">{$t('application.build.running')}</div>
 | 
												<div class="font-bold">{$t('application.build.running')}</div>
 | 
				
			||||||
 | 
												<div>
 | 
				
			||||||
 | 
													Elapsed
 | 
				
			||||||
 | 
													<span class="font-bold">{buildTook}s</span>
 | 
				
			||||||
 | 
												</div>
 | 
				
			||||||
						{:else if build.status === 'queued'}
 | 
											{:else if build.status === 'queued'}
 | 
				
			||||||
							<div class="font-bold">{$t('application.build.queued')}</div>
 | 
												<div class="font-bold">{$t('application.build.queued')}</div>
 | 
				
			||||||
						{:else}
 | 
											{:else}
 | 
				
			||||||
@@ -172,6 +178,10 @@
 | 
				
			|||||||
						{/if}
 | 
											{/if}
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
 | 
									<Tooltip triggeredBy={`#building-${build.id}`}
 | 
				
			||||||
 | 
										>{new Intl.DateTimeFormat('default', dateOptions).format(new Date(build.createdAt)) +
 | 
				
			||||||
 | 
											`\n${build.status}`}</Tooltip
 | 
				
			||||||
 | 
									>
 | 
				
			||||||
			{/each}
 | 
								{/each}
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
		{#if !noMoreBuilds}
 | 
							{#if !noMoreBuilds}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user