Skip to content

Feat/responsive - #1060

Open
jona159 wants to merge 35 commits into
devfrom
feat/responsive
Open

Feat/responsive#1060
jona159 wants to merge 35 commits into
devfrom
feat/responsive

Conversation

@jona159

@jona159 jona159 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Type of Change

  • Dependency upgrade
  • Bug fix (non-breaking change)
  • Breaking change
    • e.g. a fixed bug or new feature that may break something else
  • New feature
  • Code quality improvements
    • e.g. refactoring, documentation, tests, tooling, ...

Implementation

Checklist

  • I gave this pull request a meaningful title
  • My pull request is targeting the dev branch
  • I have added documentation to my code
  • I have deleted code that I have commented out

Additional Information

  • This PR closes #

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Enhancements
    • Improved responsive layouts across device management, dashboards, forms, settings, documentation, and landing pages.
    • Added better mobile support with adaptable controls, stacking, wrapping, sizing, and horizontally scrollable tabs.
    • Improved handling of long labels, IDs, links, search results, tables, dialogs, and API documentation.
    • Added localized device metadata, dates, timestamps, and exposure values.
    • Improved mobile navigation, dialog controls, accessibility announcements, and log viewing.
    • Device activity logs now display newest entries first.
  • Bug Fixes
    • Corrected password recovery navigation, username error messaging, and responsive overflow issues.

Walkthrough

The pull request standardizes responsive layouts across public, device, map, documentation, authentication, and settings views. It also localizes device-detail content, improves overlay behavior, updates accessibility metadata, and removes runtime viewport detection.

Changes

Responsive UI and navigation

