Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dashboard ui design #21

Draft
wants to merge 48 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
e669372
added demo feature
sarem-h Jun 10, 2024
bd80c68
Merge branch 'master' of github.com:pir8bay/new-connect into features…
sarem-h Jun 12, 2024
cd0dd2b
init commit
sarem-h Jun 12, 2024
cd0d50c
fix for RouteCard linting errors
sarem-h Jun 12, 2024
a8646c7
refactor: Improve reverse geocoding logic in RouteCard component
sarem-h Jun 12, 2024
485fa68
chore: Update Solid.js import in Timeline component
sarem-h Jun 12, 2024
5be8173
refactor: Update Solid.js import in TopAppBar and DashboardDrawer com…
sarem-h Jun 12, 2024
a567f07
refactor: Update TopAppBar and DashboardDrawer components to use Soli…
sarem-h Jun 12, 2024
c956037
refactor: Add custom scrollbar styling to RouteList component
sarem-h Jun 12, 2024
1b3f5b7
refactor: Update RouteList component to hide scrollbar on larger screens
sarem-h Jun 12, 2024
d5ba434
Fixed overflow when scrolling up (#18)
ugtthis Jun 12, 2024
9d48a2f
check line limit (#22)
adeebshihadeh Jun 12, 2024
1106456
added sort functionality
sarem-h Jun 13, 2024
a9e6bb5
fix linting errors
sarem-h Jun 13, 2024
bd6e985
more linting fixes
sarem-h Jun 13, 2024
dff6c65
addressed more linting issues
sarem-h Jun 13, 2024
243ac3a
lint ...
sarem-h Jun 13, 2024
a4f8054
refetch lint error
sarem-h Jun 13, 2024
341c9b6
updated promise type
sarem-h Jun 13, 2024
691ee99
lint error
sarem-h Jun 13, 2024
9e05fba
refactor: Implemented Virtualizer for efficient rendering and improve…
sarem-h Jun 13, 2024
f7ded17
refactor: Implemented Virtualizer for efficient rendering and improve…
sarem-h Jun 13, 2024
dec7a33
setup vitest and @solidjs/testing-library (#24)
incognitojam Jun 13, 2024
1689cd5
add wrangler package to devDependencies
incognitojam Jun 13, 2024
be4c0d9
deploy wrangler 3 (#25)
incognitojam Jun 13, 2024
813cf2c
CI: revert deploy changes
incognitojam Jun 13, 2024
d35706c
CI: use cloudflare/wrangler-action (#26)
incognitojam Jun 13, 2024
11979f8
CI: setup bun to deploy preview
incognitojam Jun 13, 2024
4d9723a
CI: revert deploy URL changes
incognitojam Jun 13, 2024
034438c
update route API types and fix timeline (#27)
incognitojam Jun 13, 2024
4aa26ed
TopAppBar: fix flashing "Device" text in Dashboard (#19)
ugtthis Jun 13, 2024
f33774c
fix: show device type name if no alias set (#28)
incognitojam Jun 13, 2024
be6a8b8
fix(RouteActivity): use route start time for title (#29)
incognitojam Jun 14, 2024
3f4ed5a
CI(Preview): add retries to find PR script (#20)
ugtthis Jun 14, 2024
fe3ad7c
lots of progress!
adeebshihadeh Jun 14, 2024
7c1c6e2
lint: set basic style rules for commas, quotes, semis and indentation…
incognitojam Jun 15, 2024
368aed9
replace Typography component with tailwind classes (#31)
incognitojam Jun 16, 2024
f935c86
cleanup: remove unused styles (#32)
incognitojam Jun 16, 2024
0a748b1
add logout button to nav drawer (#33)
incognitojam Jun 16, 2024
c392d19
More UI updates and bug fixes
sarem-h Jun 21, 2024
3548fa0
refactor: remove hover background color from login buttons
sarem-h Jun 21, 2024
790ad28
chore: optimize responsive behavior for dashboard layout
sarem-h Jun 21, 2024
0774724
refactor: update window matchMedia check for dashboard layout respons…
sarem-h Jun 21, 2024
8cd5762
refactor: improve window matchMedia check for TopAppBar responsiveness
sarem-h Jun 21, 2024
b749b37
refactor: add place name to start and end locations in RouteCard, fix…
sarem-h Jun 21, 2024
16a07e4
chore: add autoplay to RouteVideoPlayer
sarem-h Jun 21, 2024
696696b
feat: add autoplay attribute to RouteVideoPlayer
sarem-h Jun 21, 2024
47c2736
refactor: set speed to 0 when removing RouteDynamicMap
sarem-h Jun 21, 2024
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
22 changes: 14 additions & 8 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@ on:
workflow_dispatch:

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 1
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1

- run: bun install --frozen-lockfile
- run: timeout 12s bun pre-commit
- run: bun run test
- run: ./check-lines.sh

build:
runs-on: ubuntu-latest
timeout-minutes: 1
Expand All @@ -16,7 +28,6 @@ jobs:
- uses: oven-sh/setup-bun@v1

- run: bun install --frozen-lockfile
- run: bun pre-commit
- run: bun run build

- name: Upload built project
Expand All @@ -27,15 +38,10 @@ jobs:
retention-days: 1
name: build-artifacts-${{ github.run_id }}

# deploy
- name: Deploy to Cloudflare Pages
id: cloudflare-publish
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/new-connect'
uses: cloudflare/pages-action@v1.5.0
uses: cloudflare/wrangler-action@v3
with:
directory: dist
branch: new-connect
projectName: connect
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_PAGES_TOKEN }}

command: pages deploy dist --project-name=connect --branch=new-connect --commit-dirty=true
12 changes: 5 additions & 7 deletions .github/workflows/preview.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1

- name: Download build artifacts
uses: actions/download-artifact@v4
Expand All @@ -29,6 +30,7 @@ jobs:
id: pr
uses: actions/github-script@v7
with:
retries: 3
script: |
const response = await github.rest.search.issuesAndPullRequests({
q: 'repo:${{ github.repository }} is:pr sha:${{ github.event.workflow_run.head_sha }}',
Expand All @@ -40,19 +42,15 @@ jobs:
return
}
const pullRequestNumber = items[0].number
console.info("Pull request number is", pullRequestNumber)
console.info('Pull request number is', pullRequestNumber)
return pullRequestNumber

# deploy
- name: Deploy to Cloudflare Pages
id: cloudflare-publish
uses: cloudflare/[email protected]
uses: cloudflare/wrangler-action@v3
with:
directory: dist
branch: ${{ steps.pr.outputs.result }}
projectName: connect
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_PAGES_TOKEN }}
command: pages deploy dist --project-name=connect --branch=${{ steps.pr.outputs.result }} --commit-dirty=true

- name: Comment URL on PR
uses: thollander/actions-comment-pull-request@v2
Expand Down
6 changes: 0 additions & 6 deletions .prettierrc

This file was deleted.

11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ A few constraints:
These are the minimum features for parity with connect.

Drives
- [ ] list
- [ ] show map
- [ ] play qcams
- [x] list
- [x] show map
- [x] play qcams
- [x] engagement timeline
- [ ] file uploads

Navigation
Expand All @@ -35,10 +36,10 @@ Navigation
- [ ] manage home, work, and favorites

Misc
- [ ] demo mode
- [x] demo mode
- [ ] snapshot
- [ ] comma prime sign up + management
- [ ] pairing to an openpilot device
- [ ] pairing to a new device
- [ ] PWA: splash, icon, offline mode, etc.

And some eventual features beyond connect's current feature set:
Expand Down
Binary file modified bun.lockb
100644 → 100755
Binary file not shown.
13 changes: 13 additions & 0 deletions check-lines.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash
set -e

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
cd $DIR

COUNT="$(find src/ -type f | xargs wc -l | tail -n 1 | awk '{print $1}')"
echo "$COUNT total lines"

if [ "$COUNT" -gt 5000 ]; then
echo "Exceeded line limit!"
exit 1
fi
30 changes: 28 additions & 2 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/* eslint-disable */
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */
import globals from 'globals'
import js from '@eslint/js'
import ts from 'typescript-eslint'
import tailwind from 'eslint-plugin-tailwindcss'
import solid from 'eslint-plugin-solid/configs/typescript.js'
import stylistic from '@stylistic/eslint-plugin'

export default [
{ languageOptions: { globals: globals.browser } },
Expand All @@ -20,6 +21,31 @@ export default [
},
...tailwind.configs['flat/recommended'],
{
ignores: ['node_modules', 'dist']
plugins: {
'@stylistic': stylistic,
},
rules: {
'@stylistic/brace-style': ['error', '1tbs'],
'@stylistic/comma-dangle': ['error', 'always-multiline'],
'@stylistic/eol-last': ['error', 'always'],
'@stylistic/indent': ['error', 2],
'@stylistic/indent-binary-ops': ['error', 2],
'@stylistic/jsx-indent': ['error', 2, { indentLogicalExpressions: true }],
'@stylistic/jsx-indent-props': ['error', 2],
'@stylistic/jsx-quotes': ['error', 'prefer-double'],
'@stylistic/linebreak-style': ['error', 'unix'],
'@stylistic/max-len': ['error', {
code: 120,
ignoreComments: true,
ignoreStrings: true,
ignoreTemplateLiterals: true,
ignoreRegExpLiterals: true,
}],
'@stylistic/no-extra-parens': ['error', 'functions'],
'@stylistic/no-extra-semi': 'error',
'@stylistic/quotes': ['error', 'single', { avoidEscape: true }],
'@stylistic/semi': ['error', 'never'],
},
ignores: ['node_modules', 'dist'],
},
]
15 changes: 12 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@
"dev": "vite",
"serve": "vite prefix",
"lint": "eslint",
"lint:fix": "eslint --fix",
"prepare": "husky",
"pre-commit": "bun lint"
"pre-commit": "bun lint",
"test": "vitest run"
},
"packageManager": "[email protected]",
"type": "module",
"devDependencies": {
"@solidjs/testing-library": "^0.8.8",
"@stylistic/eslint-plugin": "^2.1.0",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/user-event": "^14.5.2",
"@types/eslint__js": "^8.42.3",
"@types/mapbox__polyline": "^1.0.5",
"@typescript-eslint/eslint-plugin": "^7.13.0",
Expand All @@ -30,20 +34,25 @@
"eslint-plugin-tailwindcss": "^3.17.3",
"globals": "^15.4.0",
"husky": "^9.0.11",
"jsdom": "^24.1.0",
"postcss": "^8.4.38",
"solid-devtools": "^0.30.1",
"tailwindcss": "^3.4.4",
"typescript": "^5.4.5",
"typescript-eslint": "^7.13.0",
"vite": "^5.2.13",
"vite-plugin-solid": "^2.10.2"
"vite-plugin-solid": "^2.10.2",
"vitest": "^1.6.0",
"wrangler": "^3.60.2"
},
"dependencies": {
"@mapbox/polyline": "^1.2.1",
"@solidjs/router": "^0.13.5",
"@tanstack/solid-virtual": "^3.5.1",
"clsx": "^1.2.1",
"dayjs": "^1.11.11",
"hls.js": "^1.5.11",
"mapbox-gl": "^3.4.0",
"solid-js": "^1.8.17"
},
"engines": {
Expand Down
13 changes: 13 additions & 0 deletions src/App.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { beforeAll, expect, test } from 'vitest'
import { configure, render, screen } from '@solidjs/testing-library'

import App from './App'

beforeAll(() => {
configure({ asyncUtilTimeout: 2000 })
})

test('Show login page', async () => {
render(() => <App />)
expect(await screen.findByText('Sign in with Google')).not.toBeUndefined()
})
22 changes: 22 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Suspense, lazy, type VoidComponent } from 'solid-js'
import { Router, Route } from '@solidjs/router'

const Login = lazy(() => import('./pages/auth/login'))
const Logout = lazy(() => import('./pages/auth/logout'))
const Auth = lazy(() => import('./pages/auth/auth'))

const Dashboard = lazy(() => import('./pages/dashboard'))

const App: VoidComponent = () => {
return (
<Router root={(props) => <Suspense>{props.children}</Suspense>}>
<Route path="/login" component={Login} />
<Route path="/logout" component={Logout} />
<Route path="/auth" component={Auth} />

<Route path="/*dongleId" component={Dashboard} />
</Router>
)
}

export default App
9 changes: 3 additions & 6 deletions src/api/derived.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Route } from '~/types'
import { getRouteDuration } from '~/utils/date'

export interface GPSPathPoint {
t: number
Expand Down Expand Up @@ -106,9 +107,7 @@ const generateTimelineEvents = (
route: Route,
events: DriveEvent[],
): TimelineEvent[] => {
const routeDuration =
route.segment_end_times[route.segment_end_times.length - 1] -
route.segment_start_times[0]
const routeDuration = getRouteDuration(route)?.asMilliseconds() ?? 0

// sort events by timestamp
events.sort((a, b) => {
Expand Down Expand Up @@ -218,9 +217,7 @@ const generateTimelineStatistics = (
return {
engagedDuration,
userFlags,
duration:
route.segment_end_times[route.segment_end_times.length - 1] -
route.segment_start_times[0],
duration: getRouteDuration(route)?.asMilliseconds() ?? 0,
}
}

Expand Down
27 changes: 6 additions & 21 deletions src/api/route.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { fetcher } from '.'
import { BASE_URL } from './config'
import type { Device, Route } from '~/types'
import type { Device, Route, RouteShareSignature } from '~/types'

export class RouteName {
// dongle ID date str
// 0123456789abcdef|2023-02-15--15-25-00

static readonly regex =
/^([0-9a-f]{16})\|(\d{4}-\d{2}-\d{2}--\d{2}-\d{2}-\d{2})$/
static readonly regex = /^([0-9a-f]{16})\|(\d{4}-\d{2}-\d{2}--\d{2}-\d{2}-\d{2})$/
static readonly regexGroup = {
dongleId: 1,
dateStr: 2,
Expand All @@ -18,10 +17,7 @@ export class RouteName {
if (!match) {
return null
}
return new RouteName(
match[RouteName.regexGroup.dongleId],
match[RouteName.regexGroup.dateStr],
)
return new RouteName(match[RouteName.regexGroup.dongleId], match[RouteName.regexGroup.dateStr])
}

readonly dongleId: Device['dongle_id']
Expand All @@ -40,27 +36,16 @@ export class RouteName {
export const getRoute = (routeName: Route['fullname']): Promise<Route> =>
fetcher<Route>(`/v1/route/${routeName}/`)

interface RouteShareSignature extends Record<string, string> {
exp: NonNullable<Route['share_exp']>
sig: NonNullable<Route['share_sig']>
}

export const getRouteShareSignature = (
routeName: string,
): Promise<RouteShareSignature> =>
export const getRouteShareSignature = (routeName: string): Promise<RouteShareSignature> =>
fetcher(`/v1/route/${routeName}/share_signature`)

export const createQCameraStreamUrl = (
routeName: Route['fullname'],
signature: RouteShareSignature,
): string =>
`${BASE_URL}/v1/route/${routeName}/qcamera.m3u8?${new URLSearchParams(
signature,
).toString()}`
`${BASE_URL}/v1/route/${routeName}/qcamera.m3u8?${new URLSearchParams(signature).toString()}`

export const getQCameraStreamUrl = (
routeName: Route['fullname'],
): Promise<string> =>
export const getQCameraStreamUrl = (routeName: Route['fullname']): Promise<string> =>
getRouteShareSignature(routeName).then((signature) =>
createQCameraStreamUrl(routeName, signature),
)
24 changes: 6 additions & 18 deletions src/components/DeviceStatistics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import clsx from 'clsx'
import { getDeviceStats } from '~/api/devices'
import { formatDistance, formatDuration } from '~/utils/date'

import Typography from '~/components/material/Typography'

type DeviceStatisticsProps = {
class?: string
dongleId: string
Expand All @@ -19,28 +17,18 @@ const DeviceStatistics: VoidComponent<DeviceStatisticsProps> = (props) => {
return (
<div class={clsx('flex h-10 w-full gap-8', props.class)}>
<div class="flex flex-col justify-between">
<Typography variant="body-sm" color="on-surface-variant">
Distance
</Typography>
<Typography variant="label-lg">
{formatDistance(allTime()?.distance)}
</Typography>
<span class="text-body-sm text-on-surface-variant">Distance</span>
<span class="font-mono text-label-lg uppercase">{formatDistance(allTime()?.distance)}</span>
</div>

<div class="flex flex-col justify-between">
<Typography variant="body-sm" color="on-surface-variant">
Duration
</Typography>
<Typography variant="label-lg">
{formatDuration(allTime()?.minutes)}
</Typography>
<span class="text-body-sm text-on-surface-variant">Duration</span>
<span class="font-mono text-label-lg uppercase">{formatDuration(allTime()?.minutes)}</span>
</div>

<div class="flex flex-col justify-between">
<Typography variant="body-sm" color="on-surface-variant">
Routes
</Typography>
<Typography variant="label-lg">{allTime()?.routes ?? 0}</Typography>
<span class="text-body-sm text-on-surface-variant">Routes</span>
<span class="font-mono text-label-lg uppercase">{allTime()?.routes ?? 0}</span>
</div>
</div>
)
Expand Down
Loading