Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ui): error handling in UI #374

Merged
merged 13 commits into from
Nov 13, 2024
17 changes: 0 additions & 17 deletions api/errorpkg/error_constants.go

This file was deleted.

34 changes: 17 additions & 17 deletions api/errorpkg/error_creators.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func NewGroupNotFoundError(err error) *ErrorResponse {
"group_not_found",
http.StatusNotFound,
"Group not found.",
MsgResourceNotFound,
"Group not found.",
err,
)
}
Expand All @@ -35,7 +35,7 @@ func NewFileNotFoundError(err error) *ErrorResponse {
"file_not_found",
http.StatusNotFound,
"File not found.",
MsgResourceNotFound,
"File not found.",
err,
)
}
Expand All @@ -45,7 +45,7 @@ func NewInvalidPathError(err error) *ErrorResponse {
"invalid_path",
http.StatusBadRequest,
"Invalid path.",
MsgInvalidRequest,
"An invalid request was sent to the server.",
err,
)
}
Expand All @@ -55,7 +55,7 @@ func NewWorkspaceNotFoundError(err error) *ErrorResponse {
"workspace_not_found",
http.StatusNotFound,
"Workspace not found.",
MsgResourceNotFound,
"Workspace not found.",
err,
)
}
Expand All @@ -65,7 +65,7 @@ func NewOrganizationNotFoundError(err error) *ErrorResponse {
"organization_not_found",
http.StatusNotFound,
"Organization not found.",
MsgResourceNotFound,
"Organization not found.",
err,
)
}
Expand All @@ -75,7 +75,7 @@ func NewTaskNotFoundError(err error) *ErrorResponse {
"task_not_found",
http.StatusNotFound,
"Task not found.",
MsgResourceNotFound,
"Task not found.",
err,
)
}
Expand Down Expand Up @@ -105,17 +105,17 @@ func NewUserNotFoundError(err error) *ErrorResponse {
"user_not_found",
http.StatusNotFound,
"User not found.",
MsgResourceNotFound,
"User not found.",
err,
)
}

