diff --git a/apiserver/plane/app/serializers/cycle.py b/apiserver/plane/app/serializers/cycle.py
index a041dd227..77c3f16cc 100644
--- a/apiserver/plane/app/serializers/cycle.py
+++ b/apiserver/plane/app/serializers/cycle.py
@@ -33,7 +33,6 @@ class CycleWriteSerializer(BaseSerializer):
class CycleSerializer(BaseSerializer):
- owned_by = UserLiteSerializer(read_only=True)
is_favorite = serializers.BooleanField(read_only=True)
total_issues = serializers.IntegerField(read_only=True)
cancelled_issues = serializers.IntegerField(read_only=True)
diff --git a/apiserver/plane/bgtasks/email_notification_task.py b/apiserver/plane/bgtasks/email_notification_task.py
index cc9588ca6..713835033 100644
--- a/apiserver/plane/bgtasks/email_notification_task.py
+++ b/apiserver/plane/bgtasks/email_notification_task.py
@@ -186,7 +186,7 @@ def send_email_notification(
}
)
- summary = "updates were made to the issue by"
+ summary = "Updates were made to the issue by"
# Send the mail
subject = f"{issue.project.identifier}-{issue.sequence_id} {issue.name}"
diff --git a/apiserver/templates/emails/notifications/issue-updates.html b/apiserver/templates/emails/notifications/issue-updates.html
index bdc6a53a3..fa50631c5 100644
--- a/apiserver/templates/emails/notifications/issue-updates.html
+++ b/apiserver/templates/emails/notifications/issue-updates.html
@@ -108,14 +108,33 @@
margin-bottom: 15px;
"
/>
- {% if actors_involved > 0 %}
+ {% if actors_involved == 1 %}
+
+ {{summary}}
+
+ {{ data.0.actor_detail.first_name}}
+ {{data.0.actor_detail.last_name}}
+ .
+
+ {% else %}
+
+ {{summary}}
+
+ {{ data.0.actor_detail.first_name}}
+ {{data.0.actor_detail.last_name }}
+ and others.
+
+ {% endif %}
+
+
+
{% for update in data %} {% if update.changes.name %}
diff --git a/packages/editor/core/src/ui/extensions/horizontal-rule.tsx b/packages/editor/core/src/ui/extensions/horizontal-rule.tsx
deleted file mode 100644
index cee0ded83..000000000
--- a/packages/editor/core/src/ui/extensions/horizontal-rule.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import { TextSelection } from "prosemirror-state";
-
-import { InputRule, mergeAttributes, Node, nodeInputRule, wrappingInputRule } from "@tiptap/core";
-
-/**
- * Extension based on:
- * - Tiptap HorizontalRule extension (https://tiptap.dev/api/nodes/horizontal-rule)
- */
-
-export interface HorizontalRuleOptions {
- HTMLAttributes: Record;
-}
-
-declare module "@tiptap/core" {
- interface Commands {
- horizontalRule: {
- /**
- * Add a horizontal rule
- */
- setHorizontalRule: () => ReturnType;
- };
- }
-}
-
-export const HorizontalRule = Node.create({
- name: "horizontalRule",
-
- addOptions() {
- return {
- HTMLAttributes: {},
- };
- },
-
- group: "block",
-
- addAttributes() {
- return {
- color: {
- default: "#dddddd",
- },
- };
- },
-
- parseHTML() {
- return [
- {
- tag: `div[data-type="${this.name}"]`,
- },
- ];
- },
-
- renderHTML({ HTMLAttributes }) {
- return [
- "div",
- mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
- "data-type": this.name,
- }),
- ["div", {}],
- ];
- },
-
- addCommands() {
- return {
- setHorizontalRule:
- () =>
- ({ chain }) => {
- return (
- chain()
- .insertContent({ type: this.name })
- // set cursor after horizontal rule
- .command(({ tr, dispatch }) => {
- if (dispatch) {
- const { $to } = tr.selection;
- const posAfter = $to.end();
-
- if ($to.nodeAfter) {
- tr.setSelection(TextSelection.create(tr.doc, $to.pos));
- } else {
- // add node after horizontal rule if it’s the end of the document
- const node = $to.parent.type.contentMatch.defaultType?.create();
-
- if (node) {
- tr.insert(posAfter, node);
- tr.setSelection(TextSelection.create(tr.doc, posAfter));
- }
- }
-
- tr.scrollIntoView();
- }
-
- return true;
- })
- .run()
- );
- },
- };
- },
-
- addInputRules() {
- return [
- new InputRule({
- find: /^(?:---|—-|___\s|\*\*\*\s)$/,
- handler: ({ state, range, match }) => {
- state.tr.replaceRangeWith(range.from, range.to, this.type.create());
- },
- }),
- ];
- },
-});
diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx
index 19d8ce894..5bfba3b0f 100644
--- a/packages/editor/core/src/ui/extensions/index.tsx
+++ b/packages/editor/core/src/ui/extensions/index.tsx
@@ -1,26 +1,25 @@
-import StarterKit from "@tiptap/starter-kit";
-import TiptapUnderline from "@tiptap/extension-underline";
-import TextStyle from "@tiptap/extension-text-style";
import { Color } from "@tiptap/extension-color";
import TaskItem from "@tiptap/extension-task-item";
import TaskList from "@tiptap/extension-task-list";
+import TextStyle from "@tiptap/extension-text-style";
+import TiptapUnderline from "@tiptap/extension-underline";
+import StarterKit from "@tiptap/starter-kit";
import { Markdown } from "tiptap-markdown";
-import { TableHeader } from "src/ui/extensions/table/table-header/table-header";
import { Table } from "src/ui/extensions/table/table";
import { TableCell } from "src/ui/extensions/table/table-cell/table-cell";
+import { TableHeader } from "src/ui/extensions/table/table-header/table-header";
import { TableRow } from "src/ui/extensions/table/table-row/table-row";
-import { HorizontalRule } from "src/ui/extensions/horizontal-rule";
import { ImageExtension } from "src/ui/extensions/image";
import { isValidHttpUrl } from "src/lib/utils";
import { Mentions } from "src/ui/mentions";
-import { CustomKeymap } from "src/ui/extensions/keymap";
import { CustomCodeBlockExtension } from "src/ui/extensions/code";
-import { CustomQuoteExtension } from "src/ui/extensions/quote";
import { ListKeymap } from "src/ui/extensions/custom-list-keymap";
+import { CustomKeymap } from "src/ui/extensions/keymap";
+import { CustomQuoteExtension } from "src/ui/extensions/quote";
import { DeleteImage } from "src/types/delete-image";
import { IMentionSuggestion } from "src/types/mention-suggestion";
@@ -55,7 +54,9 @@ export const CoreEditorExtensions = (
},
code: false,
codeBlock: false,
- horizontalRule: false,
+ horizontalRule: {
+ HTMLAttributes: { class: "mt-4 mb-4" },
+ },
blockquote: false,
dropcursor: {
color: "rgba(var(--color-text-100))",
@@ -104,7 +105,6 @@ export const CoreEditorExtensions = (
transformCopiedText: true,
transformPastedText: true,
}),
- HorizontalRule,
Table,
TableHeader,
TableCell,
diff --git a/packages/editor/core/src/ui/mentions/custom.tsx b/packages/editor/core/src/ui/mentions/custom.tsx
index 6a47d79f0..e723ca0d7 100644
--- a/packages/editor/core/src/ui/mentions/custom.tsx
+++ b/packages/editor/core/src/ui/mentions/custom.tsx
@@ -10,6 +10,11 @@ export interface CustomMentionOptions extends MentionOptions {
}
export const CustomMention = Mention.extend({
+ addStorage(this) {
+ return {
+ mentionsOpen: false,
+ };
+ },
addAttributes() {
return {
id: {
diff --git a/packages/editor/core/src/ui/mentions/suggestion.ts b/packages/editor/core/src/ui/mentions/suggestion.ts
index 6d706cb79..40e75a1e3 100644
--- a/packages/editor/core/src/ui/mentions/suggestion.ts
+++ b/packages/editor/core/src/ui/mentions/suggestion.ts
@@ -14,6 +14,7 @@ export const Suggestion = (suggestions: IMentionSuggestion[]) => ({
return {
onStart: (props: { editor: Editor; clientRect: DOMRect }) => {
+ props.editor.storage.mentionsOpen = true;
reactRenderer = new ReactRenderer(MentionList, {
props,
editor: props.editor,
@@ -45,10 +46,18 @@ export const Suggestion = (suggestions: IMentionSuggestion[]) => ({
return true;
}
- // @ts-ignore
- return reactRenderer?.ref?.onKeyDown(props);
+ const navigationKeys = ["ArrowUp", "ArrowDown", "Enter"];
+
+ if (navigationKeys.includes(props.event.key)) {
+ // @ts-ignore
+ reactRenderer?.ref?.onKeyDown(props);
+ event?.stopPropagation();
+ return true;
+ }
+ return false;
},
- onExit: () => {
+ onExit: (props: { editor: Editor; event: KeyboardEvent }) => {
+ props.editor.storage.mentionsOpen = false;
popup?.[0].destroy();
reactRenderer?.destroy();
},
diff --git a/packages/editor/core/src/ui/read-only/extensions.tsx b/packages/editor/core/src/ui/read-only/extensions.tsx
index b0879d8cd..cf7c4ee18 100644
--- a/packages/editor/core/src/ui/read-only/extensions.tsx
+++ b/packages/editor/core/src/ui/read-only/extensions.tsx
@@ -11,7 +11,6 @@ import { TableHeader } from "src/ui/extensions/table/table-header/table-header";
import { Table } from "src/ui/extensions/table/table";
import { TableCell } from "src/ui/extensions/table/table-cell/table-cell";
import { TableRow } from "src/ui/extensions/table/table-row/table-row";
-import { HorizontalRule } from "src/ui/extensions/horizontal-rule";
import { ReadOnlyImageExtension } from "src/ui/extensions/image/read-only-image";
import { isValidHttpUrl } from "src/lib/utils";
@@ -51,7 +50,9 @@ export const CoreReadOnlyEditorExtensions = (mentionConfig: {
},
},
codeBlock: false,
- horizontalRule: false,
+ horizontalRule: {
+ HTMLAttributes: { class: "mt-4 mb-4" },
+ },
dropcursor: {
color: "rgba(var(--color-text-100))",
width: 2,
@@ -72,7 +73,6 @@ export const CoreReadOnlyEditorExtensions = (mentionConfig: {
class: "rounded-lg border border-custom-border-300",
},
}),
- HorizontalRule,
TiptapUnderline,
TextStyle,
Color,
diff --git a/packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx b/packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx
index 129efa4ee..7d93bf36f 100644
--- a/packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx
+++ b/packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx
@@ -4,13 +4,16 @@ export const EnterKeyExtension = (onEnterKeyPress?: () => void) =>
Extension.create({
name: "enterKey",
- addKeyboardShortcuts() {
+ addKeyboardShortcuts(this) {
return {
Enter: () => {
- if (onEnterKeyPress) {
- onEnterKeyPress();
+ if (!this.editor.storage.mentionsOpen) {
+ if (onEnterKeyPress) {
+ onEnterKeyPress();
+ }
+ return true;
}
- return true;
+ return false;
},
"Shift-Enter": ({ editor }) =>
editor.commands.first(({ commands }) => [
diff --git a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx
index 527fd5674..c4b24d166 100644
--- a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx
+++ b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx
@@ -1,5 +1,3 @@
import { EnterKeyExtension } from "src/ui/extensions/enter-key-extension";
-export const LiteTextEditorExtensions = (onEnterKeyPress?: () => void) => [
- // EnterKeyExtension(onEnterKeyPress),
-];
+export const LiteTextEditorExtensions = (onEnterKeyPress?: () => void) => [EnterKeyExtension(onEnterKeyPress)];
diff --git a/packages/types/src/cycles.d.ts b/packages/types/src/cycles.d.ts
index 91c6ef1d5..12cbab4c6 100644
--- a/packages/types/src/cycles.d.ts
+++ b/packages/types/src/cycles.d.ts
@@ -30,7 +30,7 @@ export interface ICycle {
is_favorite: boolean;
issue: string;
name: string;
- owned_by: IUser;
+ owned_by: string;
project: string;
project_detail: IProjectLite;
status: TCycleGroups;
diff --git a/packages/ui/src/breadcrumbs/breadcrumbs.tsx b/packages/ui/src/breadcrumbs/breadcrumbs.tsx
index e82944c03..0f09764ac 100644
--- a/packages/ui/src/breadcrumbs/breadcrumbs.tsx
+++ b/packages/ui/src/breadcrumbs/breadcrumbs.tsx
@@ -2,8 +2,6 @@ import * as React from "react";
// icons
import { ChevronRight } from "lucide-react";
-// components
-import { Tooltip } from "../tooltip";
type BreadcrumbsProps = {
children: any;
@@ -25,42 +23,11 @@ const Breadcrumbs = ({ children }: BreadcrumbsProps) => (
type Props = {
type?: "text" | "component";
component?: React.ReactNode;
- label?: string;
- icon?: React.ReactNode;
- link?: string;
+ link?: JSX.Element;
};
const BreadcrumbItem: React.FC = (props) => {
- const { type = "text", component, label, icon, link } = props;
- return (
- <>
- {type != "text" ? (
- {component}
- ) : (
-
-
-
-
-
- )}
- >
- );
+ const { type = "text", component, link } = props;
+ return <>{type != "text" ? {component}
: link}>;
};
Breadcrumbs.BreadcrumbItem = BreadcrumbItem;
diff --git a/web/components/analytics/custom-analytics/sidebar/sidebar-header.tsx b/web/components/analytics/custom-analytics/sidebar/sidebar-header.tsx
index d46cad191..4a18011d1 100644
--- a/web/components/analytics/custom-analytics/sidebar/sidebar-header.tsx
+++ b/web/components/analytics/custom-analytics/sidebar/sidebar-header.tsx
@@ -1,7 +1,7 @@
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
// hooks
-import { useCycle, useModule, useProject } from "hooks/store";
+import { useCycle, useMember, useModule, useProject } from "hooks/store";
// helpers
import { renderEmoji } from "helpers/emoji.helper";
import { renderFormattedDate } from "helpers/date-time.helper";
@@ -15,10 +15,12 @@ export const CustomAnalyticsSidebarHeader = observer(() => {
const { getProjectById } = useProject();
const { getCycleById } = useCycle();
const { getModuleById } = useModule();
+ const { getUserDetails } = useMember();
const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined;
const moduleDetails = moduleId ? getModuleById(moduleId.toString()) : undefined;
const projectDetails = projectId ? getProjectById(projectId.toString()) : undefined;
+ const cycleOwnerDetails = cycleDetails ? getUserDetails(cycleDetails.owned_by) : undefined;
return (
<>
@@ -29,7 +31,7 @@ export const CustomAnalyticsSidebarHeader = observer(() => {
Lead
- {cycleDetails.owned_by?.display_name}
+ {cycleOwnerDetails?.display_name}
Start Date
diff --git a/web/components/common/breadcrumb-link.tsx b/web/components/common/breadcrumb-link.tsx
new file mode 100644
index 000000000..aebd7fc02
--- /dev/null
+++ b/web/components/common/breadcrumb-link.tsx
@@ -0,0 +1,36 @@
+import { Tooltip } from "@plane/ui";
+import Link from "next/link";
+
+type Props = {
+ label?: string;
+ href?: string;
+ icon?: React.ReactNode | undefined;
+};
+
+export const BreadcrumbLink: React.FC
= (props) => {
+ const { href, label, icon } = props;
+ return (
+
+
+
+ {href ? (
+
+ {icon && (
+
{icon}
+ )}
+
{label}
+
+ ) : (
+
+ {icon &&
{icon}
}
+
{label}
+
+ )}
+
+
+
+ );
+};
diff --git a/web/components/common/index.ts b/web/components/common/index.ts
index 04aaa8512..0eff24d93 100644
--- a/web/components/common/index.ts
+++ b/web/components/common/index.ts
@@ -1,3 +1,4 @@
export * from "./product-updates-modal";
export * from "./empty-state";
export * from "./latest-feature-block";
+export * from "./breadcrumb-link";
diff --git a/web/components/core/modals/gpt-assistant-popover.tsx b/web/components/core/modals/gpt-assistant-popover.tsx
index 3afd6d1b9..590015e12 100644
--- a/web/components/core/modals/gpt-assistant-popover.tsx
+++ b/web/components/core/modals/gpt-assistant-popover.tsx
@@ -157,6 +157,7 @@ export const GptAssistantPopover: React.FC = (props) => {
window.removeEventListener("keydown", handleEnterKeyPress);
window.removeEventListener("keydown", handleEscapeKeyPress);
};
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isOpen, handleSubmit, onClose]);
const responseActionButton = response !== "" && (
diff --git a/web/components/cycles/active-cycle-details.tsx b/web/components/cycles/active-cycle-details.tsx
index 12d836695..a0101b1c1 100644
--- a/web/components/cycles/active-cycle-details.tsx
+++ b/web/components/cycles/active-cycle-details.tsx
@@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
import useSWR from "swr";
import { useTheme } from "next-themes";
// hooks
-import { useCycle, useIssues, useProject, useUser } from "hooks/store";
+import { useCycle, useIssues, useMember, useProject, useUser } from "hooks/store";
import useToast from "hooks/use-toast";
// ui
import { SingleProgressStats } from "components/core";
@@ -58,6 +58,7 @@ export const ActiveCycleDetails: React.FC = observer((props
removeCycleFromFavorites,
} = useCycle();
const { currentProjectDetails } = useProject();
+ const { getUserDetails } = useMember();
// toast alert
const { setToastAlert } = useToast();
@@ -67,6 +68,7 @@ export const ActiveCycleDetails: React.FC = observer((props
);
const activeCycle = currentProjectActiveCycleId ? getActiveCycleById(currentProjectActiveCycleId) : null;
+ const cycleOwnerDetails = activeCycle ? getUserDetails(activeCycle.owned_by) : undefined;
const { data: activeCycleIssues } = useSWR(
workspaceSlug && projectId && currentProjectActiveCycleId
@@ -203,20 +205,20 @@ export const ActiveCycleDetails: React.FC = observer((props
- {activeCycle.owned_by.avatar && activeCycle.owned_by.avatar !== "" ? (
+ {cycleOwnerDetails?.avatar && cycleOwnerDetails?.avatar !== "" ? (
) : (
- {activeCycle.owned_by.display_name.charAt(0)}
+ {cycleOwnerDetails?.display_name.charAt(0)}
)}
-
{activeCycle.owned_by.display_name}
+
{cycleOwnerDetails?.display_name}
{activeCycle.assignees.length > 0 && (
diff --git a/web/components/cycles/sidebar.tsx b/web/components/cycles/sidebar.tsx
index 33c2b3c82..4bf76f91f 100644
--- a/web/components/cycles/sidebar.tsx
+++ b/web/components/cycles/sidebar.tsx
@@ -6,7 +6,7 @@ import { Disclosure, Popover, Transition } from "@headlessui/react";
// services
import { CycleService } from "services/cycle.service";
// hooks
-import { useApplication, useCycle, useUser } from "hooks/store";
+import { useApplication, useCycle, useMember, useUser } from "hooks/store";
import useToast from "hooks/use-toast";
// components
import { SidebarProgressStats } from "components/core";
@@ -73,8 +73,10 @@ export const CycleDetailsSidebar: React.FC
= observer((props) => {
membership: { currentProjectRole },
} = useUser();
const { getCycleById, updateCycleDetails } = useCycle();
+ const { getUserDetails } = useMember();
const cycleDetails = getCycleById(cycleId);
+ const cycleOwnerDetails = cycleDetails ? getUserDetails(cycleDetails.owned_by) : undefined;
const { setToastAlert } = useToast();
@@ -518,8 +520,8 @@ export const CycleDetailsSidebar: React.FC = observer((props) => {
-
-
{cycleDetails.owned_by.display_name}
+
+
{cycleOwnerDetails?.display_name}
@@ -587,14 +589,16 @@ export const CycleDetailsSidebar: React.FC
= observer((props) => {
-
+ {cycleDetails && cycleDetails.distribution && (
+
+ )}
) : (
""
diff --git a/web/components/dashboard/widgets/overview-stats.tsx b/web/components/dashboard/widgets/overview-stats.tsx
index 418f0c63f..1a4c2646b 100644
--- a/web/components/dashboard/widgets/overview-stats.tsx
+++ b/web/components/dashboard/widgets/overview-stats.tsx
@@ -7,7 +7,6 @@ import { useDashboard } from "hooks/store";
import { WidgetLoader } from "components/dashboard/widgets";
// helpers
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
-import { cn } from "helpers/common.helper";
// types
import { TOverviewStatsWidgetResponse } from "@plane/types";
diff --git a/web/components/headers/cycle-issues.tsx b/web/components/headers/cycle-issues.tsx
index fc0075030..8e2ceab10 100644
--- a/web/components/headers/cycle-issues.tsx
+++ b/web/components/headers/cycle-issues.tsx
@@ -18,6 +18,7 @@ import useLocalStorage from "hooks/use-local-storage";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
import { ProjectAnalyticsModal } from "components/analytics";
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
// ui
import { Breadcrumbs, Button, ContrastIcon, CustomMenu } from "@plane/ui";
// icons
@@ -151,25 +152,33 @@ export const CycleIssuesHeader: React.FC = observer(() => {
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- label={currentProjectDetails?.name ?? "Project"}
- link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
/>
}
- label="Cycles"
- link={`/${workspaceSlug}/projects/${projectId}/cycles`}
+ link={
+ }
+ />
+ }
/>
{
// router
@@ -32,29 +33,32 @@ export const CyclesHeader: FC = observer(() => {
return (
-
+
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
/>
}
- label="Cycles"
+ link={} />}
/>
diff --git a/web/components/headers/global-issues.tsx b/web/components/headers/global-issues.tsx
index debcbc213..cca1a972b 100644
--- a/web/components/headers/global-issues.tsx
+++ b/web/components/headers/global-issues.tsx
@@ -8,6 +8,7 @@ import { useLabel, useMember, useUser, useIssues } from "hooks/store";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection } from "components/issues";
import { CreateUpdateWorkspaceViewModal } from "components/workspace";
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
// ui
import { Breadcrumbs, Button, LayersIcon, PhotoFilterIcon, Tooltip } from "@plane/ui";
// icons
@@ -108,18 +109,22 @@ export const GlobalIssuesHeader: React.FC
= observer((props) => {
setCreateViewModal(false)} />
-
+
- ) : (
-
- )
+ link={
+
+ ) : (
+
+ )
+ }
+ />
}
- label={`All ${activeLayout === "spreadsheet" ? "Issues" : "Views"}`}
/>
diff --git a/web/components/headers/module-issues.tsx b/web/components/headers/module-issues.tsx
index 84a284f2e..5ec67a3d7 100644
--- a/web/components/headers/module-issues.tsx
+++ b/web/components/headers/module-issues.tsx
@@ -18,6 +18,7 @@ import useLocalStorage from "hooks/use-local-storage";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
import { ProjectAnalyticsModal } from "components/analytics";
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
// ui
import { Breadcrumbs, Button, CustomMenu, DiceIcon } from "@plane/ui";
// icons
@@ -154,25 +155,33 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- label={currentProjectDetails?.name ?? "Project"}
- link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
/>
}
- label="Modules"
- link={`/${workspaceSlug}/projects/${projectId}/modules`}
+ link={
+ }
+ />
+ }
/>
{
// router
@@ -33,29 +34,32 @@ export const ModulesListHeader: React.FC = observer(() => {
return (
-
+
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
/>
}
- label="Modules"
+ link={} />}
/>
diff --git a/web/components/headers/page-details.tsx b/web/components/headers/page-details.tsx
index d2a959817..83595af60 100644
--- a/web/components/headers/page-details.tsx
+++ b/web/components/headers/page-details.tsx
@@ -10,6 +10,7 @@ import { Breadcrumbs, Button } from "@plane/ui";
import { renderEmoji } from "helpers/emoji.helper";
// components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
export interface IPagesHeaderProps {
showButton?: boolean;
@@ -29,35 +30,47 @@ export const PageDetailsHeader: FC
= observer((props) => {
return (
-
+
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
/>
}
- label="Pages"
- link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/pages`}
+ link={
+ }
+ />
+ }
/>
}
- label={pageDetails?.name ?? "Page"}
+ link={
+ }
+ />
+ }
/>
diff --git a/web/components/headers/pages.tsx b/web/components/headers/pages.tsx
index 2afb549a0..28116b323 100644
--- a/web/components/headers/pages.tsx
+++ b/web/components/headers/pages.tsx
@@ -11,6 +11,7 @@ import { renderEmoji } from "helpers/emoji.helper";
import { EUserProjectRoles } from "constants/project";
// components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
export const PagesHeader = observer(() => {
// router
@@ -31,29 +32,32 @@ export const PagesHeader = observer(() => {
return (
-
+
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
/>
}
- label="Pages"
+ link={} />}
/>
diff --git a/web/components/headers/profile-preferences.tsx b/web/components/headers/profile-preferences.tsx
index 0c6329ac9..e9f37bf6e 100644
--- a/web/components/headers/profile-preferences.tsx
+++ b/web/components/headers/profile-preferences.tsx
@@ -1,12 +1,13 @@
// components
import { Breadcrumbs } from "@plane/ui";
+import { BreadcrumbLink } from "components/common";
export const ProfilePreferencesHeader = () => (
diff --git a/web/components/headers/profile-settings.tsx b/web/components/headers/profile-settings.tsx
index 76e5e6fcc..24c69f093 100644
--- a/web/components/headers/profile-settings.tsx
+++ b/web/components/headers/profile-settings.tsx
@@ -2,6 +2,7 @@ import { FC } from "react";
// ui
import { Breadcrumbs } from "@plane/ui";
import { Settings } from "lucide-react";
+import { BreadcrumbLink } from "components/common";
interface IProfileSettingHeader {
title: string;
@@ -17,11 +18,15 @@ export const ProfileSettingsHeader: FC
= (props) => {
}
- link="/profile"
+ link={
+ }
+ />
+ }
/>
-
+ } />
diff --git a/web/components/headers/project-archived-issue-details.tsx b/web/components/headers/project-archived-issue-details.tsx
index e393450af..3b3e05f1a 100644
--- a/web/components/headers/project-archived-issue-details.tsx
+++ b/web/components/headers/project-archived-issue-details.tsx
@@ -16,6 +16,7 @@ import { IssueArchiveService } from "services/issue";
import { renderEmoji } from "helpers/emoji.helper";
// components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
const issueArchiveService = new IssueArchiveService();
@@ -41,37 +42,50 @@ export const ProjectArchivedIssueDetailsHeader: FC = observer(() => {
return (
-
+
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- label={currentProjectDetails?.name ?? "Project"}
- link={`/${workspaceSlug}/projects`}
/>
}
- label="Archived Issues"
- link={`/${workspaceSlug}/projects/${projectId}/archived-issues`}
+ link={
+ }
+ />
+ }
/>
}
/>
diff --git a/web/components/headers/project-archived-issues.tsx b/web/components/headers/project-archived-issues.tsx
index ee1265374..b7ca78ede 100644
--- a/web/components/headers/project-archived-issues.tsx
+++ b/web/components/headers/project-archived-issues.tsx
@@ -11,6 +11,7 @@ import { Breadcrumbs, LayersIcon } from "@plane/ui";
// components
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "components/issues";
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
// helpers
import { renderEmoji } from "helpers/emoji.helper";
// types
@@ -71,7 +72,7 @@ export const ProjectArchivedIssuesHeader: FC = observer(() => {
return (
-
+
diff --git a/web/components/headers/project-draft-issues.tsx b/web/components/headers/project-draft-issues.tsx
index 10f07f779..0fe6a74c5 100644
--- a/web/components/headers/project-draft-issues.tsx
+++ b/web/components/headers/project-draft-issues.tsx
@@ -6,6 +6,7 @@ import { useIssues, useLabel, useMember, useProject, useProjectState } from "hoo
// components
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
// ui
import { Breadcrumbs, LayersIcon } from "@plane/ui";
// helper
@@ -75,30 +76,35 @@ export const ProjectDraftIssueHeader: FC = observer(() => {
return (
-
+
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- label={currentProjectDetails?.name ?? "Project"}
- link={`/${workspaceSlug}/projects`}
/>
}
- label="Draft Issues"
+ link={
+ } />
+ }
/>
diff --git a/web/components/headers/project-inbox.tsx b/web/components/headers/project-inbox.tsx
index 29ea9fc47..b5260edd7 100644
--- a/web/components/headers/project-inbox.tsx
+++ b/web/components/headers/project-inbox.tsx
@@ -9,6 +9,7 @@ import { Breadcrumbs, Button, LayersIcon } from "@plane/ui";
// components
import { CreateInboxIssueModal } from "components/inbox";
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
// helper
import { renderEmoji } from "helpers/emoji.helper";
@@ -24,30 +25,35 @@ export const ProjectInboxHeader: FC = observer(() => {
return (
-
+
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- label={currentProjectDetails?.name ?? "Project"}
- link={`/${workspaceSlug}/projects`}
/>
}
- label="Inbox Issues"
+ link={
+ } />
+ }
/>
diff --git a/web/components/headers/project-issue-details.tsx b/web/components/headers/project-issue-details.tsx
index 7b45d3fcf..8d3a22682 100644
--- a/web/components/headers/project-issue-details.tsx
+++ b/web/components/headers/project-issue-details.tsx
@@ -14,6 +14,7 @@ import { IssueService } from "services/issue";
import { ISSUE_DETAILS } from "constants/fetch-keys";
// components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
// services
const issueService = new IssueService();
@@ -35,37 +36,50 @@ export const ProjectIssueDetailsHeader: FC = observer(() => {
return (
-
+
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- label={currentProjectDetails?.name ?? "Project"}
- link={`/${workspaceSlug}/projects`}
/>
}
- label="Issues"
- link={`/${workspaceSlug}/projects/${projectId}/issues`}
+ link={
+ }
+ />
+ }
/>
}
/>
diff --git a/web/components/headers/project-issues.tsx b/web/components/headers/project-issues.tsx
index 04a7ecb64..29ecb16c7 100644
--- a/web/components/headers/project-issues.tsx
+++ b/web/components/headers/project-issues.tsx
@@ -9,6 +9,7 @@ import { useApplication, useLabel, useProject, useProjectState, useUser, useInbo
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
import { ProjectAnalyticsModal } from "components/analytics";
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
// ui
import { Breadcrumbs, Button, LayersIcon } from "@plane/ui";
// types
@@ -106,7 +107,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
/>
-
+
diff --git a/web/components/headers/project-settings.tsx b/web/components/headers/project-settings.tsx
index eff05aba5..fdb033a21 100644
--- a/web/components/headers/project-settings.tsx
+++ b/web/components/headers/project-settings.tsx
@@ -11,6 +11,7 @@ import { useProject, useUser } from "hooks/store";
import { EUserProjectRoles, PROJECT_SETTINGS_LINKS } from "constants/project";
// components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
export interface IProjectSettingHeader {
title: string;
@@ -38,22 +39,26 @@ export const ProjectSettingHeader: FC
= observer((props)
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
/>
-
+ } />
@@ -62,13 +67,18 @@ export const ProjectSettingHeader: FC
= observer((props)
className="flex-shrink-0 block sm:block md:hidden lg:hidden"
maxHeight="lg"
customButton={
- {title}
+
+ {title}
+
}
placement="bottom-start"
closeOnSelect
>
{PROJECT_SETTINGS_LINKS.map((item) => (
- router.push(`/${workspaceSlug}/projects/${projectId}${item.href}`)}>
+ router.push(`/${workspaceSlug}/projects/${projectId}${item.href}`)}
+ >
{item.label}
))}
diff --git a/web/components/headers/project-view-issues.tsx b/web/components/headers/project-view-issues.tsx
index abe13c4e2..050400a2c 100644
--- a/web/components/headers/project-view-issues.tsx
+++ b/web/components/headers/project-view-issues.tsx
@@ -17,6 +17,7 @@ import {
// components
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
// ui
import { Breadcrumbs, Button, CustomMenu, PhotoFilterIcon } from "@plane/ui";
// helpers
@@ -112,29 +113,37 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
- {renderEmoji(currentProjectDetails.emoji)}
-
- ) : currentProjectDetails?.icon_prop ? (
-
- {renderEmoji(currentProjectDetails.icon_prop)}
-
- ) : (
-
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {renderEmoji(currentProjectDetails.emoji)}
+
+ ) : currentProjectDetails?.icon_prop ? (
+
+ {renderEmoji(currentProjectDetails.icon_prop)}
+
+ ) : (
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
/>
}
- label="Views"
- link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/views`}
+ link={
+ }
+ />
+ }
/>
{
<>
-
+
- {renderEmoji(currentProjectDetails.emoji)}
-
- ) : currentProjectDetails?.icon_prop ? (
-
- {renderEmoji(currentProjectDetails.icon_prop)}
-
- ) : (
-
- {currentProjectDetails?.name.charAt(0)}
-
- )
+ link={
+
+ {renderEmoji(currentProjectDetails.emoji)}
+
+ ) : currentProjectDetails?.icon_prop ? (
+
+ {renderEmoji(currentProjectDetails.icon_prop)}
+
+ ) : (
+
+ {currentProjectDetails?.name.charAt(0)}
+
+ )
+ }
+ />
}
- link={`/${workspaceSlug}/projects/${currentProjectDetails?.id}/issues`}
/>
}
- label="Views"
+ link={
+ } />
+ }
/>
diff --git a/web/components/headers/projects.tsx b/web/components/headers/projects.tsx
index 96929f7b0..33192930e 100644
--- a/web/components/headers/projects.tsx
+++ b/web/components/headers/projects.tsx
@@ -8,6 +8,7 @@ import { Breadcrumbs, Button } from "@plane/ui";
import { EUserWorkspaceRoles } from "constants/workspace";
// components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
export const ProjectsHeader = observer(() => {
// store hooks
@@ -25,13 +26,12 @@ export const ProjectsHeader = observer(() => {
return (
-
+
}
- label="Projects"
+ link={} />}
/>
diff --git a/web/components/headers/user-profile.tsx b/web/components/headers/user-profile.tsx
index dca0dc7e6..d54f73009 100644
--- a/web/components/headers/user-profile.tsx
+++ b/web/components/headers/user-profile.tsx
@@ -1,15 +1,16 @@
// ui
import { Breadcrumbs } from "@plane/ui";
+import { BreadcrumbLink } from "components/common";
// components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
export const UserProfileHeader = () => (
diff --git a/web/components/headers/workspace-active-cycles.tsx b/web/components/headers/workspace-active-cycles.tsx
index 90cbccd81..195b89471 100644
--- a/web/components/headers/workspace-active-cycles.tsx
+++ b/web/components/headers/workspace-active-cycles.tsx
@@ -1,9 +1,10 @@
import { observer } from "mobx-react-lite";
// ui
import { Breadcrumbs, ContrastIcon } from "@plane/ui";
+import { BreadcrumbLink } from "components/common";
+import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
// icons
import { Crown } from "lucide-react";
-import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
export const WorkspaceActiveCycleHeader = observer(() => (
@@ -13,8 +14,12 @@ export const WorkspaceActiveCycleHeader = observer(() => (
}
- label="Active Cycles"
+ link={
+ }
+ />
+ }
/>
diff --git a/web/components/headers/workspace-analytics.tsx b/web/components/headers/workspace-analytics.tsx
index 2ae373471..8bb4c9251 100644
--- a/web/components/headers/workspace-analytics.tsx
+++ b/web/components/headers/workspace-analytics.tsx
@@ -4,6 +4,7 @@ import { ArrowLeft, BarChart2 } from "lucide-react";
import { Breadcrumbs } from "@plane/ui";
// components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
+import { BreadcrumbLink } from "components/common";
export const WorkspaceAnalyticsHeader = () => {
const router = useRouter();
@@ -28,8 +29,9 @@ export const WorkspaceAnalyticsHeader = () => {
}
- label="Analytics"
+ link={
+ } />
+ }
/>
diff --git a/web/components/headers/workspace-dashboard.tsx b/web/components/headers/workspace-dashboard.tsx
index d576cb963..b7c05929c 100644
--- a/web/components/headers/workspace-dashboard.tsx
+++ b/web/components/headers/workspace-dashboard.tsx
@@ -6,7 +6,7 @@ import { useTheme } from "next-themes";
import githubBlackImage from "/public/logos/github-black.png";
import githubWhiteImage from "/public/logos/github-white.png";
// components
-import { ProductUpdatesModal } from "components/common";
+import { BreadcrumbLink, ProductUpdatesModal } from "components/common";
import { Breadcrumbs } from "@plane/ui";
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
@@ -25,8 +25,9 @@ export const WorkspaceDashboardHeader = () => {
}
- label="Dashboard"
+ link={
+ } />
+ }
/>
diff --git a/web/components/headers/workspace-settings.tsx b/web/components/headers/workspace-settings.tsx
index 625b7991c..5ced55204 100644
--- a/web/components/headers/workspace-settings.tsx
+++ b/web/components/headers/workspace-settings.tsx
@@ -8,6 +8,7 @@ import { observer } from "mobx-react-lite";
// components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
import { WORKSPACE_SETTINGS_LINKS } from "constants/workspace";
+import { BreadcrumbLink } from "components/common";
export interface IWorkspaceSettingHeader {
title: string;
@@ -27,12 +28,16 @@ export const WorkspaceSettingHeader: FC
= observer((pro
}
- link={`/${workspaceSlug}/settings`}
+ link={
+ }
+ />
+ }
/>
-
+ } />
@@ -40,7 +45,9 @@ export const WorkspaceSettingHeader: FC
= observer((pro
className="flex-shrink-0 block sm:block md:hidden lg:hidden"
maxHeight="lg"
customButton={
- {title}
+
+ {title}
+
}
placement="bottom-start"
closeOnSelect
diff --git a/web/components/integration/jira/give-details.tsx b/web/components/integration/jira/give-details.tsx
index efeca487a..0d90ba0a5 100644
--- a/web/components/integration/jira/give-details.tsx
+++ b/web/components/integration/jira/give-details.tsx
@@ -7,6 +7,8 @@ import { Plus } from "lucide-react";
import { useApplication, useProject } from "hooks/store";
// components
import { CustomSelect, Input } from "@plane/ui";
+// helpers
+import { checkEmailValidity } from "helpers/string.helper";
// types
import { IJiraImporterForm } from "@plane/types";
@@ -46,17 +48,18 @@ export const JiraGetImportDetail: React.FC = observer(() => {
render={({ field: { value, onChange, ref } }) => (
)}
/>
+ {errors.metadata?.api_token && {errors.metadata.api_token.message}
}
@@ -75,7 +78,6 @@ export const JiraGetImportDetail: React.FC = observer(() => {
render={({ field: { value, onChange, ref } }) => (
{
/>
)}
/>
+ {errors.metadata?.project_key && (
+
{errors.metadata.project_key.message}
+ )}
@@ -100,11 +105,11 @@ export const JiraGetImportDetail: React.FC = observer(() => {
name="metadata.email"
rules={{
required: "Please enter email address.",
+ validate: (value) => checkEmailValidity(value) || "Please enter a valid email address",
}}
render={({ field: { value, onChange, ref } }) => (
{
/>
)}
/>
+ {errors.metadata?.email &&
{errors.metadata.email.message}
}
@@ -129,12 +135,11 @@ export const JiraGetImportDetail: React.FC = observer(() => {
name="metadata.cloud_hostname"
rules={{
required: "Please enter your cloud host name.",
+ validate: (value) => !/^https?:\/\//.test(value) || "Hostname should not begin with http:// or https://",
}}
render={({ field: { value, onChange, ref } }) => (
{
/>
)}
/>
+ {errors.metadata?.cloud_hostname && (
+
{errors.metadata.cloud_hostname.message}
+ )}
diff --git a/web/components/issues/draft-issue-form.tsx b/web/components/issues/draft-issue-form.tsx
index 3c9870469..cfd6370fa 100644
--- a/web/components/issues/draft-issue-form.tsx
+++ b/web/components/issues/draft-issue-form.tsx
@@ -170,17 +170,6 @@ export const DraftIssueForm: FC
= observer((props) => {
// handleClose();
// };
- useEffect(() => {
- if (!isOpen || data) return;
-
- setLocalStorageValue(
- JSON.stringify({
- ...payload,
- })
- );
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [JSON.stringify(payload), isOpen, data]);
-
// const onClose = () => {
// handleClose();
// };
@@ -258,13 +247,7 @@ export const DraftIssueForm: FC = observer((props) => {
useEffect(() => {
setFocus("name");
-
- reset({
- ...defaultValues,
- ...(prePopulatedData ?? {}),
- ...(data ?? {}),
- });
- }, [setFocus, prePopulatedData, reset, data]);
+ }, [setFocus]);
// update projectId in form when projectId changes
useEffect(() => {
diff --git a/web/components/issues/issue-detail/issue-activity/comments/comment-create.tsx b/web/components/issues/issue-detail/issue-activity/comments/comment-create.tsx
index 172a0bb82..bb79c9817 100644
--- a/web/components/issues/issue-detail/issue-activity/comments/comment-create.tsx
+++ b/web/components/issues/issue-detail/issue-activity/comments/comment-create.tsx
@@ -10,7 +10,7 @@ import { TActivityOperations } from "../root";
import { TIssueComment } from "@plane/types";
// icons
import { Globe2, Lock } from "lucide-react";
-import { useWorkspace } from "hooks/store";
+import { useMention, useWorkspace } from "hooks/store";
const fileService = new FileService();
@@ -43,6 +43,8 @@ export const IssueCommentCreate: FC = (props) => {
const workspaceStore = useWorkspace();
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string;
+ const { mentionHighlights, mentionSuggestions } = useMention();
+
// refs
const editorRef = useRef(null);
// react hook form
@@ -61,7 +63,14 @@ export const IssueCommentCreate: FC = (props) => {
};
return (
-
+
{
+ // if (e.key === "Enter" && !e.shiftKey) {
+ // e.preventDefault();
+ // // handleSubmit(onSubmit)(e);
+ // }
+ // }}
+ >
= (props) => {
render={({ field: { value, onChange } }) => (
{
+ console.log("yo");
handleSubmit(onSubmit)(e);
}}
cancelUploadImage={fileService.cancelUpload}
@@ -86,6 +96,8 @@ export const IssueCommentCreate: FC = (props) => {
onChange={(comment_json: Object, comment_html: string) => {
onChange(comment_html);
}}
+ mentionSuggestions={mentionSuggestions}
+ mentionHighlights={mentionHighlights}
commentAccessSpecifier={
showAccessSpecifier
? { accessValue: accessValue ?? "INTERNAL", onAccessChange, showAccessSpecifier, commentAccess }
diff --git a/web/components/issues/issue-layouts/calendar/base-calendar-root.tsx b/web/components/issues/issue-layouts/calendar/base-calendar-root.tsx
index 3b3ef887e..7cb53ad39 100644
--- a/web/components/issues/issue-layouts/calendar/base-calendar-root.tsx
+++ b/web/components/issues/issue-layouts/calendar/base-calendar-root.tsx
@@ -61,7 +61,8 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
projectId?.toString(),
issueStore,
issueMap,
- groupedIssueIds
+ groupedIssueIds,
+ viewId
).catch((err) => {
setToastAlert({
title: "Error",
diff --git a/web/components/issues/issue-layouts/empty-states/module.tsx b/web/components/issues/issue-layouts/empty-states/module.tsx
index aa3a8dc19..109a903a2 100644
--- a/web/components/issues/issue-layouts/empty-states/module.tsx
+++ b/web/components/issues/issue-layouts/empty-states/module.tsx
@@ -2,7 +2,7 @@ import { useState } from "react";
import { observer } from "mobx-react-lite";
import { PlusIcon } from "lucide-react";
// hooks
-import { useApplication, useIssueDetail, useIssues, useUser } from "hooks/store";
+import { useApplication, useIssues, useUser } from "hooks/store";
import useToast from "hooks/use-toast";
// components
import { EmptyState } from "components/common";
@@ -29,7 +29,6 @@ export const ModuleEmptyState: React.FC = observer((props) => {
const [moduleIssuesListModal, setModuleIssuesListModal] = useState(false);
// store hooks
const { issues } = useIssues(EIssuesStoreType.MODULE);
- const { updateIssue, fetchIssue } = useIssueDetail();
const {
commandPalette: { toggleCreateIssueModal },
diff --git a/web/components/issues/issue-layouts/spreadsheet/base-spreadsheet-root.tsx b/web/components/issues/issue-layouts/spreadsheet/base-spreadsheet-root.tsx
index a5667f99d..54df6ca24 100644
--- a/web/components/issues/issue-layouts/spreadsheet/base-spreadsheet-root.tsx
+++ b/web/components/issues/issue-layouts/spreadsheet/base-spreadsheet-root.tsx
@@ -97,6 +97,7 @@ export const BaseSpreadsheetRoot = observer((props: IBaseSpreadsheetRoot) => {
portalElement={portalElement}
/>
),
+ // eslint-disable-next-line react-hooks/exhaustive-deps
[handleIssues]
);
diff --git a/web/components/issues/issue-modal/form.tsx b/web/components/issues/issue-modal/form.tsx
index 703a9783f..31cb9dd66 100644
--- a/web/components/issues/issue-modal/form.tsx
+++ b/web/components/issues/issue-modal/form.tsx
@@ -132,6 +132,7 @@ export const IssueFormRoot: FC = observer((props) => {
parent_id: formData.parent_id,
});
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [projectId]);
const issueName = watch("name");
diff --git a/web/components/project/form.tsx b/web/components/project/form.tsx
index f4ab3e846..5be7033a4 100644
--- a/web/components/project/form.tsx
+++ b/web/components/project/form.tsx
@@ -1,4 +1,4 @@
-import { FC, useEffect } from "react";
+import { FC, useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
// hooks
import { useApplication, useProject, useWorkspace } from "hooks/store";
@@ -29,6 +29,8 @@ const projectService = new ProjectService();
export const ProjectDetailsForm: FC = (props) => {
const { project, workspaceSlug, isAdmin } = props;
+ // states
+ const [isLoading, setIsLoading] = useState(false);
// store hooks
const {
eventTracker: { postHogEventTracker },
@@ -45,7 +47,7 @@ export const ProjectDetailsForm: FC = (props) => {
setValue,
setError,
reset,
- formState: { errors, isSubmitting },
+ formState: { errors },
} = useForm({
defaultValues: {
...project,
@@ -114,6 +116,7 @@ export const ProjectDetailsForm: FC = (props) => {
const onSubmit = async (formData: IProject) => {
if (!workspaceSlug) return;
+ setIsLoading(true);
const payload: Partial = {
name: formData.name,
@@ -139,6 +142,10 @@ export const ProjectDetailsForm: FC = (props) => {
else await handleUpdateChange(payload);
});
else await handleUpdateChange(payload);
+
+ setTimeout(() => {
+ setIsLoading(false);
+ }, 300);
};
const currentNetwork = NETWORK_CHOICES.find((n) => n.key === project?.network);
@@ -308,8 +315,8 @@ export const ProjectDetailsForm: FC = (props) => {
<>
-
)}
diff --git a/web/lib/app-provider.tsx b/web/lib/app-provider.tsx
index 027800cd8..dad6253c9 100644
--- a/web/lib/app-provider.tsx
+++ b/web/lib/app-provider.tsx
@@ -47,7 +47,7 @@ export const AppProvider: FC = observer((props) => {
- {/* = observer((props) => {
posthogHost={envConfig?.posthog_host || null}
>
{children}
- */}
- {children}
+
diff --git a/web/lib/wrappers/posthog-wrapper.tsx b/web/lib/wrappers/posthog-wrapper.tsx
index 6ce830517..f310f0c39 100644
--- a/web/lib/wrappers/posthog-wrapper.tsx
+++ b/web/lib/wrappers/posthog-wrapper.tsx
@@ -40,9 +40,9 @@ const PosthogWrapper: FC = (props) => {
posthog.init(posthogAPIKey, {
api_host: posthogHost || "https://app.posthog.com",
// Enable debug mode in development
- loaded: (posthog) => {
- if (process.env.NODE_ENV === "development") posthog.debug();
- },
+ // loaded: (posthog) => {
+ // if (process.env.NODE_ENV === "development") posthog.debug();
+ // },
autocapture: false,
capture_pageview: false, // Disable automatic pageview capture, as we capture manually
});
diff --git a/web/pages/profile/index.tsx b/web/pages/profile/index.tsx
index 3174c53f3..294ef3574 100644
--- a/web/pages/profile/index.tsx
+++ b/web/pages/profile/index.tsx
@@ -39,6 +39,7 @@ const fileService = new FileService();
const ProfileSettingsPage: NextPageWithLayout = observer(() => {
// states
+ const [isLoading, setIsLoading] = useState(false);
const [isRemoving, setIsRemoving] = useState(false);
const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false);
const [deactivateAccountModal, setDeactivateAccountModal] = useState(false);
@@ -48,7 +49,7 @@ const ProfileSettingsPage: NextPageWithLayout = observer(() => {
reset,
watch,
control,
- formState: { errors, isSubmitting },
+ formState: { errors },
} = useForm({ defaultValues });
// toast alert
const { setToastAlert } = useToast();
@@ -62,6 +63,7 @@ const ProfileSettingsPage: NextPageWithLayout = observer(() => {
}, [myProfile, reset]);
const onSubmit = async (formData: IUser) => {
+ setIsLoading(true);
const payload: Partial = {
first_name: formData.first_name,
last_name: formData.last_name,
@@ -87,6 +89,9 @@ const ProfileSettingsPage: NextPageWithLayout = observer(() => {
message: "There was some error in updating your profile. Please try again.",
})
);
+ setTimeout(() => {
+ setIsLoading(false);
+ }, 300);
};
const handleDelete = (url: string | null | undefined, updateUser: boolean = false) => {
@@ -388,8 +393,8 @@ const ProfileSettingsPage: NextPageWithLayout = observer(() => {
-
- {isSubmitting ? "Saving..." : "Save changes"}
+
+ {isLoading ? "Saving..." : "Save changes"}
diff --git a/web/store/issue/cycle/issue.store.ts b/web/store/issue/cycle/issue.store.ts
index 1a8343006..286222e4a 100644
--- a/web/store/issue/cycle/issue.store.ts
+++ b/web/store/issue/cycle/issue.store.ts
@@ -200,6 +200,7 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
if (!cycleId) throw new Error("Cycle Id is required");
const response = await this.rootIssueStore.projectIssues.updateIssue(workspaceSlug, projectId, issueId, data);
+ this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
@@ -267,9 +268,7 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
});
runInAction(() => {
- update(this.issues, cycleId, (cycleIssueIds = []) => {
- return uniq(concat(cycleIssueIds, issueIds));
- });
+ update(this.issues, cycleId, (cycleIssueIds = []) => uniq(concat(cycleIssueIds, issueIds)));
});
issueIds.forEach((issueId) => {
this.rootStore.issues.updateIssue(issueId, { cycle_id: cycleId });
diff --git a/web/store/issue/module/issue.store.ts b/web/store/issue/module/issue.store.ts
index da2b127c1..e32b97df0 100644
--- a/web/store/issue/module/issue.store.ts
+++ b/web/store/issue/module/issue.store.ts
@@ -205,6 +205,7 @@ export class ModuleIssues extends IssueHelperStore implements IModuleIssues {
if (!moduleId) throw new Error("Module Id is required");
const response = await this.rootIssueStore.projectIssues.updateIssue(workspaceSlug, projectId, issueId, data);
+ this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", moduleId);
diff --git a/web/store/issue/root.store.ts b/web/store/issue/root.store.ts
index 04f46c280..b2425757c 100644
--- a/web/store/issue/root.store.ts
+++ b/web/store/issue/root.store.ts
@@ -38,6 +38,8 @@ export interface IIssueRootStore {
members: string[] | undefined;
projects: string[] | undefined;
+ rootStore: RootStore;
+
issues: IIssueStore;
state: IStateStore;
@@ -87,6 +89,8 @@ export class IssueRootStore implements IIssueRootStore {
members: string[] | undefined = undefined;
projects: string[] | undefined = undefined;
+ rootStore: RootStore;
+
issues: IIssueStore;
state: IStateStore;
@@ -136,6 +140,8 @@ export class IssueRootStore implements IIssueRootStore {
projects: observable,
});
+ this.rootStore = rootStore;
+
autorun(() => {
if (rootStore.user.currentUser?.id) this.currentUserId = rootStore.user.currentUser?.id;
if (rootStore.app.router.workspaceSlug) this.workspaceSlug = rootStore.app.router.workspaceSlug;