Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
20 changes: 19 additions & 1 deletion apiserver/back_migration.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# All the python scripts that are used for back migrations

from plane.db.models import ProjectIdentifier
from plane.db.models import Issue, IssueComment

# Update description and description html values for old descriptions
Expand Down Expand Up @@ -40,3 +40,21 @@ def update_comments():
except Exception as e:
print(e)
print("Failed")


def update_project_identifiers():
try:
project_identifiers = ProjectIdentifier.objects.filter(workspace_id=None).select_related("project", "project__workspace")
updated_identifiers = []

for identifier in project_identifiers:
identifier.workspace_id = identifier.project.workspace_id
updated_identifiers.append(identifier)

ProjectIdentifier.objects.bulk_update(
updated_identifiers, ["workspace_id"], batch_size=50
)
print("Success")
except Exception as e:
print(e)
print("Failed")
4 changes: 2 additions & 2 deletions apps/app/components/account/email-signin-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const EmailSignInForm: FC<EmailSignInFormProps> = (props) => {
<span className="bg-white px-2 text-gray-500">or</span>
</div>
</div>
<div className="mt-6 flex w-full flex-col items-stretch gap-y-2">
{/* <div className="mt-6 flex w-full flex-col items-stretch gap-y-2">
<button
type="button"
className="flex w-full items-center rounded border border-gray-300 px-3 py-2 text-sm duration-300 hover:bg-gray-100"
Expand All @@ -39,7 +39,7 @@ export const EmailSignInForm: FC<EmailSignInFormProps> = (props) => {
{useCode ? "Continue with Password" : "Continue with Code"}
</span>
</button>
</div>
</div> */}
</div>
</>
);
Expand Down
94 changes: 47 additions & 47 deletions apps/app/components/common/bulk-delete-issues-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import { IIssue, IssueResponse } from "types";
import { PROJECT_ISSUES_LIST, PROJECT_DETAILS } from "constants/fetch-keys";

type FormInput = {
issue_ids: string[];
cycleId: string;
delete_issue_ids: string[];
};

type Props = {
Expand Down Expand Up @@ -61,17 +60,27 @@ const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
const { setToastAlert } = useToast();

const {
register,
handleSubmit,
watch,
reset,
setValue,
formState: { isSubmitting },
} = useForm<FormInput>();
} = useForm<FormInput>({
defaultValues: {
delete_issue_ids: [],
},
});

const filteredIssues: IIssue[] =
query === ""
? issues?.results ?? []
: issues?.results.filter((issue) => issue.name.toLowerCase().includes(query.toLowerCase())) ??
[];
: issues?.results.filter(
(issue) =>
issue.name.toLowerCase().includes(query.toLowerCase()) ||
`${issue.project_detail.identifier}-${issue.sequence_id}`
.toLowerCase()
.includes(query.toLowerCase())
) ?? [];

const handleClose = () => {
setIsOpen(false);
Expand All @@ -80,7 +89,7 @@ const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
};

