diff --git a/admin/components/admin-sidebar/help-section.tsx b/admin/components/admin-sidebar/help-section.tsx index 62e5039339..38edd06fc2 100644 --- a/admin/components/admin-sidebar/help-section.tsx +++ b/admin/components/admin-sidebar/help-section.tsx @@ -8,7 +8,7 @@ import { Transition } from "@headlessui/react"; // ui import { DiscordIcon, GithubIcon, Tooltip } from "@plane/ui"; // helpers -import { cn, WEB_BASE_URL } from "@/helpers/common.helper"; +import { WEB_BASE_URL, cn } from "@/helpers/common.helper"; // hooks import { useTheme } from "@/hooks/store"; // assets diff --git a/apiserver/plane/db/models/asset.py b/apiserver/plane/db/models/asset.py index 7dd2f2c91c..86e5ceef82 100644 --- a/apiserver/plane/db/models/asset.py +++ b/apiserver/plane/db/models/asset.py @@ -12,6 +12,7 @@ from .base import BaseModel def get_upload_path(instance, filename): + filename = filename[:50] if instance.workspace_id is not None: return f"{instance.workspace.id}/{uuid4().hex}-{filename}" return f"user-{uuid4().hex}-{filename}" diff --git a/packages/editor/core/src/ui/plugins/image/image-upload-handler.ts b/packages/editor/core/src/ui/plugins/image/image-upload-handler.ts index 0be22e0dda..eb70218199 100644 --- a/packages/editor/core/src/ui/plugins/image/image-upload-handler.ts +++ b/packages/editor/core/src/ui/plugins/image/image-upload-handler.ts @@ -50,9 +50,25 @@ export async function startImageUpload( }; try { + const fileNameTrimmed = trimFileName(file.name); + const fileWithTrimmedName = new File([file], fileNameTrimmed, { type: file.type }); + + const resolvedPos = view.state.doc.resolve(pos ?? 0); + const nodeBefore = resolvedPos.nodeBefore; + + // if the image is at the start of the line i.e. when nodeBefore is null + if (nodeBefore === null) { + if (pos) { + // so that the image is not inserted at the next line, else incase the + // image is inserted at any line where there's some content, the + // position is kept as it is to be inserted at the next line + pos -= 1; + } + } + view.focus(); - const src = await uploadAndValidateImage(file, uploadFile); + const src = await uploadAndValidateImage(fileWithTrimmedName, uploadFile); if (src == null) { throw new Error("Resolved image URL is undefined."); @@ -112,3 +128,14 @@ async function uploadAndValidateImage(file: File, uploadFile: UploadImage): Prom throw error; } } + +function trimFileName(fileName: string, maxLength = 100) { + if (fileName.length > maxLength) { + const extension = fileName.split(".").pop(); + const nameWithoutExtension = fileName.slice(0, -(extension?.length ?? 0 + 1)); + const allowedNameLength = maxLength - (extension?.length ?? 0) - 1; // -1 for the dot + return `${nameWithoutExtension.slice(0, allowedNameLength)}.${extension}`; + } + + return fileName; +} diff --git a/web/components/core/modals/gpt-assistant-popover.tsx b/web/components/core/modals/gpt-assistant-popover.tsx index 5fd992a28c..099b90254e 100644 --- a/web/components/core/modals/gpt-assistant-popover.tsx +++ b/web/components/core/modals/gpt-assistant-popover.tsx @@ -210,11 +210,7 @@ export const GptAssistantPopover: React.FC = (props) => { {response !== "" && (
Response: - ${response}

