Skip to content

Revert "[FEAT] Implement Email service & Send emails for workspace invitations"#19

Merged
martian56 merged 1 commit into
mainfrom
revert-18-17-implement-email-service-send-emails-for-workspace-invitations
Mar 8, 2026
Merged

Revert "[FEAT] Implement Email service & Send emails for workspace invitations"#19
martian56 merged 1 commit into
mainfrom
revert-18-17-implement-email-service-send-emails-for-workspace-invitations

Conversation

@martian56
Copy link
Copy Markdown
Member

Reverts #18

Copilot AI review requested due to automatic review settings March 8, 2026 22:47
@martian56 martian56 merged commit 20b770d into main Mar 8, 2026
4 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR nominally reverts the previously added email/invite email functionality, but the diff also introduces several new UI + API capabilities around image uploads/cover images, project icons, and favoriting projects.

Changes:

  • Removes email invite acceptance UI flow and SMTP sender integration, switching queue email handling to a noop sender.
  • Adds authenticated file upload + file serving endpoints backed by MinIO, plus UI modals for uploading/selecting images (including Unsplash search).
  • Adds “favorite projects” feature (API persistence + UI toggles + global Favorites context) and expands project/workspace/user models to support logos/covers/icons.

Reviewed changes

Copilot reviewed 53 out of 53 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
ui/vite.config.ts Adjusts manual chunking and warning limit for larger vendor bundles.
ui/src/types/index.ts Adds coverImageUrl to User type.
ui/src/services/workspaceService.ts Extends workspace update payload to support logo; removes joinByToken.
ui/src/services/userService.ts Minor signature formatting change for createToken.
ui/src/services/uploadService.ts Adds image upload helper calling /api/upload.
ui/src/services/projectService.ts Extends project update payload to support cover/icon fields.
ui/src/services/instanceService.ts Adds Unsplash search client method + types.
ui/src/routes/index.tsx Removes invite accept route; comments out unused instance-admin login route.
ui/src/pages/instance-admin/InstanceAdminImagePage.tsx Casts payload for updateSection call.
ui/src/pages/instance-admin/InstanceAdminEmailPage.tsx Casts payload for updateSection call.
ui/src/pages/instance-admin/InstanceAdminAuthenticationPage.tsx Type tweaks for icon component type; minor state rename.
ui/src/pages/instance-admin/InstanceAdminAIPage.tsx Casts payload for updateSection call.
ui/src/pages/WorkspaceViewsPage.tsx Refines placeholder getUser return type.
ui/src/pages/WorkspaceHomePage.tsx Comments out unused helpers; minor state naming changes.
ui/src/pages/SettingsPage.tsx Adds cover/avatar/logo upload + project icon/cover selection UI.
ui/src/pages/ProjectsListPage.tsx Adds project cards with cover/icon display + favorite toggle UI.
ui/src/pages/ProfilePage.tsx Adds cover image rendering, assignee display improvements, and activity shaping.
ui/src/pages/LoginPage.tsx Simplifies post-login redirect extraction from location state.
ui/src/pages/IssueListPage.tsx Uses member avatar URLs and getImageUrl for assignee avatars.
ui/src/pages/IssueDetailPage.tsx Aligns project object fields with API response shape.
ui/src/pages/InviteAcceptPage.tsx Deletes invite acceptance page.
ui/src/pages/CyclesPage.tsx Refines placeholder getUser return type.
ui/src/pages/BoardPage.tsx Removes unused Avatar import.
ui/src/pages/AnalyticsWorkItemsPage.tsx Fixes issue field name usage (project_id, state_id).
ui/src/lib/utils.ts Adds getImageUrl helper using configured API base URL.
ui/src/contexts/FavoritesContext.tsx Introduces Favorites context/provider.
ui/src/contexts/AuthContext.tsx Maps cover_image into coverImageUrl.
ui/src/components/work-item/CommentEditor.tsx Changes TipTap codeBlock config shape.
ui/src/components/layout/Sidebar.tsx Integrates favorites and image URL handling; passes API project types to modal.
ui/src/components/layout/PageHeader.tsx Minor state naming changes.
ui/src/components/UploadImageModal.tsx Adds modal UI for uploading an image file.
ui/src/components/ProjectIconModal.tsx Adds modal UI for selecting emoji/icon-based project icons.
ui/src/components/CoverImageModal.tsx Adds modal UI for Unsplash search + upload cover selection.
ui/src/api/types.ts Adds workspace logo, project cover/icon fields, user cover image, and page fields.
ui/src/App.tsx Wraps app with FavoritesProvider.
api/internal/store/user_favorite.go Adds persistence layer for user favorite projects.
api/internal/service/workspace.go Adds workspace logo update support.
api/internal/service/project.go Adds project cover/emoji/icon update support.
api/internal/router/router.go Adds favorites endpoints, Unsplash proxy, MinIO upload/serve endpoints; removes AppBaseURL handling from handler wiring.
api/internal/model/user_favorite.go Adds unique index for favorites across (user, entity_type, entity_identifier).
api/internal/model/user.go Adds cover_image field to user model.
api/internal/model/project.go Adds cover_image field to project model.
api/internal/minio/minio.go Adds PutObject/GetObject helpers.
api/internal/mail/mail.go Removes SMTP email sender implementation.
api/internal/handler/workspace.go Removes email invite enqueueing; adds logo to workspace update body.
api/internal/handler/upload.go Adds authenticated upload + file streaming handlers backed by MinIO.
api/internal/handler/project.go Accepts/propagates cover/emoji/icon updates for projects.
api/internal/handler/instance.go Adds Unsplash proxy endpoint using instance “image” settings access key.
api/internal/handler/favorite.go Adds favorite-project CRUD endpoints for current user.
api/internal/handler/auth.go Adds avatar + cover_image fields to UpdateMe and response.
api/internal/config/config.go Removes AppBaseURL config.
api/cmd/api/main.go Makes MinIO optional; switches email consumer to noop sender; removes SMTP wiring.
api/.env.example Removes APP_BASE_URL example.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +242 to +274
<Link
to={`${baseUrl}/projects/${project.id}/issues`}
className="block no-underline"
>
{/* Cover image */}
<div
className="relative h-32 w-full shrink-0 rounded-t-xl overflow-hidden"
style={
coverUrl
? {
backgroundImage: `url(${coverUrl})`,
backgroundSize: "cover",
backgroundPosition: "center",
}
: { background: getCoverGradient(project.id) }
}
>
{/* Banner with overlay */}
<div
className="relative h-28 min-h-[7rem] w-full shrink-0 rounded-t-md"
style={{ background: getCoverGradient(project.id) }}
{/* Star favorite (right side, vertically centered) */}
<button
type="button"
onClick={(e) => toggleFavorite(e, project.id)}
disabled={favoriteRequestInFlight[project.id]}
className="absolute right-3 top-1/2 z-10 flex size-9 -translate-y-1/2 items-center justify-center rounded-full bg-white/30 backdrop-blur-sm text-white shadow-sm hover:bg-white/45 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/80 disabled:opacity-60 disabled:pointer-events-none"
aria-label={
favoriteProjectIds.includes(project.id)
? "Remove from favorites"
: "Add to favorites"
}
>
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/60 to-transparent p-4 pt-8">
<p className="truncate text-base font-semibold text-white">
<IconStar
filled={favoriteProjectIds.includes(project.id)}
/>
</button>
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

