Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion packages/editor/src/core/extensions/custom-image/custom-image.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Editor, mergeAttributes } from "@tiptap/core";
import { Image } from "@tiptap/extension-image";
import { MarkdownSerializerState } from "@tiptap/pm/markdown";
import { Node } from "@tiptap/pm/model";
import { ReactNodeViewRenderer } from "@tiptap/react";
import { v4 as uuidv4 } from "uuid";
// extensions
import { CustomImageNode } from "@/extensions/custom-image";
import { CustomImageNode, ImageAttributes } from "@/extensions/custom-image";
// plugins
import { TrackImageDeletionPlugin, TrackImageRestorationPlugin, isFileValid } from "@/plugins/image";
// types
Expand Down Expand Up @@ -121,6 +123,15 @@ export const CustomImageExtension = (props: TFileHandler) => {
deletedImageSet: new Map<string, boolean>(),
uploadInProgress: false,
maxFileSize,
markdown: {
serialize(state: MarkdownSerializerState, node: Node) {
const attrs = node.attrs as ImageAttributes;
const imageSource = state.esc(this?.editor?.commands?.getImageSource?.(attrs.src) || attrs.src);
const imageWidth = state.esc(attrs.width?.toString());
state.write(`<img src="${state.esc(imageSource)}" width="${imageWidth}" />`);
state.closeBlock(node);
},
},
};
},

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { mergeAttributes } from "@tiptap/core";
import { Image } from "@tiptap/extension-image";
import { MarkdownSerializerState } from "@tiptap/pm/markdown";
import { Node } from "@tiptap/pm/model";
import { ReactNodeViewRenderer } from "@tiptap/react";
// components
import { CustomImageNode, UploadImageExtensionStorage } from "@/extensions/custom-image";
import { CustomImageNode, ImageAttributes, UploadImageExtensionStorage } from "@/extensions/custom-image";
// types
import { TFileHandler } from "@/types";

Expand Down Expand Up @@ -52,6 +54,15 @@ export const CustomReadOnlyImageExtension = (props: Pick<TFileHandler, "getAsset
addStorage() {
return {
fileMap: new Map(),
markdown: {
serialize(state: MarkdownSerializerState, node: Node) {
const attrs = node.attrs as ImageAttributes;
const imageSource = state.esc(this?.editor?.commands?.getImageSource?.(attrs.src) || attrs.src);
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix invocation of getImageSource command

The current implementation doesn't address the issue raised in a previous review. The getImageSource command returns a function that needs to be invoked to get the actual image source. Currently, the function is not being called, which may result in imageSource being assigned a function instead of the expected string.

Apply the following diff to fix the issue:

- const imageSource = state.esc(this?.editor?.commands?.getImageSource?.(attrs.src) || attrs.src);
+ const imageSource = state.esc(this?.editor?.commands?.getImageSource?.(attrs.src)?.() || attrs.src);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const imageSource = state.esc(this?.editor?.commands?.getImageSource?.(attrs.src) || attrs.src);
const imageSource = state.esc(this?.editor?.commands?.getImageSource?.(attrs.src)?.() || attrs.src);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you check this issue. getImageSource is returning a function here

getImageSource: (path: string) => () => getAssetSrc(path),

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SatishGandham, thank you for bringing this to my attention. You're correct; in read-only-custom-image.ts, the getImageSource command returns a string directly, not a function. Therefore, the current implementation is correct, and my previous suggestion isn't necessary. I apologize for the oversight.

(>_<) Sorry about that.


✏️ Learnings added
Learnt from: SatishGandham
PR: makeplane/plane#5864
File: packages/editor/src/core/extensions/custom-image/read-only-custom-image.ts:60-60
Timestamp: 2024-10-22T08:03:04.172Z
Learning: In `packages/editor/src/core/extensions/custom-image/read-only-custom-image.ts`, the `getImageSource` command returns a string directly, not a function.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

const imageWidth = state.esc(attrs.width?.toString());
state.write(`<img src="${state.esc(imageSource)}" width="${imageWidth}" />`);
state.closeBlock(node);
},
},
};
},

Expand Down
13 changes: 13 additions & 0 deletions packages/editor/src/core/extensions/mentions/extension.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Editor, mergeAttributes } from "@tiptap/core";
import Mention, { MentionOptions } from "@tiptap/extension-mention";
import { MarkdownSerializerState } from "@tiptap/pm/markdown";
import { Node } from "@tiptap/pm/model";
import { ReactNodeViewRenderer, ReactRenderer } from "@tiptap/react";
import tippy from "tippy.js";
// extensions
Expand All @@ -25,8 +27,19 @@ export const CustomMention = ({
addStorage(this) {
return {
mentionsOpen: false,
markdown: {
serialize(state: MarkdownSerializerState, node: Node) {
const { attrs } = node;
const label = `@${state.esc(attrs.label)}`;
const originUrl = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
const safeRedirectionPath = state.esc(attrs.redirect_uri);
const url = `${originUrl}${safeRedirectionPath}`;
state.write(`[${label}](${url})`);
},
},
};
},

addAttributes() {
return {
id: {
Expand Down
45 changes: 24 additions & 21 deletions web/ce/components/pages/editor/embed/issue-embed-upgrade-card.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
// ui
import { Button } from "@plane/ui";
// plane ui
import { getButtonStyling } from "@plane/ui";
// components
import { ProIcon } from "@/components/common";
// helpers
import { cn } from "@/helpers/common.helper";

export const IssueEmbedUpgradeCard: React.FC<any> = (props) => (
<div
className={`${
props.selected ? "border-custom-primary-200 border-[2px]" : ""
} w-full h-[100px] cursor-pointer space-y-2 rounded-md border-[0.5px] border-custom-border-200 shadow-custom-shadow-2xs`}
className={cn(
"w-full h-20 bg-custom-background-80 rounded-md border-[0.5px] border-custom-border-200 shadow-custom-shadow-2xs",
{
"border-2": props.selected,
}
)}
>
<h5 className="h-[20%] text-xs text-custom-text-300 p-2">
{props.node?.attrs?.project_identifier}-{props?.node?.attrs?.sequence_id}
</h5>
<div className="relative h-[71%]">
<div className="h-full backdrop-filter backdrop-blur-[30px] bg-custom-background-80 bg-opacity-30 flex items-center w-full justify-between gap-5 mt-2.5 pl-4 pr-5 py-3 max-md:max-w-full max-md:flex-wrap relative">
<div className="flex gap-2 items-center">
<div className="rounded">
<ProIcon className="m-2 w-4 h-4" />
</div>
<div className="text-custom-text text-sm">
Embed and access issues in pages seamlessly, upgrade to plane pro now.
</div>
</div>
<a href="https://plane.so/pricing" target="_blank" rel="noopener noreferrer">
<Button>Upgrade</Button>
</a>
<div className="flex items-center justify-between gap-5 mt-2.5 pl-4 pr-5 py-3 w-full max-md:max-w-full max-md:flex-wrap rounded-md">
<div className="flex items-center gap-4">
<ProIcon className="flex-shrink-0 size-4" />
<p className="text-custom-text !text-base">
Embed and access issues in pages seamlessly, upgrade to Plane Pro now.
</p>
</div>
<a
href="https://plane.so/pro"
target="_blank"
rel="noopener noreferrer"
className={cn(getButtonStyling("primary", "md"), "no-underline")}
>
Upgrade
</a>
</div>
</div>
);