-
Pending issues
+
Pending issues
{pendingUnAssignedIssuesUser && (
Unassigned: {pendingUnAssignedIssuesUser.count}
@@ -48,7 +51,7 @@ export const AnalyticsScope: React.FC
= ({ pendingUnAssignedIssuesUser, p
renderTick: (datum) => {
const assignee = pendingAssignedIssues[datum.tickIndex] ?? "";
- if (assignee && assignee?.assignees__avatar && assignee?.assignees__avatar !== "")
+ if (assignee && assignee?.assignees__avatar_url && assignee?.assignees__avatar_url !== "")
return (
= ({ pendingUnAssignedIssuesUser, p
y={10}
width={16}
height={16}
- xlinkHref={assignee?.assignees__avatar}
+ xlinkHref={getFileURL(assignee?.assignees__avatar_url)}
style={{ clipPath: "circle(50%)" }}
/>
diff --git a/web/core/components/command-palette/actions/issue-actions/change-assignee.tsx b/web/core/components/command-palette/actions/issue-actions/change-assignee.tsx
index 30ef22aaf..319adf8f2 100644
--- a/web/core/components/command-palette/actions/issue-actions/change-assignee.tsx
+++ b/web/core/components/command-palette/actions/issue-actions/change-assignee.tsx
@@ -4,13 +4,16 @@ import { Command } from "cmdk";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { Check } from "lucide-react";
+// plane types
import { TIssue } from "@plane/types";
-// mobx store
+// plane ui
import { Avatar } from "@plane/ui";
+// constants
import { EIssuesStoreType } from "@/constants/issue";
+// helpers
+import { getFileURL } from "@/helpers/file.helper";
+// hooks
import { useIssues, useMember } from "@/hooks/store";
-// ui
-// types
type Props = {
closePalette: () => void;
@@ -41,7 +44,7 @@ export const ChangeIssueAssignee: React.FC = observer((props) => {
{memberDetails?.member?.display_name}
diff --git a/web/core/components/common/applied-filters/members.tsx b/web/core/components/common/applied-filters/members.tsx
index 6f5301320..87d339366 100644
--- a/web/core/components/common/applied-filters/members.tsx
+++ b/web/core/components/common/applied-filters/members.tsx
@@ -2,8 +2,10 @@
import { observer } from "mobx-react";
import { X } from "lucide-react";
-// ui
+// plane ui
import { Avatar } from "@plane/ui";
+// helpers
+import { getFileURL } from "@/helpers/file.helper";
// types
import { useMember } from "@/hooks/store";
@@ -29,7 +31,12 @@ export const AppliedMembersFilters: React.FC
= observer((props) => {
return (
-
+
{memberDetails.display_name}
{editable && (
)}
@@ -218,6 +230,8 @@ export const GptAssistantPopover: React.FC = (props) => {
id="ai-assistant-response"
initialValue={`${response}
`}
ref={responseRef}
+ workspaceSlug={workspaceSlug}
+ projectId={projectId}
/>
)}
diff --git a/web/core/components/core/modals/user-image-upload-modal.tsx b/web/core/components/core/modals/user-image-upload-modal.tsx
index 7e033053f..ad7a4daac 100644
--- a/web/core/components/core/modals/user-image-upload-modal.tsx
+++ b/web/core/components/core/modals/user-image-upload-modal.tsx
@@ -5,34 +5,33 @@ import { observer } from "mobx-react";
import { useDropzone } from "react-dropzone";
import { UserCircle2 } from "lucide-react";
import { Transition, Dialog } from "@headlessui/react";
+// plane types
+import { EFileAssetType } from "@plane/types/src/enums";
// hooks
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
// constants
-import { MAX_FILE_SIZE } from "@/constants/common";
-// hooks
-import { useInstance } from "@/hooks/store";
+import { MAX_STATIC_FILE_SIZE } from "@/constants/common";
+// helpers
+import { getAssetIdFromUrl, getFileURL } from "@/helpers/file.helper";
+import { checkURLValidity } from "@/helpers/string.helper";
// services
import { FileService } from "@/services/file.service";
+const fileService = new FileService();
type Props = {
- handleDelete?: () => void;
+ handleRemove: () => Promise;
isOpen: boolean;
- isRemoving: boolean;
onClose: () => void;
onSuccess: (url: string) => void;
value: string | null;
};
-// services
-const fileService = new FileService();
-
export const UserImageUploadModal: React.FC = observer((props) => {
- const { value, onSuccess, isOpen, onClose, isRemoving, handleDelete } = props;
+ const { handleRemove, isOpen, onClose, onSuccess, value } = props;
// states
const [image, setImage] = useState(null);
+ const [isRemoving, setIsRemoving] = useState(false);
const [isImageUploading, setIsImageUploading] = useState(false);
- // store hooks
- const { config } = useInstance();
const onDrop = (acceptedFiles: File[]) => setImage(acceptedFiles[0]);
@@ -41,7 +40,7 @@ export const UserImageUploadModal: React.FC = observer((props) => {
accept: {
"image/*": [".png", ".jpg", ".jpeg", ".webp"],
},
- maxSize: config?.file_size_limit ?? MAX_FILE_SIZE,
+ maxSize: MAX_STATIC_FILE_SIZE,
multiple: false,
});
@@ -53,31 +52,46 @@ export const UserImageUploadModal: React.FC = observer((props) => {
const handleSubmit = async () => {
if (!image) return;
-
setIsImageUploading(true);
- const formData = new FormData();
- formData.append("asset", image);
- formData.append("attributes", JSON.stringify({}));
+ try {
+ const { asset_url } = await fileService.uploadUserAsset(
+ {
+ entity_identifier: "",
+ entity_type: EFileAssetType.USER_AVATAR,
+ },
+ image
+ );
+ onSuccess(asset_url);
+ setImage(null);
+ } catch (error) {
+ setToast({
+ type: TOAST_TYPE.ERROR,
+ title: "Error!",
+ message: error?.toString() ?? "Something went wrong. Please try again.",
+ });
+ throw new Error("Error in uploading file.");
+ } finally {
+ setIsImageUploading(false);
+ }
+ };
- fileService
- .uploadUserFile(formData)
- .then((res) => {
- const imageUrl = res.asset;
-
- onSuccess(imageUrl);
- setImage(null);
-
- if (value) fileService.deleteUserFile(value);
- })
- .catch((err) =>
- setToast({
- type: TOAST_TYPE.ERROR,
- title: "Error!",
- message: err?.error ?? "Something went wrong. Please try again.",
- })
- )
- .finally(() => setIsImageUploading(false));
+ const handleImageRemove = async () => {
+ if (!value) return;
+ setIsRemoving(true);
+ try {
+ if (checkURLValidity(value)) {
+ await fileService.deleteOldUserAsset(value);
+ } else {
+ const assetId = getAssetIdFromUrl(value);
+ await fileService.deleteUserAsset(assetId);
+ }
+ await handleRemove();
+ } catch (error) {
+ console.log("Error in uploading user asset:", error);
+ } finally {
+ setIsRemoving(false);
+ }
};
return (
@@ -130,7 +144,7 @@ export const UserImageUploadModal: React.FC = observer((props) => {
Edit
@@ -158,11 +172,9 @@ export const UserImageUploadModal: React.FC = observer((props) => {
File formats supported- .jpeg, .jpg, .png, .webp
- {handleDelete && (
-
- )}
+
diff --git a/web/core/components/core/modals/workspace-image-upload-modal.tsx b/web/core/components/core/modals/workspace-image-upload-modal.tsx
index 614fe5f41..cc7248a62 100644
--- a/web/core/components/core/modals/workspace-image-upload-modal.tsx
+++ b/web/core/components/core/modals/workspace-image-upload-modal.tsx
@@ -1,23 +1,27 @@
"use client";
import React, { useState } from "react";
import { observer } from "mobx-react";
-import { useParams, usePathname } from "next/navigation";
+import { useParams } from "next/navigation";
import { useDropzone } from "react-dropzone";
import { UserCircle2 } from "lucide-react";
import { Transition, Dialog } from "@headlessui/react";
+// plane types
+import { EFileAssetType } from "@plane/types/src/enums";
// hooks
-import { Button, TOAST_TYPE, setToast } from "@plane/ui";
+import { Button } from "@plane/ui";
// constants
-import { MAX_FILE_SIZE } from "@/constants/common";
+import { MAX_STATIC_FILE_SIZE } from "@/constants/common";
+// helpers
+import { getAssetIdFromUrl, getFileURL } from "@/helpers/file.helper";
+import { checkURLValidity } from "@/helpers/string.helper";
// hooks
-import { useWorkspace, useInstance } from "@/hooks/store";
+import { useWorkspace } from "@/hooks/store";
// services
import { FileService } from "@/services/file.service";
type Props = {
- handleRemove?: () => void;
+ handleRemove: () => Promise
;
isOpen: boolean;
- isRemoving: boolean;
onClose: () => void;
onSuccess: (url: string) => void;
value: string | null;
@@ -27,16 +31,15 @@ type Props = {
const fileService = new FileService();
export const WorkspaceImageUploadModal: React.FC = observer((props) => {
- const { value, onSuccess, isOpen, onClose, isRemoving, handleRemove } = props;
+ const { handleRemove, isOpen, onClose, onSuccess, value } = props;
// states
const [image, setImage] = useState(null);
+ const [isRemoving, setIsRemoving] = useState(false);
const [isImageUploading, setIsImageUploading] = useState(false);
// router
const { workspaceSlug } = useParams();
- const pathname = usePathname();
// store hooks
- const { config } = useInstance();
- const { currentWorkspace } = useWorkspace();
+ const { currentWorkspace, updateWorkspaceLogo } = useWorkspace();
const onDrop = (acceptedFiles: File[]) => setImage(acceptedFiles[0]);
@@ -45,45 +48,58 @@ export const WorkspaceImageUploadModal: React.FC = observer((props) => {
accept: {
"image/*": [".png", ".jpg", ".jpeg", ".webp"],
},
- maxSize: config?.file_size_limit ?? MAX_FILE_SIZE,
+ maxSize: MAX_STATIC_FILE_SIZE,
multiple: false,
});
const handleClose = () => {
- setImage(null);
setIsImageUploading(false);
onClose();
+ setTimeout(() => {
+ setImage(null);
+ }, 300);
};
const handleSubmit = async () => {
- if (!image || (!workspaceSlug && pathname !== "/onboarding")) return;
-
+ if (!image || !workspaceSlug || !currentWorkspace) return;
setIsImageUploading(true);
- const formData = new FormData();
- formData.append("asset", image);
- formData.append("attributes", JSON.stringify({}));
+ try {
+ const { asset_url } = await fileService.uploadWorkspaceAsset(
+ workspaceSlug.toString(),
+ {
+ entity_identifier: currentWorkspace.id,
+ entity_type: EFileAssetType.WORKSPACE_LOGO,
+ },
+ image
+ );
+ updateWorkspaceLogo(workspaceSlug.toString(), asset_url);
+ onSuccess(asset_url);
+ } catch (error) {
+ console.log("error", error);
+ throw new Error("Error in uploading file.");
+ } finally {
+ setIsImageUploading(false);
+ }
+ };
- if (!workspaceSlug) return;
-
- fileService
- .uploadFile(workspaceSlug.toString(), formData)
- .then((res) => {
- const imageUrl = res.asset;
-
- onSuccess(imageUrl);
- setImage(null);
-
- if (value && currentWorkspace) fileService.deleteFile(currentWorkspace.id, value);
- })
- .catch((err) =>
- setToast({
- type: TOAST_TYPE.ERROR,
- title: "Error!",
- message: err?.error ?? "Something went wrong. Please try again.",
- })
- )
- .finally(() => setIsImageUploading(false));
+ const handleImageRemove = async () => {
+ if (!workspaceSlug || !value) return;
+ setIsRemoving(true);
+ try {
+ if (checkURLValidity(value)) {
+ await fileService.deleteOldWorkspaceAsset(currentWorkspace?.id ?? "", value);
+ } else {
+ const assetId = getAssetIdFromUrl(value);
+ await fileService.deleteWorkspaceAsset(workspaceSlug.toString(), assetId);
+ }
+ await handleRemove();
+ handleClose();
+ } catch (error) {
+ console.log("Error in removing workspace asset:", error);
+ } finally {
+ setIsRemoving(false);
+ }
};
return (
@@ -115,7 +131,7 @@ export const WorkspaceImageUploadModal: React.FC = observer((props) => {
- Upload Image
+ Upload image
@@ -136,7 +152,7 @@ export const WorkspaceImageUploadModal: React.FC
= observer((props) => {
Edit
@@ -164,11 +180,9 @@ export const WorkspaceImageUploadModal: React.FC = observer((props) => {
File formats supported- .jpeg, .jpg, .png, .webp
- {handleRemove && (
-
- )}
+
diff --git a/web/core/components/cycles/active-cycle/cycle-stats.tsx b/web/core/components/cycles/active-cycle/cycle-stats.tsx
index 1ee86a620..8e1d82349 100644
--- a/web/core/components/cycles/active-cycle/cycle-stats.tsx
+++ b/web/core/components/cycles/active-cycle/cycle-stats.tsx
@@ -17,15 +17,17 @@ import { EmptyState } from "@/components/empty-state";
// constants
import { EmptyStateType } from "@/constants/empty-state";
import { EIssuesStoreType } from "@/constants/issue";
-// helper
+// helpers
import { cn } from "@/helpers/common.helper";
import { renderFormattedDate, renderFormattedDateWithoutYear } from "@/helpers/date-time.helper";
+import { getFileURL } from "@/helpers/file.helper";
// hooks
import { useIssueDetail, useIssues } from "@/hooks/store";
import { useIntersectionObserver } from "@/hooks/use-intersection-observer";
import useLocalStorage from "@/hooks/use-local-storage";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
+// store
import { ActiveCycleIssueDetails } from "@/store/issue/cycle";
export type ActiveCycleStatsProps = {
@@ -250,7 +252,10 @@ export const ActiveCycleStats: FC
= observer((props) => {
key={assignee.assignee_id}
title={
-
+
{assignee.display_name}
diff --git a/web/core/components/cycles/active-cycle/header.tsx b/web/core/components/cycles/active-cycle/header.tsx
deleted file mode 100644
index 73d36f992..000000000
--- a/web/core/components/cycles/active-cycle/header.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-"use client";
-
-import { FC } from "react";
-import Link from "next/link";
-// types
-import { ICycle, TCycleGroups } from "@plane/types";
-// ui
-import { Tooltip, CycleGroupIcon, getButtonStyling, Avatar, AvatarGroup } from "@plane/ui";
-// helpers
-import { renderFormattedDate, findHowManyDaysLeft } from "@/helpers/date-time.helper";
-import { truncateText } from "@/helpers/string.helper";
-// hooks
-import { useMember } from "@/hooks/store";
-
-export type ActiveCycleHeaderProps = {
- cycle: ICycle;
- workspaceSlug: string;
- projectId: string;
-};
-
-export const ActiveCycleHeader: FC = (props) => {
- const { cycle, workspaceSlug, projectId } = props;
- // store
- const { getUserDetails } = useMember();
- const cycleOwnerDetails = cycle && cycle.owned_by_id ? getUserDetails(cycle.owned_by_id) : undefined;
-
- const daysLeft = findHowManyDaysLeft(cycle.end_date) ?? 0;
- const currentCycleStatus = cycle.status?.toLocaleLowerCase() as TCycleGroups | undefined;
-
- const cycleAssignee = (cycle.distribution?.assignees ?? []).filter((assignee) => assignee.display_name);
-
- return (
-
-
-
-
- {truncateText(cycle.name, 70)}
-
-
-
- {`${daysLeft} ${daysLeft > 1 ? "days" : "day"} left`}
-
-
-
-
-
-
-
- {cycleAssignee.length > 0 && (
-
-
- {cycleAssignee.map((member) => (
-
- ))}
-
-
- )}
-
-
-
- View Cycle
-
-
-
- );
-};
diff --git a/web/core/components/cycles/active-cycle/index.ts b/web/core/components/cycles/active-cycle/index.ts
index c21978252..bf5f3e9b4 100644
--- a/web/core/components/cycles/active-cycle/index.ts
+++ b/web/core/components/cycles/active-cycle/index.ts
@@ -1,7 +1,3 @@
-export * from "./header";
-export * from "./stats";
-export * from "./upcoming-cycles-list-item";
-export * from "./upcoming-cycles-list";
export * from "./cycle-stats";
-export * from "./progress";
export * from "./productivity";
+export * from "./progress";
diff --git a/web/core/components/cycles/active-cycle/stats.tsx b/web/core/components/cycles/active-cycle/stats.tsx
deleted file mode 100644
index 1a91fdfc8..000000000
--- a/web/core/components/cycles/active-cycle/stats.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-"use client";
-
-import React, { Fragment } from "react";
-import { Tab } from "@headlessui/react";
-import { ICycle } from "@plane/types";
-// hooks
-import { Avatar } from "@plane/ui";
-import { SingleProgressStats } from "@/components/core";
-import useLocalStorage from "@/hooks/use-local-storage";
-// components
-// ui
-// types
-
-type Props = {
- cycle: ICycle;
-};
-
-export const ActiveCycleProgressStats: React.FC = ({ cycle }) => {
- const { storedValue: tab, setValue: setTab } = useLocalStorage("activeCycleTab", "Assignees");
-
- const currentValue = (tab: string | null) => {
- switch (tab) {
- case "Assignees":
- return 0;
- case "Labels":
- return 1;
-
- default:
- return 0;
- }
- };
-
- return (
- {
- switch (i) {
- case 0:
- return setTab("Assignees");
- case 1:
- return setTab("Labels");
-
- default:
- return setTab("Assignees");
- }
- }}
- >
-
-
- `rounded-3xl border border-custom-border-200 px-3 py-1 text-custom-text-100 ${
- selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80"
- }`
- }
- >
- Assignees
-
-
- `rounded-3xl border border-custom-border-200 px-3 py-1 text-custom-text-100 ${
- selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80"
- }`
- }
- >
- Labels
-
-
- {cycle && cycle.total_issues > 0 ? (
-
-
- {cycle.distribution?.assignees?.map((assignee, index) => {
- if (assignee.assignee_id)
- return (
-
-
-
- {assignee?.display_name ?? ""}
-
- }
- completed={assignee.completed_issues}
- total={assignee.total_issues}
- />
- );
- else
- return (
-
-
-

-
- No assignee
-
- }
- completed={assignee.completed_issues}
- total={assignee.total_issues}
- />
- );
- })}
-
-
-
- {cycle.distribution?.labels?.map((label, index) => (
-
-
- {label.label_name ?? "No labels"}
-
- }
- completed={label.completed_issues}
- total={label.total_issues}
- />
- ))}
-
-
- ) : (
-
- There are no issues present in this cycle.
-
- )}
-
- );
-};
diff --git a/web/core/components/cycles/active-cycle/upcoming-cycles-list-item.tsx b/web/core/components/cycles/active-cycle/upcoming-cycles-list-item.tsx
deleted file mode 100644
index 4cdadac97..000000000
--- a/web/core/components/cycles/active-cycle/upcoming-cycles-list-item.tsx
+++ /dev/null
@@ -1,137 +0,0 @@
-"use client";
-
-import { useRef } from "react";
-import { observer } from "mobx-react";
-import Link from "next/link";
-import { useParams } from "next/navigation";
-import { Users } from "lucide-react";
-// ui
-import { Avatar, AvatarGroup, FavoriteStar, setPromiseToast } from "@plane/ui";
-// components
-import { CycleQuickActions } from "@/components/cycles";
-// constants
-import { CYCLE_FAVORITED, CYCLE_UNFAVORITED } from "@/constants/event-tracker";
-// helpers
-import { renderFormattedDate } from "@/helpers/date-time.helper";
-// hooks
-import { useCycle, useEventTracker, useMember } from "@/hooks/store";
-
-type Props = {
- cycleId: string;
-};
-
-export const UpcomingCycleListItem: React.FC
= observer((props) => {
- const { cycleId } = props;
- // refs
- const parentRef = useRef(null);
- // router
- const { workspaceSlug, projectId } = useParams();
- // store hooks
- const { captureEvent } = useEventTracker();
- const { addCycleToFavorites, getCycleById, removeCycleFromFavorites } = useCycle();
- const { getUserDetails } = useMember();
- // derived values
- const cycle = getCycleById(cycleId);
-
- const handleAddToFavorites = (e: React.MouseEvent) => {
- e.preventDefault();
- if (!workspaceSlug || !projectId) return;
-
- const addToFavoritePromise = addCycleToFavorites(workspaceSlug?.toString(), projectId.toString(), cycleId).then(
- () => {
- captureEvent(CYCLE_FAVORITED, {
- cycle_id: cycleId,
- element: "List layout",
- state: "SUCCESS",
- });
- }
- );
-
- setPromiseToast(addToFavoritePromise, {
- loading: "Adding cycle to favorites...",
- success: {
- title: "Success!",
- message: () => "Cycle added to favorites.",
- },
- error: {
- title: "Error!",
- message: () => "Couldn't add the cycle to favorites. Please try again.",
- },
- });
- };
-
- const handleRemoveFromFavorites = (e: React.MouseEvent) => {
- e.preventDefault();
- if (!workspaceSlug || !projectId) return;
-
- const removeFromFavoritePromise = removeCycleFromFavorites(
- workspaceSlug?.toString(),
- projectId.toString(),
- cycleId
- ).then(() => {
- captureEvent(CYCLE_UNFAVORITED, {
- cycle_id: cycleId,
- element: "List layout",
- state: "SUCCESS",
- });
- });
-
- setPromiseToast(removeFromFavoritePromise, {
- loading: "Removing cycle from favorites...",
- success: {
- title: "Success!",
- message: () => "Cycle removed from favorites.",
- },
- error: {
- title: "Error!",
- message: () => "Couldn't remove the cycle from favorites. Please try again.",
- },
- });
- };
-
- if (!cycle) return null;
-
- return (
-
- {cycle.name}
-
- {cycle.start_date && cycle.end_date && (
-
- {renderFormattedDate(cycle.start_date)} - {renderFormattedDate(cycle.end_date)}
-
- )}
- {cycle.assignee_ids && cycle.assignee_ids?.length > 0 ? (
-
- {cycle.assignee_ids?.map((assigneeId) => {
- const member = getUserDetails(assigneeId);
- return ;
- })}
-
- ) : (
-
- )}
-
-
{
- if (cycle.is_favorite) handleRemoveFromFavorites(e);
- else handleAddToFavorites(e);
- }}
- selected={!!cycle.is_favorite}
- />
-
- {workspaceSlug && projectId && (
-
- )}
-
-
- );
-});
diff --git a/web/core/components/cycles/active-cycle/upcoming-cycles-list.tsx b/web/core/components/cycles/active-cycle/upcoming-cycles-list.tsx
deleted file mode 100644
index 221ffab0b..000000000
--- a/web/core/components/cycles/active-cycle/upcoming-cycles-list.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import { FC } from "react";
-import { observer } from "mobx-react";
-import Image from "next/image";
-import { useTheme } from "next-themes";
-// components
-import { UpcomingCycleListItem } from "@/components/cycles";
-// hooks
-import { useCycle } from "@/hooks/store";
-
-type Props = {
- handleEmptyStateAction: () => void;
-};
-
-export const UpcomingCyclesList: FC = observer((props) => {
- const { handleEmptyStateAction } = props;
- // store hooks
- const { currentProjectUpcomingCycleIds } = useCycle();
-
- // theme
- const { resolvedTheme } = useTheme();
-
- const resolvedEmptyStatePath = `/empty-state/active-cycle/cycle-${resolvedTheme === "light" ? "light" : "dark"}.webp`;
-
- if (!currentProjectUpcomingCycleIds) return null;
-
- return (
-
-
- Next cycles
-
- {currentProjectUpcomingCycleIds.length > 0 ? (
-
- {currentProjectUpcomingCycleIds.map((cycleId) => (
-
- ))}
-
- ) : (
-
-
-
-
-
-
No upcoming cycles
-
- Create new cycles to find them here or check
-
- {"'"}All{"'"} cycles tab to see all cycles or{" "}
-
-
-
-
- )}
-
- );
-});
diff --git a/web/core/components/cycles/analytics-sidebar/progress-stats.tsx b/web/core/components/cycles/analytics-sidebar/progress-stats.tsx
index e98871b40..069ccb2ff 100644
--- a/web/core/components/cycles/analytics-sidebar/progress-stats.tsx
+++ b/web/core/components/cycles/analytics-sidebar/progress-stats.tsx
@@ -17,6 +17,7 @@ import { Avatar, StateGroupIcon } from "@plane/ui";
import { SingleProgressStats } from "@/components/core";
// helpers
import { cn } from "@/helpers/common.helper";
+import { getFileURL } from "@/helpers/file.helper";
// hooks
import { useProjectState } from "@/hooks/store";
import useLocalStorage from "@/hooks/use-local-storage";
@@ -28,7 +29,7 @@ import emptyMembers from "@/public/empty-state/empty_members.svg";
type TAssigneeData = {
id: string | undefined;
title: string | undefined;
- avatar: string | undefined;
+ avatar_url: string | undefined;
completed: number;
total: number;
}[];
@@ -82,7 +83,7 @@ export const AssigneeStatComponent = observer((props: TAssigneeStatComponent) =>
key={assignee?.id}
title={
-
+
{assignee?.title ?? ""}
}
@@ -277,14 +278,14 @@ export const CycleProgressStats: FC = observer((props) => {
? (currentDistribution?.assignees || []).map((assignee) => ({
id: assignee?.assignee_id || undefined,
title: assignee?.display_name || undefined,
- avatar: assignee?.avatar || undefined,
+ avatar_url: assignee?.avatar_url || undefined,
completed: assignee.completed_issues,
total: assignee.total_issues,
}))
: (currentEstimateDistribution?.assignees || []).map((assignee) => ({
id: assignee?.assignee_id || undefined,
title: assignee?.display_name || undefined,
- avatar: assignee?.avatar || undefined,
+ avatar_url: assignee?.avatar_url || undefined,
completed: assignee.completed_estimates,
total: assignee.total_estimates,
}));
diff --git a/web/core/components/cycles/analytics-sidebar/root.tsx b/web/core/components/cycles/analytics-sidebar/root.tsx
index 8bea7edfe..fd8c984a6 100644
--- a/web/core/components/cycles/analytics-sidebar/root.tsx
+++ b/web/core/components/cycles/analytics-sidebar/root.tsx
@@ -7,8 +7,8 @@ import { useParams } from "next/navigation";
import { Loader } from "@plane/ui";
// components
import { CycleAnalyticsProgress, CycleSidebarHeader, CycleSidebarDetails } from "@/components/cycles";
-import useCyclesDetails from "../active-cycle/use-cycles-details";
// hooks
+import useCyclesDetails from "../active-cycle/use-cycles-details";
type Props = {
handleClose: () => void;
diff --git a/web/core/components/cycles/analytics-sidebar/sidebar-details.tsx b/web/core/components/cycles/analytics-sidebar/sidebar-details.tsx
index 708b9c217..c60b5dae9 100644
--- a/web/core/components/cycles/analytics-sidebar/sidebar-details.tsx
+++ b/web/core/components/cycles/analytics-sidebar/sidebar-details.tsx
@@ -3,13 +3,15 @@ import React, { FC } from "react";
import isEmpty from "lodash/isEmpty";
import { observer } from "mobx-react";
import { LayersIcon, SquareUser, Users } from "lucide-react";
-// types
+// plane types
import { ICycle } from "@plane/types";
-// ui
+// plane ui
import { Avatar, AvatarGroup, TextArea } from "@plane/ui";
+// helpers
+import { getFileURL } from "@/helpers/file.helper";
// hooks
import { useMember, useProjectEstimates } from "@/hooks/store";
-// plane web
+// plane web constants
import { EEstimateSystem } from "@/plane-web/constants/estimates";
type Props = {
@@ -72,7 +74,7 @@ export const CycleSidebarDetails: FC = observer((props) => {