From b47c7d363f260256ba36b712ee089c55b87be067 Mon Sep 17 00:00:00 2001 From: "M. Palanikannan" <73993394+Palanikannan1437@users.noreply.github.com> Date: Thu, 7 Sep 2023 12:22:02 +0530 Subject: [PATCH 01/11] fix: Improved Image Deletion Logic, Image ID Issue in Modals and Performance Optimization in Editor (#2092) * added improved delete logic in modals * added better ts support * impoved complexity to O(1) from O(n) for large docs * regression: removed ts nocheck --- web/components/tiptap/extensions/index.tsx | 222 +++++++++--------- .../tiptap/plugins/delete-image.tsx | 58 +++-- .../tiptap/plugins/upload-image.tsx | 1 - 3 files changed, 146 insertions(+), 135 deletions(-) diff --git a/web/components/tiptap/extensions/index.tsx b/web/components/tiptap/extensions/index.tsx index ea5d421a6..f5dc11384 100644 --- a/web/components/tiptap/extensions/index.tsx +++ b/web/components/tiptap/extensions/index.tsx @@ -32,122 +32,122 @@ export const TiptapExtensions = ( workspaceSlug: string, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ) => [ - StarterKit.configure({ - bulletList: { - HTMLAttributes: { - class: "list-disc list-outside leading-3 -mt-2", + StarterKit.configure({ + bulletList: { + HTMLAttributes: { + class: "list-disc list-outside leading-3 -mt-2", + }, }, - }, - orderedList: { - HTMLAttributes: { - class: "list-decimal list-outside leading-3 -mt-2", + orderedList: { + HTMLAttributes: { + class: "list-decimal list-outside leading-3 -mt-2", + }, }, - }, - listItem: { - HTMLAttributes: { - class: "leading-normal -mb-2", + listItem: { + HTMLAttributes: { + class: "leading-normal -mb-2", + }, }, - }, - blockquote: { - HTMLAttributes: { - class: "border-l-4 border-custom-border-300", + blockquote: { + HTMLAttributes: { + class: "border-l-4 border-custom-border-300", + }, }, - }, - code: { + code: { + HTMLAttributes: { + class: + "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000", + spellcheck: "false", + }, + }, + codeBlock: false, + horizontalRule: false, + dropcursor: { + color: "rgba(var(--color-text-100))", + width: 2, + }, + gapcursor: false, + }), + CodeBlockLowlight.configure({ + lowlight, + }), + HorizontalRule.extend({ + addInputRules() { + return [ + new InputRule({ + find: /^(?:---|—-|___\s|\*\*\*\s)$/, + handler: ({ state, range, commands }) => { + commands.splitBlock(); + + const attributes = {}; + const { tr } = state; + const start = range.from; + const end = range.to; + // @ts-ignore + tr.replaceWith(start - 1, end, this.type.create(attributes)); + }, + }), + ]; + }, + }).configure({ + HTMLAttributes: { + class: "mb-6 border-t border-custom-border-300", + }, + }), + Gapcursor, + TiptapLink.configure({ + protocols: ["http", "https"], + validate: (url) => isValidHttpUrl(url), HTMLAttributes: { class: - "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000", - spellcheck: "false", + "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", }, - }, - codeBlock: false, - horizontalRule: false, - dropcursor: { - color: "rgba(var(--color-text-100))", - width: 2, - }, - gapcursor: false, - }), - CodeBlockLowlight.configure({ - lowlight, - }), - HorizontalRule.extend({ - addInputRules() { - return [ - new InputRule({ - find: /^(?:---|—-|___\s|\*\*\*\s)$/, - handler: ({ state, range, commands }) => { - commands.splitBlock(); + }), + UpdatedImage.configure({ + HTMLAttributes: { + class: "rounded-lg border border-custom-border-300", + }, + }), + Placeholder.configure({ + placeholder: ({ node }) => { + if (node.type.name === "heading") { + return `Heading ${node.attrs.level}`; + } + if (node.type.name === "image" || node.type.name === "table") { + return ""; + } - const attributes = {}; - const { tr } = state; - const start = range.from; - const end = range.to; - // @ts-ignore - tr.replaceWith(start - 1, end, this.type.create(attributes)); - }, - }), - ]; - }, - }).configure({ - HTMLAttributes: { - class: "mb-6 border-t border-custom-border-300", - }, - }), - Gapcursor, - TiptapLink.configure({ - protocols: ["http", "https"], - validate: (url) => isValidHttpUrl(url), - HTMLAttributes: { - class: - "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", - }, - }), - UpdatedImage.configure({ - HTMLAttributes: { - class: "rounded-lg border border-custom-border-300", - }, - }), - Placeholder.configure({ - placeholder: ({ node }) => { - if (node.type.name === "heading") { - return `Heading ${node.attrs.level}`; - } - if (node.type.name === "image" || node.type.name === "table") { - return ""; - } - - return "Press '/' for commands..."; - }, - includeChildren: true, - }), - UniqueID.configure({ - types: ["image"], - }), - SlashCommand(workspaceSlug, setIsSubmitting), - TiptapUnderline, - TextStyle, - Color, - Highlight.configure({ - multicolor: true, - }), - TaskList.configure({ - HTMLAttributes: { - class: "not-prose pl-2", - }, - }), - TaskItem.configure({ - HTMLAttributes: { - class: "flex items-start my-4", - }, - nested: true, - }), - Markdown.configure({ - html: true, - transformCopiedText: true, - }), - Table, - TableHeader, - CustomTableCell, - TableRow, -]; + return "Press '/' for commands..."; + }, + includeChildren: true, + }), + UniqueID.configure({ + types: ["image"], + }), + SlashCommand(workspaceSlug, setIsSubmitting), + TiptapUnderline, + TextStyle, + Color, + Highlight.configure({ + multicolor: true, + }), + TaskList.configure({ + HTMLAttributes: { + class: "not-prose pl-2", + }, + }), + TaskItem.configure({ + HTMLAttributes: { + class: "flex items-start my-4", + }, + nested: true, + }), + Markdown.configure({ + html: true, + transformCopiedText: true, + }), + Table, + TableHeader, + CustomTableCell, + TableRow, + ]; diff --git a/web/components/tiptap/plugins/delete-image.tsx b/web/components/tiptap/plugins/delete-image.tsx index 568e4b748..fdf515ccc 100644 --- a/web/components/tiptap/plugins/delete-image.tsx +++ b/web/components/tiptap/plugins/delete-image.tsx @@ -1,43 +1,51 @@ -import { Plugin, PluginKey } from "@tiptap/pm/state"; +import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; import { Node as ProseMirrorNode } from "@tiptap/pm/model"; import fileService from "services/file.service"; const deleteKey = new PluginKey("delete-image"); +const IMAGE_NODE_TYPE = "image"; -const TrackImageDeletionPlugin = () => +interface ImageNode extends ProseMirrorNode { + attrs: { + src: string; + id: string; + }; +} + +const TrackImageDeletionPlugin = (): Plugin => new Plugin({ key: deleteKey, - appendTransaction: (transactions, oldState, newState) => { + appendTransaction: (transactions: readonly Transaction[], oldState: EditorState, newState: EditorState) => { + const newImageSources = new Set(); + newState.doc.descendants((node) => { + if (node.type.name === IMAGE_NODE_TYPE) { + newImageSources.add(node.attrs.src); + } + }); + transactions.forEach((transaction) => { if (!transaction.docChanged) return; - const removedImages: ProseMirrorNode[] = []; + const removedImages: ImageNode[] = []; oldState.doc.descendants((oldNode, oldPos) => { - if (oldNode.type.name !== "image") return; - + if (oldNode.type.name !== IMAGE_NODE_TYPE) return; if (oldPos < 0 || oldPos > newState.doc.content.size) return; if (!newState.doc.resolve(oldPos).parent) return; + const newNode = newState.doc.nodeAt(oldPos); // Check if the node has been deleted or replaced - if (!newNode || newNode.type.name !== "image") { - // Check if the node still exists elsewhere in the document - let nodeExists = false; - newState.doc.descendants((node) => { - if (node.attrs.id === oldNode.attrs.id) { - nodeExists = true; - } - }); - if (!nodeExists) { - removedImages.push(oldNode as ProseMirrorNode); + if (!newNode || newNode.type.name !== IMAGE_NODE_TYPE) { + if (!newImageSources.has(oldNode.attrs.src)) { + removedImages.push(oldNode as ImageNode); } } }); - removedImages.forEach((node) => { + removedImages.forEach(async (node) => { const src = node.attrs.src; - onNodeDeleted(src); + await onNodeDeleted(src); }); }); @@ -47,10 +55,14 @@ const TrackImageDeletionPlugin = () => export default TrackImageDeletionPlugin; -async function onNodeDeleted(src: string) { - const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1); - const resStatus = await fileService.deleteImage(assetUrlWithWorkspaceId); - if (resStatus === 204) { - console.log("Image deleted successfully"); +async function onNodeDeleted(src: string): Promise { + try { + const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1); + const resStatus = await fileService.deleteImage(assetUrlWithWorkspaceId); + if (resStatus === 204) { + console.log("Image deleted successfully"); + } + } catch (error) { + console.error("Error deleting image: ", error); } } diff --git a/web/components/tiptap/plugins/upload-image.tsx b/web/components/tiptap/plugins/upload-image.tsx index 499a00455..bc0acdc54 100644 --- a/web/components/tiptap/plugins/upload-image.tsx +++ b/web/components/tiptap/plugins/upload-image.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state"; import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view"; import fileService from "services/file.service"; From d26aa1b2da6300e1ca292e3f801293b029a3c747 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Thu, 7 Sep 2023 12:53:49 +0530 Subject: [PATCH 02/11] chore: render proper icons for due dates (#2114) --- .../issues/board-views/block-due-date.tsx | 33 ++++++++-------- .../issues/peek-overview/issue-properties.tsx | 38 +++++-------------- space/constants/helpers.ts | 36 ------------------ space/helpers/date-time.helper.ts | 23 +++++++++++ 4 files changed, 49 insertions(+), 81 deletions(-) delete mode 100644 space/constants/helpers.ts diff --git a/space/components/issues/board-views/block-due-date.tsx b/space/components/issues/board-views/block-due-date.tsx index f96836098..f88c82d0f 100644 --- a/space/components/issues/board-views/block-due-date.tsx +++ b/space/components/issues/board-views/block-due-date.tsx @@ -1,17 +1,9 @@ "use client"; // helpers -import { renderFullDate } from "constants/helpers"; +import { renderFullDate } from "helpers/date-time.helper"; -export const findHowManyDaysLeft = (date: string | Date) => { - const today = new Date(); - const eventDate = new Date(date); - const timeDiff = Math.abs(eventDate.getTime() - today.getTime()); - - return Math.ceil(timeDiff / (1000 * 3600 * 24)); -}; - -const dueDateIcon = ( +export const dueDateIconDetails = ( date: string, stateGroup: string ): { @@ -26,17 +18,24 @@ const dueDateIcon = ( className = ""; } else { const today = new Date(); - const dueDate = new Date(date); + today.setHours(0, 0, 0, 0); + const targetDate = new Date(date); + targetDate.setHours(0, 0, 0, 0); - if (dueDate < today) { + const timeDifference = targetDate.getTime() - today.getTime(); + + if (timeDifference < 0) { iconName = "event_busy"; className = "text-red-500"; - } else if (dueDate > today) { - iconName = "calendar_today"; - className = ""; - } else { + } else if (timeDifference === 0) { iconName = "today"; className = "text-red-500"; + } else if (timeDifference === 24 * 60 * 60 * 1000) { + iconName = "event"; + className = "text-yellow-500"; + } else { + iconName = "calendar_today"; + className = ""; } } @@ -47,7 +46,7 @@ const dueDateIcon = ( }; export const IssueBlockDueDate = ({ due_date, group }: { due_date: string; group: string }) => { - const iconDetails = dueDateIcon(due_date, group); + const iconDetails = dueDateIconDetails(due_date, group); return (
diff --git a/space/components/issues/peek-overview/issue-properties.tsx b/space/components/issues/peek-overview/issue-properties.tsx index 6b3394b56..c7a08faed 100644 --- a/space/components/issues/peek-overview/issue-properties.tsx +++ b/space/components/issues/peek-overview/issue-properties.tsx @@ -2,9 +2,10 @@ import useToast from "hooks/use-toast"; // icons import { Icon } from "components/ui"; -import { copyTextToClipboard, addSpaceIfCamelCase } from "helpers/string.helper"; // helpers -import { renderDateFormat } from "constants/helpers"; +import { copyTextToClipboard, addSpaceIfCamelCase } from "helpers/string.helper"; +import { renderFullDate } from "helpers/date-time.helper"; +import { dueDateIconDetails } from "../board-views/block-due-date"; // types import { IIssue } from "types/issue"; import { IPeekMode } from "store/issue_details"; @@ -16,35 +17,16 @@ type Props = { mode?: IPeekMode; }; -const validDate = (date: any, state: string): string => { - if (date === null || ["backlog", "unstarted", "cancelled"].includes(state)) - return `bg-gray-500/10 text-gray-500 border-gray-500/50`; - else { - const today = new Date(); - const dueDate = new Date(date); - - if (dueDate < today) return `bg-red-500/10 text-red-500 border-red-500/50`; - else return `bg-green-500/10 text-green-500 border-green-500/50`; - } -}; - export const PeekOverviewIssueProperties: React.FC = ({ issueDetails, mode }) => { const { setToastAlert } = useToast(); - const startDate = issueDetails.start_date; - const targetDate = issueDetails.target_date; - - const minDate = startDate ? new Date(startDate) : null; - minDate?.setDate(minDate.getDate()); - - const maxDate = targetDate ? new Date(targetDate) : null; - maxDate?.setDate(maxDate.getDate()); - const state = issueDetails.state_detail; const stateGroup = issueGroupFilter(state.group); const priority = issueDetails.priority ? issuePriorityFilter(issueDetails.priority) : null; + const dueDateIcon = dueDateIconDetails(issueDetails.target_date, state.group); + const handleCopyLink = () => { const urlToCopy = window.location.href; @@ -125,11 +107,11 @@ export const PeekOverviewIssueProperties: React.FC = ({ issueDetails, mod
{issueDetails.target_date ? ( -
- {renderDateFormat(issueDetails.target_date)} +
+ + {dueDateIcon.iconName} + + {renderFullDate(issueDetails.target_date)}
) : ( Empty diff --git a/space/constants/helpers.ts b/space/constants/helpers.ts deleted file mode 100644 index 0cf142353..000000000 --- a/space/constants/helpers.ts +++ /dev/null @@ -1,36 +0,0 @@ -export const renderDateFormat = (date: string | Date | null) => { - if (!date) return "N/A"; - - var d = new Date(date), - month = "" + (d.getMonth() + 1), - day = "" + d.getDate(), - year = d.getFullYear(); - - if (month.length < 2) month = "0" + month; - if (day.length < 2) day = "0" + day; - - return [year, month, day].join("-"); -}; - -/** - * @description Returns date and month, if date is of the current year - * @description Returns date, month adn year, if date is of a different year than current - * @param {string} date - * @example renderFullDate("2023-01-01") // 1 Jan - * @example renderFullDate("2021-01-01") // 1 Jan, 2021 - */ - -export const renderFullDate = (date: string): string => { - if (!date) return ""; - - const months: string[] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; - - const currentDate: Date = new Date(); - const [year, month, day]: number[] = date.split("-").map(Number); - - const formattedMonth: string = months[month - 1]; - const formattedDay: string = day < 10 ? `0${day}` : day.toString(); - - if (currentDate.getFullYear() === year) return `${formattedDay} ${formattedMonth}`; - else return `${formattedDay} ${formattedMonth}, ${year}`; -}; diff --git a/space/helpers/date-time.helper.ts b/space/helpers/date-time.helper.ts index 625871625..f19a5358b 100644 --- a/space/helpers/date-time.helper.ts +++ b/space/helpers/date-time.helper.ts @@ -12,3 +12,26 @@ export const timeAgo = (time: any) => { time = +new Date(); } }; + +/** + * @description Returns date and month, if date is of the current year + * @description Returns date, month adn year, if date is of a different year than current + * @param {string} date + * @example renderFullDate("2023-01-01") // 1 Jan + * @example renderFullDate("2021-01-01") // 1 Jan, 2021 + */ + +export const renderFullDate = (date: string): string => { + if (!date) return ""; + + const months: string[] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + + const currentDate: Date = new Date(); + const [year, month, day]: number[] = date.split("-").map(Number); + + const formattedMonth: string = months[month - 1]; + const formattedDay: string = day < 10 ? `0${day}` : day.toString(); + + if (currentDate.getFullYear() === year) return `${formattedDay} ${formattedMonth}`; + else return `${formattedDay} ${formattedMonth}, ${year}`; +}; From 81436902a3b8480aacb4321b82905a1ddbba84e3 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Thu, 7 Sep 2023 12:54:30 +0530 Subject: [PATCH 03/11] chore: option to switch access of a comment (#2116) --- web/components/inbox/inbox-issue-activity.tsx | 6 +- web/components/issues/activity.tsx | 9 ++- .../issues/comment/comment-card.tsx | 63 +++++++++++++++---- web/components/issues/main-content.tsx | 7 ++- .../issues/peek-overview/issue-activity.tsx | 19 +++--- web/services/issues.service.ts | 2 +- 6 files changed, 75 insertions(+), 31 deletions(-) diff --git a/web/components/inbox/inbox-issue-activity.tsx b/web/components/inbox/inbox-issue-activity.tsx index efa237162..dfcbf0262 100644 --- a/web/components/inbox/inbox-issue-activity.tsx +++ b/web/components/inbox/inbox-issue-activity.tsx @@ -38,7 +38,7 @@ export const InboxIssueActivity: React.FC = ({ issueDetails }) => { : null ); - const handleCommentUpdate = async (comment: IIssueComment) => { + const handleCommentUpdate = async (commentId: string, data: Partial) => { if (!workspaceSlug || !projectId || !inboxIssueId) return; await issuesService @@ -46,8 +46,8 @@ export const InboxIssueActivity: React.FC = ({ issueDetails }) => { workspaceSlug as string, projectId as string, inboxIssueId as string, - comment.id, - comment, + commentId, + data, user ) .then(() => mutateIssueActivity()); diff --git a/web/components/issues/activity.tsx b/web/components/issues/activity.tsx index 5a82907f2..fe322afe9 100644 --- a/web/components/issues/activity.tsx +++ b/web/components/issues/activity.tsx @@ -15,14 +15,16 @@ import { IIssueActivity, IIssueComment } from "types"; type Props = { activity: IIssueActivity[] | undefined; - handleCommentUpdate: (comment: IIssueComment) => Promise; + handleCommentUpdate: (commentId: string, data: Partial) => Promise; handleCommentDelete: (commentId: string) => Promise; + showAccessSpecifier?: boolean; }; export const IssueActivitySection: React.FC = ({ activity, handleCommentUpdate, handleCommentDelete, + showAccessSpecifier = false, }) => { const router = useRouter(); const { workspaceSlug } = router.query; @@ -131,10 +133,11 @@ export const IssueActivitySection: React.FC = ({ return (
); diff --git a/web/components/issues/comment/comment-card.tsx b/web/components/issues/comment/comment-card.tsx index 089aa9db9..3d3e43b39 100644 --- a/web/components/issues/comment/comment-card.tsx +++ b/web/components/issues/comment/comment-card.tsx @@ -7,7 +7,7 @@ import { ChatBubbleLeftEllipsisIcon, CheckIcon, XMarkIcon } from "@heroicons/rea // hooks import useUser from "hooks/use-user"; // ui -import { CustomMenu } from "components/ui"; +import { CustomMenu, Icon } from "components/ui"; import { CommentReaction } from "components/issues"; import { TipTapEditor } from "components/tiptap"; // helpers @@ -16,17 +16,19 @@ import { timeAgo } from "helpers/date-time.helper"; import type { IIssueComment } from "types"; type Props = { - workspaceSlug: string; comment: IIssueComment; - onSubmit: (comment: IIssueComment) => void; handleCommentDeletion: (comment: string) => void; + onSubmit: (commentId: string, data: Partial) => void; + showAccessSpecifier?: boolean; + workspaceSlug: string; }; export const CommentCard: React.FC = ({ comment, - workspaceSlug, - onSubmit, handleCommentDeletion, + onSubmit, + showAccessSpecifier = false, + workspaceSlug, }) => { const { user } = useUser(); @@ -45,11 +47,11 @@ export const CommentCard: React.FC = ({ defaultValues: comment, }); - const onEnter = (formData: IIssueComment) => { + const onEnter = (formData: Partial) => { if (isSubmitting) return; setIsEditing(false); - onSubmit(formData); + onSubmit(comment.id, formData); editorRef.current?.setEditorValue(formData.comment_html); showEditorRef.current?.setEditorValue(formData.comment_html); @@ -99,7 +101,7 @@ export const CommentCard: React.FC = ({ : comment.actor_detail.display_name}

- Commented {timeAgo(comment.created_at)} + commented {timeAgo(comment.created_at)}

@@ -137,7 +139,15 @@ export const CommentCard: React.FC = ({
-
+
+ {showAccessSpecifier && ( +
+ +
+ )} = ({
{user?.id === comment.actor && ( - setIsEditing(true)}>Edit + setIsEditing(true)} + className="flex items-center gap-1" + > + + Edit comment + + {showAccessSpecifier && ( + <> + {comment.access === "INTERNAL" ? ( + onSubmit(comment.id, { access: "EXTERNAL" })} + className="flex items-center gap-1" + > + + Switch to public comment + + ) : ( + onSubmit(comment.id, { access: "INTERNAL" })} + className="flex items-center gap-1" + > + + Switch to private comment + + )} + + )} { handleCommentDeletion(comment.id); }} + className="flex items-center gap-1" > - Delete + + Delete comment )} diff --git a/web/components/issues/main-content.tsx b/web/components/issues/main-content.tsx index bab384523..b7b154ce2 100644 --- a/web/components/issues/main-content.tsx +++ b/web/components/issues/main-content.tsx @@ -77,7 +77,7 @@ export const IssueMainContent: React.FC = ({ : null ); - const handleCommentUpdate = async (comment: IIssueComment) => { + const handleCommentUpdate = async (commentId: string, data: Partial) => { if (!workspaceSlug || !projectId || !issueId) return; await issuesService @@ -85,8 +85,8 @@ export const IssueMainContent: React.FC = ({ workspaceSlug as string, projectId as string, issueId as string, - comment.id, - comment, + commentId, + data, user ) .then(() => mutateIssueActivity()); @@ -222,6 +222,7 @@ export const IssueMainContent: React.FC = ({ activity={issueActivity} handleCommentUpdate={handleCommentUpdate} handleCommentDelete={handleCommentDelete} + showAccessSpecifier={projectDetails && projectDetails.is_deployed} /> = ({ workspaceSlug, issu const { setToastAlert } = useToast(); const { user } = useUser(); + const { projectDetails } = useProjectDetails(); const { data: issueActivity, mutate: mutateIssueActivity } = useSWR( workspaceSlug && issue ? PROJECT_ISSUES_ACTIVITY(issue.id) : null, @@ -30,18 +32,11 @@ export const PeekOverviewIssueActivity: React.FC = ({ workspaceSlug, issu : null ); - const handleCommentUpdate = async (comment: IIssueComment) => { + const handleCommentUpdate = async (commentId: string, data: Partial) => { if (!workspaceSlug || !issue) return; await issuesService - .patchIssueComment( - workspaceSlug as string, - issue.project, - issue.id, - comment.id, - comment, - user - ) + .patchIssueComment(workspaceSlug as string, issue.project, issue.id, commentId, data, user) .then(() => mutateIssueActivity()); }; @@ -80,9 +75,13 @@ export const PeekOverviewIssueActivity: React.FC = ({ workspaceSlug, issu activity={issueActivity} handleCommentUpdate={handleCommentUpdate} handleCommentDelete={handleCommentDelete} + showAccessSpecifier={projectDetails && projectDetails.is_deployed} />
- +
diff --git a/web/services/issues.service.ts b/web/services/issues.service.ts index b8875e6c5..af5d722e3 100644 --- a/web/services/issues.service.ts +++ b/web/services/issues.service.ts @@ -204,7 +204,7 @@ class ProjectIssuesServices extends APIService { projectId: string, issueId: string, commentId: string, - data: IIssueComment, + data: Partial, user: ICurrentUserResponse | undefined ): Promise { return this.patch( From 9c3510851daaf82a6d8c5d3d55e919dfdcab7af7 Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Thu, 7 Sep 2023 13:20:32 +0530 Subject: [PATCH 04/11] dev: update python packages (#2095) --- apiserver/requirements/base.txt | 26 +++++++++++++------------- apiserver/requirements/production.txt | 10 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/apiserver/requirements/base.txt b/apiserver/requirements/base.txt index ca9d881ef..969ab3c89 100644 --- a/apiserver/requirements/base.txt +++ b/apiserver/requirements/base.txt @@ -1,36 +1,36 @@ # base requirements -Django==4.2.3 +Django==4.2.5 django-braces==1.15.0 django-taggit==4.0.0 -psycopg==3.1.9 +psycopg==3.1.10 django-oauth-toolkit==2.3.0 mistune==3.0.1 djangorestframework==3.14.0 redis==4.6.0 django-nested-admin==4.0.2 -django-cors-headers==4.1.0 +django-cors-headers==4.2.0 whitenoise==6.5.0 -django-allauth==0.54.0 +django-allauth==0.55.2 faker==18.11.2 django-filter==23.2 jsonmodels==2.6.0 -djangorestframework-simplejwt==5.2.2 -sentry-sdk==1.27.0 +djangorestframework-simplejwt==5.3.0 +sentry-sdk==1.30.0 django-s3-storage==0.14.0 django-crum==0.7.9 django-guardian==2.4.0 dj_rest_auth==2.2.5 -google-auth==2.21.0 -google-api-python-client==2.92.0 +google-auth==2.22.0 +google-api-python-client==2.97.0 django-redis==5.3.0 -uvicorn==0.22.0 +uvicorn==0.23.2 channels==4.0.0 -openai==0.27.8 +openai==0.28.0 slack-sdk==3.21.3 -celery==5.3.1 +celery==5.3.4 django_celery_beat==2.5.0 -psycopg-binary==3.1.9 -psycopg-c==3.1.9 +psycopg-binary==3.1.10 +psycopg-c==3.1.10 scout-apm==2.26.1 openpyxl==3.1.2 \ No newline at end of file diff --git a/apiserver/requirements/production.txt b/apiserver/requirements/production.txt index 4da619d49..5e3483a96 100644 --- a/apiserver/requirements/production.txt +++ b/apiserver/requirements/production.txt @@ -1,11 +1,11 @@ -r base.txt -dj-database-url==2.0.0 -gunicorn==20.1.0 +dj-database-url==2.1.0 +gunicorn==21.2.0 whitenoise==6.5.0 -django-storages==1.13.2 -boto3==1.27.0 -django-anymail==10.0 +django-storages==1.14 +boto3==1.28.40 +django-anymail==10.1 django-debug-toolbar==4.1.0 gevent==23.7.0 psycogreen==1.0.2 \ No newline at end of file From 866eead35f13662b0520af8096c9ecadadb7cf82 Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Thu, 7 Sep 2023 13:21:05 +0530 Subject: [PATCH 05/11] fix: issue comment ordering for public boards (#2108) --- apiserver/plane/api/views/issue.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index d97b546d3..8a817a674 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -1575,7 +1575,7 @@ class IssueCommentPublicViewSet(BaseViewSet): ) ) .distinct() - ) + ).order_by("created_at") else: return IssueComment.objects.none() except ProjectDeployBoard.DoesNotExist: From 39bc975994c0774ce18d0078dd104826e838fd62 Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Thu, 7 Sep 2023 13:21:58 +0530 Subject: [PATCH 06/11] fix: remove triage issue status from public boards (#2110) --- apiserver/plane/api/views/issue.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index 8a817a674..334ad2514 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -2195,6 +2195,7 @@ class ProjectIssuesPublicEndpoint(BaseAPIView): states = ( State.objects.filter( + ~Q(name="Triage"), workspace__slug=slug, project_id=project_id, ) From 8ea6dd4e846cc8b9b4552eaf706d60c3d280a4ac Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Thu, 7 Sep 2023 13:40:50 +0530 Subject: [PATCH 07/11] fix: onboarding role select dropdown text color (#2117) --- space/components/accounts/onboarding-form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/space/components/accounts/onboarding-form.tsx b/space/components/accounts/onboarding-form.tsx index c40465b3f..4cca97a64 100644 --- a/space/components/accounts/onboarding-form.tsx +++ b/space/components/accounts/onboarding-form.tsx @@ -131,7 +131,7 @@ export const OnBoardingForm: React.FC = observer(({ user }) => { type="button" className={`flex items-center justify-between gap-1 w-full rounded-md border border-custom-border-300 shadow-sm duration-300 focus:outline-none px-3 py-2 text-sm`} > - {value || "Select your role..."} + {value || "Select your role..."}