`} - containerClassName={response ? "-mx-3 -my-3" : ""} - ref={responseRef} - /> + ${response}

`} ref={responseRef} />
)} {invalidResponse && ( diff --git a/web/components/inbox/root.tsx b/web/components/inbox/root.tsx index 7d4aff955d..759dce50c3 100644 --- a/web/components/inbox/root.tsx +++ b/web/components/inbox/root.tsx @@ -1,6 +1,5 @@ -import { FC, useState } from "react"; +import { FC, useEffect, useState } from "react"; import { observer } from "mobx-react"; -import useSWR from "swr"; import { Inbox, PanelLeft } from "lucide-react"; // components import { EmptyState } from "@/components/empty-state"; @@ -10,6 +9,7 @@ import { InboxLayoutLoader } from "@/components/ui"; import { EmptyStateType } from "@/constants/empty-state"; // helpers import { cn } from "@/helpers/common.helper"; +import { EInboxIssueCurrentTab } from "@/helpers/inbox.helper"; // hooks import { useProjectInbox } from "@/hooks/store"; @@ -18,25 +18,25 @@ type TInboxIssueRoot = { projectId: string; inboxIssueId: string | undefined; inboxAccessible: boolean; + navigationTab?: EInboxIssueCurrentTab | undefined; }; export const InboxIssueRoot: FC = observer((props) => { - const { workspaceSlug, projectId, inboxIssueId, inboxAccessible } = props; + const { workspaceSlug, projectId, inboxIssueId, inboxAccessible, navigationTab } = props; // states const [isMobileSidebar, setIsMobileSidebar] = useState(true); // hooks - const { loader, error, fetchInboxIssues } = useProjectInbox(); + const { loader, error, currentTab, handleCurrentTab, fetchInboxIssues } = useProjectInbox(); - useSWR( - inboxAccessible && workspaceSlug && projectId ? `PROJECT_INBOX_ISSUES_${workspaceSlug}_${projectId}` : null, - async () => { - inboxAccessible && - workspaceSlug && - projectId && - (await fetchInboxIssues(workspaceSlug.toString(), projectId.toString())); - }, - { revalidateOnFocus: false, revalidateIfStale: false } - ); + useEffect(() => { + if (!inboxAccessible || !workspaceSlug || !projectId) return; + if (navigationTab && navigationTab !== currentTab) { + handleCurrentTab(navigationTab); + } else { + fetchInboxIssues(workspaceSlug.toString(), projectId.toString()); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [inboxAccessible, workspaceSlug, projectId]); // loader if (loader === "init-loading") diff --git a/web/components/inbox/sidebar/root.tsx b/web/components/inbox/sidebar/root.tsx index ed6d0cdd2d..f0cd9657b5 100644 --- a/web/components/inbox/sidebar/root.tsx +++ b/web/components/inbox/sidebar/root.tsx @@ -1,4 +1,4 @@ -import { FC, useCallback, useRef } from "react"; +import { FC, useCallback, useRef, useState } from "react"; import { observer } from "mobx-react"; import { useRouter } from "next/router"; import { TInboxIssueCurrentTab } from "@plane/types"; @@ -37,7 +37,7 @@ export const InboxSidebar: FC = observer((props) => { const { workspaceSlug, projectId, setIsMobileSidebar } = props; // ref const containerRef = useRef(null); - const elementRef = useRef(null); + const [elementRef, setElementRef] = useState(null); // store const { currentProjectDetails } = useProject(); const { @@ -72,8 +72,10 @@ export const InboxSidebar: FC = observer((props) => { currentTab === option?.key ? `text-custom-primary-100` : `hover:text-custom-text-200` )} onClick={() => { - if (currentTab != option?.key) handleCurrentTab(option?.key); - router.push(`/${workspaceSlug}/projects/${projectId}/inbox?currentTab=${option?.key}`); + if (currentTab != option?.key) { + handleCurrentTab(option?.key); + router.push(`/${workspaceSlug}/projects/${projectId}/inbox?currentTab=${option?.key}`); + } }} >
{option?.label}
@@ -126,14 +128,14 @@ export const InboxSidebar: FC = observer((props) => { /> )} - {inboxIssuePaginationInfo?.next_page_results && ( -
+
+ {inboxIssuePaginationInfo?.next_page_results && ( + )}
- )}
)} diff --git a/web/components/issues/issue-detail/reactions/reaction-selector.tsx b/web/components/issues/issue-detail/reactions/reaction-selector.tsx index da517e975b..e3d58b5048 100644 --- a/web/components/issues/issue-detail/reactions/reaction-selector.tsx +++ b/web/components/issues/issue-detail/reactions/reaction-selector.tsx @@ -44,11 +44,11 @@ export const ReactionSelector: React.FC = (props) => { leaveTo="opacity-0 translate-y-1" > -
+
{reactionEmojis.map((emoji) => (
diff --git a/web/store/inbox/project-inbox.store.ts b/web/store/inbox/project-inbox.store.ts index 2aecb17cbe..2557f79797 100644 --- a/web/store/inbox/project-inbox.store.ts +++ b/web/store/inbox/project-inbox.store.ts @@ -321,8 +321,6 @@ export class ProjectInboxStore implements IProjectInboxStore { (this.inboxIssuePaginationInfo?.total_results && this.inboxIssueIds.length < this.inboxIssuePaginationInfo?.total_results)) ) { - this.loader = "pagination-loading"; - const queryParams = this.inboxIssueQueryParams( this.inboxFilters, this.inboxSorting, @@ -332,7 +330,6 @@ export class ProjectInboxStore implements IProjectInboxStore { const { results, ...paginationInfo } = await this.inboxIssueService.list(workspaceSlug, projectId, queryParams); runInAction(() => { - this.loader = undefined; set(this, "inboxIssuePaginationInfo", paginationInfo); if (results && results.length > 0) { const issueIds = results.map((value) => value?.issue?.id); @@ -343,7 +340,6 @@ export class ProjectInboxStore implements IProjectInboxStore { } else set(this, ["inboxIssuePaginationInfo", "next_page_results"], false); } catch (error) { console.error("Error fetching the inbox issues", error); - this.loader = undefined; this.error = { message: "Error fetching the paginated inbox issues please try again later.", status: "pagination-error",