diff --git a/web/components/command-palette/command-pallette.tsx b/web/components/command-palette/command-pallette.tsx index 507d8a49c..f183de9c6 100644 --- a/web/components/command-palette/command-pallette.tsx +++ b/web/components/command-palette/command-pallette.tsx @@ -41,7 +41,7 @@ export const CommandPalette: React.FC = observer(() => { const [isCreateUpdatePageModalOpen, setIsCreateUpdatePageModalOpen] = useState(false); const router = useRouter(); - const { workspaceSlug, projectId, issueId, inboxId } = router.query; + const { workspaceSlug, projectId, issueId, inboxId, cycleId, moduleId } = router.query; const { user } = useUser(); @@ -183,6 +183,13 @@ export const CommandPalette: React.FC = observer(() => { isOpen={isIssueModalOpen} handleClose={() => setIsIssueModalOpen(false)} fieldsToShow={inboxId ? ["name", "description", "priority"] : ["all"]} + prePopulateData={ + cycleId + ? { cycle: cycleId.toString() } + : moduleId + ? { module: moduleId.toString() } + : undefined + } /> , }, - blocks: { + blocked_by: { message: (activity) => { if (activity.old_value === "") return ( @@ -176,6 +177,44 @@ const activityDetails: { }, icon: , }, + duplicate: { + message: (activity) => { + if (activity.old_value === "") + return ( + <> + marked this issue as duplicate of{" "} + {activity.new_value}. + + ); + else + return ( + <> + removed this issue as a duplicate of{" "} + {activity.old_value}. + + ); + }, + icon: , + }, + relates_to: { + message: (activity) => { + if (activity.old_value === "") + return ( + <> + marked that this issue relates to{" "} + {activity.new_value}. + + ); + else + return ( + <> + removed the relation from{" "} + {activity.old_value}. + + ); + }, + icon: , + }, cycles: { message: (activity, showIssue, workspaceSlug) => { if (activity.verb === "created") diff --git a/web/components/core/views/issues-view.tsx b/web/components/core/views/issues-view.tsx index 98b687207..55eefc396 100644 --- a/web/components/core/views/issues-view.tsx +++ b/web/components/core/views/issues-view.tsx @@ -23,7 +23,6 @@ import { CreateUpdateIssueModal, DeleteIssueModal, DeleteDraftIssueModal, - IssuePeekOverview, CreateUpdateDraftIssueModal, } from "components/issues"; import { CreateUpdateViewModal } from "components/views"; @@ -484,15 +483,7 @@ export const IssuesView: React.FC = ({ } : null } - fieldsToShow={[ - "name", - "description", - "label", - "assignee", - "priority", - "dueDate", - "priority", - ]} + fieldsToShow={["all"]} /> { ) : ( -

No previous export available.

+

+ No previous export available. +

) ) : ( diff --git a/web/components/integration/guide.tsx b/web/components/integration/guide.tsx index a819566bf..2ee0e0121 100644 --- a/web/components/integration/guide.tsx +++ b/web/components/integration/guide.tsx @@ -129,7 +129,7 @@ const IntegrationGuide = () => { -
+
{importerServices ? ( importerServices.length > 0 ? (
@@ -145,7 +145,7 @@ const IntegrationGuide = () => {
) : ( -

+

No previous imports available.

) diff --git a/web/components/issues/delete-draft-issue-modal.tsx b/web/components/issues/delete-draft-issue-modal.tsx index ddbe2a269..6fc4f4218 100644 --- a/web/components/issues/delete-draft-issue-modal.tsx +++ b/web/components/issues/delete-draft-issue-modal.tsx @@ -50,12 +50,12 @@ export const DeleteDraftIssueModal: React.FC = (props) => { }; const handleDeletion = async () => { - if (!workspaceSlug || !data) return; + if (!workspaceSlug || !data || !user) return; setIsDeleteLoading(true); await issueServices - .deleteDraftIssue(workspaceSlug as string, data.project, data.id) + .deleteDraftIssue(workspaceSlug as string, data.project, data.id, user) .then(() => { setIsDeleteLoading(false); handleClose(); diff --git a/web/components/issues/draft-issue-modal.tsx b/web/components/issues/draft-issue-modal.tsx index 489a09d18..3b0664cb8 100644 --- a/web/components/issues/draft-issue-modal.tsx +++ b/web/components/issues/draft-issue-modal.tsx @@ -14,6 +14,7 @@ import useIssuesView from "hooks/use-issues-view"; import useCalendarIssuesView from "hooks/use-calendar-issues-view"; import useToast from "hooks/use-toast"; import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view"; +import useLocalStorage from "hooks/use-local-storage"; import useProjects from "hooks/use-projects"; import useMyIssues from "hooks/my-issues/use-my-issues"; // components @@ -79,6 +80,8 @@ export const CreateUpdateDraftIssueModal: React.FC = ({ const { user } = useUser(); const { projects } = useProjects(); + const { clearValue: clearDraftIssueLocalStorage } = useLocalStorage("draftedIssue", {}); + const { groupedIssues, mutateMyIssues } = useMyIssues(workspaceSlug?.toString()); const { setToastAlert } = useToast(); @@ -111,11 +114,14 @@ export const CreateUpdateDraftIssueModal: React.FC = ({ return; } + if (prePopulateData && prePopulateData.project) + return setActiveProject(prePopulateData.project); + // if data is not present, set active project to the project // in the url. This has the least priority. if (projects && projects.length > 0 && !activeProject) setActiveProject(projects?.find((p) => p.id === projectId)?.id ?? projects?.[0].id ?? null); - }, [activeProject, data, projectId, projects, isOpen]); + }, [activeProject, data, projectId, projects, isOpen, prePopulateData]); const calendarFetchKey = cycleId ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), calendarParams) @@ -228,6 +234,8 @@ export const CreateUpdateDraftIssueModal: React.FC = ({ if (!data) await createIssue(payload); else await updateIssue(payload); + clearDraftIssueLocalStorage(); + if (onSubmit) await onSubmit(payload); }; diff --git a/web/components/issues/form.tsx b/web/components/issues/form.tsx index e6b4f9e08..2e53f3866 100644 --- a/web/components/issues/form.tsx +++ b/web/components/issues/form.tsx @@ -8,7 +8,6 @@ import { Controller, useForm } from "react-hook-form"; import aiService from "services/ai.service"; // hooks import useToast from "hooks/use-toast"; -import useLocalStorage from "hooks/use-local-storage"; // components import { GptAssistantModal } from "components/core"; import { ParentIssuesListModal } from "components/issues"; @@ -62,11 +61,9 @@ export interface IssueFormProps { setActiveProject: React.Dispatch>; createMore: boolean; setCreateMore: React.Dispatch>; - handleClose: () => void; handleDiscardClose: () => void; status: boolean; user: ICurrentUserResponse | undefined; - setIsConfirmDiscardOpen: React.Dispatch>; handleFormDirty: (payload: Partial | null) => void; fieldsToShow: ( | "project" @@ -107,8 +104,6 @@ export const IssueForm: FC = (props) => { const [gptAssistantModal, setGptAssistantModal] = useState(false); const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false); - const { setValue: setValueInLocalStorage } = useLocalStorage("draftedIssue", null); - const editorRef = useRef(null); const router = useRouter(); @@ -139,9 +134,11 @@ export const IssueForm: FC = (props) => { state: getValues("state"), priority: getValues("priority"), assignees: getValues("assignees"), - target_date: getValues("target_date"), labels: getValues("labels"), + start_date: getValues("start_date"), + target_date: getValues("target_date"), project: getValues("project"), + parent: getValues("parent"), }; useEffect(() => { @@ -571,8 +568,6 @@ export const IssueForm: FC = (props) => {
{ - const data = JSON.stringify(getValues()); - setValueInLocalStorage(data); handleDiscardClose(); }} > diff --git a/web/components/issues/modal.tsx b/web/components/issues/modal.tsx index d6ab43491..65580c94a 100644 --- a/web/components/issues/modal.tsx +++ b/web/components/issues/modal.tsx @@ -19,6 +19,7 @@ import useInboxView from "hooks/use-inbox-view"; import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view"; import useProjects from "hooks/use-projects"; import useMyIssues from "hooks/my-issues/use-my-issues"; +import useLocalStorage from "hooks/use-local-storage"; // components import { IssueForm, ConfirmIssueDiscard } from "components/issues"; // types @@ -92,10 +93,11 @@ export const CreateUpdateIssueModal: React.FC = ({ const { groupedIssues, mutateMyIssues } = useMyIssues(workspaceSlug?.toString()); + const { setValue: setValueInLocalStorage, clearValue: clearLocalStorageValue } = + useLocalStorage("draftedIssue", {}); + const { setToastAlert } = useToast(); - if (cycleId) prePopulateData = { ...prePopulateData, cycle: cycleId as string }; - if (moduleId) prePopulateData = { ...prePopulateData, module: moduleId as string }; if (router.asPath.includes("my-issues") || router.asPath.includes("assigned")) prePopulateData = { ...prePopulateData, @@ -103,6 +105,13 @@ export const CreateUpdateIssueModal: React.FC = ({ }; const onClose = () => { + if (!showConfirmDiscard) handleClose(); + if (formDirtyState === null) return setActiveProject(null); + const data = JSON.stringify(formDirtyState); + setValueInLocalStorage(data); + }; + + const onDiscardClose = () => { if (formDirtyState !== null) { setShowConfirmDiscard(true); } else { @@ -111,11 +120,6 @@ export const CreateUpdateIssueModal: React.FC = ({ } }; - const onDiscardClose = () => { - handleClose(); - setActiveProject(null); - }; - const handleFormDirty = (data: any) => { setFormDirtyState(data); }; @@ -397,6 +401,7 @@ export const CreateUpdateIssueModal: React.FC = ({ setActiveProject(null); setFormDirtyState(null); setShowConfirmDiscard(false); + clearLocalStorageValue(); }} /> @@ -431,9 +436,7 @@ export const CreateUpdateIssueModal: React.FC = ({ initialData={data ?? prePopulateData} createMore={createMore} setCreateMore={setCreateMore} - handleClose={onClose} handleDiscardClose={onDiscardClose} - setIsConfirmDiscardOpen={setShowConfirmDiscard} projectId={activeProject ?? ""} setActiveProject={setActiveProject} status={data ? true : false} diff --git a/web/components/issues/sidebar-select/blocked.tsx b/web/components/issues/sidebar-select/blocked.tsx index 9554a83ba..d7e448377 100644 --- a/web/components/issues/sidebar-select/blocked.tsx +++ b/web/components/issues/sidebar-select/blocked.tsx @@ -73,7 +73,7 @@ export const SidebarBlockedSelect: React.FC = ({ ...selectedIssues.map((issue) => ({ issue: issueId as string, relation_type: "blocked_by" as const, - related_issue_detail: issue.blocked_issue_detail, + issue_detail: issue.blocked_issue_detail, related_issue: issue.blocked_issue_detail.id, })), ], @@ -111,17 +111,17 @@ export const SidebarBlockedSelect: React.FC = ({ {blockedByIssue && blockedByIssue.length > 0 ? blockedByIssue.map((relation) => (
- {`${relation.related_issue_detail?.project_detail.identifier}-${relation.related_issue_detail?.sequence_id}`} + {`${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`}
} @@ -61,7 +66,12 @@ export const MemberSelect: React.FC = ({ value, onChange }) => { { value: "none", query: "none", - content:
None
, + content: ( +
+ + None +
+ ), }, ] } diff --git a/web/components/project/settings-sidebar.tsx b/web/components/project/settings-sidebar.tsx index a147c8a3a..123dc6282 100644 --- a/web/components/project/settings-sidebar.tsx +++ b/web/components/project/settings-sidebar.tsx @@ -2,11 +2,7 @@ import React from "react"; import { useRouter } from "next/router"; import Link from "next/link"; -type Props = { - profilePage?: boolean; -}; - -export const SettingsSidebar: React.FC = ({ profilePage = false }) => { +export const SettingsSidebar = () => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; diff --git a/web/components/ui/buttons/type.d.ts b/web/components/ui/buttons/type.d.ts index 1391e0771..b227887ef 100644 --- a/web/components/ui/buttons/type.d.ts +++ b/web/components/ui/buttons/type.d.ts @@ -1,7 +1,7 @@ export type ButtonProps = { children: React.ReactNode; className?: string; - onClick?: () => void; + onClick?: (e: any) => void; type?: "button" | "submit" | "reset"; disabled?: boolean; loading?: boolean; diff --git a/web/components/web-view/activity-message.tsx b/web/components/web-view/activity-message.tsx index 7100cadc4..17548a386 100644 --- a/web/components/web-view/activity-message.tsx +++ b/web/components/web-view/activity-message.tsx @@ -1,9 +1,10 @@ import { useRouter } from "next/router"; // icons +import { CopyPlus } from "lucide-react"; import { Icon, Tooltip } from "components/ui"; import { Squares2X2Icon } from "@heroicons/react/24/outline"; -import { BlockedIcon, BlockerIcon } from "components/icons"; +import { BlockedIcon, BlockerIcon, RelatedIcon } from "components/icons"; // helpers import { renderShortDateWithYearFormat } from "helpers/date-time.helper"; import { capitalizeFirstLetter } from "helpers/string.helper"; @@ -117,7 +118,7 @@ const activityDetails: { icon: , }, - blocks: { + blocked_by: { message: (activity) => ( <> {activity.old_value === "" @@ -132,6 +133,36 @@ const activityDetails: { icon: , }, + duplicate: { + message: (activity) => ( + <> + {activity.old_value === "" + ? "marked this issue as duplicate of " + : "removed this issue as a duplicate of "} + + {activity.verb === "created" ? activity.new_value : activity.old_value} + + . + + ), + icon: , + }, + + relates_to: { + message: (activity) => ( + <> + {activity.old_value === "" + ? "marked that this issue relates to " + : "removed the relation from "} + + {activity.old_value === "" ? activity.new_value : activity.old_value} + + . + + ), + icon: , + }, + cycles: { message: (activity) => ( <> diff --git a/web/components/web-view/issue-properties-detail.tsx b/web/components/web-view/issue-properties-detail.tsx index 089f8950f..2c745febe 100644 --- a/web/components/web-view/issue-properties-detail.tsx +++ b/web/components/web-view/issue-properties-detail.tsx @@ -351,25 +351,23 @@ export const IssuePropertiesDetail: React.FC = (props) => { {blockedIssue && blockedIssue.map((issue) => (
- {`${issue?.related_issue_detail?.project_detail?.identifier}-${issue?.related_issue_detail?.sequence_id}`} + {`${issue?.issue_detail?.project_detail?.identifier}-${issue?.issue_detail?.sequence_id}`}