func NewUserPictureNotFoundError(err error) *ErrorResponse {
func NewPictureNotFoundError(err error) *ErrorResponse {
return NewErrorResponse(
"user_picture_not_found",
"Picture_not_found",
http.StatusNotFound,
"User picture not found.",
MsgResourceNotFound,
"Picture not found.",
"Picture not found.",
err,
)
}
Expand Down Expand Up @@ -145,7 +145,7 @@ func NewInvitationNotFoundError(err error) *ErrorResponse {
"invitation_not_found",
http.StatusNotFound,
"Invitation not found.",
MsgResourceNotFound,
"Invitation not found.",
err,
)
}
Expand Down Expand Up @@ -195,7 +195,7 @@ func NewInternalServerError(err error) *ErrorResponse {
"internal_server_error",
http.StatusInternalServerError,
"Internal server error.",
MsgSomethingWentWrong,
"Oops! something went wrong.",
err,
)
}
Expand Down Expand Up @@ -277,7 +277,7 @@ func NewS3Error(message string) *ErrorResponse {
"s3_error",
http.StatusInternalServerError,
message,
MsgSomethingWentWrong,
"Storage error occurred.",
nil,
)
}
Expand All @@ -287,7 +287,7 @@ func NewMissingQueryParamError(param string) *ErrorResponse {
"missing_query_param",
http.StatusBadRequest,
fmt.Sprintf("Query param '%s' is required.", param),
MsgInvalidRequest,
"An invalid request was sent to the server.",
nil,
)
}
Expand All @@ -297,7 +297,7 @@ func NewInvalidQueryParamError(param string) *ErrorResponse {
"invalid_query_param",
http.StatusBadRequest,
fmt.Sprintf("Query param '%s' is invalid.", param),
MsgInvalidRequest,
"An invalid request was sent to the server.",
nil,
)
}
Expand Down Expand Up @@ -332,7 +332,7 @@ func NewRequestBodyValidationError(err error) *ErrorResponse {
"request_validation_error",
http.StatusBadRequest,
fmt.Sprintf("Failed validation for fields: %s.", strings.Join(fields, ",")),
MsgInvalidRequest,
"An invalid request was sent to the server.",
err,
)
}
Expand Down
2 changes: 1 addition & 1 deletion api/router/user_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ func (r *UserRouter) DownloadPicture(c *fiber.Ctx) error {
return err
}
if *ext != c.Params("extension") {
return errorpkg.NewUserPictureNotFoundError(nil)
return errorpkg.NewPictureNotFoundError(nil)
}
c.Set("Content-Type", *mime)
c.Set("Content-Disposition", fmt.Sprintf("filename=\"picture%s\"", *ext))
Expand Down
12 changes: 6 additions & 6 deletions api/service/user_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,13 +270,13 @@ func (svc *UserService) ExtractPicture(id string, justification ExtractPictureJu
return nil, nil, nil, err
}
if user.GetPicture() == nil {
return nil, nil, nil, errorpkg.NewUserPictureNotFoundError(nil)
return nil, nil, nil, errorpkg.NewPictureNotFoundError(nil)
}
mime := helper.Base64ToMIME(*user.GetPicture())
ext := helper.Base64ToExtension(*user.GetPicture())
b, err := helper.Base64ToBytes(*user.GetPicture())
if err != nil {
return nil, nil, nil, errorpkg.NewUserPictureNotFoundError(nil)
return nil, nil, nil, errorpkg.NewPictureNotFoundError(nil)
}
return b, &ext, &mime, nil
}
Expand All @@ -290,7 +290,7 @@ func (svc *UserService) findUserForPicture(id string, justification ExtractPictu
return user, nil
}
if justification.OrganizationID == nil && justification.GroupID == nil && justification.InvitationID == nil {
return nil, errorpkg.NewUserPictureNotFoundError(nil)
return nil, errorpkg.NewPictureNotFoundError(nil)
}
if justification.OrganizationID != nil {
org, err := svc.orgCache.Get(*justification.OrganizationID)
Expand All @@ -301,7 +301,7 @@ func (svc *UserService) findUserForPicture(id string, justification ExtractPictu
return nil, err
}
if !slices.Contains(org.GetMembers(), id) {
return nil, errorpkg.NewUserPictureNotFoundError(nil)
return nil, errorpkg.NewPictureNotFoundError(nil)
}
} else if justification.GroupID != nil {
group, err := svc.groupCache.Get(*justification.GroupID)
Expand All @@ -312,15 +312,15 @@ func (svc *UserService) findUserForPicture(id string, justification ExtractPictu
return nil, err
}
if !slices.Contains(group.GetMembers(), id) {
return nil, errorpkg.NewUserPictureNotFoundError(nil)
return nil, errorpkg.NewPictureNotFoundError(nil)
}
} else if justification.InvitationID != nil {
invitation, err := svc.invitationRepo.Find(*justification.InvitationID)
if err != nil {
return nil, err
}
if invitation.GetOwnerID() != id {
return nil, errorpkg.NewUserPictureNotFoundError(nil)
return nil, errorpkg.NewPictureNotFoundError(nil)
}
}
return user, nil
Expand Down
Binary file modified ui/bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@emotion/react": "11.13.3",
"@emotion/styled": "11.13.0",
"@google/model-viewer": "4.0.0",
"@koupr/ui": "1.10.9",
"@koupr/ui": "1.10.10",
"@nivo/core": "0.87.0",
"@nivo/pie": "0.87.0",
"@reduxjs/toolkit": "2.3.0",
Expand Down
145 changes: 72 additions & 73 deletions ui/src/components/common/group-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,16 @@ const GroupSelector = ({
const [selected, setSelected] = useState<Group>()
const {
data: list,
error,
error: listError,
isLoading: isListLoading,
mutate,
} = GroupAPI.useList(
{ query, organizationId, page, size: 5, sortOrder: SortOrder.Desc },
swrConfig(),
)
const isListError = !list && listError
const isListEmpty = list && !listError && list.totalElements === 0
const isListReady = list && !listError && list.totalElements > 0

useEffect(() => {
mutate().then()
Expand Down Expand Up @@ -116,84 +120,79 @@ const GroupSelector = ({
query={query}
onChange={handleSearchInputChange}
/>
{!list && error ? (
{isListLoading ? <SectionSpinner /> : null}
{isListError ? (
<SectionError text="Failed to load groups." />
) : null}
{!list && !error ? <SectionSpinner /> : null}
{list && !error ? (
<>
{list.totalElements > 0 ? (
<div
className={cx(
'flex',
'flex-col',
'justify-between',
'gap-1.5',
'h-[320px]',
)}
>
<Table variant="simple" size="sm">
<colgroup>
<col className={cx('w-[40px]')} />
<col className={cx('w-[auto]')} />
</colgroup>
<Tbody>
{list.data.map((g) => (
<Tr
key={g.id}
{isListEmpty ? (
<SectionPlaceholder text="There are no groups." />
) : null}
{isListReady ? (
<div
className={cx(
'flex',
'flex-col',
'justify-between',
'gap-1.5',
'h-[320px]',
)}
>
<Table variant="simple" size="sm">
<colgroup>
<col className={cx('w-[40px]')} />
<col className={cx('w-[auto]')} />
</colgroup>
<Tbody>
{list.data.map((g) => (
<Tr
key={g.id}
className={cx(
'cursor-pointer',
'h-[52px]',
{ 'bg-gray-100': selected?.id === g.id },
{ 'dark:bg-gray-600': selected?.id === g.id },
{ 'bg-transparent': selected?.id !== g.id },
)}
onClick={() => setSelected(g)}
>
<Td className={cx('px-0.5', 'text-center')}>
<Radio
size="md"
isChecked={selected?.id === g.id}
/>
</Td>
<Td className={cx('p-0.5')}>
<div
className={cx(
'cursor-pointer',
'h-[52px]',
{ 'bg-gray-100': selected?.id === g.id },
{ 'dark:bg-gray-600': selected?.id === g.id },
{ 'bg-transparent': selected?.id !== g.id },
'flex',
'flex-row',
'items-center',
'gap-1.5',
)}
onClick={() => setSelected(g)}
>
<Td className={cx('px-0.5', 'text-center')}>
<Radio
size="md"
isChecked={selected?.id === g.id}
/>
</Td>
<Td className={cx('p-0.5')}>
<div
className={cx(
'flex',
'flex-row',
'items-center',
'gap-1.5',
)}
>
<Avatar
name={g.name}
size="sm"
className={cx('w-[40px]', 'h-[40px]')}
/>
<span className={cx('text-base')}>
{g.name}
</span>
</div>
</Td>
</Tr>
))}
</Tbody>
</Table>
{list.totalPages > 1 ? (
<div className={cx('self-end')}>
<Pagination
maxButtons={3}
page={page}
totalPages={list.totalPages}
onPageChange={(value) => setPage(value)}
/>
</div>
) : null}
<Avatar
name={g.name}
size="sm"
className={cx('w-[40px]', 'h-[40px]')}
/>
<span className={cx('text-base')}>{g.name}</span>
</div>
</Td>
</Tr>
))}
</Tbody>
</Table>
{list.totalPages > 1 ? (
<div className={cx('self-end')}>
<Pagination
maxButtons={3}
page={page}
totalPages={list.totalPages}
onPageChange={(value) => setPage(value)}
/>
</div>
) : (
<SectionPlaceholder text="There are no groups." />
)}
</>
) : null}
</div>
) : null}
</div>
</ModalBody>
Expand Down
Loading
Loading