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

[WEB-2941]chore: added transfer issues button to cycles #6294

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/ui/src/icons/transfer-icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as React from "react";
import { ISvgIcons } from "./type";

export const TransferIcon: React.FC<ISvgIcons> = ({ className = "fill-current", ...rest }) => (
<svg viewBox="0 0 24 24" className={`${className} `} fill="none" xmlns="http://www.w3.org/2000/svg" {...rest}>
<svg viewBox="0 0 24 20" className={`${className} `} fill="none" xmlns="http://www.w3.org/2000/svg" {...rest}>
<path d="M6.16683 14.6667C4.54183 14.6667 3.16336 14.1007 2.03141 12.9688C0.899468 11.8368 0.333496 10.4583 0.333496 8.83333C0.333496 7.125 0.941135 5.73264 2.15641 4.65625C3.37169 3.57986 4.72933 3.09028 6.22933 3.1875L4.87516 1.83333C4.75016 1.70833 4.68766 1.55903 4.68766 1.38542C4.68766 1.21181 4.75016 1.0625 4.87516 0.9375C5.00016 0.8125 5.14947 0.75 5.32308 0.75C5.49669 0.75 5.646 0.8125 5.771 0.9375L8.22933 3.39583C8.29877 3.46528 8.34739 3.53472 8.37516 3.60417C8.40294 3.67361 8.41683 3.75 8.41683 3.83333C8.41683 3.91667 8.40294 3.99306 8.37516 4.0625C8.34739 4.13194 8.29877 4.20139 8.22933 4.27083L5.771 6.72917C5.646 6.85417 5.50016 6.91319 5.3335 6.90625C5.16683 6.89931 5.021 6.83333 4.896 6.70833C4.771 6.58333 4.7085 6.43403 4.7085 6.26042C4.7085 6.08681 4.771 5.9375 4.896 5.8125L6.29183 4.41667C4.97239 4.38889 3.8578 4.79167 2.94808 5.625C2.03836 6.45833 1.5835 7.52778 1.5835 8.83333C1.5835 10.0972 2.03141 11.1771 2.92725 12.0729C3.82308 12.9688 4.90294 13.4167 6.16683 13.4167H8.04183C8.22239 13.4167 8.37169 13.4757 8.48975 13.5938C8.6078 13.7118 8.66683 13.8611 8.66683 14.0417C8.66683 14.2222 8.6078 14.3715 8.48975 14.4896C8.37169 14.6076 8.22239 14.6667 8.04183 14.6667H6.16683ZM11.5835 14.6667C11.2363 14.6667 10.9411 14.5451 10.6981 14.3021C10.455 14.059 10.3335 13.7639 10.3335 13.4167V10.0833C10.3335 9.73611 10.455 9.44097 10.6981 9.19792C10.9411 8.95486 11.2363 8.83333 11.5835 8.83333H16.5835C16.9307 8.83333 17.2259 8.95486 17.4689 9.19792C17.712 9.44097 17.8335 9.73611 17.8335 10.0833V13.4167C17.8335 13.7639 17.712 14.059 17.4689 14.3021C17.2259 14.5451 16.9307 14.6667 16.5835 14.6667H11.5835ZM11.5835 13.4167H16.5835V10.0833H11.5835V13.4167ZM11.5835 7.16667C11.2363 7.16667 10.9411 7.04514 10.6981 6.80208C10.455 6.55903 10.3335 6.26389 10.3335 5.91667V2.58333C10.3335 2.23611 10.455 1.94097 10.6981 1.69792C10.9411 1.45486 11.2363 1.33333 11.5835 1.33333H16.5835C16.9307 1.33333 17.2259 1.45486 17.4689 1.69792C17.712 1.94097 17.8335 2.23611 17.8335 2.58333V5.91667C17.8335 6.26389 17.712 6.55903 17.4689 6.80208C17.2259 7.04514 16.9307 7.16667 16.5835 7.16667H11.5835Z" />
</svg>
);
1 change: 1 addition & 0 deletions web/ce/components/cycles/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./active-cycle";
export * from "./analytics-sidebar";
export * from "./quick-actions";
1 change: 0 additions & 1 deletion web/core/components/cycles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export * from "./cycles-view";
export * from "./delete-modal";
export * from "./form";
export * from "./modal";
export * from "./quick-actions";
export * from "./transfer-issues-modal";
export * from "./transfer-issues";
export * from "./cycles-view-header";
Expand Down
28 changes: 26 additions & 2 deletions web/core/components/cycles/list/cycle-list-item-action.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import React, { FC, MouseEvent, useEffect, useMemo } from "react";
import React, { FC, MouseEvent, useEffect, useMemo, useState } from "react";
import { observer } from "mobx-react";
import { usePathname, useSearchParams } from "next/navigation";
import { Controller, useForm } from "react-hook-form";
Expand All @@ -15,11 +15,12 @@ import {
LayersIcon,
TOAST_TYPE,
Tooltip,
TransferIcon,
setPromiseToast,
setToast,
} from "@plane/ui";
// components
import { CycleQuickActions } from "@/components/cycles";
import { TransferIssuesModal } from "@/components/cycles";
import { DateRangeDropdown } from "@/components/dropdowns";
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
// constants
Expand All @@ -32,6 +33,8 @@ import { generateQueryParams } from "@/helpers/router.helper";
import { useCycle, useEventTracker, useMember, useUserPermissions } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web
import { CycleQuickActions } from "@/plane-web/components/cycles";
// plane web constants
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
// services
Expand All @@ -55,6 +58,8 @@ const defaultValues: Partial<ICycle> = {

export const CycleListItemAction: FC<Props> = observer((props) => {
const { workspaceSlug, projectId, cycleId, cycleDetails, parentRef, isActive = false } = props;
//states
const [transferIssuesModal, setTransferIssuesModal] = useState(false);
// hooks
const { isMobile } = usePlatformOS();
// router
Expand All @@ -76,6 +81,8 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
// derived values
const cycleStatus = cycleDetails.status ? (cycleDetails.status.toLocaleLowerCase() as TCycleGroups) : "draft";
const showIssueCount = useMemo(() => cycleStatus === "draft" || cycleStatus === "upcoming", [cycleStatus]);
const transferableIssuesCount = cycleDetails ? cycleDetails.total_issues - cycleDetails.completed_issues : 0;
const showTransferIssues = transferableIssuesCount > 0 && cycleStatus === "completed";
const isEditingAllowed = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.PROJECT,
Expand Down Expand Up @@ -218,6 +225,11 @@ export const CycleListItemAction: FC<Props> = observer((props) => {

return (
<>
<TransferIssuesModal
handleClose={() => setTransferIssuesModal(false)}
isOpen={transferIssuesModal}
cycleId={cycleId.toString()}
/>
<button
onClick={openCycleOverview}
className={`z-[1] flex text-custom-primary-200 text-xs gap-1 flex-shrink-0 ${isMobile || (isActive && !searchParams.has("peekCycle")) ? "flex" : "hidden group-hover:flex"}`}
Expand All @@ -233,6 +245,18 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
</div>
)}

{showTransferIssues && (
<div
className="px-2 h-6 text-custom-primary-200 flex items-center gap-1 cursor-pointer"
onClick={() => {
setTransferIssuesModal(true);
}}
>
<TransferIcon className="fill-custom-primary-200 w-4" />
<span>Transfer {transferableIssuesCount} issues</span>
</div>
)}

{!isActive && (
<Controller
control={control}
Expand Down
3 changes: 2 additions & 1 deletion web/core/components/cycles/list/cycles-list-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import { generateQueryParams } from "@/helpers/router.helper";
import { useCycle } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
import { usePlatformOS } from "@/hooks/use-platform-os";
import { CycleQuickActions } from "../quick-actions";
// plane web
import { CycleQuickActions } from "@/plane-web/components/cycles";

type TCyclesListItem = {
cycleId: string;
Expand Down
36 changes: 26 additions & 10 deletions web/core/components/cycles/transfer-issues-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,58 @@ import { useCycle, useIssues } from "@/hooks/store";
type Props = {
isOpen: boolean;
handleClose: () => void;
cycleId: string;
};

export const TransferIssuesModal: React.FC<Props> = observer((props) => {
const { isOpen, handleClose } = props;
const { isOpen, handleClose, cycleId } = props;
// states
const [query, setQuery] = useState("");

// store hooks
const { currentProjectIncompleteCycleIds, getCycleById } = useCycle();
const { currentProjectIncompleteCycleIds, getCycleById, fetchCycleDetails } = useCycle();
const {
issues: { transferIssuesFromCycle },
} = useIssues(EIssuesStoreType.CYCLE);

const { workspaceSlug, projectId, cycleId } = useParams();
const { workspaceSlug, projectId } = useParams();

const transferIssue = async (payload: any) => {
const transferIssue = async (payload: { new_cycle_id: string }) => {
if (!workspaceSlug || !projectId || !cycleId) return;

// TODO: import transferIssuesFromCycle from store
await transferIssuesFromCycle(workspaceSlug.toString(), projectId.toString(), cycleId.toString(), payload)
.then(() => {
.then(async () => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
message: "Issues have been transferred successfully",
});
await getCycleDetails(payload.new_cycle_id);
})
.catch(() => {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Issues cannot be transfer. Please try again.",
message: "Unable to transfer Issues. Please try again.",
});
});
};

/**To update issue counts in target cycle and current cycle */
const getCycleDetails = async (newCycleId: string) => {
const cyclesFetch = [
fetchCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleId),
fetchCycleDetails(workspaceSlug.toString(), projectId.toString(), newCycleId),
];
await Promise.all(cyclesFetch).catch((error) => {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error",
message: error.error || "Unable to fetch cycle details",
});
});
};

const filteredOptions = currentProjectIncompleteCycleIds?.filter((optionId) => {
const cycleDetails = getCycleById(optionId);

Expand Down Expand Up @@ -96,8 +112,8 @@ export const TransferIssuesModal: React.FC<Props> = observer((props) => {
<Dialog.Panel className="relative transform rounded-lg bg-custom-background-100 py-5 text-left shadow-custom-shadow-md transition-all sm:w-full sm:max-w-2xl">
<div className="flex flex-col gap-4">
<div className="flex items-center justify-between px-5">
<div className="flex items-center gap-3">
<TransferIcon className="h-4 w-4" color="#495057" />
<div className="flex items-center gap-1">
<TransferIcon className="w-5 fill-custom-text-100" />
<h4 className="text-xl font-medium text-custom-text-100">Transfer Issues</h4>
</div>
<button onClick={handleClose}>
Expand All @@ -107,7 +123,7 @@ export const TransferIssuesModal: React.FC<Props> = observer((props) => {
<div className="flex items-center gap-2 border-b border-custom-border-200 px-5 pb-3">
<Search className="h-4 w-4 text-custom-text-200" />
<input
className="bg-custom-background-90 outline-none"
className="outline-none text-sm"
placeholder="Search for a cycle..."
onChange={(e) => setQuery(e.target.value)}
value={query}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export const CycleLayoutRoot: React.FC = observer(() => {

return (
<IssuesStoreContext.Provider value={EIssuesStoreType.CYCLE}>
<TransferIssuesModal handleClose={() => setTransferIssuesModal(false)} isOpen={transferIssuesModal} />
<TransferIssuesModal handleClose={() => setTransferIssuesModal(false)} cycleId="" isOpen={transferIssuesModal} />
vamsikrishnamathala marked this conversation as resolved.
Show resolved Hide resolved
<div className="relative flex h-full w-full flex-col overflow-hidden">
{cycleStatus === "completed" && (
<TransferIssues
Expand Down
5 changes: 5 additions & 0 deletions web/core/constants/cycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,8 @@ export const WORKSPACE_ACTIVE_CYCLES_DETAILS = [
icon: Microscope,
},
];

export enum ECycleAction {
START = "start",
STOP = "stop",
}
6 changes: 6 additions & 0 deletions web/core/store/cycle.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
TCycleDistribution,
TCycleEstimateType,
} from "@plane/types";
// constants
import { ECycleAction } from "@/constants/cycle";
// helpers
import { orderCycles, shouldFilterCycle } from "@/helpers/cycle.helper";
import { getDate } from "@/helpers/date-time.helper";
Expand Down Expand Up @@ -91,6 +93,7 @@ export interface ICycleStore {
// archive
archiveCycle: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<void>;
restoreCycle: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<void>;
updateCycleState: (workspaceSlug: string, projectId: string, cycleId: string, action: ECycleAction) => Promise<void>;
}

export class CycleStore implements ICycleStore {
Expand Down Expand Up @@ -718,4 +721,7 @@ export class CycleStore implements ICycleStore {
console.error("Failed to restore cycle in cycle store", error);
});
};

// eslint-disable-next-line @typescript-eslint/no-unused-vars
updateCycleState = async (workspaceSlug: string, projectId: string, cycleId: string, action: ECycleAction) => {};
vamsikrishnamathala marked this conversation as resolved.
Show resolved Hide resolved
}
1 change: 1 addition & 0 deletions web/ee/components/cycles/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./active-cycle";
export * from "./analytics-sidebar";
export * from "ce/components/cycles/quick-actions";
Loading