Skip to content

Feature task 3634 tdei theme#54

Open
shweta2101 wants to merge 18 commits into
masterfrom
feature-task-3634-tdei-theme
Open

Feature task 3634 tdei theme#54
shweta2101 wants to merge 18 commits into
masterfrom
feature-task-3634-tdei-theme

Conversation

@shweta2101
Copy link
Copy Markdown
Contributor

@shweta2101 shweta2101 commented May 25, 2026

DevBoard Task

https://dev.azure.com/TDEI-UW/TDEI/_workitems/edit/3634/

This PR applies TDEI brand theming across the application — updating colours, typography, layout, and accessibility throughout.

Visual changes

  • Navbar — Redesigned with TDEI brand colour (#32006e), new responsive mobile side-menu with slide-in animation, user profile dropdown, and sticky positioning
  • Sign-in page — Fully redesigned card layout with TDEI logo, styled inputs, show/hide password toggle, and responsive mobile view
  • Dashboard — Split-panel layout with scrollable workspace list and sticky detail panel; workspace type icons added
  • Homepage — New hero section with brand imagery and workspace type icons (OSW, Pathways, Flex)
  • Buttons & links — Replaced ad-hoc Bootstrap variants with consistent utility classes (tdei-primary-button, tdei-secondary-button, tdei-primary-link, tdei-rounded-button)

Screenshots:

Screenshot 2026-05-25 at 8 02 16 PM Screenshot 2026-05-25 at 8 02 40 PM Screenshot 2026-05-25 at 8 06 00 PM Screenshot 2026-05-25 at 8 08 21 PM Screenshot 2026-05-25 at 8 08 42 PM Screenshot 2026-05-25 at 8 16 01 PM Screenshot 2026-05-25 at 8 17 03 PM

Theming & Core Styling

Updated TDEI brand theming throughout the application by changing the primary color from #9b0092 to #32006e in theme.scss. Added comprehensive CSS custom properties for font families (Open Sans, Montserrat) and color variables in main.scss. Extended global styling with a new "TDEI Utility Classes" section introducing standardized button/link classes (tdei-primary-button, tdei-secondary-button, tdei-rounded-button, tdei-primary-link, tdei-secondary-link), header/title/subtitle typography helpers, and form-related utilities. Added browser autofill styling with smooth transitions and updated dropdown menu active states.

Font Management & Assets

Integrated @nuxtjs/google-fonts module via nuxt.config.ts to serve Open Sans (weights 300–800) and Montserrat (weights 100, 300–900) with swap display strategy. Updated AppLogo.vue to use the new TDEI logo (tdei-logo.png) instead of the generic icon SVG.

Navigation & Header

Completely rebuilt AppNavbar.vue with a custom responsive design replacing Bootstrap-style collapsed layout. Added sticky positioning with updated spacing and colors. Implemented interactive mobile side menu with slide-in animation, backdrop, and keyboard management (Escape to close, Tab focus trapping). Added focus management on mount/window resize and mobile view detection. Updated logout behavior to close the mobile menu before navigating. Desktop and mobile typography and menu item states were adjusted.

Authentication

Redesigned SigninForm.vue with TDEI-branded auth card styling. Implemented toggleable password field with visibility icon button. Refined error handling with stricter fetch-error type guard (isFetchError) that validates response.status and response.json() function availability before interpreting HTTP statuses (400/401/404 show user-facing messages; others fall back to error message). Updated form/card markup with new styling classes and responsive mobile layout with adjusted padding/max-width for small screens.

Updated pages/signin.vue by simplifying the layout to use a signin-shell wrapper containing only the sign-in form, maintaining redirect behavior to /dashboard when authentication is complete.

Homepage & Landing Page

Updated pages/index.vue with a new hero section layout replacing the previous centered jumbo-content. Introduced hero-shell, hero-copy, hero-divider, and hero-actions structure. Made the primary CTA conditionally route to /dashboard (when authenticated) or /signin (when not), with label changing accordingly. Exposed auth state from tdeiClient to drive conditional routing. Extensively revised SCSS styling across responsive breakpoints (lg, md, sm) for padding, typography, action layout, and button sizing.

Dashboard & Workspace Management

Converted dashboard to split-panel layout in pages/dashboard.vue with scrollable left panel for workspace list and sticky right detail panel. Introduced workspace-split-layout structure and new responsive/sticky positioning styles. Added selectedProjectGroupName computed property from project groups data. Updated workspace list to display scrollable cards with new scrollbar styling.

Redesigned WorkspaceItem.vue cards to display workspace type icons (derived from workspace type), separate type/status labels, and title with inline ID. Replaced badge-based markup with structured card layout using .workspaceCard* CSS classes and introduced typeIconSrc and formatTypeLabel helper functions.

Updated components/dashboard/Toolbar.vue to use tdei-toolbar-primary-button for dropdown/action buttons and tdei-secondary-button for export/settings buttons, maintaining existing routing and aria-disabled behavior.

Button & Link Standardization

Systematically replaced Bootstrap button variants (btn-primary, btn-success, btn-danger, etc.) with new TDEI utility classes across the entire application:

  • Primary buttons: tdei-primary-button in toolbar, settings panels (General, Imagery, Apps), review tools, workspace creation flows, export pages, help page, and team dialogs
  • Secondary buttons: tdei-secondary-button in review toolbar, dashboard toolbar, help page, join dialogs, and team-related components
  • Secondary links: tdei-secondary-link for download/QR code links
  • Primary links: tdei-primary-link for team member links
  • Maroon/destructive buttons: maroon-bg class for delete confirmations in settings and team removal dialogs
  • Tertiary links: tdei-primary-link with bg-transparent for cancel buttons in various dialogs

Affected components: DatasetTypeRadio.vue, review/FilterDropdown.vue, review/Toolbar.vue, settings/panel/ (General, Imagery, Apps, Delete), settings/teams/JoinDialog.vue, teams/Item.vue, teams/JoinDialog.vue, teams/MembersDialog.vue, teams/SettingsDialog.vue, pages/help.vue, pages/workspace/[id]/export/ (index and tdei), pages/workspace/[id]/settings/teams/index.vue, pages/workspace/[id]/teams/[teamId].vue, pages/workspace/create/ (blank, file, index, tdei).

Accessibility & Keyboard Navigation

Enhanced focus management in navbar with modal-like keyboard trapping in mobile side menu. Added global keydown handler for Escape and Tab key support. Applied focus-visible outline overrides for buttons/links with new TDEI utility classes. Updated form styling with custom focus states for inputs and buttons.

Minor Updates

Reformatted AppSpinner.vue template markup with multi-line attribute structure (no logic changes). Updated layouts/default.vue to use taller/throttled nuxt-loading-indicator with gradient color via CSS variables. Added TypeScript type annotation to selectWorkspace(workspace: Workspace) in dashboard page.

Review Change Stack

shweta2101 added 18 commits May 19, 2026 18:09
Introduce TDEI branding: add tdei-logo.png, import Lato/Open Sans/Montserrat fonts, update theme primary color to #32006e, and add extensive utility CSS (color variables, button/link styles, layout helpers, accessibility focus styles) in main.scss. Replace many Bootstrap button/variant uses across components/pages with new tdei-* classes (tdei-primary-button, tdei-secondary-button, maroon-bg, tdei-primary-link) and adjust dialog button classes/confirm styles to match the new design system. These changes unify styling and apply the updated TDEI visual identity across the app.
Add new asset (osw-type.svg) and update global styles and pages to improve layout and mobile UX. Main changes:

- components/AppNavbar.vue: Rework navbar into a responsive, sticky header with a mobile side menu and updated user dropdown. Adds state and lifecycle hooks to manage mobile menu visibility, accessibility attributes, and dedicated mobile interactions (close button, backdrop, logout flow). Extensive SCSS added to style the navbar, side menu, and responsive behaviors.
- pages/index.vue: Make the primary CTA conditional on authentication (redirect to dashboard when signed in), import auth in the script, and update hero styling to use CSS variables and refined colors/hover states.
- assets/scss/main.scss: Update font imports (remove Lato, ensure Open Sans and Montserrat are imported).
- assets/img/osw-type.svg: Add new SVG asset.

These changes are intended to improve navigation on small screens, unify header styling, and make the landing CTA reflect user authentication state.
Revamp dashboard workspace list and toolbar styling: remove duplicate Montserrat font import; rename toolbar button classes to tdei-toolbar-primary-button and add scoped styles for toolbar buttons and grouped button radii. Overhaul WorkspaceItem into a card-style layout (new markup, styles, responsive adjustments), show workspace ID, format type/status labels, and simplify class logic. Update dashboard page to add a page header subtitle, adjust Project Group label styling, wrap workspace list in a template, and add getLastProjectGroupName + selectedProjectGroupName computed to derive the displayed project group name from sessionStorage or project groups.
Add flex and pathways SVG icons and update WorkspaceItem.vue to select the correct icon based on workspace.type. Imports osw, flex, and pathways assets, introduces a computed typeIconSrc that maps types to their icons (falls back to osw), and replaces the hardcoded img src with a bound :src. Enables showing the appropriate icon for different workspace types.
Refactor the homepage template and SCSS to introduce a new hero layout and visual update. Replaced .jumbo-content with .hero-shell and .hero-copy, moved CTAs into a .hero-actions container (primary Nuxt link + external "Learn more"), and kept the auth-based dashboard/signin routing. Reworked background to use layered gradients over the existing bg.webp, added a decorative overlay, improved typography, spacing, and app-logo styling, and refined responsive behavior across breakpoints (lg, md, sm). These changes modernize the landing hero, improve readability and responsiveness, and polish CTA styles and spacing.
SCSS: Remove unnecessary !important from primary button rules, add proper :focus styles (box-shadow) for accessibility, and introduce .tdei-outline-cyan-button (replacing .tdei-button2) with hover/focus/disabled states. Unify radio focus styling and update shadow color to match brand. Minor CSS cleanup and spacing adjustments. Components: remove d-block from the Apply button in FilterDropdown. Pages: simplify selectedProjectGroupName logic in dashboard.vue (drop getLastProjectGroupName fallback) and reduce hero-primary-action min-height in index.vue.
Add an accessible alt attribute for workspace type images and adjust SCSS variables and styles. In WorkspaceItem.vue the img alt is now dynamic (uses formatTypeLabel) to improve accessibility. In assets/scss/main.scss: remove duplicate --primary-color-dark, add --tdei-cyan, change .jsonContent border to use --secondary-color, remove custom radio focus styles, and adjust .column-style flex/margins. Also restore/move text-transform: capitalize for .workspaceStatus to the stronger selector to keep visual consistency.
Add focus management and keyboard support for the mobile side menu: add refs for the toggle button and side menu, focus the close button when opened and restore focus to the toggle when closed, trap Tab/Shift+Tab inside the menu, handle Escape to close, and add aria-modal="true". Attach/detach keydown listener on mount/unmount. Minor style updates: introduce --primary-color-dark and small SCSS cleanup. Remove an unused getLastProjectGroupName() helper from dashboard.vue. Add rel="noopener noreferrer" to an external link for security.
SCSS: Update .tdei-rounded-button to .btn.tdei-rounded-button, remove unnecessary !important rules, nest hover/active state and use --primary-color-dark for hover/border. Also fix stray brace and tighten selector scope.

AppNavbar.vue: Use focusable.at(0) and .at(-1) for first/last element and add a null check to avoid runtime errors when focusable is empty.

pages/dashboard.vue: Render the "in <project group>" phrase only when a project group name exists and change the computed fallback from a literal 'project group' to null to avoid showing a placeholder when none is selected.
Overhaul the sign-in experience and adjust several layout components. Add a new background image asset and replace the signin page to render the new SigninForm component with a centered card, background, and responsive styles. Revamp SigninForm: new header, show/hide password toggle, improved loading/error states, and extensive SCSS for desktop/mobile. Tidy up AppNavbar templates and mobile menu markup (focus handling/focus trap fixes and markup formatting). Minor tweaks: AppSpinner markup, default layout nuxt-loading-indicator props, and refactor dashboard into a split layout with scrollable workspace list and sticky details panel.
Bind aria-modal to return 'true' or 'false' based on mobileMenuOpen/isMobileView to fix accessibility attribute type. Strengthen SigninForm error handling by adding a fetch-error type guard, parsing 400 responses for validation errors, and providing specific messages for 401 and 404 cases; also normalize other errors to strings. Add missing 'btn' class to the Close button in JoinDialog for consistent styling.
Add role="dialog" to the side menu element in AppNavbar.vue to improve accessibility and complement existing ARIA attributes. Remove an explicit color rule from .team-members-btn in teams/Item.vue to stop overriding the global body color and keep link styling consistent.
Remove external @import URL lines from assets/scss/main.scss and add the @nuxtjs/google-fonts module and configuration in nuxt.config.ts (register Open Sans and Montserrat, set display: 'swap', download: true). Also add @nuxtjs/google-fonts to devDependencies in package.json. Centralizes font loading, enables local font download/optimization, and avoids inline external CSS imports.
Add a long CSS transition to neutralize Chrome's autofill background, preventing the yellow/blue autofill styling from showing. Replace the AppNavbar side menu <aside> with a <div> to match the component structure. Scope SigninForm styles (add scoped) and remove the preset input background so autofill styling is handled consistently. Add an explicit Workspace type import and annotate selectWorkspace(workspace) with the Workspace type.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 25, 2026

📝 Walkthrough

Walkthrough

This PR implements a comprehensive design system refresh, introducing new TDEI-branded utility classes throughout the application. Global SCSS styling is expanded with CSS variables and typography helpers. Navigation, sign-in, and landing pages are restructured with improved layouts. Components are systematically converted from Bootstrap variants to custom button classes. Dashboard and workspace management UIs are redesigned with split layouts and card-based presentations.

Changes

Design System & UI Styling Refresh

Layer / File(s) Summary
Design System Foundation & Global Styles
assets/scss/main.scss, assets/scss/theme.scss, package.json, nuxt.config.ts, layouts/default.vue
SCSS global styling expanded with utility classes, CSS variables for fonts and brand colors, dropdown styling. Primary theme color updated. Google Fonts module integrated for typography. Loading indicator enhanced with gradient and throttling.
Navigation & App Shell
components/AppLogo.vue, components/AppNavbar.vue
AppLogo now renders TDEI-branded image. AppNavbar completely redesigned from Bootstrap collapse to custom responsive layout with mobile off-canvas menu, backdrop, keyboard accessibility (Escape, Tab focus trapping), and state management for mobile/desktop views.
Authentication: Sign-in Form & Page
components/SigninForm.vue, pages/signin.vue
SigninForm restructured with new card layout, error display block, password visibility toggle, stricter error handling with fetch-error type guard. signin.vue page simplified to direct signin-shell wrapper with centered flex layout and background image.
Landing Page: Hero Layout
pages/index.vue
Homepage restructured with hero section (hero-shell, hero-divider, hero-actions). Primary CTA conditionally routes based on auth.ok state. Script imports tdeiClient to expose auth. Responsive adjustments for md and sm breakpoints.
Dashboard: Workspace Management & Toolbar
pages/dashboard.vue, components/dashboard/Toolbar.vue, components/dashboard/WorkspaceItem.vue
Dashboard refactored with workspace-split-layout (scrollable list + sticky details panels). Toolbar buttons updated to custom classes. WorkspaceItem redesigned from badges to structured card layout with type icons and inline IDs; script introduces typeIconSrc and formatTypeLabel helpers.
Forms, Modals & Button Styling Consistency
components/DatasetTypeRadio.vue, components/review/FilterDropdown.vue, components/review/Toolbar.vue, components/settings/panel/*, components/teams/*, pages/help.vue, pages/workspace/[id]/*, pages/workspace/create/*
25+ components updated: Bootstrap variants (btn-primary, btn-dark, btn-danger, btn-outline-primary) replaced with custom TDEI classes (tdei-primary-button, tdei-secondary-button, tdei-primary-link, maroon-bg). Modal footer buttons updated from variant props to explicit classes.
Minor Formatting
components/AppSpinner.vue
Template markup reformatted across multiple lines for readability; no behavioral changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 The design system hops with grace,
New classes paint each place,
Buttons shine in TDEI's way,
Fresh navbars lead the day,
From hero to form, all redesigned—
A cohesive brand, beautifully aligned!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Feature task 3634 tdei theme' is vague and uses task reference numbers and generic terms without clearly conveying the scope or nature of the changes. Replace with a more descriptive title such as 'Apply TDEI brand theming: redesigned UI with new colors, components, and accessibility improvements' to clearly communicate the main changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

components/AppLogo.vue

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

components/AppNavbar.vue

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

components/AppSpinner.vue

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

  • 29 others

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@shweta2101 shweta2101 requested a review from cyrossignol May 25, 2026 15:13
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@assets/scss/main.scss`:
- Around line 9-10: The two CSS `@import` directives for
"maplibre-gl/dist/maplibre-gl.css" and "vue3-toastify/dist/index.css" are placed
after the input:-webkit-autofill rule, causing the
no-invalid-position-at-import-rule lint error; fix this by moving both `@import`
lines to the very top of assets/scss/main.scss so they appear before any style
rules (specifically before the input:-webkit-autofill selector and its block),
preserving their exact strings and order.

In `@components/AppNavbar.vue`:
- Around line 318-324: The CSS currently removes the keyboard focus indicator
for the mobile nav toggler (box-shadow: none) and only defines hover styles for
drawer controls, which hides focus for keyboard users; restore a visible focus
indicator by replacing the "box-shadow: none" rule on the toggler with a focused
style (use :focus and :focus-visible) that applies a visible outline or
box-shadow (e.g. using a --focus-ring-color and matching border-radius) and add
equivalent :focus/:focus-visible rules for the drawer controls so they show the
same focus ring as hover (but distinct for keyboard focus), ensuring you target
the same selectors used for the toggler and drawer controls in AppNavbar.vue so
keyboard users can track focus.
- Around line 65-74: The dropdown toggle currently nests a native <button>
inside the b-dropdown `#button-content` which breaks toggle semantics; replace the
inner interactive element (class "userProfile" button) with a non-interactive
wrapper (e.g., div or span) and move any click/keyboard handling to the
dropdown/toggle itself so the dropdown controls activation; ensure the wrapper
keeps the same classes/visual markup (class "userProfile") and accessible
labeling (use aria attributes on the toggle if needed) to preserve appearance
and accessibility.

In `@components/dashboard/WorkspaceItem.vue`:
- Around line 15-20: The role chip currently only handles 'lead' and 'validator'
and leaves 'contributor' or undefined blank; update the template in
WorkspaceItem.vue to add a v-else fallback that renders a span with class
"workspaceStatus" showing ROLE_LABELS.member (treat undefined the same as
'contributor'). Ensure you reference the existing workspace.role checks and
ROLE_LABELS constant so the new fallback collapses contributor/undefined into
the Member label.

In `@components/SigninForm.vue`:
- Around line 23-27: In SigninForm.vue, add autocomplete attributes to the
credential inputs so browsers/password managers work correctly: set
autocomplete="username" on the input using v-model="username" (id="username")
and set autocomplete="current-password" on the input using v-model="password"
(the password field around lines 43-47); ensure attributes are added to the same
element nodes that currently have class "form-control signin-input" and aria
attributes.
- Around line 107-113: The 400 error branch currently calls await
e.response.json() which can throw if the response body isn't valid JSON; wrap
the JSON parse in a safe guard (e.g., inspect
e.response.headers.get('content-type') for application/json and/or use a
try/catch around await e.response.json()) and fall back to a generic message
when parsing fails so error.value still gets set; update the logic around the
existing body variable and the error.value assignment in the SigninForm.vue
catch block to use the parsed body only when parse succeeds and otherwise set a
sensible fallback error.

In `@pages/signin.vue`:
- Around line 12-14: The redirect currently calls navigateTo('/dashboard')
without awaiting its promise; update the branch that checks tdeiAuth.complete to
await (or return) the navigateTo call so Nuxt handles the navigation
immediately—e.g., inside the script setup where tdeiAuth.complete is checked,
replace navigateTo('/dashboard') with await navigateTo('/dashboard') (or return
await navigateTo('/dashboard')) so the promise is not ignored.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 784db07f-7b18-4614-9663-5037757aebfd

📥 Commits

Reviewing files that changed from the base of the PR and between d41aec5 and 20e7ba3.

⛔ Files ignored due to path filters (5)
  • assets/img/bg_login.png is excluded by !**/*.png
  • assets/img/flex-type.svg is excluded by !**/*.svg
  • assets/img/osw-type.svg is excluded by !**/*.svg
  • assets/img/pathways-type.svg is excluded by !**/*.svg
  • assets/img/tdei-logo.png is excluded by !**/*.png
📒 Files selected for processing (35)
  • assets/scss/main.scss
  • assets/scss/theme.scss
  • components/AppLogo.vue
  • components/AppNavbar.vue
  • components/AppSpinner.vue
  • components/DatasetTypeRadio.vue
  • components/SigninForm.vue
  • components/dashboard/Toolbar.vue
  • components/dashboard/WorkspaceItem.vue
  • components/review/FilterDropdown.vue
  • components/review/Toolbar.vue
  • components/settings/panel/Apps.vue
  • components/settings/panel/Delete.vue
  • components/settings/panel/General.vue
  • components/settings/panel/Imagery.vue
  • components/settings/teams/JoinDialog.vue
  • components/teams/Item.vue
  • components/teams/JoinDialog.vue
  • components/teams/MembersDialog.vue
  • components/teams/SettingsDialog.vue
  • layouts/default.vue
  • nuxt.config.ts
  • package.json
  • pages/dashboard.vue
  • pages/help.vue
  • pages/index.vue
  • pages/signin.vue
  • pages/workspace/[id]/export/index.vue
  • pages/workspace/[id]/export/tdei.vue
  • pages/workspace/[id]/settings/teams/index.vue
  • pages/workspace/[id]/teams/[teamId].vue
  • pages/workspace/create/blank.vue
  • pages/workspace/create/file.vue
  • pages/workspace/create/index.vue
  • pages/workspace/create/tdei.vue

Comment thread assets/scss/main.scss
Comment on lines 9 to 10
@import "maplibre-gl/dist/maplibre-gl.css";
@import "vue3-toastify/dist/index.css";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether any `@import` appears after a non-import rule in main.scss
set -euo pipefail

FILE="$(fd '^main\.scss$' -a | head -n1)"
echo "Checking: $FILE"

awk '
  BEGIN { seen_non_import=0; bad=0 }
  {
    line=$0
    trimmed=line
    sub(/^[[:space:]]+/, "", trimmed)
    if (trimmed == "" || trimmed ~ /^\/\// || trimmed ~ /^\/\*/) next
    if (trimmed ~ /^`@import`[[:space:]]+/) {
      if (seen_non_import) {
        printf("Invalid import position at line %d: %s\n", NR, line)
        bad=1
      }
      next
    }
    # treat other top-level statements as non-import
    seen_non_import=1
  }
  END {
    if (bad) exit 1
    print "OK: no invalid `@import` positions detected."
  }
' "$FILE"

Repository: TaskarCenterAtUW/workspaces-frontend

Length of output: 286


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="assets/scss/main.scss"
echo "== $FILE =="
nl -ba "$FILE" | sed -n '1,25p'

Repository: TaskarCenterAtUW/workspaces-frontend

Length of output: 169


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="assets/scss/main.scss"
echo "== $FILE =="
cat -n "$FILE" | sed -n '1,25p'

Repository: TaskarCenterAtUW/workspaces-frontend

Length of output: 1043


Move CSS @import directives to the top of assets/scss/main.scss (before style rules)

@import statements at lines 9-10 come after the input:-webkit-autofill rule block (lines 4-8), which triggers no-invalid-position-at-import-rule and can fail linting.

💡 Proposed fix
 `@import` "theme.scss";
 `@import` "bootstrap/scss/bootstrap.scss";
+@import "maplibre-gl/dist/maplibre-gl.css";
+@import "vue3-toastify/dist/index.css";
 
 input:-webkit-autofill,
 input:-webkit-autofill:hover,
 input:-webkit-autofill:focus {
   transition: background-color 600000s, color 600000s;
 }
-@import "maplibre-gl/dist/maplibre-gl.css";
-@import "vue3-toastify/dist/index.css";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@import "maplibre-gl/dist/maplibre-gl.css";
@import "vue3-toastify/dist/index.css";
`@import` "theme.scss";
`@import` "bootstrap/scss/bootstrap.scss";
`@import` "maplibre-gl/dist/maplibre-gl.css";
`@import` "vue3-toastify/dist/index.css";
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
transition: background-color 600000s, color 600000s;
}
🧰 Tools
🪛 Stylelint (17.11.1)

[error] 9-9: Invalid position for @import rule (no-invalid-position-at-import-rule)

(no-invalid-position-at-import-rule)


[error] 10-10: Invalid position for @import rule (no-invalid-position-at-import-rule)

(no-invalid-position-at-import-rule)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/scss/main.scss` around lines 9 - 10, The two CSS `@import` directives
for "maplibre-gl/dist/maplibre-gl.css" and "vue3-toastify/dist/index.css" are
placed after the input:-webkit-autofill rule, causing the
no-invalid-position-at-import-rule lint error; fix this by moving both `@import`
lines to the very top of assets/scss/main.scss so they appear before any style
rules (specifically before the input:-webkit-autofill selector and its block),
preserving their exact strings and order.

Comment thread components/AppNavbar.vue
Comment on lines +65 to +74
<template #button-content>
<button class="userProfile">
<div>{{ auth.displayName }}</div>
<app-icon
variant="account_circle"
size="32"
no-margin
/>
</button>
</template>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In bootstrap-vue-next b-dropdown, is it valid to place a native <button> inside the #button-content slot, or should slot content be non-interactive because the component already renders the toggle button?

💡 Result:

Yes, it’s valid to put a native inside b-dropdown’s #button-content slot, because the BootstrapVueNext docs explicitly state that the button-content slot allows “basic HTML and icons in the button content” (i.e., it isn’t limited to non-interactive markup) [1]. However, for correct behavior and accessibility, you generally shouldn’t place another interactive control that the user can click to trigger its own separate action inside the dropdown-toggle button, because the entire header is already the control that toggles the dropdown. In practice: keep the slot content simple (text/icons) or ensure any nested interactive element does not interfere with the dropdown toggle’s click/keyboard handling. Evidence from the component docs: the #button-content slot is provided specifically to customize the dropdown toggle’s content with HTML/icons, and is not documented as “non-interactive only” [1].

Citations:


Avoid nested interactive semantics in b-dropdown #button-content (accessibility/behavior risk).
b-dropdown’s #button-content slot supports arbitrary HTML/icons (so nesting isn’t inherently “invalid markup”), but placing a native nested button inside the dropdown toggle content can interfere with the toggle’s click/focus/keyboard semantics and confuse screen readers. Prefer a non-interactive wrapper.

Suggested fix
 <template `#button-content`>
-  <button class="userProfile">
+  <span class="userProfile">
     <div>{{ auth.displayName }}</div>
     <app-icon
       variant="account_circle"
       size="32"
       no-margin
     />
-  </button>
+  </span>
 </template>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<template #button-content>
<button class="userProfile">
<div>{{ auth.displayName }}</div>
<app-icon
variant="account_circle"
size="32"
no-margin
/>
</button>
</template>
<template `#button-content`>
<span class="userProfile">
<div>{{ auth.displayName }}</div>
<app-icon
variant="account_circle"
size="32"
no-margin
/>
</span>
</template>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/AppNavbar.vue` around lines 65 - 74, The dropdown toggle currently
nests a native <button> inside the b-dropdown `#button-content` which breaks
toggle semantics; replace the inner interactive element (class "userProfile"
button) with a non-interactive wrapper (e.g., div or span) and move any
click/keyboard handling to the dropdown/toggle itself so the dropdown controls
activation; ensure the wrapper keeps the same classes/visual markup (class
"userProfile") and accessible labeling (use aria attributes on the toggle if
needed) to preserve appearance and accessibility.

Comment thread components/AppNavbar.vue
Comment on lines +318 to +324
&:focus {
box-shadow: none;
}

&:hover {
background-color: var(--primary-color-dark);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore visible keyboard focus styles for mobile nav controls.

Lines 318-320 remove the toggler focus indicator (box-shadow: none) without a replacement, and drawer controls only define hover styles. Keyboard users can lose track of focus in the menu flow.

Suggested fix
  .mobileMenuIcon {
    padding: 5px 8px;
    border: none;

-   &:focus {
-     box-shadow: none;
-   }
+   &:focus-visible {
+     outline: 2px solid `#ffffff`;
+     outline-offset: 2px;
+     box-shadow: none;
+   }

    &:hover {
      background-color: var(--primary-color-dark);
    }
  }

+ .sideMenuClose:focus-visible,
+ .sideMenuLink:focus-visible,
+ .sideMenuButton:focus-visible {
+   outline: 2px solid var(--primary-color);
+   outline-offset: -2px;
+ }

Also applies to: 447-452, 460-481

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/AppNavbar.vue` around lines 318 - 324, The CSS currently removes
the keyboard focus indicator for the mobile nav toggler (box-shadow: none) and
only defines hover styles for drawer controls, which hides focus for keyboard
users; restore a visible focus indicator by replacing the "box-shadow: none"
rule on the toggler with a focused style (use :focus and :focus-visible) that
applies a visible outline or box-shadow (e.g. using a --focus-ring-color and
matching border-radius) and add equivalent :focus/:focus-visible rules for the
drawer controls so they show the same focus ring as hover (but distinct for
keyboard focus), ensuring you target the same selectors used for the toggler and
drawer controls in AppNavbar.vue so keyboard users can track focus.

Comment on lines +15 to +20
<span v-if="workspace.role === 'lead'" class="workspaceStatus">
{{ ROLE_LABELS.lead }}
</span>
<span v-else-if="workspace.role === 'validator'" class="workspaceStatus">
{{ ROLE_LABELS.validator }}
</span>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a Member fallback for non-lead/non-validator roles.

At Line 15-20, workspace.role === 'contributor' (or undefined) currently renders no role chip. Add a v-else fallback so those users are consistently shown as Member.

Suggested fix
             <span v-else-if="workspace.role === 'validator'" class="workspaceStatus">
               {{ ROLE_LABELS.validator }}
             </span>
+            <span v-else class="workspaceStatus">
+              Member
+            </span>

Based on learnings: treat missing workspace.role (undefined) the same as workspace.role === 'contributor', collapsing both into a single 'Member' fallback in dashboard-related role UI.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<span v-if="workspace.role === 'lead'" class="workspaceStatus">
{{ ROLE_LABELS.lead }}
</span>
<span v-else-if="workspace.role === 'validator'" class="workspaceStatus">
{{ ROLE_LABELS.validator }}
</span>
<span v-if="workspace.role === 'lead'" class="workspaceStatus">
{{ ROLE_LABELS.lead }}
</span>
<span v-else-if="workspace.role === 'validator'" class="workspaceStatus">
{{ ROLE_LABELS.validator }}
</span>
<span v-else class="workspaceStatus">
Member
</span>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/dashboard/WorkspaceItem.vue` around lines 15 - 20, The role chip
currently only handles 'lead' and 'validator' and leaves 'contributor' or
undefined blank; update the template in WorkspaceItem.vue to add a v-else
fallback that renders a span with class "workspaceStatus" showing
ROLE_LABELS.member (treat undefined the same as 'contributor'). Ensure you
reference the existing workspace.role checks and ROLE_LABELS constant so the new
fallback collapses contributor/undefined into the Member label.

Comment thread components/SigninForm.vue
Comment on lines +23 to +27
id="username"
v-model="username"
class="form-control signin-input"
aria-describedby="usernameHelp"
>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add autocomplete hints for credential fields.

Use autocomplete="username" and autocomplete="current-password" so browsers/password managers behave correctly.

Suggested fix
         <input
           id="username"
           v-model="username"
           class="form-control signin-input"
           aria-describedby="usernameHelp"
+          autocomplete="username"
         >
...
          <input
            id="password"
            v-model="password"
            :type="showPassword ? 'text' : 'password'"
            class="form-control signin-input password-input"
+           autocomplete="current-password"
          >

Also applies to: 43-47

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/SigninForm.vue` around lines 23 - 27, In SigninForm.vue, add
autocomplete attributes to the credential inputs so browsers/password managers
work correctly: set autocomplete="username" on the input using
v-model="username" (id="username") and set autocomplete="current-password" on
the input using v-model="password" (the password field around lines 43-47);
ensure attributes are added to the same element nodes that currently have class
"form-control signin-input" and aria attributes.

Comment thread components/SigninForm.vue
Comment on lines +107 to +113
if (e.response.status === 400) {
const body = await e.response.json() as { errors?: string[] }

if (body.errors && body.errors.length > 0) {
error.value = 'Error: ' + body.errors[0]
return
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard JSON parsing in the 400 error branch.

If a 400 response is not JSON, await e.response.json() throws inside the catch block and bypasses your user-facing fallback error handling.

Suggested fix
      if (e.response.status === 400) {
-       const body = await e.response.json() as { errors?: string[] }
-
-       if (body.errors && body.errors.length > 0) {
-         error.value = 'Error: ' + body.errors[0]
-         return
-       }
+       try {
+         const body = await e.response.json() as { errors?: string[] }
+         if (body.errors && body.errors.length > 0) {
+           error.value = 'Error: ' + body.errors[0]
+           return
+         }
+       }
+       catch {
+         // fall through to generic message below
+       }
      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (e.response.status === 400) {
const body = await e.response.json() as { errors?: string[] }
if (body.errors && body.errors.length > 0) {
error.value = 'Error: ' + body.errors[0]
return
}
if (e.response.status === 400) {
try {
const body = await e.response.json() as { errors?: string[] }
if (body.errors && body.errors.length > 0) {
error.value = 'Error: ' + body.errors[0]
return
}
}
catch {
// fall through to generic message below
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/SigninForm.vue` around lines 107 - 113, The 400 error branch
currently calls await e.response.json() which can throw if the response body
isn't valid JSON; wrap the JSON parse in a safe guard (e.g., inspect
e.response.headers.get('content-type') for application/json and/or use a
try/catch around await e.response.json()) and fall back to a generic message
when parsing fails so error.value still gets set; update the logic around the
existing body variable and the error.value assignment in the SigninForm.vue
catch block to use the parsed body only when parse succeeds and otherwise set a
sensible fallback error.

Comment thread pages/signin.vue
Comment on lines 12 to 14
if (tdeiAuth.complete) {
navigateTo('/dashboard');
navigateTo('/dashboard')
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In Nuxt 4 page <script setup>, what is the recommended pattern for immediate auth redirects: plain navigateTo(...) vs return/await navigateTo(...)?

💡 Result:

Recommended pattern in a Nuxt 4 page <script setup> for immediate auth redirects is to use await (or return) with navigateTo, i.e. await navigateTo('/login') and then prevent further work as needed. What to do 1) In <script setup>, do: - await navigateTo('/login') (or await navigateTo({ path: '/login' })). Nuxt’s navigateTo docs explicitly show await navigateTo(...) usage in <script setup> examples. [1] 2) Avoid “fire-and-forget” usage like navigateTo('/login') without awaiting/returning. Nuxt’s navigateTo docs explicitly state: “Make sure to always use await or return on result of navigateTo when calling it.” [2][1] Plain navigateTo(...) vs return/await navigateTo(...) - navigateTo(...) without awaiting/returning: not the recommended approach; Nuxt advises awaiting/returning the result to ensure the navigation outcome is properly handled. [2][1] - return navigateTo(...): generally discouraged/fragile in <script setup> if you’re trying to “terminate” execution. Nuxt issue discussions note that there’s no reliable way to terminate execution in the <script setup> block and that return navigateTo() was previously possible but has been deprecated; the recommended approach becomes handling redirects with await (or other control-flow patterns). [3] - await navigateTo(...): the documented and recommended way in <script setup> to perform the redirect. [1] Practical guidance for auth redirect in a page - Use middleware for route guarding when possible (so pages don’t render at all). Nuxt’s routing docs show returning navigateTo from route middleware for auth gating. [4] - If you must do it in the page itself, use await navigateTo(...) early in the script. In short: prefer await navigateTo(...) in a page <script setup>; don’t call navigateTo(...) without awaiting/returning; and avoid relying on return navigateTo(...) to stop the rest of <script setup> execution. [2][1][3]

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
ls -la
# Show the relevant portion of pages/signin.vue
if [ -f "pages/signin.vue" ]; then
  echo "---- pages/signin.vue (context) ----"
  nl -ba pages/signin.vue | sed -n '1,80p'
