Feature-3984: Edit Project Implementation#90
Conversation
Introduce a full-featured Project Edit page (pages/workspace/[id]/projects/[projectId]/edit.vue) that lets project leads edit description/instructions, manage team members (search, add, update roles, remove), change configuration (lock timeout, review requirement) and run project actions (reset, close, delete) with confirmation flows. Add a reusable AppConfirmationDialog component for consistent confirmation UI and keyboard handling. Update RichTextEditor to track last emitted value and avoid re-applying identical editor updates (prevents echo/loop when syncing modelValue). Also include supporting changes to project-related services/types and the projects index view to integrate the new edit functionality and API calls.
Add support for a single custom imagery JSON object throughout the project wizard and project edit/create flows. Introduces parseProjectWizardCustomImagery and validateProjectCustomImagery (new services/project-custom-imagery.ts) with schema-based validation and debounced client-side checks; UI now shows validation state and error messages. Wire custom imagery into payloads and project updates (services/project-wizard-payload.ts, services/projects.ts) and update types accordingly. Add resolveHttpErrorMessage helper to normalize API error messages and replace many ad-hoc error handling sites to surface clearer messages. Minor UX/styling fixes: overflow-wrap for toast/text areas, JSON textarea styling, and change project name validation to use the validate-name endpoint.
Introduce a shared usePagination composable and refactor ContributorsTab and TasksTab to use it (DRY pagination logic, visible pagination items, clamping). Add workspace user error handling and retry support in project wizard components (AssignUsersField, SettingsStep, create page, and useProjectWizardSettings). Harden useProjectWizard persistence: validate stored state, debounce writes with a timer, handle storage errors, and preserve createdProject correctly. Update AppConfirmationDialog class names and prevent closing on Escape when busy. Add unsaved-edits confirmation to task editor and change back navigation to a button to intercept navigation. Improve pages: prevent cancelling while member mutation is in progress and surface load errors from contributors. Service updates: require VITE_NEW_API_URL at startup, sanitize project instructions before payload submission, and refine WorkspaceProjectsClient error handling (return null on 404, rethrow other errors). Misc: small UI/logic tweaks (AOI/details step gating on create, workspace route load error handling).
Pass project.customImagery through to RapidManager by adding a customImagerySource parameter to switchWorkspace, init, and #addCustomImagerySource. Update addCustomImagerySource to accept the passed data and create the imagery source; keep context assignment commented (left as a note). Add async/await and try/catch around manager.init in mountEditor to log initialization failures instead of failing silently.
Resolved the custom imagery handling
Enhance rich text rendering (overflow-x, blockquote and table styles) in RichTextContent.vue. Improve HTTP error extraction in services/http.ts to read body.message/body.error and fallback to plain text bodies. Use resolveHttpErrorMessage in useProjectWizardSettings to show detailed workspace user load errors. Refactor RapidManager to accept an optional customImagerySource, guard against null, add converted imagery sources to the imagery system, adjust init/switchWorkspace flow (auth patching, event binding, and async reset), and remove the example imagery block from util/rapid-imagery.ts.
Add strong typing and validation for custom imagery conversion and usage. - services/rapid.ts: import ImagerySource type, cast incoming source for conversion, and bail out early if conversion returns null before creating/registering a Rapid.ImagerySource. - util/rapid-imagery.ts: introduce RapidImagerySource interface, add isExtentWithZoom type guard, change convertToRapidImagerySource signature to accept ImagerySource|null and return RapidImagerySource|null, and compute safe min/max zoom defaults instead of reading raw values. These changes improve type-safety and prevent creating invalid imagery sources when required fields are missing.
Introduce useProjectEditActions and useProjectEditMembers composables and refactor the project edit page to use them (removing duplicated member/action logic). Improve AppConfirmationDialog accessibility by adding tabindex, generating unique title IDs, restoring focus on close, and implementing a focus trap/Tab handling. Enhance HTTP error parsing to extract detailed JSON messages and existing lock info. Update imagery-related types and Rapid service to use the ImagerySource type and adjust related type aliases. Remove obsolete notes.md.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds a project editing page with contributor and lifecycle actions, custom imagery validation and Rapid integration, wizard persistence and error recovery, shared pagination and HTTP error handling, richer text rendering, and confirmation dialogs. ChangesProject editing and custom imagery
Project creation wizard
Shared UI and service infrastructure
Estimated code review effort: 5 (Critical) | ~120 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
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
ESLint install timed out. The project may have too many dependencies for the sandbox. 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. Comment |
There was a problem hiding this comment.
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 `@composables/useProjectEditActions.ts`:
- Around line 95-133: Separate persisted mutation success from subsequent
refresh and navigation failures across the affected sites: in
composables/useProjectEditActions.ts lines 95-133, clear the dialog immediately
after close/reset/delete succeeds and handle navigation errors independently; in
services/projects.ts lines 288-297, remove the unused post-close GET or expose
its refresh failure separately; in composables/useProjectEditMembers.ts lines
150-168, 170-198, and 200-232, preserve added, updated, and removed contributor
state after the mutation succeeds even if refresh fails, so refresh errors are
reported separately and do not trigger duplicate requests or role rollback.
In `@composables/useProjectWizard.ts`:
- Around line 26-31: Update isValidStoredState to validate the complete
ProjectWizardStoredState contract before hydration: validate each nested draft
field using the expected field shapes rather than only checking that area,
details, review, and settings are objects, and validate createdProject as either
null or the expected checkpoint shape. Reject missing, invalid, or truthy
malformed checkpoint values while preserving valid persisted states.
In `@pages/workspace/`[id]/projects/[projectId]/edit.vue:
- Around line 5-10: Protect all navigation from unsaved changes, not only custom
controls: in pages/workspace/[id]/projects/[projectId]/edit.vue lines 5-10,
route breadcrumb links through the existing guarded leave flow; in lines
587-610, add route-leave and beforeunload guards driven by isDirty. In
pages/workspace/[id]/projects/[projectId]/tasks/[taskId]/editor.vue lines 43-46,
retain the custom Back handler while ensuring it is not the sole protection; in
lines 378-423, add equivalent route-leave and beforeunload guards driven by
hasActiveEdits.
In `@pages/workspace/`[id]/projects/[projectId]/tasks/[taskId]/editor.vue:
- Line 308: Update mountEditor() and the switchWorkspace() call to handle
promise rejections instead of discarding them: await or catch the
switchWorkspace promise, catch initialization failures from mountEditor(), and
expose a clear actionable page error for either failure so the editor does not
remain blank without user feedback.
In `@pages/workspace/`[id]/projects/create.vue:
- Around line 459-495: Update the imagery validation flow in the watcher and
validateCustomImagery/primary-action path to invalidate pending runs whenever
the input changes, capture and validate the exact input value for each run, and
check the request ID before applying results or navigating. Wrap validation in
exception-safe handling so rejected requests do not escape, and reset
imageryValidating in a finally block for every active validation, including
manual validation.
In `@services/http.ts`:
- Around line 74-77: Remove all newly introduced trailing commas at the
specified sites: the fallbackMessage parameter in services/http.ts#L74-L77; the
maxVisibleButtons parameter, computed call, object property, and array item in
composables/usePagination.ts#L12-L16, `#L19-L21`, `#L29-L37`, and `#L52-L54`; and the
trailing arguments in ContributorsTab.vue#L312-L315, TasksTab.vue#L292-L295, and
RichTextContent.vue#L25-L27. Preserve the repository’s semicolon style in normal
source files.
In `@util/rapid-imagery.ts`:
- Around line 72-82: Update the minZoom calculation in the custom imagery
conversion to use the schema’s default lower bound, or 0, when extent.min_zoom
is missing instead of 12; leave maxZoom and the surrounding zoomExtent
construction unchanged.
🪄 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: 07c40186-2453-4137-8c10-296bfc466400
📒 Files selected for processing (30)
assets/scss/main.scsscomponents/AppConfirmationDialog.vuecomponents/project-wizard/AssignUsersField.vuecomponents/project-wizard/RichTextEditor.vuecomponents/project-wizard/StatusDialog.vuecomponents/project-wizard/steps/ProjectDetailsStep.vuecomponents/project-wizard/steps/SettingsStep.vuecomponents/workspace-project-details/ContributorsTab.vuecomponents/workspace-project-details/RichTextContent.vuecomponents/workspace-project-details/TasksTab.vuecomposables/usePagination.tscomposables/useProjectEditActions.tscomposables/useProjectEditMembers.tscomposables/useProjectWizard.tscomposables/useProjectWizardSettings.tsdata/project-wizard-step-config.jsonpages/workspace/[id]/projects/[projectId]/edit.vuepages/workspace/[id]/projects/[projectId]/index.vuepages/workspace/[id]/projects/[projectId]/tasks/[taskId]/editor.vuepages/workspace/[id]/projects/create.vueservices/http.tsservices/index.tsservices/project-custom-imagery.tsservices/project-wizard-payload.tsservices/project-wizard.tsservices/projects.tsservices/rapid.tstypes/project-wizard.tstypes/projects.tsutil/rapid-imagery.ts
Reformat Vue templates and TypeScript files for consistent styling (line breaks, attribute wrapping, spacing). Add comments indicating sanitized HTML for ReviewStep and RichTextContent. Import sanitizeReviewHtml in project-wizard-payload (remove duplicate import). Remove unused type imports from ContributorsTab and TasksTab, adjust emits typing quote, and make minor whitespace/formatting fixes in usePagination, useProjectWizardSettings, rapid, and rapid-imagery utilities. Primarily non-functional cleanups and documentation annotations.
Multiple fixes and UX improvements across project wizard, project edit, task editor, membership management, and imagery validation: - Add util/project-wizard-storage.ts and switch useProjectWizard to validate stored wizard state via isValidProjectWizardStoredState. - AoiGeometryMap: initialize AOI source with createAoiFeatureCollection and call syncSources/syncInteractionState/applyViewport on mount. - RichTextEditor: prevent mousedown on toolbar buttons and avoid update loops by checking focus/getHTML before applying external updates. - usePagination and small component files: minor formatting/whitespace fixes. - useProjectEditActions: reorder toast/navigation to occur after successful server operations, handle navigation failures, and ensure dialog state is cleared correctly. - useProjectEditMembers: add optimistic updates and robust error handling (refreshAfterPersistedMutation, persistMemberRole), update add/update/remove member flows to keep UI responsive and retry/notify on refresh failures. - pages/workspace/.../edit.vue and tasks editor: add beforeunload and onBeforeRouteLeave handling for unsaved changes, introduce allowNextRouteLeave/navigateAfterSave, show discard confirmation, and adjust layout scrolling/flex behavior. - Task editor: improved unsaved-edits dialog integration, editor load error reporting, safer mountEditor error propagation, and beforeunload handling. - pages/workspace/.../create.vue: rewrite imagery validation flow to use request ids, better debounce handling, centralized validateCustomImagery with error fallback, and helpers to validate the current imagery state before submissions. - services/projects.ts: closeWorkspaceProject now returns void (no extra GET) and services/http small signature formatting cleanup. - util/rapid-imagery.ts: change default minZoom fallback from 12 to 0. Also includes various small UI/CSS tweaks and console error reporting for editor/imagery failures. These changes aim to make state persistence safer, avoid editor update loops, improve member mutation UX, and provide clearer handling of unsaved changes and imagery validation errors.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
util/project-wizard-storage.ts (1)
3-6: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the trailing comma from the import statement.
As per coding guidelines, new code must not include trailing commas after the last item in imports to align with the repository’s lint/style rules.
🧹 Proposed fix
import type { ProjectWizardStepId, - ProjectWizardStoredState, + ProjectWizardStoredState } from '~/types/project-wizard';🤖 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 `@util/project-wizard-storage.ts` around lines 3 - 6, Update the type-only import of ProjectWizardStepId and ProjectWizardStoredState to remove the trailing comma after the final imported item, preserving the existing import structure.Source: Learnings
🤖 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.
Nitpick comments:
In `@util/project-wizard-storage.ts`:
- Around line 3-6: Update the type-only import of ProjectWizardStepId and
ProjectWizardStoredState to remove the trailing comma after the final imported
item, preserving the existing import structure.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 02445a7a-9c3d-4b8e-b310-b9d7736da504
📒 Files selected for processing (24)
components/AppConfirmationDialog.vuecomponents/project-wizard/AoiGeometryMap.vuecomponents/project-wizard/AssignUsersField.vuecomponents/project-wizard/RichTextEditor.vuecomponents/project-wizard/steps/ProjectDetailsStep.vuecomponents/project-wizard/steps/ReviewStep.vuecomponents/workspace-project-details/ContributorsTab.vuecomponents/workspace-project-details/RichTextContent.vuecomponents/workspace-project-details/TasksTab.vuecomposables/usePagination.tscomposables/useProjectEditActions.tscomposables/useProjectEditMembers.tscomposables/useProjectWizard.tscomposables/useProjectWizardSettings.tspages/workspace/[id]/projects/[projectId]/edit.vuepages/workspace/[id]/projects/[projectId]/index.vuepages/workspace/[id]/projects/[projectId]/tasks/[taskId]/editor.vuepages/workspace/[id]/projects/create.vueservices/http.tsservices/project-wizard-payload.tsservices/projects.tsservices/rapid.tsutil/project-wizard-storage.tsutil/rapid-imagery.ts
🚧 Files skipped from review as they are similar to previous changes (18)
- components/project-wizard/steps/ProjectDetailsStep.vue
- services/project-wizard-payload.ts
- composables/usePagination.ts
- components/workspace-project-details/RichTextContent.vue
- components/project-wizard/AssignUsersField.vue
- composables/useProjectEditActions.ts
- util/rapid-imagery.ts
- components/workspace-project-details/ContributorsTab.vue
- components/workspace-project-details/TasksTab.vue
- components/AppConfirmationDialog.vue
- pages/workspace/[id]/projects/[projectId]/index.vue
- services/rapid.ts
- pages/workspace/[id]/projects/[projectId]/tasks/[taskId]/editor.vue
- composables/useProjectEditMembers.ts
- composables/useProjectWizardSettings.ts
- services/http.ts
- pages/workspace/[id]/projects/create.vue
- pages/workspace/[id]/projects/[projectId]/edit.vue
Changes: - Update action help texts (reset/close) for clearer, consistent wording. - Shorten project name hint to "Project name cannot be edited". - Remove some explanatory helper paragraphs to reduce redundancy (detailed instructions, team header, imagery label helper). - Rename "Custom Imagery" header to "Imagery JSON Definition" and change section label to "Imagery". - Increase custom imagery textarea rows from 18 to 26 and remove the separate label to favor inline placeholder. - Reword locked settings message and action preview heading for clarity. - In rapid-imagery conversion, change default minZoom from 0 to 12 to avoid overly broad low-zoom defaults when extent zoom is unspecified.
DevBoard Task
https://dev.azure.com/TDEI-UW/TDEI/_workitems/edit/3984/
Changes Implemented
Project Editing
Added a project edit page at:
Restricted project editing to project leads.
Added editable sections for:
Added dirty-state detection and confirmation before leaving with unsaved changes.
Disabled configuration changes after tasks have been generated or the project has left draft status.
Added project actions:
Added API methods for updating, resetting, closing, and deleting projects.
Added an edit button to the project details page for project leads.
Standardized task mutation errors through the shared HTTP error resolver.
Shared API Error Handling
Expanded
resolveHttpErrorMessage()to support:detailstringsdetail.messageobjectsmsgmessagemessageerrortask_numberThe shared resolver is used by:
Custom Imagery
ImagerySource.Rapid Authentication and Integration
/loginendpoint during changeset upload.Confirmation Dialog Accessibility
Improved the confirmation dialog with:
role="dialog"aria-modal="true"useId()Impacted Areas Of Testing
Project Editing
403response.Contributor Management
Project Actions
Reset Tasks
Close Project
Delete Project
Custom Imagery Validation
Example:
{ "id": "example-imagery", "name": "Example Imagery", "type": "xyz", "url": "https://tiles.example.com/{z}/{x}/{y}.png", "icon": "https://example.com/icon.svg", "description": "Example imagery", "extent": { "polygon": [], "max_zoom": 19 }, "attribution": { "required": true, "text": "Example attribution", "url": "https://example.com/attribution" } }Rapid Custom Imagery
Screenshots:
Summary
/workspace/:workspaceId/projects/:projectId/edit, restricted to project leads, including editable fields for project description, rich-text instructions, custom imagery (single JSON object + schema validation), team members and roles, configuration (lock timeout + review-required), and project actions (reset tasks, close project, permanently delete).onBeforeRouteLeaveandbeforeunloadusing an accessible confirmation dialog.updateWorkspaceProject,closeWorkspaceProject,resetWorkspaceProject, anddeleteWorkspaceProject, plus improved normalization (e.g.,description/summary, nullableinstructions,custom_imagery) and tighter user-role 404 handling.components/AppConfirmationDialog.vuewith focus restoration, Escape-to-close, Tab focus trapping, busy/disabled states, and spinner primary action.overflow-wrap: anywhere, including Toastify toast body layout) to prevent long unbroken messages from overflowing.aria-livevalidating help).composables/usePagination(applied to contributors and tasks tabs).validateProjectCustomImagery(debounced async + request-id to ignore stale results) and blocks progression/creation on validation failure.isValidProjectWizardStoredState) and made localStorage persistence safer (debounced writes, try/catch for quota/access failures).RapidManagerinit/switch now accepts an optionalcustomImagerySourceand wires it into Rapid after init/reset; Rapid auth patching was refactored.project.customImagery.services/http.tsnow provides consistent HTTP error message resolution (JSON/non-JSON parsing, nesteddetailhandling, lock/task-specific messaging).services/index.tsnow requiresVITE_NEW_API_URLto be set.services/project-wizard.tsswitches name availability checks to a dedicated validate-name endpoint (existsboolean).util/rapid-imagery.tsconversion fromImagerySourceto Rapid imagery source.useProjectEditActions(reset/close/delete flows with dialog + toasts + navigation) anduseProjectEditMembers(role editing with lead constraint enforcement, optimistic updates, rollback on failure, and confirmation-based removals).