Skip to content

Commit 9b9500b

Browse files
authored
fix(manifest): prioritize previous channel bundle (#1540)
1 parent 9bfdea0 commit 9b9500b

File tree

1 file changed

+131
-8
lines changed

1 file changed

+131
-8
lines changed

src/pages/app/[package].bundle.[bundle].manifest.vue

Lines changed: 131 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { useDisplayStore } from '~/stores/display'
1717
type ManifestEntry = Database['public']['Tables']['manifest']['Row']
1818
1919
type VersionRow = Pick<Database['public']['Tables']['app_versions']['Row'], 'id' | 'name' | 'created_at' | 'manifest_count' | 'app_id'>
20+
type DeployHistoryRow = Pick<Database['public']['Tables']['deploy_history']['Row'], 'channel_id' | 'version_id' | 'created_at' | 'deployed_at'>
2021
2122
const route = useRoute('/app/[package].bundle.[bundle].manifest')
2223
const router = useRouter()
@@ -31,6 +32,7 @@ const compareSearchLoading = ref(false)
3132
const version = ref<Database['public']['Tables']['app_versions']['Row']>()
3233
const manifestEntries = ref<ManifestEntry[]>([])
3334
const latestCompareVersions = ref<VersionRow[]>([])
35+
const preferredCompareVersions = ref<VersionRow[]>([])
3436
const compareSearchResults = ref<VersionRow[]>([])
3537
const compareSearch = ref('')
3638
const compareVersionId = ref<number | null>(null)
@@ -42,6 +44,7 @@ const currentPage = ref(1)
4244
const MANIFEST_PAGE_SIZE = 1000
4345
const compareRequestId = ref(0)
4446
const compareSearchRequestId = ref(0)
47+
let preferredCompareRequestId = 0
4548
4649
function hideHash(hash: string) {
4750
if (!hash)
@@ -92,6 +95,7 @@ const compareVersion = computed(() => {
9295
return null
9396
return (
9497
compareSearchResults.value.find(v => v.id === compareVersionId.value)
98+
?? preferredCompareVersions.value.find(v => v.id === compareVersionId.value)
9599
?? latestCompareVersions.value.find(v => v.id === compareVersionId.value)
96100
?? null
97101
)
@@ -100,7 +104,11 @@ const compareVersion = computed(() => {
100104
const compareOptions = computed(() => {
101105
if (compareSearch.value.trim())
102106
return compareSearchResults.value
103-
return latestCompareVersions.value
107+
const preferredIds = new Set(preferredCompareVersions.value.map(version => version.id))
108+
return [
109+
...preferredCompareVersions.value,
110+
...latestCompareVersions.value.filter(version => !preferredIds.has(version.id)),
111+
]
104112
})
105113
106114
const diffEntries = computed(() => {
@@ -253,11 +261,126 @@ async function loadLatestCompareVersions() {
253261
latestCompareVersions.value = data ?? []
254262
}
255263
264+
async function loadPreferredCompareVersions() {
265+
const requestId = ++preferredCompareRequestId
266+
preferredCompareVersions.value = []
267+
if (!packageId.value || !id.value)
268+
return
269+
270+
const channelIds = new Set<number>()
271+
const deployedAtByChannel = new Map<number, string | null>()
272+
273+
const { data: currentChannels, error: currentChannelsError } = await supabase
274+
.from('channels')
275+
.select('id')
276+
.eq('app_id', packageId.value)
277+
.eq('version', id.value)
278+
279+
if (requestId !== preferredCompareRequestId)
280+
return
281+
282+
if (currentChannelsError) {
283+
console.error('Failed to load current channels', currentChannelsError)
284+
}
285+
else {
286+
for (const channel of currentChannels ?? [])
287+
channelIds.add(channel.id)
288+
}
289+
290+
const { data: deployHistory, error: deployHistoryError } = await supabase
291+
.from('deploy_history')
292+
.select('channel_id, version_id, created_at, deployed_at')
293+
.eq('app_id', packageId.value)
294+
.eq('version_id', id.value)
295+
.order('created_at', { ascending: false })
296+
297+
if (requestId !== preferredCompareRequestId)
298+
return
299+
300+
if (deployHistoryError) {
301+
console.error('Failed to load deploy history for bundle', deployHistoryError)
302+
}
303+
else {
304+
for (const entry of deployHistory ?? []) {
305+
const entryTime = entry.created_at ?? entry.deployed_at ?? null
306+
if (!channelIds.has(entry.channel_id))
307+
channelIds.add(entry.channel_id)
308+
if (!deployedAtByChannel.has(entry.channel_id))
309+
deployedAtByChannel.set(entry.channel_id, entryTime)
310+
}
311+
}
312+
313+
if (channelIds.size === 0)
314+
return
315+
316+
const preferredHistory: Array<{ versionId: number, deployedAt: string | null }> = []
317+
for (const channelId of channelIds) {
318+
const cutoff = deployedAtByChannel.get(channelId)
319+
let query = supabase
320+
.from('deploy_history')
321+
.select('version_id, created_at, deployed_at')
322+
.eq('app_id', packageId.value)
323+
.eq('channel_id', channelId)
324+
.neq('version_id', id.value)
325+
326+
if (cutoff)
327+
query = query.lt('created_at', cutoff)
328+
329+
const { data, error } = await query
330+
.order('created_at', { ascending: false })
331+
.limit(1)
332+
333+
if (requestId !== preferredCompareRequestId)
334+
return
335+
336+
if (error) {
337+
console.error('Failed to load previous deploy history', error)
338+
continue
339+
}
340+
341+
const entry = (data ?? [])[0] as DeployHistoryRow | undefined
342+
if (!entry)
343+
continue
344+
preferredHistory.push({
345+
versionId: entry.version_id,
346+
deployedAt: entry.created_at ?? entry.deployed_at ?? null,
347+
})
348+
}
349+
350+
if (!preferredHistory.length)
351+
return
352+
353+
const uniqueIds = [...new Set(preferredHistory.map(entry => entry.versionId))]
354+
const { data: versions, error } = await supabase
355+
.from('app_versions')
356+
.select('id, name, created_at, manifest_count, app_id')
357+
.eq('app_id', packageId.value)
358+
.gt('manifest_count', 0)
359+
.in('id', uniqueIds)
360+
361+
if (requestId !== preferredCompareRequestId)
362+
return
363+
364+
if (error) {
365+
console.error('Failed to load preferred compare versions', error)
366+
return
367+
}
368+
369+
const versionMap = new Map((versions ?? []).map(version => [version.id, version]))
370+
const sorted = preferredHistory
371+
.filter(entry => versionMap.has(entry.versionId))
372+
.sort((a, b) => (b.deployedAt ?? '').localeCompare(a.deployedAt ?? ''))
373+
374+
preferredCompareVersions.value = sorted
375+
.map(entry => versionMap.get(entry.versionId))
376+
.filter((version): version is VersionRow => Boolean(version))
377+
}
378+
256379
async function reloadManifest() {
257380
if (!id.value)
258381
return
259382
tableLoading.value = true
260-
await Promise.all([loadManifest(), loadLatestCompareVersions()])
383+
await Promise.all([loadManifest(), loadLatestCompareVersions(), loadPreferredCompareVersions()])
261384
if (compareVersionId.value) {
262385
const cached = compareManifestCache.value[compareVersionId.value]
263386
compareManifestEntries.value = cached ?? await fetchManifestEntries(compareVersionId.value)
@@ -370,7 +493,7 @@ watchEffect(async () => {
370493
packageId.value = route.params.package as string
371494
id.value = Number(route.params.bundle as string)
372495
resetCompareSelection()
373-
await Promise.all([getVersion(), loadManifest(), loadLatestCompareVersions()])
496+
await Promise.all([getVersion(), loadManifest(), loadLatestCompareVersions(), loadPreferredCompareVersions()])
374497
loading.value = false
375498
if (!version.value?.name)
376499
displayStore.NavTitle = t('bundle')
@@ -411,10 +534,10 @@ watchEffect(async () => {
411534
<div class="w-full d-dropdown">
412535
<button
413536
tabindex="0"
414-
class="inline-flex w-full items-center justify-between rounded-lg border border-slate-300 bg-white px-3 py-2 text-left text-sm text-slate-700 shadow-sm transition hover:border-slate-400 dark:border-slate-600 dark:bg-slate-900 dark:text-slate-200"
537+
class="inline-flex w-full min-w-0 items-center justify-between rounded-lg border border-slate-300 bg-white px-3 py-2 text-left text-sm text-slate-700 shadow-sm transition hover:border-slate-400 dark:border-slate-600 dark:bg-slate-900 dark:text-slate-200"
415538
:disabled="loading"
416539
>
417-
<span class="truncate">
540+
<span class="truncate min-w-0">
418541
{{ compareVersion?.name ?? t('manifest-compare-none') }}
419542
</span>
420543
<IconDown class="w-4 h-4 shrink-0 text-slate-400" />
@@ -446,11 +569,11 @@ watchEffect(async () => {
446569
v-for="option in compareOptions"
447570
:key="option.id"
448571
type="button"
449-
class="flex w-full items-center justify-between rounded-md px-3 py-2 text-sm hover:bg-slate-100 dark:hover:bg-slate-800"
572+
class="flex w-full min-w-0 items-center justify-between rounded-md px-3 py-2 text-sm hover:bg-slate-100 dark:hover:bg-slate-800"
450573
@click="selectCompareVersion(option)"
451574
>
452-
<span class="truncate">{{ option.name }}</span>
453-
<span class="ml-2 text-xs text-slate-400">{{ option.created_at ? formatLocalDate(option.created_at) : t('unknown') }}</span>
575+
<span class="truncate min-w-0">{{ option.name }}</span>
576+
<span class="ml-2 shrink-0 text-xs text-slate-400">{{ option.created_at ? formatLocalDate(option.created_at) : t('unknown') }}</span>
454577
</button>
455578
<div v-if="compareSearchLoading" class="px-3 py-2 text-xs text-slate-400">
456579
{{ t('loading') }}

0 commit comments

Comments
 (0)