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
16 changes: 8 additions & 8 deletions apps/app/components/core/modals/gpt-assistant-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,14 @@ export const GptAssistantModal: React.FC<Props> = ({

return (
<div
className={`absolute ${inset} z-20 w-full space-y-4 rounded-[10px] border border-custom-border-200 bg-custom-background-100 p-4 shadow ${
isOpen ? "block" : "hidden"
}`}
className={`absolute ${inset} z-20 w-full space-y-4 rounded-[10px] border border-custom-border-200 bg-custom-background-100 p-4 shadow ${isOpen ? "block" : "hidden"
}`}
>
{((content && content !== "") || (htmlContent && htmlContent !== "<p></p>")) && (
<div className="text-sm">
Content:
<TiptapEditor
workspaceSlug={workspaceSlug as string}
value={htmlContent ?? `<p>${content}</p>`}
customClassName="-m-3"
noBorder
Expand All @@ -161,6 +161,7 @@ export const GptAssistantModal: React.FC<Props> = ({
<div className="page-block-section text-sm">
Response:
<Tiptap
workspaceSlug={workspaceSlug as string}
value={`<p>${response}</p>`}
customClassName="-mx-3 -my-3"
noBorder
Expand All @@ -179,11 +180,10 @@ export const GptAssistantModal: React.FC<Props> = ({
type="text"
name="task"
register={register}
placeholder={`${
content && content !== ""
placeholder={`${content && content !== ""
? "Tell AI what action to perform on this content..."
: "Ask AI anything..."
}`}
}`}
autoComplete="off"
/>
<div className={`flex gap-2 ${response === "" ? "justify-end" : "justify-between"}`}>
Expand Down Expand Up @@ -219,8 +219,8 @@ export const GptAssistantModal: React.FC<Props> = ({
{isSubmitting
? "Generating response..."
: response === ""
? "Generate response"
: "Generate again"}
? "Generate response"
: "Generate again"}
</PrimaryButton>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions apps/app/components/inbox/inbox-main-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ export const InboxMainContent: React.FC = () => {
</div>
<div>
<IssueDescriptionForm
workspaceSlug={workspaceSlug as string}
issue={{
name: issueDetails.name,
description: issueDetails.description,
Expand Down
1 change: 1 addition & 0 deletions apps/app/components/issues/activity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export const IssueActivitySection: React.FC<Props> = ({ issueId, user }) => {
return (
<div key={activityItem.id} className="mt-4">
<CommentCard
workspaceSlug={workspaceSlug as string}
comment={activityItem as IIssueComment}
onSubmit={handleCommentUpdate}
handleCommentDeletion={handleCommentDelete}
Expand Down
5 changes: 3 additions & 2 deletions apps/app/components/issues/comment/add-comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,12 @@ export const AddComment: React.FC<Props> = ({ issueId, user, disabled = false })
control={control}
render={({ field: { value, onChange } }) => (
<TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={editorRef}
value={
!value ||
value === "" ||
(typeof value === "object" && Object.keys(value).length === 0)
value === "" ||
(typeof value === "object" && Object.keys(value).length === 0)
? watch("comment_html")
: value
}
Expand Down
5 changes: 4 additions & 1 deletion apps/app/components/issues/comment/comment-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ const TiptapEditor = React.forwardRef<ITiptapRichTextEditor, ITiptapRichTextEdit
TiptapEditor.displayName = "TiptapEditor";

type Props = {
workspaceSlug: string;
comment: IIssueComment;
onSubmit: (comment: IIssueComment) => void;
handleCommentDeletion: (comment: string) => void;
};

export const CommentCard: React.FC<Props> = ({ comment, onSubmit, handleCommentDeletion }) => {
export const CommentCard: React.FC<Props> = ({ comment, workspaceSlug, onSubmit, handleCommentDeletion }) => {
const { user } = useUser();

const editorRef = React.useRef<any>(null);
Expand Down Expand Up @@ -103,6 +104,7 @@ export const CommentCard: React.FC<Props> = ({ comment, onSubmit, handleCommentD
>
<div>
<TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={editorRef}
value={watch("comment_html")}
debouncedUpdatesEnabled={false}
Expand Down Expand Up @@ -132,6 +134,7 @@ export const CommentCard: React.FC<Props> = ({ comment, onSubmit, handleCommentD
</form>
<div className={`${isEditing ? "hidden" : ""}`}>
<TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={showEditorRef}
value={comment.comment_html}
editable={false}
Expand Down
25 changes: 16 additions & 9 deletions apps/app/components/issues/description-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ export interface IssueDetailsProps {
description: string;
description_html: string;
};
workspaceSlug: string;
handleFormSubmit: (value: IssueDescriptionFormValues) => Promise<void>;
isAllowed: boolean;
}

export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
issue,
handleFormSubmit,
workspaceSlug,
isAllowed,
}) => {
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
Expand Down Expand Up @@ -69,11 +71,15 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({

useEffect(() => {
if (isSubmitting === "submitted") {
setShowAlert(false);
setTimeout(async () => {
setIsSubmitting("saved");
}, 2000);
} else if (isSubmitting === "submitting") {
setShowAlert(true);
}
}, [isSubmitting]);
}, [isSubmitting, setShowAlert]);


// reset form values
useEffect(() => {
Expand Down Expand Up @@ -112,9 +118,8 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
{characterLimit && (
<div className="pointer-events-none absolute bottom-1 right-1 z-[2] rounded bg-custom-background-100 text-custom-text-200 p-0.5 text-xs">
<span
className={`${
watch("name").length === 0 || watch("name").length > 255 ? "text-red-500" : ""
}`}
className={`${watch("name").length === 0 || watch("name").length > 255 ? "text-red-500" : ""
}`}
>
{watch("name").length}
</span>
Expand All @@ -134,16 +139,19 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
<Tiptap
value={
!value ||
value === "" ||
(typeof value === "object" && Object.keys(value).length === 0)
value === "" ||
(typeof value === "object" && Object.keys(value).length === 0)
? watch("description_html")
: value
}
workspaceSlug={workspaceSlug}
debouncedUpdatesEnabled={true}
setShouldShowAlert={setShowAlert}
setIsSubmitting={setIsSubmitting}
customClassName="min-h-[150px] shadow-sm"
editorContentCustomClassNames="pb-9"
onChange={(description: Object, description_html: string) => {
setShowAlert(true);
setIsSubmitting("submitting");
onChange(description_html);
setValue("description", description);
Expand All @@ -156,9 +164,8 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
}}
/>
<div
className={`absolute right-5 bottom-5 text-xs text-custom-text-200 border border-custom-border-400 rounded-xl w-[6.5rem] py-1 z-10 flex items-center justify-center ${
isSubmitting === "saved" ? "fadeOut" : "fadeIn"
}`}
className={`absolute right-5 bottom-5 text-xs text-custom-text-200 border border-custom-border-400 rounded-xl w-[6.5rem] py-1 z-10 flex items-center justify-center ${isSubmitting === "saved" ? "fadeOut" : "fadeIn"
}`}
>
{isSubmitting === "submitting" ? "Saving..." : "Saved"}
</div>
Expand Down
1 change: 1 addition & 0 deletions apps/app/components/issues/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ export const IssueForm: FC<IssueFormProps> = ({

return (
<TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={editorRef}
debouncedUpdatesEnabled={false}
value={
Expand Down
1 change: 1 addition & 0 deletions apps/app/components/issues/main-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export const IssueMainContent: React.FC<Props> = ({
</div>
) : null}
<IssueDescriptionForm
workspaceSlug={workspaceSlug as string}
issue={issueDetails}
handleFormSubmit={submitChanges}
isAllowed={memberRole.isMember || memberRole.isOwner || !uneditable}
Expand Down
19 changes: 9 additions & 10 deletions apps/app/components/pages/create-update-block-inline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,9 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
description:
!data.description || data.description === ""
? {
type: "doc",
content: [{ type: "paragraph" }],
}
type: "doc",
content: [{ type: "paragraph" }],
}
: data.description,
description_html: data.description_html ?? "<p></p>",
});
Expand Down Expand Up @@ -292,6 +292,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
if (!data)
return (
<TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={editorRef}
value={"<p></p>"}
debouncedUpdatesEnabled={false}
Expand All @@ -311,12 +312,11 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({

return (
<TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={editorRef}
value={
value && value !== "" && Object.keys(value).length > 0
Copy link
Member

Choose a reason for hiding this comment

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

Here, value and watch("description_html") hold the same value, double check is redundant. Can we remove watch("description_html")?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ohh yeah sure! I've done it!

? value
: watch("description_html") && watch("description_html") !== ""
? watch("description_html")
: { type: "doc", content: [{ type: "paragraph" }] }
}
debouncedUpdatesEnabled={false}
Expand All @@ -334,9 +334,8 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
<div className="m-2 mt-6 flex">
<button
type="button"
className={`flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-custom-background-80 ${
iAmFeelingLucky ? "cursor-wait bg-custom-background-90" : ""
}`}
className={`flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-custom-background-80 ${iAmFeelingLucky ? "cursor-wait bg-custom-background-90" : ""
}`}
onClick={handleAutoGenerateDescription}
disabled={iAmFeelingLucky}
>
Expand Down Expand Up @@ -368,8 +367,8 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
? "Updating..."
: "Update block"
: isSubmitting
? "Adding..."
: "Add block"}
? "Adding..."
: "Add block"}
</PrimaryButton>
</div>
</form>
Expand Down
1 change: 1 addition & 0 deletions apps/app/components/pages/single-page-block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ export const SinglePageBlock: React.FC<Props> = ({
{showBlockDetails
? block.description_html.length > 7 && (
<TiptapEditor
workspaceSlug={workspaceSlug as string}
value={block.description_html}
customClassName="text-sm min-h-[150px]"
noBorder
Expand Down
37 changes: 25 additions & 12 deletions apps/app/components/tiptap/bubble-menu/link-selector.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import { Editor } from "@tiptap/core";
import { Check, Trash } from "lucide-react";
import { Dispatch, FC, SetStateAction, useEffect, useRef } from "react";
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useRef } from "react";
import { cn } from "../utils";

import isValidHttpUrl from "./utils/link-validator";
interface LinkSelectorProps {
editor: Editor;
isOpen: boolean;
setIsOpen: Dispatch<SetStateAction<boolean>>;
}


export const LinkSelector: FC<LinkSelectorProps> = ({ editor, isOpen, setIsOpen }) => {
const inputRef = useRef<HTMLInputElement>(null);

const onLinkSubmit = useCallback(() => {
const input = inputRef.current;
const url = input?.value;
if (url && isValidHttpUrl(url)) {
editor.chain().focus().setLink({ href: url }).run();
setIsOpen(false);
}
}, [editor, inputRef, setIsOpen]);

useEffect(() => {
inputRef.current && inputRef.current?.focus();
});
Expand All @@ -38,15 +48,13 @@ export const LinkSelector: FC<LinkSelectorProps> = ({ editor, isOpen, setIsOpen
</p>
</button>
{isOpen && (
<form
onSubmit={(e) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
const input = form.elements[0] as HTMLInputElement;
editor.chain().focus().setLink({ href: input.value }).run();
setIsOpen(false);
}}
<div
className="fixed top-full z-[99999] mt-1 flex w-60 overflow-hidden rounded border border-custom-border-300 bg-custom-background-100 dow-xl animate-in fade-in slide-in-from-top-1"
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault(); onLinkSubmit();
}
}}
>
<input
ref={inputRef}
Expand All @@ -57,6 +65,7 @@ export const LinkSelector: FC<LinkSelectorProps> = ({ editor, isOpen, setIsOpen
/>
{editor.getAttributes("link").href ? (
<button
type="button"
className="flex items-center rounded-sm p-1 text-red-600 transition-all hover:bg-red-100 dark:hover:bg-red-800"
onClick={() => {
editor.chain().focus().unsetLink().run();
Expand All @@ -66,11 +75,15 @@ export const LinkSelector: FC<LinkSelectorProps> = ({ editor, isOpen, setIsOpen
<Trash className="h-4 w-4" />
</button>
) : (
<button className="flex items-center rounded-sm p-1 text-custom-text-300 transition-all hover:bg-custom-background-90">
<button className="flex items-center rounded-sm p-1 text-custom-text-300 transition-all hover:bg-custom-background-90" type="button"
onClick={() => {
onLinkSubmit();
}}
>
<Check className="h-4 w-4" />
</button>
)}
</form>
</div>
)}
</div>
);
Expand Down
12 changes: 12 additions & 0 deletions apps/app/components/tiptap/bubble-menu/utils/link-validator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default function isValidHttpUrl(string: string): boolean {
let url;

try {
url = new URL(string);
} catch (_) {
return false;
}

return url.protocol === "http:" || url.protocol === "https:";
}

Loading