forked from github/plane
fix: issue archive improvement, chore: code refactor (#1520)
* style: select month modal * chore: automation setting dropdown updated ,style: month dropdown styling * chore: restore issue alert message updated * chore: archive issue fetching updated and code refactor * fix: build fix
This commit is contained in:
parent
a829e6fc40
commit
3f3fb373cc
@ -33,8 +33,8 @@ export const AutoArchiveAutomation: React.FC<Props> = ({ projectDetails, handleC
|
||||
<div className="flex flex-col gap-2.5">
|
||||
<h4 className="text-lg font-semibold">Auto-archive closed issues</h4>
|
||||
<p className="text-sm text-brand-secondary">
|
||||
Plane will automatically archive issues that have been completed or canceled for the
|
||||
configured time period
|
||||
Plane will automatically archive issues that have been completed or cancelled for the
|
||||
configured time period.
|
||||
</p>
|
||||
</div>
|
||||
<ToggleSwitch
|
||||
@ -59,7 +59,9 @@ export const AutoArchiveAutomation: React.FC<Props> = ({ projectDetails, handleC
|
||||
value={projectDetails?.archive_in}
|
||||
customButton={
|
||||
<button className="flex w-full items-center justify-between gap-1 rounded-md border border-brand-base shadow-sm duration-300 text-brand-secondary hover:text-brand-base hover:bg-brand-surface-2 focus:outline-none px-3 py-2 text-sm text-left">
|
||||
{`${projectDetails?.archive_in} Months`}
|
||||
{`${projectDetails?.archive_in} ${
|
||||
projectDetails?.archive_in === 1 ? "Month" : "Months"
|
||||
}`}
|
||||
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
||||
</button>
|
||||
}
|
||||
@ -67,6 +69,7 @@ export const AutoArchiveAutomation: React.FC<Props> = ({ projectDetails, handleC
|
||||
handleChange({ archive_in: val });
|
||||
}}
|
||||
input
|
||||
verticalPosition="top"
|
||||
width="w-full"
|
||||
>
|
||||
<>
|
||||
@ -78,12 +81,10 @@ export const AutoArchiveAutomation: React.FC<Props> = ({ projectDetails, handleC
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full select-none items-center rounded py-2 px-1 hover:bg-custom-background-80"
|
||||
className="flex w-full select-none items-center rounded px-1 py-1.5 text-custom-text-200 hover:bg-custom-background-80"
|
||||
onClick={() => setmonthModal(true)}
|
||||
>
|
||||
<span className="flex items-center justify-start gap-1 text-custom-text-200">
|
||||
<span>Customize Time Range</span>
|
||||
</span>
|
||||
Customize Time Range
|
||||
</button>
|
||||
</>
|
||||
</CustomSelect>
|
||||
|
@ -109,7 +109,9 @@ export const AutoCloseAutomation: React.FC<Props> = ({ projectDetails, handleCha
|
||||
value={projectDetails?.close_in}
|
||||
customButton={
|
||||
<button className="flex w-full items-center justify-between gap-1 rounded-md border border-brand-base shadow-sm duration-300 text-brand-secondary hover:text-brand-base hover:bg-brand-surface-2 focus:outline-none px-3 py-2 text-sm text-left">
|
||||
{`${projectDetails?.close_in} Months`}
|
||||
{`${projectDetails?.close_in} ${
|
||||
projectDetails?.close_in === 1 ? "Month" : "Months"
|
||||
}`}
|
||||
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
||||
</button>
|
||||
}
|
||||
@ -125,15 +127,12 @@ export const AutoCloseAutomation: React.FC<Props> = ({ projectDetails, handleCha
|
||||
{month.label}
|
||||
</CustomSelect.Option>
|
||||
))}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full select-none items-center rounded py-2 px-1 hover:bg-custom-background-80"
|
||||
className="flex w-full select-none items-center rounded px-1 py-1.5 text-custom-text-200 hover:bg-custom-background-80"
|
||||
onClick={() => setmonthModal(true)}
|
||||
>
|
||||
<span className="flex items-center justify-start gap-1 text-custom-text-200">
|
||||
<span>Customize Time Range</span>
|
||||
</span>
|
||||
Customize Time Range
|
||||
</button>
|
||||
</>
|
||||
</CustomSelect>
|
||||
|
@ -65,7 +65,7 @@ export const SelectMonthModal: React.FC<Props> = ({
|
||||
min: 1,
|
||||
max: 12,
|
||||
}}
|
||||
style={{ appearance: "none" }}
|
||||
className="border-custom-border-200"
|
||||
/>
|
||||
<span className="absolute text-sm text-custom-text-200 top-2.5 right-8">Months</span>
|
||||
</div>
|
||||
|
@ -28,13 +28,13 @@ import { SUB_ISSUES } from "constants/fetch-keys";
|
||||
type Props = {
|
||||
issueDetails: IIssue;
|
||||
submitChanges: (formData: Partial<IIssue>) => Promise<void>;
|
||||
nonEditable?: boolean;
|
||||
uneditable?: boolean;
|
||||
};
|
||||
|
||||
export const IssueMainContent: React.FC<Props> = ({
|
||||
issueDetails,
|
||||
submitChanges,
|
||||
nonEditable = false,
|
||||
uneditable = false,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, issueId, archivedIssueId } = router.query;
|
||||
@ -100,16 +100,16 @@ export const IssueMainContent: React.FC<Props> = ({
|
||||
<IssueDescriptionForm
|
||||
issue={issueDetails}
|
||||
handleFormSubmit={submitChanges}
|
||||
isAllowed={memberRole.isMember || memberRole.isOwner || !nonEditable}
|
||||
isAllowed={memberRole.isMember || memberRole.isOwner || !uneditable}
|
||||
/>
|
||||
<div className="mt-2 space-y-2">
|
||||
<SubIssuesList parentIssue={issueDetails} user={user} disabled={nonEditable} />
|
||||
<SubIssuesList parentIssue={issueDetails} user={user} disabled={uneditable} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-3 py-3">
|
||||
<h3 className="text-lg">Attachments</h3>
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4">
|
||||
<IssueAttachmentUpload disabled={nonEditable} />
|
||||
<IssueAttachmentUpload disabled={uneditable} />
|
||||
<IssueAttachments />
|
||||
</div>
|
||||
</div>
|
||||
@ -122,7 +122,7 @@ export const IssueMainContent: React.FC<Props> = ({
|
||||
<AddComment
|
||||
issueId={(archivedIssueId as string) ?? (issueId as string)}
|
||||
user={user}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
@ -73,7 +73,7 @@ type Props = {
|
||||
| "delete"
|
||||
| "all"
|
||||
)[];
|
||||
nonEditable?: boolean;
|
||||
uneditable?: boolean;
|
||||
};
|
||||
|
||||
const defaultValues: Partial<IIssueLabels> = {
|
||||
@ -87,7 +87,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
issueDetail,
|
||||
watch: watchIssue,
|
||||
fieldsToShow = ["all"],
|
||||
nonEditable = false,
|
||||
uneditable = false,
|
||||
}) => {
|
||||
const [createLabelForm, setCreateLabelForm] = useState(false);
|
||||
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
|
||||
@ -310,7 +310,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={`divide-y-2 divide-custom-border-100 ${nonEditable ? "opacity-60" : ""}`}>
|
||||
<div className={`divide-y-2 divide-custom-border-100 ${uneditable ? "opacity-60" : ""}`}>
|
||||
{showFirstSection && (
|
||||
<div className="py-1">
|
||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("state")) && (
|
||||
@ -322,7 +322,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
value={value}
|
||||
onChange={(val: string) => submitChanges({ state: val })}
|
||||
userAuth={memberRole}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -336,7 +336,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
value={value}
|
||||
onChange={(val: string[]) => submitChanges({ assignees_list: val })}
|
||||
userAuth={memberRole}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -350,7 +350,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
value={value}
|
||||
onChange={(val: string) => submitChanges({ priority: val })}
|
||||
userAuth={memberRole}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -364,7 +364,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
value={value}
|
||||
onChange={(val: number | null) => submitChanges({ estimate_point: val })}
|
||||
userAuth={memberRole}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -396,7 +396,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
}
|
||||
watch={watchIssue}
|
||||
userAuth={memberRole}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
/>
|
||||
)}
|
||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("blocker")) && (
|
||||
@ -405,7 +405,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
submitChanges={submitChanges}
|
||||
watch={watchIssue}
|
||||
userAuth={memberRole}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
/>
|
||||
)}
|
||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("blocked")) && (
|
||||
@ -414,7 +414,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
submitChanges={submitChanges}
|
||||
watch={watchIssue}
|
||||
userAuth={memberRole}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
/>
|
||||
)}
|
||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("dueDate")) && (
|
||||
@ -437,7 +437,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
})
|
||||
}
|
||||
className="bg-custom-background-90"
|
||||
disabled={isNotAllowed || nonEditable}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -453,7 +453,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
issueDetail={issueDetail}
|
||||
handleCycleChange={handleCycleChange}
|
||||
userAuth={memberRole}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
/>
|
||||
)}
|
||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("module")) && (
|
||||
@ -461,14 +461,14 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
issueDetail={issueDetail}
|
||||
handleModuleChange={handleModuleChange}
|
||||
userAuth={memberRole}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("label")) && (
|
||||
<div className={`space-y-3 py-3 ${nonEditable ? "opacity-60" : ""}`}>
|
||||
<div className={`space-y-3 py-3 ${uneditable ? "opacity-60" : ""}`}>
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex basis-1/2 items-center gap-x-2 text-sm text-custom-text-200">
|
||||
<TagIcon className="h-4 w-4" />
|
||||
@ -515,13 +515,13 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
onChange={(val: any) => submitChanges({ labels_list: val })}
|
||||
className="flex-shrink-0"
|
||||
multiple
|
||||
disabled={isNotAllowed || nonEditable}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
>
|
||||
{({ open }) => (
|
||||
<div className="relative">
|
||||
<Listbox.Button
|
||||
className={`flex ${
|
||||
isNotAllowed || nonEditable
|
||||
isNotAllowed || uneditable
|
||||
? "cursor-not-allowed"
|
||||
: "cursor-pointer hover:bg-custom-background-90"
|
||||
} items-center gap-2 rounded-2xl border border-custom-border-100 px-2 py-0.5 text-xs text-custom-text-200`}
|
||||
@ -626,12 +626,12 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
<button
|
||||
type="button"
|
||||
className={`flex ${
|
||||
isNotAllowed || nonEditable
|
||||
isNotAllowed || uneditable
|
||||
? "cursor-not-allowed"
|
||||
: "cursor-pointer hover:bg-custom-background-90"
|
||||
} items-center gap-1 rounded-2xl border border-custom-border-100 px-2 py-0.5 text-xs text-custom-text-200`}
|
||||
onClick={() => setCreateLabelForm((prevData) => !prevData)}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
>
|
||||
{createLabelForm ? (
|
||||
<>
|
||||
@ -722,17 +722,17 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("link")) && (
|
||||
<div className={`min-h-[116px] py-1 text-xs ${nonEditable ? "opacity-60" : ""}`}>
|
||||
<div className={`min-h-[116px] py-1 text-xs ${uneditable ? "opacity-60" : ""}`}>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<h4>Links</h4>
|
||||
{!isNotAllowed && (
|
||||
<button
|
||||
type="button"
|
||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-custom-background-90 ${
|
||||
nonEditable ? "cursor-not-allowed" : "cursor-pointer"
|
||||
uneditable ? "cursor-not-allowed" : "cursor-pointer"
|
||||
}`}
|
||||
onClick={() => setLinkModal(true)}
|
||||
disabled={nonEditable}
|
||||
disabled={uneditable}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
</button>
|
||||
|
@ -71,11 +71,11 @@ export const PROJECT_ISSUES_LIST_WITH_PARAMS = (projectId: string, params?: any)
|
||||
return `PROJECT_ISSUES_LIST_WITH_PARAMS_${projectId.toUpperCase()}_${paramsKey}`;
|
||||
};
|
||||
export const PROJECT_ARCHIVED_ISSUES_LIST_WITH_PARAMS = (projectId: string, params?: any) => {
|
||||
if (!params) return `PROJECT_ARCHIVED_ISSUES_LIST_WITH_PARAMS${projectId.toUpperCase()}`;
|
||||
if (!params) return `PROJECT_ARCHIVED_ISSUES_LIST_WITH_PARAMS_${projectId.toUpperCase()}`;
|
||||
|
||||
const paramsKey = paramsToKey(params);
|
||||
|
||||
return `PROJECT_ARCHIVED_ISSUES_LIST_WITH_PARAMS${projectId.toUpperCase()}_${paramsKey}`;
|
||||
return `PROJECT_ARCHIVED_ISSUES_LIST_WITH_PARAMS_${projectId.toUpperCase()}_${paramsKey}`;
|
||||
};
|
||||
export const PROJECT_ISSUES_DETAILS = (issueId: string) =>
|
||||
`PROJECT_ISSUES_DETAILS_${issueId.toUpperCase()}`;
|
||||
|
@ -28,7 +28,7 @@ export const MONTHS = [
|
||||
export const DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
||||
|
||||
export const PROJECT_AUTOMATION_MONTHS = [
|
||||
{ label: "1 Months", value: 1 },
|
||||
{ label: "1 Month", value: 1 },
|
||||
{ label: "3 Months", value: 3 },
|
||||
{ label: "6 Months", value: 6 },
|
||||
{ label: "9 Months", value: 9 },
|
||||
|
@ -44,7 +44,7 @@ const useIssuesView = () => {
|
||||
} = useContext(issueViewContext);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId, archivedIssueId } = router.query;
|
||||
const isArchivedIssues = router.pathname.includes("archived-issues");
|
||||
|
||||
const params: any = {
|
||||
@ -76,10 +76,10 @@ const useIssuesView = () => {
|
||||
);
|
||||
|
||||
const { data: projectArchivedIssues } = useSWR(
|
||||
workspaceSlug && projectId
|
||||
workspaceSlug && projectId && params && isArchivedIssues && !archivedIssueId
|
||||
? PROJECT_ARCHIVED_ISSUES_LIST_WITH_PARAMS(projectId as string, params)
|
||||
: null,
|
||||
workspaceSlug && projectId && params
|
||||
workspaceSlug && projectId && params && isArchivedIssues && !archivedIssueId
|
||||
? () => issuesService.getArchivedIssues(workspaceSlug as string, projectId as string, params)
|
||||
: null
|
||||
);
|
||||
|
@ -118,12 +118,12 @@ const ArchivedIssueDetailsPage: NextPage = () => {
|
||||
if (!workspaceSlug || !projectId || !archivedIssueId) return;
|
||||
|
||||
await issuesService
|
||||
.unArchivedIssue(workspaceSlug as string, projectId as string, archivedIssueId as string)
|
||||
.unarchiveIssue(workspaceSlug as string, projectId as string, archivedIssueId as string)
|
||||
.then(() => {
|
||||
setToastAlert({
|
||||
type: "success",
|
||||
title: "Success!",
|
||||
message: "Issue restored successfully.",
|
||||
title: "Success",
|
||||
message: `${issueDetails?.project_detail?.identifier}-${issueDetails?.sequence_id} is restored successfully under the project ${issueDetails?.project_detail?.name}`,
|
||||
});
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/issues/${archivedIssueId}`);
|
||||
})
|
||||
@ -174,7 +174,7 @@ const ArchivedIssueDetailsPage: NextPage = () => {
|
||||
<IssueMainContent
|
||||
issueDetails={issueDetails}
|
||||
submitChanges={submitChanges}
|
||||
nonEditable
|
||||
uneditable
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -184,7 +184,7 @@ const ArchivedIssueDetailsPage: NextPage = () => {
|
||||
issueDetail={issueDetails}
|
||||
submitChanges={submitChanges}
|
||||
watch={watch}
|
||||
nonEditable
|
||||
uneditable
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -536,7 +536,7 @@ class ProjectIssuesServices extends APIService {
|
||||
});
|
||||
}
|
||||
|
||||
async unArchivedIssue(workspaceSlug: string, projectId: string, issueId: string): Promise<any> {
|
||||
async unarchiveIssue(workspaceSlug: string, projectId: string, issueId: string): Promise<any> {
|
||||
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/unarchive/${issueId}/`)
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
|
Loading…
Reference in New Issue
Block a user