else
  echo "pages/signin.vue not found"
  fd signin.vue -a . || true
fi

Repository: TaskarCenterAtUW/workspaces-frontend

Length of output: 2282


🌐 Web query:

Nuxt 4 navigateTo in <script setup> "Make sure to always use await or return"

💡 Result:

In Nuxt 4, navigateTo returns a value/promise (depending on context), and the docs explicitly instruct: “Make sure to always use await or return on result of navigateTo when calling it.” [1] What this means in <script setup> 1) If you call navigateTo directly from your setup code, you should await it: await navigateTo('/search') [1] or await navigateTo({ path: '/search' }) [1] 2) If you are in an async function, you can also return the navigateTo call instead of awaiting it, as long as you “return its result” to keep the calling flow consistent (the docs’ wording covers both await and return) [1]. Route middleware special case If you call navigateTo inside defineNuxtRouteMiddleware, you must return it so the middleware execution flow works correctly. The docs show the correct form: return navigateTo('/search', { redirectCode: 301 }) [1] and the incorrect form (navigateTo executed but not returned): navigateTo('/search', { redirectCode: 301 }) return [1] Why you should do this The official docs warn that not awaiting/returning can lead to “unexpected behavior” in middleware, and they also provide concrete examples of calling navigateTo with await in <script setup> [1]. Note on “return navigateTo” vs “terminate setup execution” Nuxt maintainers have discussed that terminating execution inside <script setup> is not straightforward; using return navigateTo there can be deprecated/insufficient for aborting setup flow. A tracked Nuxt issue discusses the limitation and suggests patterns/workarounds, but the core, source-backed guidance for navigateTo usage is still to await or return its result when you call it [2].