The favorite star <button> is rendered inside a <Link> (anchor). Nesting interactive elements is invalid HTML and can cause accessibility/keyboard and click handling issues across browsers/screen readers, even with preventDefault/stopPropagation. Consider moving the favorite toggle button outside the link (e.g., absolutely positioned in the card but not nested under the anchor) or make the whole card a button/link and handle navigation separately.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +16
const returnPath =
(location.state as { from?: { pathname?: string } })?.from?.pathname ?? "/";
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

returnPath now only uses from.pathname and drops any from.search query string. Since ProtectedRoute passes the full location (including search), this change will lose query params on post-login redirects (e.g. deep-links that rely on ?foo=bar). Consider restoring the previous behavior by appending from.search when present (and update the cast type accordingly).

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +20
const form = new FormData();
form.append("file", file);
const { data } = await apiClient.post<UploadResponse>("/api/upload", form);
return data;
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

uploadImage posts FormData using the shared apiClient, which sets a default Content-Type: application/json header. For multipart uploads this can result in the request being sent with the wrong content type/boundary. Consider overriding/removing Content-Type for this request (or using a dedicated axios instance for multipart) so the browser/axios can set the correct multipart/form-data boundary.

Copilot uses AI. Check for mistakes.
Comment on lines +347 to +356
apiURL := "https://api.unsplash.com/search/photos?query=" + url.QueryEscape(q) + "&per_page=20"
req, err := http.NewRequestWithContext(c.Request.Context(), http.MethodGet, apiURL, nil)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to search"})
return
}
req.Header.Set("Authorization", "Client-ID "+keyVal)

resp, err := http.DefaultClient.Do(req)
if err != nil {
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

UnsplashSearch uses http.DefaultClient.Do(req) which has no timeout by default. A slow/hung upstream Unsplash request can tie up handler goroutines and degrade API availability. Consider using an http.Client with a reasonable timeout (or enforcing a context deadline) for this outbound call.

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +48
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "No file provided", "detail": err.Error()})
return
}
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

The upload handler does not enforce any maximum upload size (it relies on whatever the client sends as file.Size). This can allow very large uploads and lead to memory/disk/bandwidth exhaustion. Consider enforcing a server-side size limit (and/or configuring Gin's MaxMultipartMemory) and returning a clear 413/400 error when exceeded.

Copilot uses AI. Check for mistakes.
Comment on lines +128 to +135
api.GET("/users/me/favorite-projects/", favoriteHandler.ListFavoriteProjects)
api.GET("/instance/settings/", instanceSettingsHandler.GetSettings)
api.PATCH("/instance/settings/:key", instanceSettingsHandler.UpdateSetting)
api.GET("/instance/unsplash/search", instanceSettingsHandler.UnsplashSearch)

uploadHandler := &handler.UploadHandler{Minio: cfg.Minio}
api.POST("/upload", uploadHandler.Upload)
api.GET("/files/*path", uploadHandler.ServeFile)
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

The PR metadata says this is a revert of the email service / invite emails, but the diff also introduces new functionality (favorites endpoints, MinIO upload endpoints, Unsplash proxy, cover images, project icons, etc.). Please update the PR title/description to match the scope, or split these changes into separate PRs so the revert can be reviewed/rolled back independently.

Copilot uses AI. Check for mistakes.
@martian56 martian56 deleted the revert-18-17-implement-email-service-send-emails-for-workspace-invitations branch May 2, 2026 15:03
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