Skip to content

Web#55

Merged
suggestied merged 27 commits intomainfrom
web
Feb 16, 2026
Merged

Web#55
suggestied merged 27 commits intomainfrom
web

Conversation

@suggestied
Copy link
Contributor

@suggestied suggestied commented Feb 16, 2026

Summary

Create web app


Note

Medium Risk
Introduces a new web app surface area with auth/tenant switching and role/permission management flows plus new bulk-import RPC wrappers; primary risk is incorrect tenant/session context or permission mutations causing cross-tenant data access or admin actions to misapply.

Overview
Adds a new apps/web Vite + React app wired to Supabase via @workorder-systems/sdk, including auth pages (login/signup/forgot/reset), a protected dashboard layout, and route-based redirects/prefetching using TanStack Router + Query.

Implements multi-tenant UX: tenant list prefetch in /_protected, persistent active-tenant selection in Zustand/localStorage, tenant switching that resets Supabase session, and dashboard navigation with breadcrumbs.

Introduces CSV bulk import pages for work orders, assets, locations, and departments (shared parseCsv + CsvImportPage grid UI), plus new SDK RPC wrappers for bulkImport on those resources.

Adds admin/team management screens for users and roles (invite/remove member, assign roles, assign/revoke permissions) and updates the UI AppShell to support explicit left sidebar/header slots and persisted sidebar open state; also persists only catalog queries to IndexedDB.

Written by Cursor Bugbot for commit 7e0713c. This will update automatically on new commits. Configure here.

…sidebar structure and add support for customizable sidebar content
… in dashboard, and enhance WorkOrdersPage with import functionality
…orkOrdersPage to conditionally render details sidebar based on mobile view
… fields, improving CSV parsing, and implementing bulk import capabilities. Update data grid cell handling for better select options management.
…plifying the work order selection process. Update the data table to display work order titles directly and enhance the create work order modal functionality.
… content area for improved layout consistency.
…ions and departments, and implement bulk import functionality for departments and locations in the SDK.
…rs, assets, locations, and departments, setting them to null for future implementation.
… integrate it into the DashboardLayout for enhanced navigation clarity.
…ders by consolidating CSV parsing logic, removing unused code, and implementing standardized CSV options for improved maintainability and functionality.
…s for Departments, Users, and Roles, and update the sidebar navigation documentation to reflect these changes. Additionally, introduce new SDK parameters for removing members and revoking permissions from roles.
…ns, team, and configuration sections for improved sidebar navigation organization.
@suggestied suggestied merged commit 9b50b01 into main Feb 16, 2026
1 check passed
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 5 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

setActiveTenantIdSync(targetId)
client
.setTenant(targetId)
.then(() =>
Copy link

Choose a reason for hiding this comment

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

Tenant switch races initial data queries

Medium Severity

useTenant sets activeTenantId via setActiveTenantIdSync before client.setTenant(...) completes. Queries keyed by activeTenantId can run immediately and call client.*.list() with stale tenant context, so pages may fetch the wrong tenant’s data or error during first load/refresh.

Additional Locations (1)

Fix in Cursor Fix in Web

const { canonicalColumns, requiredColumn, headerAliases = {} } = options
const normalized = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(BOM, '')
const lines = normalized.split('\n').filter((line) => line.trim().length > 0)
if (lines.length < 2) return []
Copy link

Choose a reason for hiding this comment

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

CSV parser breaks quoted multiline fields

Medium Severity

parseCsv splits input with normalized.split('\n') before parsing rows, so newline characters inside quoted cells are treated as row breaks. Valid CSV files with multiline quoted values become misaligned rows, leading to corrupted imports or row-level errors.

Fix in Cursor Fix in Web

headerAliases: {
name: [/^(name|title|assetname)$/],
description: [/^(description|desc|notes)$/],
asset_number: [/^(assetnumber|asset_number|number|tag)$/],
Copy link

Choose a reason for hiding this comment

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

Asset number column never maps

Medium Severity

The asset_number header alias is case-sensitive, but headerToKey normalizes headers to camelCase like assetNumber. This prevents parseCsv from mapping the asset_number column, so imported assets can silently lose asset_number values even when the CSV header matches the provided template.

Additional Locations (1)

Fix in Cursor Fix in Web

const tenantId = window.localStorage.getItem(TENANT_STORAGE_KEY)
if (!tenantId) return
await context.dbClient.setTenant(tenantId)
await prefetchCatalogs(context.queryClient, context.dbClient, tenantId)
Copy link

Choose a reason for hiding this comment

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

Invalid stored tenant blocks protected routes

Medium Severity

Route beforeLoad trusts localStorage and always calls context.dbClient.setTenant(tenantId). If dashboard_tenant_id is stale or no longer accessible, setTenant can throw and prevent route loading before useTenant can recover to a valid tenant.

Additional Locations (2)

Fix in Cursor Fix in Web

}, [segments, segmentLabels, basePath])

if (hideWhenOnlyRoot && items.length === 0 && !showRoot) return null
if (items.length === 0 && showRoot) {
Copy link

Choose a reason for hiding this comment

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

Root-hide option never hides breadcrumb

Low Severity

hideWhenOnlyRoot is effectively ignored when showRoot is true. The early-return condition requires !showRoot, then the next branch renders the root item, so breadcrumb visibility at root does not match the hideWhenOnlyRoot contract.

Fix in Cursor Fix in Web

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.

1 participant