Citations:


🌐 Web query:

Nuxt 4 navigateTo return vs await guidance in pages

💡 Result:

In Nuxt 4, for programmatic navigation with navigateTo, you should either: 1) return navigateTo(...) from functions that use it (notably route middleware), or 2) await navigateTo(...) in async contexts where you just need to wait for the navigation to complete. Key guidance differences A) In route middleware: you must return Nuxt’s docs explicitly say that when using navigateTo within route middleware, you must return its result to ensure the middleware execution flow works correctly, and they show the non-working pattern where navigateTo(...) is called but not returned. [1] Example (middleware redirect): ts export default defineNuxtRouteMiddleware((to, from) => { if (to.path !== '/search') { return navigateTo('/search', { redirectCode: 301 }) } }) [1] B) In pages/components: prefer await for “do this after navigation” Nuxt’s navigateTo docs also show using await navigateTo('/search') (or awaiting a route object) in pages/components style usage. [1] Example (page/component): ts <script setup lang="ts"> await navigateTo({ path: '/search', query: { page: 1 } }) </script> [1] What “return vs await” really changes - return navigateTo(...) is mainly about control flow: it passes the navigation result back to the caller. This is required in middleware because the router/middleware runner needs the return value. [1] - await navigateTo(...) is about sequencing: it pauses your async code until navigation finishes/settles. The docs instruct to “always use await or return on result of navigateTo when calling it.” [1] C) Why “await but not return” can be problematic in middleware A Nuxt issue discusses middleware behavior and highlights that you need correct handling of navigateTo result in middleware contexts. [2] So: concise recommendation - Route middleware: use return navigateTo(...) (or return await navigateTo(...) if you want, but return is the important part). [1] - Pages/components (async handler): use await navigateTo(...) if you need to wait; otherwise, just ensure you use either await or return as recommended by the docs (don’t call it and ignore the result). [1]

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Show the relevant portion of pages/signin.vue
if [ -f "pages/signin.vue" ]; then
  echo "---- pages/signin.vue (context) ----"
  nl -ba pages/signin.vue | sed -n '1,120p'