Layer / File(s) Summary
Shared containers and controls
app/components/ui/*, app/components/mydevices/dt/data-table.tsx, app/components/search/search-list.tsx
Dialogs, tables, tabs, data tables, and search results now constrain dimensions and support scrolling, wrapping, and touch-friendly controls.
Navigation and authentication overlays
app/components/header/*, app/components/landing/header/header.tsx, app/routes/account.password-reset.tsx, app/routes/explore*.tsx, app/routes/explore.tsx
Navigation uses CSS breakpoints. Authentication overlays use local scrollable containers. Menu accessibility attributes and username error references were updated.

Public and application pages

Layer / File(s) Summary
Landing and about pages
app/components/landing/*, app/routes/about.tsx
Landing sections use responsive columns, grids, spacing, image sizing, wrapping, and globe visibility.
Device workflows and detail views
app/components/device-detail/*, app/components/device/new/*, app/routes/device*
Device views and forms use responsive sizing, stacking, scrolling, truncation, localized content, and flexible controls.
Map, documentation, and settings
app/components/map/topbar.tsx, app/routes/docs.tsx, app/routes/profile.$username.tsx, app/routes/settings*.tsx
Map, Swagger, profile, and settings views use responsive layouts, wrapping, tab scrolling, and mobile-sized controls.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🟡 Moderate · up to bca51

This responsive UI change can leave tablet search results with reduced touch targets, render dates inconsistently across locales and time zones, and shift desktop content when the globe appears after hydration. These are bounded but actionable current-head risks, so merge should wait for fixes or explicit owner acceptance.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description is an unfilled template and does not explain the responsive layout changes or implementation details. Complete the description with the change type, implementation summary, rationale, limitations, and relevant checklist or issue details.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title identifies the main responsive-layout change and is concise, but it is not written as a sentence.
Docstring Coverage ✅ Passed Docstring check was indeterminate for this PR — some files could not be analyzed in time. Not blocking.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/responsive

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 66% 2243 / 3398
🔵 Statements 64.54% 2317 / 3590
🔵 Functions 63.26% 434 / 686
🔵 Branches 50.84% 1081 / 2126
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
app/db/models/device.server.ts 61.36% 65.93% 60% 62.4% 91-96, 104, 211, 223-224, 289-346, 386, 420, 449, 478, 508, 512, 520-522, 528-530, 548-550, 554-556, 598-600, 615, 626-798, 849-853, 881-887, 892-908, 990-992, 1003, 1010-1011, 1023-1030, 1034-1045, 1085, 1193-1213, 1232
Generated in workflow #2911 for commit bca51a8 by the Vitest Coverage Report Action

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f6928b6e-2c50-4134-9e77-a104f3a92bf1

📥 Commits

Reviewing files that changed from the base of the PR and between ec7891c and ae1472f.

📒 Files selected for processing (61)
  • app/components/device-detail/device-detail-box.tsx
  • app/components/device-detail/graph.tsx
  • app/components/device/new/custom-device-config.tsx
  • app/components/device/new/general-info.tsx
  • app/components/device/new/location-info.tsx
  • app/components/device/new/new-device-stepper.tsx
  • app/components/error-message.tsx
  • app/components/header/download.tsx
  • app/components/header/home/index.tsx
  • app/components/header/info/index.tsx
  • app/components/header/menu/index.tsx
  • app/components/header/nav-bar/index.tsx
  • app/components/landing/footer.tsx
  • app/components/landing/header/header.tsx
  • app/components/landing/header/language-selector.tsx
  • app/components/landing/header/theme-toggle.tsx
  • app/components/landing/sections/connect.tsx
  • app/components/landing/sections/features.tsx
  • app/components/landing/sections/integrations.tsx
  • app/components/landing/sections/partners.tsx
  • app/components/landing/sections/pricing-plans.tsx
  • app/components/landing/stats.tsx
  • app/components/language-select.tsx
  • app/components/map/legend.tsx
  • app/components/map/topbar.tsx
  • app/components/markdown-content.tsx
  • app/components/mydevices/dt/data-table.tsx
  • app/components/nav-bar.tsx
  • app/components/search/search-list-item.tsx
  • app/components/search/search-list.tsx
  • app/components/theme-select.tsx
  • app/components/ui/alert-dialog.tsx
  • app/components/ui/dialog.tsx
  • app/components/ui/drawer.tsx
  • app/components/ui/sheet.tsx
  • app/components/ui/table.tsx
  • app/components/ui/tabs.tsx
  • app/components/ui/toast.tsx
  • app/components/viewport-portal.tsx
  • app/root.tsx
  • app/routes/about.tsx
  • app/routes/account.password-reset.tsx
  • app/routes/device.$deviceId.dataupload.tsx
  • app/routes/device.$deviceId.edit.security.tsx
  • app/routes/device.$deviceId.edit.sensors.tsx
  • app/routes/device.$deviceId.edit.transfer.tsx
  • app/routes/device.$deviceId.edit.tsx
  • app/routes/device.dashboard.$deviceId.tsx
  • app/routes/device.new.tsx
  • app/routes/device.transfer.tsx
  • app/routes/docs.tsx
  • app/routes/explore.forgot.tsx
  • app/routes/explore.login.tsx
  • app/routes/explore.register.tsx
  • app/routes/imprint.tsx
  • app/routes/privacy.tsx
  • app/routes/profile.$username.tsx
  • app/routes/settings.account.tsx
  • app/routes/settings.preferences.tsx
  • app/routes/settings.profile.tsx
  • app/routes/settings.tsx

Comment thread app/components/landing/header/header.tsx
Comment thread app/components/landing/sections/pricing-plans.tsx Outdated
Comment thread app/components/map/topbar.tsx
Comment thread app/components/search/search-list-item.tsx Outdated
Comment thread app/routes/about.tsx
Comment thread app/routes/explore.register.tsx Outdated
Comment thread app/routes/settings.preferences.tsx Outdated
@scheidtdav scheidtdav linked an issue Aug 18, 2026 that may be closed by this pull request
@jona159
jona159 marked this pull request as ready for review August 24, 2026 10:10

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/components/device-detail/device-detail-box.tsx (1)

100-104: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Timezone-dependent date formatting runs during server render in both components. Neither call site sets timeZone, so the server output uses the server timezone and the client output uses the user timezone. This produces hydration mismatches, and for date-only output it can show a different day.

  • app/components/device-detail/device-detail-box.tsx#L100-L104: add an explicit timeZone to the Intl.DateTimeFormat options, and wrap the formatter in useMemo.
  • app/components/device-detail/entry-logs.tsx#L48-L48: pass an options object with an explicit timeZone to toLocaleString, and apply the same change to the LogList call on line 105.

Source: Linters/SAST tools


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e84fa16f-1bb7-4cb1-9ae6-599172607358

📥 Commits

Reviewing files that changed from the base of the PR and between ae1472f and a318fc7.

📒 Files selected for processing (15)
  • app/components/device-detail/device-detail-box.tsx
  • app/components/device-detail/entry-logs.tsx
  • app/components/header/nav-bar/index.tsx
  • app/components/landing/header/header.tsx
  • app/components/landing/sections/pricing-plans.tsx
  • app/components/map/topbar.tsx
  • app/routes/about.tsx
  • app/routes/account.password-reset.tsx
  • app/routes/device.$deviceId.edit.tsx
  • app/routes/explore.forgot.tsx
  • app/routes/explore.login.tsx
  • app/routes/explore.register.tsx
  • app/routes/explore.tsx
  • app/routes/settings.preferences.tsx
  • package.json
💤 Files with no reviewable changes (1)
  • app/routes/account.password-reset.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/routes/settings.preferences.tsx

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Comment on lines +30 to +32
const latestEntry = entryLogs.at(-1)

if (isDesktop) {
return (
<div className="flex flex-col">
<p className="pb-4 font-bold">{t('logs')}</p>
<div className="flex items-center">
<div className="flex w-full items-start space-x-4">
<div className="border-muted-foreground text-muted-foreground flex h-10 w-10 shrink-0 items-center justify-center rounded-full border-4">
<Activity className="h-5 w-5" />
</div>
<div className="grow">
<p className="mb-2 text-sm font-medium">
{entryLogs[entryLogs.length - 1].content}
</p>
<div className="text-muted-foreground flex items-center text-xs">
<Clock className="mr-1 h-3 w-3" />
{new Date(entryLogs[0].createdAt).toLocaleString(i18n.language)}
</div>
</div>
</div>
<div className="shrink">
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="ghost">
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
{' '}
<ExternalLink className="ml-2 h-5 w-5" />
</TooltipTrigger>
<TooltipContent className="z-auto overflow-visible">
<p>{t('show_all_logs')}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-2/3">
<DialogHeader>
<DialogTitle>{t('device_logs')}</DialogTitle>
<DialogDescription>{t('logs_owner_hint')}</DialogDescription>
</DialogHeader>
<LogList entryLogs={entryLogs} locale={i18n.language} />
</DialogContent>
</Dialog>
</div>
</div>
</div>
)
}
if (!latestEntry) return null

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find where logEntries are loaded and check the ordering clause.
set -euo pipefail

rg -n -C6 'logEntries' --type=ts --type=tsx | head -100
fd -t f 'log-entry' | while IFS= read -r f; do echo "=== $f ==="; cat -n "$f"; done
rg -n -C8 'logEntry' app/db/models 2>/dev/null || rg -n -C8 'logEntry' app/db

Repository: openSenseMap/frontend

Length of output: 191


🏁 Script executed:

set -euo pipefail

printf '%s\n' '=== target file ==='
cat -n app/components/device-detail/entry-logs.tsx

printf '%s\n' '=== log-entry schema and related files ==='
cat -n app/db/schema/log-entry.ts
printf '%s\n' '=== candidate source files ==='
git ls-files | rg '(^|/)(log-entry|entry-log|device-detail|loader|loaders|api|route)' | head -200

printf '%s\n' '=== logEntries references ==='
rg -n -C8 'logEntries|entryLogs|LogEntry' --glob '*.ts' --glob '*.tsx' . | head -300

printf '%s\n' '=== ordering expressions ==='
rg -n -C6 'createdAt|orderBy|order\(' --glob '*.ts' --glob '*.tsx' app | head -400

Repository: openSenseMap/frontend

Length of output: 50377


🏁 Script executed:

set -euo pipefail

printf '%s\n' '=== device model relation query ==='
cat -n app/db/models/device.server.ts | sed -n '80,145p'

printf '%s\n' '=== log-entry model ==='
cat -n app/db/models/log-entry.server.ts | sed -n '1,65p'

printf '%s\n' '=== device detail data loaders ==='
rg -n -C10 'getDevice|device-detail-box|DeviceDetailBox|logEntries' \
  app/routes/device.\$deviceId.overview.tsx \
  app/routes/device.dashboard.\$deviceId.tsx \
  app/components/device-detail/device-detail-box.tsx \
  app/db/models/device.server.ts

printf '%s\n' '=== all relation query orderBy options ==='
rg -n -C5 'with:|logEntries:|orderBy:' app/db app/routes --glob '*.ts' --glob '*.tsx' | head -250

Repository: openSenseMap/frontend

Length of output: 36016


🏁 Script executed:

set -euo pipefail

printf '%s\n' '=== consumer route ==='
rg -n -C12 'getDevice\(|DeviceDetailBox|loader' \
  app/routes/explore.\$deviceId.tsx \
  app/components/device-detail/device-detail-box.tsx

printf '%s\n' '=== device model declarations and uses ==='
rg -n -C4 'export function getDevice|export async function getDevice|getDevice\(' \
  app/db/models/device.server.ts app/routes --glob '*.ts' --glob '*.tsx'

printf '%s\n' '=== read-only structural check of the logEntries relation config ==='
python3 - <<'PY'
from pathlib import Path
import re

path = Path("app/db/models/device.server.ts")
text = path.read_text()
match = re.search(r"logEntries:\s*\{(?P<body>.*?)\n\s*\},\n\s*locations:", text, re.S)
if not match:
    raise SystemExit("logEntries relation block not found")
body = match.group("body")
print("logEntries relation block:")
print(body)
print("contains orderBy:", bool(re.search(r"\borderBy\s*:", body)))
print("contains createdAt:", "createdAt" in body)
PY

Repository: openSenseMap/frontend

Length of output: 24086


Define the logEntries order before using .at(-1). The getDevice relation has no orderBy, so entryLogs.at(-1) is not guaranteed to return the newest entry. Use an explicit ascending order or select the entry with the greatest createdAt.

Comment thread app/components/landing/header/header.tsx Outdated
Comment thread app/routes/about.tsx
Comment thread package.json

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
app/routes/about.tsx (1)

200-202: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Reserve the desktop globe space before mounting GlobeComponent.

useMediaQuery returns false on the first render and updates in useEffect (app/hooks/use-media-query.ts:3-17). On desktop, this hidden wrapper therefore has no layout space during SSR and hydration. After the effect, the globe appears and shifts Stats and the following content down. Keep a fixed-size desktop wrapper and hide only the globe content until the query resolves.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 03bb3ccd-ba42-4178-b883-89cbccf53fda

📥 Commits

Reviewing files that changed from the base of the PR and between a318fc7 and bca51a8.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • app/components/device-detail/entry-logs.tsx
  • app/components/landing/header/header.tsx
  • app/db/models/device.server.ts
  • app/hooks/use-media-query.ts
  • app/routes/about.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/components/landing/header/header.tsx

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

make UI responsive for mobile devices

1 participant