Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
9adbb38
rebased
greatgitsby Mar 22, 2025
de817f0
heavily simplify the upload queue
greatgitsby Mar 22, 2025
ac85ca0
bump bundle limit to 260kb
greatgitsby Mar 22, 2025
6b375be
upload queue row more responsive
greatgitsby Mar 23, 2025
6a579c9
progress bar shimmer
greatgitsby Mar 23, 2025
bead7ea
shimmer in tailwind, only poll online temp
greatgitsby Mar 23, 2025
e2762f1
fix: combine solid stores, missing icons
greatgitsby Mar 23, 2025
9177a73
cleanup
greatgitsby Mar 23, 2025
bda62f8
move sorting to hook, stable sort by route -> segment -> filename
greatgitsby Mar 23, 2025
a7f04ef
need ID
greatgitsby Mar 23, 2025
dcc50f4
reformat feature code
greatgitsby Mar 23, 2025
4b07aba
format progress
greatgitsby Mar 23, 2025
5f58ace
this is fine
greatgitsby Mar 23, 2025
5ad3bbb
some formatting, removing unused fields
greatgitsby Mar 23, 2025
c0a4fc1
rebase
greatgitsby Mar 23, 2025
2e29747
guard multiple poll schedules
greatgitsby Mar 23, 2025
d89a982
remove 2 lines
greatgitsby Mar 23, 2025
39fcf41
support possibility of other types of athena offline messages
greatgitsby Mar 23, 2025
f539d8f
progress
greatgitsby Mar 23, 2025
0b26ee5
rename
greatgitsby Mar 23, 2025
f8c7e20
fix transitions
greatgitsby Mar 23, 2025
d4ce6f8
remove log
greatgitsby Mar 23, 2025
7a047bf
progress shimmer fix
greatgitsby Mar 23, 2025
d8cb419
less lines
greatgitsby Mar 23, 2025
a174f2e
brighter, slower
greatgitsby Mar 23, 2025
86687d5
condense upload queue, make it smaller on mobile
greatgitsby Mar 24, 2025
b7ce2cf
little more space on desktop
greatgitsby Mar 24, 2025
2ef62f3
remove added shimmer, stats bar
greatgitsby Mar 24, 2025
314ae63
debug
greatgitsby Mar 24, 2025
b750140
order
greatgitsby Mar 24, 2025
c4e42f8
break up UploadQueue into separate components
greatgitsby Mar 24, 2025
a66fa17
order
greatgitsby Mar 24, 2025
0c3fcf4
order
greatgitsby Mar 24, 2025
5ee607a
less
greatgitsby Mar 24, 2025
c45fefd
define animations once
greatgitsby Mar 24, 2025
765426e
remove unused dep, move solid-transition-group to reg dep
greatgitsby Mar 25, 2025
4bd9300
alpha order
greatgitsby Mar 25, 2025
43d7e8c
just use statsbar
greatgitsby Mar 25, 2025
696a1fb
more reactive
greatgitsby Mar 25, 2025
26ea286
fix suspense handling
greatgitsby Mar 25, 2025
c88ecc1
type errors, logic
greatgitsby Mar 25, 2025
6aa3de9
remove testing wait
greatgitsby Mar 25, 2025
edd2e89
format
greatgitsby Mar 25, 2025
2d6d416
remove comment
greatgitsby Mar 25, 2025
cd40799
refactoring
greatgitsby Mar 26, 2025
9740d82
shared
greatgitsby Mar 26, 2025
44de4e8
switch-match, less nesting
greatgitsby Mar 26, 2025
a03a3c4
logic fixes
greatgitsby Mar 26, 2025
590b5c0
lower bundle size, only needed 252
greatgitsby Mar 26, 2025
89f4ff4
create scoped fn for poller to work
greatgitsby Mar 26, 2025
a6c59c8
spacing
greatgitsby Mar 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
"dayjs": "work with dates (e.g., parse, validate, etc.)",
"hls.js": "stream video data",
"leaflet": "interactive maps",
"solid-js": "JS ui framework"
"solid-js": "JS ui framework",
"solid-transition-group": "animate components when they are inserted/removed from the DOM"
},
"dependencies": {
"@mapbox/polyline": "^1.2.1",
Expand All @@ -80,7 +81,8 @@
"hls.js": "^1.5.20",
"leaflet": "^1.9.4",
"qr-scanner": "^1.4.2",
"solid-js": "^1.9.5"
"solid-js": "^1.9.5",
"solid-transition-group": "^0.3.0"
},
"engines": {
"node": ">=20.11.0"
Expand Down
2 changes: 1 addition & 1 deletion src/ci/check_bundle_size.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ files.push({ path: '', sizeKB: '', compressedSizeKB: '' }, { path: 'Total', size
console.table(files, ['path', 'sizeKB', 'compressedSizeKB'])

const lowerBoundKB = 200
const upperBoundKB = 250
const upperBoundKB = 252
if (totalCompressedSize < lowerBoundKB * 1024) {
console.warn(`Bundle size lower than expected, let's lower the limit! (${totalCompressedSizeKB}KB < ${lowerBoundKB}KB)`)
process.exit(1)
Expand Down
7 changes: 4 additions & 3 deletions src/components/material/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import clsx from 'clsx'
// https://developers.google.com/fonts/docs/material_symbols#optimize_the_icon_font
// biome-ignore format: the array should not be formatted
export const Icons = [
'add', 'arrow_back', 'camera', 'check', 'chevron_right', 'clear', 'close', 'description', 'directions_car', 'download', 'error',
'file_copy', 'info', 'menu', 'my_location', 'open_in_new', 'payments', 'person', 'progress_activity', 'satellite_alt', 'search',
'settings', 'sync', 'upload', 'videocam',
'add', 'arrow_back', 'camera', 'check', 'chevron_right', 'clear', 'cloud_done', 'close', 'delete', 'description',
'directions_car', 'download', 'error', 'face', 'file_copy', 'info', 'keyboard_arrow_down', 'keyboard_arrow_up',
'local_fire_department', 'menu', 'my_location', 'open_in_new', 'payments', 'person', 'progress_activity',
'satellite_alt', 'search', 'settings', 'signal_disconnected', 'sync', 'upload', 'videocam',
] as const

export type IconName = (typeof Icons)[number]
Expand Down
52 changes: 52 additions & 0 deletions src/components/upload-queue/QueueItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Component, createMemo } from 'solid-js'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just put all of the components in the same file if they aren't going to be used elsewhere in the app


import { COMMA_CONNECT_PRIORITY } from '~/api/athena'
import Icon from '~/components/material/Icon'
import LinearProgress from '~/components/material/LinearProgress'
import { UploadItem } from '~/types'

const QueueItem: Component<{ item: UploadItem }> = (props) => {
const progress = createMemo(() => {
if (props.item.status === 'waiting_for_network') return 'Waiting for network'
if (props.item.status === 'queued') return 'Queued'
if (props.item.progress === 100) return 'Finishing'
return `${props.item.progress}%`
})

const progressColor = createMemo(() => {
switch (props.item.status) {
case 'completed':
return 'tertiary'
case 'queued':
case 'waiting_for_network':
return 'secondary'
default:
return 'primary'
}
})

const icon = createMemo(() => (props.item.priority === COMMA_CONNECT_PRIORITY ? 'face' : 'local_fire_department'))

return (
<div class="flex flex-col">
<div class="flex items-center justify-between flex-wrap mb-1 gap-x-4 min-w-0">
<div class="flex items-center min-w-0 flex-1">
<Icon class="text-on-surface-variant flex-shrink-0 mr-2" name={icon()} />
<div class="flex min-w-0 gap-1">
<span class="text-body-sm font-mono truncate text-on-surface">
{[props.item.route, props.item.segment, props.item.filename].join(' ')}
</span>
</div>
</div>
<div class="flex items-center gap-2 flex-shrink-0 justify-end">
<span class="text-body-sm font-mono whitespace-nowrap">{progress()}</span>
</div>
</div>
<div class="h-1.5 w-full overflow-hidden rounded-full bg-surface-container-highest">
<LinearProgress progress={props.item.progress / 100} color={progressColor()} />
</div>
</div>
)
}

export default QueueItem
69 changes: 69 additions & 0 deletions src/components/upload-queue/QueueItemTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Component, Suspense } from 'solid-js'
import { For, Match, Switch } from 'solid-js'
import { Transition, TransitionGroup } from 'solid-transition-group'

import Icon from '~/components/material/Icon'
import { UploadItem } from '~/types'

import QueueItem from './QueueItem'
import clsx from 'clsx'

const animations = (slide: boolean) => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Animations look like something which could just be added in a separate PR later, where there is time to test them properly

return {
enterActiveClass: 'transition-all duration-300 ease-in-out',
exitActiveClass: 'transition-all duration-300 ease-in-out',
enterClass: clsx('opacity-0', slide && 'transform translate-x-4'),
enterToClass: clsx('opacity-100', slide && 'transform translate-x-0'),
exitClass: clsx('opacity-100', slide && 'transform translate-x-0'),
exitToClass: clsx('opacity-0', slide && 'transform -translate-x-4'),
moveClass: clsx(slide && 'transition-transform duration-300'),
}
}

const QueueItemTable: Component<{ items?: () => UploadItem[] | undefined; error?: () => string | undefined; offline?: boolean }> = (
props,
) => {
return (
<div class="relative h-[calc(4*3rem)] sm:h-[calc(6*3rem)]">
<Transition appear {...animations(false)}>
<Suspense
fallback={
<div class="flex justify-center items-center h-full animate-spin absolute inset-0">
<Icon name="progress_activity" />
</div>
}
>
<Switch>
<Match when={props.error?.() !== undefined && props.items?.()?.length === 0}>
<div class="flex items-center justify-center h-full gap-2 text-on-surface-variant absolute inset-0">
<Icon name="signal_disconnected" />
<span>{props.error?.()}</span>
</div>
</Match>
<Match when={props.items?.()?.length === 0}>
<div class="flex items-center justify-center h-full gap-2 text-on-surface-variant absolute inset-0">
<Icon name="cloud_done" />
<span>No files in queue</span>
</div>
</Match>
<Match when={true}>
<div class="absolute inset-0 overflow-y-auto hide-scrollbar">
<TransitionGroup name="list" {...animations(true)}>
<For each={props.items?.()}>
{(item) => (
<div class="bg-surface-container-lowest rounded-md pb-1 sm:pb-2">
<QueueItem item={item} />
</div>
)}
</For>
</TransitionGroup>
</div>
</Match>
</Switch>
</Suspense>
</Transition>
</div>
)
}

export default QueueItemTable
56 changes: 56 additions & 0 deletions src/components/upload-queue/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import clsx from 'clsx'
import { createResource, Suspense } from 'solid-js'
import type { Component } from 'solid-js'

import IconButton from '~/components/material/IconButton'
import { useUploadQueue } from '~/hooks/use-upload-queue'

import QueueItemTable from './QueueItemTable'
import StatisticBar from '../StatisticBar'

const UploadQueue: Component<{ dongleId: string }> = (props) => {
const [queue] = createResource(() => props.dongleId, useUploadQueue)
const items = () => queue()?.items()
return (
<div class="flex flex-col border-2 border-t-0 border-surface-container-high bg-surface-container-lowest">
<div class="flex">
<div class="flex-auto p-4">
<StatisticBar
statistics={[
{
label: 'Uploading',
value: () =>
queue()
?.items()
.filter((i) => i.status === 'uploading').length,
},
{
label: 'Waiting',
value: () =>
queue()
?.items()
.filter((i) => i.status === 'queued').length,
},
{ label: 'Total', value: () => queue()?.items().length },
Comment on lines +20 to +34
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this formatting can be more compact but Biome was doing this.

]}
/>
</div>
<div class="flex p-4">
<Suspense fallback={<IconButton name="delete" />}>
<IconButton
class={clsx(queue()?.clearingQueue() && 'animate-spin')}
name={queue()?.clearingQueue() ? 'progress_activity' : queue()?.clearQueueError() ? 'error' : 'delete'}
onClick={() => void queue()?.clearQueue()}
disabled={queue()?.clearingQueue()}
/>
</Suspense>
</div>
</div>
<div class="rounded-md border-2 border-surface-container-high mx-4 mb-4 p-4">
<QueueItemTable items={items} error={queue()?.error} offline={queue()?.offline()} />
</div>
</div>
)
}

export default UploadQueue
Loading
Loading