else
  echo "pages/signin.vue not found"
  fd -a -i "signin.vue" . || true
fi

Repository: TaskarCenterAtUW/workspaces-frontend

Length of output: 178


🌐 Web query:

Nuxt 4 navigateTo in <script setup> "Make sure to always use await or return"

💡 Result:

In Nuxt 4, when you call navigateTo in <script setup>, you should “always use await or return” because navigateTo returns a value/promise that you need to handle to make the control-flow and navigation behavior correct. The official docs explicitly say: “Make sure to always use await or return on result of navigateTo when calling it.” [1] What to do in <script setup> 1) Use await inside an async function or top-level await in <script setup>: await navigateTo('/search') [1] 2) If your function returns the navigation result, return it: return navigateTo('/search') (Using await or return ensures you don’t ignore the navigation result.) [1] Why the rule matters (route middleware example) Nuxt’s docs also show that inside route middleware you must return navigateTo’s result; otherwise the redirect won’t integrate correctly with the middleware flow: return navigateTo('/search', { redirectCode: 301 }) // ✅ [1] navigateTo('/search', { redirectCode: 301 }); return // ❌ not returned [1] So the underlying principle is: don’t fire navigateTo and drop its return value; use await or return so Nuxt/your code can correctly observe/propagate the navigation result. [1] Notes on return type The docs describe navigateTo’s signature returning a Promise (among other union members), which is consistent with why awaiting/returning is recommended. [1]