const handleDelete: SubmitHandler<FormInput> = async (data) => {
if (!data.issue_ids || data.issue_ids.length === 0) {
if (!data.delete_issue_ids || data.delete_issue_ids.length === 0) {
setToastAlert({
title: "Error",
type: "error",
Expand All @@ -89,30 +98,34 @@ const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
return;
}

if (!Array.isArray(data.issue_ids)) data.issue_ids = [data.issue_ids];
if (!Array.isArray(data.delete_issue_ids)) data.delete_issue_ids = [data.delete_issue_ids];

if (workspaceSlug && projectId) {
await issuesServices
.bulkDeleteIssues(workspaceSlug as string, projectId as string, data)
.bulkDeleteIssues(workspaceSlug as string, projectId as string, {
issue_ids: data.delete_issue_ids,
})
.then((res) => {
setToastAlert({
title: "Success",
type: "success",
message: res.message,
});

mutate<IssueResponse>(
PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
(prevData) => ({
...(prevData as IssueResponse),
count: (prevData?.results ?? []).filter(
(p) => !data.issue_ids.some((id) => p.id === id)
(p) => !data.delete_issue_ids.some((id) => p.id === id)
).length,
results: (prevData?.results ?? []).filter(
(p) => !data.issue_ids.some((id) => p.id === id)
(p) => !data.delete_issue_ids.some((id) => p.id === id)
),
}),
false
);
handleClose();
})
.catch((e) => {
console.log(e);
Expand All @@ -123,18 +136,6 @@ const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
return (
<Transition.Root show={isOpen} as={React.Fragment} afterLeave={() => setQuery("")} appear>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-gray-500 bg-opacity-25 transition-opacity" />
</Transition.Child>

<div className="fixed inset-0 z-20 overflow-y-auto p-4 sm:p-6 md:p-20">
<Transition.Child
as={React.Fragment}
Expand All @@ -145,15 +146,31 @@ const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative mx-auto max-w-2xl transform divide-y divide-gray-500 divide-opacity-10 rounded-xl bg-white bg-opacity-80 shadow-2xl ring-1 ring-black ring-opacity-5 backdrop-blur backdrop-filter transition-all">
<Dialog.Panel className="relative mx-auto max-w-2xl transform divide-y divide-gray-500 divide-opacity-10 rounded-xl bg-white shadow-2xl ring-1 ring-black ring-opacity-5 transition-all">
<form>
<Combobox>
<Combobox
onChange={(val: string) => {
const selectedIssues = watch("delete_issue_ids");
if (selectedIssues.includes(val))
setValue(
"delete_issue_ids",
selectedIssues.filter((i) => i !== val)
);
else {
const newToDelete = selectedIssues;
newToDelete.push(val);

setValue("delete_issue_ids", newToDelete);
}
}}
>
<div className="relative m-1">
<MagnifyingGlassIcon
className="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-gray-900 text-opacity-40"
aria-hidden="true"
/>
<Combobox.Input
<input
type="text"
className="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-gray-900 placeholder-gray-500 outline-none focus:ring-0 sm:text-sm"
placeholder="Search..."
onChange={(event) => setQuery(event.target.value)}
Expand All @@ -175,12 +192,8 @@ const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
{filteredIssues.map((issue) => (
<Combobox.Option
key={issue.id}
as="label"
htmlFor={`issue-${issue.id}`}
value={{
name: issue.name,
url: `/${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`,
}}
as="div"
value={issue.id}
className={({ active }) =>
`flex cursor-pointer select-none items-center justify-between rounded-md px-3 py-2 ${
active ? "bg-gray-900 bg-opacity-5 text-gray-900" : ""
Expand All @@ -190,9 +203,8 @@ const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
<div className="flex items-center gap-2">
<input
type="checkbox"
{...register("issue_ids")}
id={`issue-${issue.id}`}
value={issue.id}
checked={watch("delete_issue_ids").includes(issue.id)}
readOnly
/>
<span
className="block h-1.5 w-1.5 flex-shrink-0 rounded-full"
Expand All @@ -219,18 +231,6 @@ const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
</div>
)}
</Combobox.Options>

{query !== "" && filteredIssues.length === 0 && (
<div className="py-14 px-6 text-center sm:px-14">
<FolderIcon
className="mx-auto h-6 w-6 text-gray-900 text-opacity-40"
aria-hidden="true"
/>
<p className="mt-4 text-sm text-gray-900">
We couldn{"'"}t find any issue with that term. Please try again.
</p>
</div>
)}
</Combobox>

{filteredIssues.length > 0 && (
Expand Down
5 changes: 3 additions & 2 deletions apps/app/components/cycles/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import useSWR from "swr";
// headless ui
import { Listbox, Transition } from "@headlessui/react";
// icons
import { PlusIcon, ArrowPathIcon } from "@heroicons/react/24/outline";
import { PlusIcon } from "@heroicons/react/24/outline";
import { CyclesIcon } from "components/icons";
// services
import cycleServices from "services/cycles.service";
// components
Expand Down Expand Up @@ -65,7 +66,7 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({
<Listbox.Button
className={`flex cursor-pointer items-center gap-1 rounded-md border px-2 py-1 text-xs shadow-sm duration-300 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500`}
>
<ArrowPathIcon className="h-3 w-3 text-gray-500" />
<CyclesIcon className="h-3 w-3 text-gray-500" />
<div className="flex items-center gap-2 truncate">
{cycles?.find((c) => c.id === value)?.name ?? "Cycles"}
</div>
Expand Down
7 changes: 1 addition & 6 deletions apps/app/components/issues/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,6 @@ export const IssueForm: FC<IssueFormProps> = ({
setMostSimilarIssue(similarIssue);
};

const handleDiscard = () => {
reset({ ...defaultValues, project: projectId });
handleClose();
};

const handleCreateUpdateIssue = async (formData: Partial<IIssue>) => {
await handleFormSubmit(formData);

Expand Down Expand Up @@ -367,7 +362,7 @@ export const IssueForm: FC<IssueFormProps> = ({
</button>
</div>
<div className="flex items-center gap-2">
<Button theme="secondary" onClick={handleDiscard}>
<Button theme="secondary" onClick={handleClose}>
Discard
</Button>
<Button type="submit" disabled={isSubmitting}>
Expand Down
2 changes: 1 addition & 1 deletion apps/app/components/project/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const ProjectCard: React.FC<ProjectCardProps> = (props) => {
{project.icon && (
<span className="text-base">{String.fromCodePoint(parseInt(project.icon))}</span>
)}
<span className="w-3/4 max-w-[225px] md:max-w-[140px] xl:max-w-[225px] text-ellipsis overflow-hidden">
<span className=" max-w-[225px] w-[125px] xl:max-w-[225px] text-ellipsis overflow-hidden">
{project.name}
</span>
<span className="text-xs text-gray-500 ">{project.identifier}</span>
Expand Down
12 changes: 6 additions & 6 deletions apps/app/components/project/cycles/stats-view/single-stat.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// react
import React from "react";
// next

import Link from "next/link";
import Image from "next/image";
import { useRouter } from "next/router";

// swr
import useSWR from "swr";
// services
import { CalendarDaysIcon } from "@heroicons/react/20/solid";
import { ArrowPathIcon, UserIcon } from "@heroicons/react/24/outline";
import cyclesService from "services/cycles.service";
// hooks
// ui
import { Button, CustomMenu } from "components/ui";
// icons
import { CalendarDaysIcon } from "@heroicons/react/20/solid";
import { UserIcon } from "@heroicons/react/24/outline";
import { CyclesIcon } from "components/icons";
// helpers
import { renderShortNumericDateFormat } from "helpers/date-time.helper";
import { groupBy } from "helpers/array.helper";
Expand Down Expand Up @@ -120,7 +120,7 @@ const SingleStat: React.FC<TSingleStatProps> = (props) => {
router.push(`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`)
}
>
<ArrowPathIcon className="h-3 w-3" />
<CyclesIcon className="h-3 w-3" />
Open Cycle
</Button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { RectangleStackIcon, MagnifyingGlassIcon } from "@heroicons/react/24/out
// services
import issuesServices from "services/issues.service";
// types
import { IIssue } from "types";
import { IIssue, IssueResponse } from "types";
// constants
import { PROJECT_ISSUES_LIST, SUB_ISSUES } from "constants/fetch-keys";

Expand Down Expand Up @@ -54,6 +54,22 @@ const AddAsSubIssue: React.FC<Props> = ({ isOpen, setIsOpen, parent }) => {
.patchIssue(workspaceSlug as string, projectId as string, issueId, { parent: parent?.id })
.then((res) => {
mutate(SUB_ISSUES(parent?.id ?? ""));
mutate<IssueResponse>(
PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
(prevData) => ({
...(prevData as IssueResponse),
results: (prevData?.results ?? []).map((p) => {
if (p.id === res.id)
return {
...p,
...res,
};

return p;
}),
}),
false
);
})
.catch((e) => {
console.log(e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
// react
import React, { useEffect, useState } from "react";
// next

import Image from "next/image";
import dynamic from "next/dynamic";

// react-hook-form
import { useForm } from "react-hook-form";
// icons
import { CheckIcon, XMarkIcon } from "@heroicons/react/24/outline";
// types
import type { IIssueComment } from "types";
// hooks
import useUser from "hooks/use-user";
// ui
import { CustomMenu } from "components/ui";
// helpers
import { timeAgo } from "helpers/date-time.helper";
// types
import type { IIssueComment } from "types";

const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor"), { ssr: false });

Expand Down Expand Up @@ -76,7 +75,7 @@ const CommentCard: React.FC<Props> = ({ comment, onSubmit, handleCommentDeletion
</span>
<span>{timeAgo(comment.created_at)}</span>
</p>
<div>
<div className="issue-comments-section">
{isEditing ? (
<form className="flex flex-col gap-2" onSubmit={handleSubmit(onEnter)}>
<RemirrorRichTextEditor
Expand Down
Loading