Citations:


🌐 Web query:

Nuxt 4 navigateTo return vs await guidance in pages redirect

💡 Result:

In Nuxt 4, use either await or return from navigateTo, but the best guidance depends on where you call it. 1) In route middleware (defineNuxtRouteMiddleware): you must return navigateTo - Nuxt’s docs explicitly say that when using navigateTo within route middleware, you must return its result so the middleware execution flow works correctly [1]. - The middleware docs also list return values such as “return navigateTo('/')” for redirects, and “return abortNavigation” for cancellation [2]. Example (correct): export default defineNuxtRouteMiddleware((to, from) => { if (to.path!== '/') { return navigateTo('/', { redirectCode: 301 }) } }) 2) In pages/components (e.g., a composable, watch, onMounted, etc.): prefer await (or explicitly return) so you stop further logic - Nuxt’s navigateTo API docs state: “Make sure to always use await or return on result of navigateTo when calling it.” [1] - Practically, in a page you often write “await navigateTo(...)” to ensure execution order (and avoid running code meant for the current page). Nuxt also shows auth/recipe examples that do “await navigateTo('/')” after side effects like refreshing session [3]. Example (typical in pages): await navigateTo('/login') Important nuance - If you call navigateTo and do NOT return/await it (e.g., in middleware), Nuxt warns it can lead to unexpected behavior (because the redirect isn’t properly wired into the middleware flow) [1][2]. - If you redirect on the client side during initial load (client-side middleware), you may see hydration issues; Nuxt community guidance suggests redirecting on the server or after hydration for those cases [4]. So, what should you do for “Nuxt 4 navigateTo return vs await guidance in pages redirect”? - In middleware: return navigateTo(...), not just call it. - In pages (scripts/watches/effects): await navigateTo(...) (or return it from the surrounding async function) and then exit/guard further logic.

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "---- pages/signin.vue (lines 1-80) ----"
if [ -f "pages/signin.vue" ]; then
  awk 'NR>=1 && NR<=80 {printf "%5d\t%s\n", NR, $0}' pages/signin.vue | sed -n '1,80p'
else
  echo "pages/signin.vue not found"
fi

echo "---- pages/signin.vue (lines 8-20) ----"
if [ -f "pages/signin.vue" ]; then
  awk 'NR>=8 && NR<=20 {printf "%5d\t%s\n", NR, $0}' pages/signin.vue
fi

Repository: TaskarCenterAtUW/workspaces-frontend

Length of output: 1591


Await navigateTo for immediate redirect in <script setup>

In pages/signin.vue (lines 12-14), calling navigateTo('/dashboard') without await/return ignores navigateTo’s returned promise; Nuxt recommends always awaiting/returning navigateTo results.

if (tdeiAuth.complete) {
  await navigateTo('/dashboard')
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pages/signin.vue` around lines 12 - 14, The redirect currently calls
navigateTo('/dashboard') without awaiting its promise; update the branch that
checks tdeiAuth.complete to await (or return) the navigateTo call so Nuxt
handles the navigation immediately—e.g., inside the script setup where
tdeiAuth.complete is checked, replace navigateTo('/dashboard') with await
navigateTo('/dashboard') (or return await navigateTo('/dashboard')) so the
promise is not ignored.

Copy link
Copy Markdown
Collaborator

@cyrossignol cyrossignol left a comment

Choose a reason for hiding this comment

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

@shweta2101 Initial observation: if we change the logo here, we'll need to update it in the AVIV ScoutRoute apps as well. Those both display the old Workspaces logo.

Looks nice!

cc @sureshgaussian

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.

2 participants