mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
feat: link option in remirror (#240)
* feat: link option in remirror * fix: removed link import from remirror toolbar
This commit is contained in:
parent
f308fe2ce1
commit
859fef24f4
@ -16,7 +16,7 @@ import issuesServices from "services/issues.service";
|
|||||||
// ui
|
// ui
|
||||||
import { Button } from "components/ui";
|
import { Button } from "components/ui";
|
||||||
// icons
|
// icons
|
||||||
import { FolderIcon, MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
import { MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||||
import { BlockerIcon, LayerDiagonalIcon } from "components/icons";
|
import { BlockerIcon, LayerDiagonalIcon } from "components/icons";
|
||||||
// types
|
// types
|
||||||
import { IIssue, UserAuth } from "types";
|
import { IIssue, UserAuth } from "types";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useCallback, useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
@ -113,7 +113,8 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCycleChange = (cycleDetail: ICycle) => {
|
const handleCycleChange = useCallback(
|
||||||
|
(cycleDetail: ICycle) => {
|
||||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
if (!workspaceSlug || !projectId || !issueDetail) return;
|
||||||
|
|
||||||
issuesServices
|
issuesServices
|
||||||
@ -123,9 +124,12 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate(ISSUE_DETAILS(issueId as string));
|
mutate(ISSUE_DETAILS(issueId as string));
|
||||||
});
|
});
|
||||||
};
|
},
|
||||||
|
[workspaceSlug, projectId, issueId, issueDetail]
|
||||||
|
);
|
||||||
|
|
||||||
const handleModuleChange = (moduleDetail: IModule) => {
|
const handleModuleChange = useCallback(
|
||||||
|
(moduleDetail: IModule) => {
|
||||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
if (!workspaceSlug || !projectId || !issueDetail) return;
|
||||||
|
|
||||||
modulesService
|
modulesService
|
||||||
@ -135,7 +139,9 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate(ISSUE_DETAILS(issueId as string));
|
mutate(ISSUE_DETAILS(issueId as string));
|
||||||
});
|
});
|
||||||
};
|
},
|
||||||
|
[workspaceSlug, projectId, issueId, issueDetail]
|
||||||
|
);
|
||||||
|
|
||||||
const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
|
const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@ import { Combobox, Dialog, Transition } from "@headlessui/react";
|
|||||||
import { RectangleStackIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
|
import { RectangleStackIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
|
||||||
// services
|
// services
|
||||||
import issuesServices from "services/issues.service";
|
import issuesServices from "services/issues.service";
|
||||||
|
// helpers
|
||||||
|
import { orderArrayBy } from "helpers/array.helper";
|
||||||
// types
|
// types
|
||||||
import { IIssue, IssueResponse } from "types";
|
import { IIssue, IssueResponse } from "types";
|
||||||
// constants
|
// constants
|
||||||
@ -47,11 +49,24 @@ export const SubIssuesListModal: React.FC<Props> = ({ isOpen, handleClose, paren
|
|||||||
setQuery("");
|
setQuery("");
|
||||||
};
|
};
|
||||||
|
|
||||||
const addAsSubIssue = (issueId: string) => {
|
const addAsSubIssue = (issue: IIssue) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
|
mutate<IIssue[]>(
|
||||||
|
SUB_ISSUES(parent?.id ?? ""),
|
||||||
|
(prevData) => {
|
||||||
|
let newSubIssues = [...(prevData as IIssue[])];
|
||||||
|
newSubIssues.push(issue);
|
||||||
|
|
||||||
|
newSubIssues = orderArrayBy(newSubIssues, "created_at", "descending");
|
||||||
|
|
||||||
|
return newSubIssues;
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
issuesServices
|
issuesServices
|
||||||
.patchIssue(workspaceSlug as string, projectId as string, issueId, { parent: parent?.id })
|
.patchIssue(workspaceSlug as string, projectId as string, issue.id, { parent: parent?.id })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate(SUB_ISSUES(parent?.id ?? ""));
|
mutate(SUB_ISSUES(parent?.id ?? ""));
|
||||||
mutate<IssueResponse>(
|
mutate<IssueResponse>(
|
||||||
@ -146,7 +161,7 @@ export const SubIssuesListModal: React.FC<Props> = ({ isOpen, handleClose, paren
|
|||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
addAsSubIssue(issue.id);
|
addAsSubIssue(issue);
|
||||||
handleClose();
|
handleClose();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -36,6 +36,7 @@ import { Spinner } from "components/ui";
|
|||||||
// components
|
// components
|
||||||
import { RichTextToolbar } from "./toolbar";
|
import { RichTextToolbar } from "./toolbar";
|
||||||
import { MentionAutoComplete } from "./mention-autocomplete";
|
import { MentionAutoComplete } from "./mention-autocomplete";
|
||||||
|
import { FloatingLinkToolbar } from "./toolbar/link";
|
||||||
|
|
||||||
export interface IRemirrorRichTextEditor {
|
export interface IRemirrorRichTextEditor {
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
@ -125,7 +126,7 @@ const RemirrorRichTextEditor: FC<IRemirrorRichTextEditor> = (props) => {
|
|||||||
new CalloutExtension({ defaultType: "warn" }),
|
new CalloutExtension({ defaultType: "warn" }),
|
||||||
new CodeBlockExtension(),
|
new CodeBlockExtension(),
|
||||||
new CodeExtension(),
|
new CodeExtension(),
|
||||||
new PlaceholderExtension({ placeholder: placeholder || `Enter text...` }),
|
new PlaceholderExtension({ placeholder: placeholder || "Enter text..." }),
|
||||||
new HistoryExtension(),
|
new HistoryExtension(),
|
||||||
new LinkExtension({ autoLink: true }),
|
new LinkExtension({ autoLink: true }),
|
||||||
new ImageExtension({
|
new ImageExtension({
|
||||||
@ -165,6 +166,7 @@ const RemirrorRichTextEditor: FC<IRemirrorRichTextEditor> = (props) => {
|
|||||||
setJsonValue(json);
|
setJsonValue(json);
|
||||||
onJSONChange(json);
|
onJSONChange(json);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleHTMLChange = (value: string) => {
|
const handleHTMLChange = (value: string) => {
|
||||||
setHtmlValue(value);
|
setHtmlValue(value);
|
||||||
onHTMLChange(value);
|
onHTMLChange(value);
|
||||||
@ -194,6 +196,7 @@ const RemirrorRichTextEditor: FC<IRemirrorRichTextEditor> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{/* <TableComponents /> */}
|
{/* <TableComponents /> */}
|
||||||
|
<FloatingLinkToolbar />
|
||||||
<MentionAutoComplete mentions={mentions} tags={tags} />
|
<MentionAutoComplete mentions={mentions} tags={tags} />
|
||||||
{<OnChangeJSON onChange={handleJSONChange} />}
|
{<OnChangeJSON onChange={handleJSONChange} />}
|
||||||
{<OnChangeHTML onChange={handleHTMLChange} />}
|
{<OnChangeHTML onChange={handleHTMLChange} />}
|
||||||
|
@ -6,7 +6,6 @@ import { BoldButton } from "./bold";
|
|||||||
import { ItalicButton } from "./italic";
|
import { ItalicButton } from "./italic";
|
||||||
import { UnderlineButton } from "./underline";
|
import { UnderlineButton } from "./underline";
|
||||||
import { StrikeButton } from "./strike";
|
import { StrikeButton } from "./strike";
|
||||||
import { LinkButton } from "./link";
|
|
||||||
// headings
|
// headings
|
||||||
import HeadingControls from "./heading-controls";
|
import HeadingControls from "./heading-controls";
|
||||||
// list
|
// list
|
||||||
|
@ -1,241 +1,196 @@
|
|||||||
import { useCommands, useActive } from "@remirror/react";
|
import React, {
|
||||||
|
ChangeEvent,
|
||||||
|
HTMLProps,
|
||||||
|
KeyboardEvent,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useLayoutEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
|
||||||
export const LinkButton = () => {
|
import { createMarkPositioner, LinkExtension, ShortcutHandlerProps } from "remirror/extensions";
|
||||||
const { focus } = useCommands();
|
import {
|
||||||
|
CommandButton,
|
||||||
|
FloatingToolbar,
|
||||||
|
FloatingWrapper,
|
||||||
|
useActive,
|
||||||
|
useAttrs,
|
||||||
|
useChainedCommands,
|
||||||
|
useCurrentSelection,
|
||||||
|
useExtensionEvent,
|
||||||
|
useUpdateReason,
|
||||||
|
} from "@remirror/react";
|
||||||
|
|
||||||
const active = useActive();
|
const useLinkShortcut = () => {
|
||||||
|
const [linkShortcut, setLinkShortcut] = useState<ShortcutHandlerProps | undefined>();
|
||||||
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
|
|
||||||
return (
|
useExtensionEvent(
|
||||||
<button
|
LinkExtension,
|
||||||
type="button"
|
"onShortcut",
|
||||||
onClick={() => {
|
useCallback(
|
||||||
// toggleLink();
|
(props) => {
|
||||||
focus();
|
if (!isEditing) {
|
||||||
}}
|
setIsEditing(true);
|
||||||
className={`${active.link() ? "bg-gray-200" : "hover:bg-gray-100"} rounded p-1`}
|
}
|
||||||
>
|
|
||||||
<svg
|
return setLinkShortcut(props);
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
},
|
||||||
height="18"
|
[isEditing]
|
||||||
width="18"
|
)
|
||||||
fill="black"
|
);
|
||||||
viewBox="0 0 48 48"
|
|
||||||
>
|
return { linkShortcut, isEditing, setIsEditing };
|
||||||
<path d="M22.5 34H14q-4.15 0-7.075-2.925T4 24q0-4.15 2.925-7.075T14 14h8.5v3H14q-2.9 0-4.95 2.05Q7 21.1 7 24q0 2.9 2.05 4.95Q11.1 31 14 31h8.5Zm-6.25-8.5v-3h15.5v3ZM25.5 34v-3H34q2.9 0 4.95-2.05Q41 26.9 41 24q0-2.9-2.05-4.95Q36.9 17 34 17h-8.5v-3H34q4.15 0 7.075 2.925T44 24q0 4.15-2.925 7.075T34 34Z" />
|
};
|
||||||
</svg>
|
|
||||||
</button>
|
const useFloatingLinkState = () => {
|
||||||
|
const chain = useChainedCommands();
|
||||||
|
const { isEditing, linkShortcut, setIsEditing } = useLinkShortcut();
|
||||||
|
const { to, empty } = useCurrentSelection();
|
||||||
|
|
||||||
|
const url = (useAttrs().link()?.href as string) ?? "";
|
||||||
|
const [href, setHref] = useState<string>(url);
|
||||||
|
|
||||||
|
// A positioner which only shows for links.
|
||||||
|
const linkPositioner = useMemo(() => createMarkPositioner({ type: "link" }), []);
|
||||||
|
|
||||||
|
const onRemove = useCallback(() => chain.removeLink().focus().run(), [chain]);
|
||||||
|
|
||||||
|
const updateReason = useUpdateReason();
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (!isEditing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateReason.doc || updateReason.selection) {
|
||||||
|
setIsEditing(false);
|
||||||
|
}
|
||||||
|
}, [isEditing, setIsEditing, updateReason.doc, updateReason.selection]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHref(url);
|
||||||
|
}, [url]);
|
||||||
|
|
||||||
|
const submitHref = useCallback(() => {
|
||||||
|
setIsEditing(false);
|
||||||
|
const range = linkShortcut ?? undefined;
|
||||||
|
|
||||||
|
if (href === "") {
|
||||||
|
chain.removeLink();
|
||||||
|
} else {
|
||||||
|
chain.updateLink({ href, auto: false }, range);
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.focus(range?.to ?? to).run();
|
||||||
|
}, [setIsEditing, linkShortcut, chain, href, to]);
|
||||||
|
|
||||||
|
const cancelHref = useCallback(() => {
|
||||||
|
setIsEditing(false);
|
||||||
|
}, [setIsEditing]);
|
||||||
|
|
||||||
|
const clickEdit = useCallback(() => {
|
||||||
|
if (empty) {
|
||||||
|
chain.selectLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsEditing(true);
|
||||||
|
}, [chain, empty, setIsEditing]);
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() => ({
|
||||||
|
href,
|
||||||
|
setHref,
|
||||||
|
linkShortcut,
|
||||||
|
linkPositioner,
|
||||||
|
isEditing,
|
||||||
|
clickEdit,
|
||||||
|
onRemove,
|
||||||
|
submitHref,
|
||||||
|
cancelHref,
|
||||||
|
}),
|
||||||
|
[href, linkShortcut, linkPositioner, isEditing, clickEdit, onRemove, submitHref, cancelHref]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// import type { ChangeEvent, HTMLProps, KeyboardEvent } from 'react';
|
const DelayAutoFocusInput = ({ autoFocus, ...rest }: HTMLProps<HTMLInputElement>) => {
|
||||||
// import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
// import { createMarkPositioner, LinkExtension, ShortcutHandlerProps } from 'remirror/extensions';
|
|
||||||
// import {
|
|
||||||
// CommandButton,
|
|
||||||
// EditorComponent,
|
|
||||||
// FloatingToolbar,
|
|
||||||
// FloatingWrapper,
|
|
||||||
// Remirror,
|
|
||||||
// ThemeProvider,
|
|
||||||
// useActive,
|
|
||||||
// useAttrs,
|
|
||||||
// useChainedCommands,
|
|
||||||
// useCurrentSelection,
|
|
||||||
// useExtensionEvent,
|
|
||||||
// useRemirror,
|
|
||||||
// useUpdateReason,
|
|
||||||
// } from '@remirror/react';
|
|
||||||
|
|
||||||
// function useLinkShortcut() {
|
useEffect(() => {
|
||||||
// const [linkShortcut, setLinkShortcut] = useState<ShortcutHandlerProps | undefined>();
|
if (!autoFocus) {
|
||||||
// const [isEditing, setIsEditing] = useState(false);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// useExtensionEvent(
|
const frame = window.requestAnimationFrame(() => {
|
||||||
// LinkExtension,
|
inputRef.current?.focus();
|
||||||
// 'onShortcut',
|
});
|
||||||
// useCallback(
|
|
||||||
// (props) => {
|
|
||||||
// if (!isEditing) {
|
|
||||||
// setIsEditing(true);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return setLinkShortcut(props);
|
return () => {
|
||||||
// },
|
window.cancelAnimationFrame(frame);
|
||||||
// [isEditing],
|
};
|
||||||
// ),
|
}, [autoFocus]);
|
||||||
// );
|
|
||||||
|
|
||||||
// return { linkShortcut, isEditing, setIsEditing };
|
return <input ref={inputRef} {...rest} />;
|
||||||
// }
|
};
|
||||||
|
|
||||||
// function useFloatingLinkState() {
|
export const FloatingLinkToolbar = () => {
|
||||||
// const chain = useChainedCommands();
|
const { isEditing, linkPositioner, clickEdit, onRemove, submitHref, href, setHref, cancelHref } =
|
||||||
// const { isEditing, linkShortcut, setIsEditing } = useLinkShortcut();
|
useFloatingLinkState();
|
||||||
// const { to, empty } = useCurrentSelection();
|
const active = useActive();
|
||||||
|
const activeLink = active.link();
|
||||||
|
const { empty } = useCurrentSelection();
|
||||||
|
|
||||||
// const url = (useAttrs().link()?.href as string) ?? '';
|
const handleClickEdit = useCallback(() => {
|
||||||
// const [href, setHref] = useState<string>(url);
|
clickEdit();
|
||||||
|
}, [clickEdit]);
|
||||||
|
|
||||||
// // A positioner which only shows for links.
|
const linkEditButtons = activeLink ? (
|
||||||
// const linkPositioner = useMemo(() => createMarkPositioner({ type: 'link' }), []);
|
<>
|
||||||
|
<CommandButton
|
||||||
|
commandName="updateLink"
|
||||||
|
onSelect={handleClickEdit}
|
||||||
|
icon="pencilLine"
|
||||||
|
enabled
|
||||||
|
/>
|
||||||
|
<CommandButton commandName="removeLink" onSelect={onRemove} icon="linkUnlink" enabled />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<CommandButton commandName="updateLink" onSelect={handleClickEdit} icon="link" enabled />
|
||||||
|
);
|
||||||
|
|
||||||
// const onRemove = useCallback(() => {
|
return (
|
||||||
// return chain.removeLink().focus().run();
|
<>
|
||||||
// }, [chain]);
|
{!isEditing && <FloatingToolbar>{linkEditButtons}</FloatingToolbar>}
|
||||||
|
{!isEditing && empty && (
|
||||||
|
<FloatingToolbar positioner={linkPositioner}>{linkEditButtons}</FloatingToolbar>
|
||||||
|
)}
|
||||||
|
|
||||||
// const updateReason = useUpdateReason();
|
<FloatingWrapper
|
||||||
|
positioner="always"
|
||||||
|
placement="bottom"
|
||||||
|
enabled={isEditing}
|
||||||
|
renderOutsideEditor
|
||||||
|
>
|
||||||
|
<DelayAutoFocusInput
|
||||||
|
autoFocus
|
||||||
|
placeholder="Enter link..."
|
||||||
|
onChange={(e: ChangeEvent<HTMLInputElement>) => setHref(e.target.value)}
|
||||||
|
value={href}
|
||||||
|
onKeyDown={(e: KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
const { code } = e;
|
||||||
|
|
||||||
// useLayoutEffect(() => {
|
if (code === "Enter") {
|
||||||
// if (!isEditing) {
|
submitHref();
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// if (updateReason.doc || updateReason.selection) {
|
if (code === "Escape") {
|
||||||
// setIsEditing(false);
|
cancelHref();
|
||||||
// }
|
}
|
||||||
// }, [isEditing, setIsEditing, updateReason.doc, updateReason.selection]);
|
}}
|
||||||
|
/>
|
||||||
// useEffect(() => {
|
</FloatingWrapper>
|
||||||
// setHref(url);
|
</>
|
||||||
// }, [url]);
|
);
|
||||||
|
};
|
||||||
// const submitHref = useCallback(() => {
|
|
||||||
// setIsEditing(false);
|
|
||||||
// const range = linkShortcut ?? undefined;
|
|
||||||
|
|
||||||
// if (href === '') {
|
|
||||||
// chain.removeLink();
|
|
||||||
// } else {
|
|
||||||
// chain.updateLink({ href, auto: false }, range);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// chain.focus(range?.to ?? to).run();
|
|
||||||
// }, [setIsEditing, linkShortcut, chain, href, to]);
|
|
||||||
|
|
||||||
// const cancelHref = useCallback(() => {
|
|
||||||
// setIsEditing(false);
|
|
||||||
// }, [setIsEditing]);
|
|
||||||
|
|
||||||
// const clickEdit = useCallback(() => {
|
|
||||||
// if (empty) {
|
|
||||||
// chain.selectLink();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// setIsEditing(true);
|
|
||||||
// }, [chain, empty, setIsEditing]);
|
|
||||||
|
|
||||||
// return useMemo(
|
|
||||||
// () => ({
|
|
||||||
// href,
|
|
||||||
// setHref,
|
|
||||||
// linkShortcut,
|
|
||||||
// linkPositioner,
|
|
||||||
// isEditing,
|
|
||||||
// clickEdit,
|
|
||||||
// onRemove,
|
|
||||||
// submitHref,
|
|
||||||
// cancelHref,
|
|
||||||
// }),
|
|
||||||
// [href, linkShortcut, linkPositioner, isEditing, clickEdit, onRemove, submitHref, cancelHref],
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const DelayAutoFocusInput = ({ autoFocus, ...rest }: HTMLProps<HTMLInputElement>) => {
|
|
||||||
// const inputRef = useRef<HTMLInputElement>(null);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (!autoFocus) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const frame = window.requestAnimationFrame(() => {
|
|
||||||
// inputRef.current?.focus();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return () => {
|
|
||||||
// window.cancelAnimationFrame(frame);
|
|
||||||
// };
|
|
||||||
// }, [autoFocus]);
|
|
||||||
|
|
||||||
// return <input ref={inputRef} {...rest} />;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const FloatingLinkToolbar = () => {
|
|
||||||
// const { isEditing, linkPositioner, clickEdit, onRemove, submitHref, href, setHref, cancelHref } =
|
|
||||||
// useFloatingLinkState();
|
|
||||||
// const active = useActive();
|
|
||||||
// const activeLink = active.link();
|
|
||||||
// const { empty } = useCurrentSelection();
|
|
||||||
|
|
||||||
// const handleClickEdit = useCallback(() => {
|
|
||||||
// clickEdit();
|
|
||||||
// }, [clickEdit]);
|
|
||||||
|
|
||||||
// const linkEditButtons = activeLink ? (
|
|
||||||
// <>
|
|
||||||
// <CommandButton
|
|
||||||
// commandName='updateLink'
|
|
||||||
// onSelect={handleClickEdit}
|
|
||||||
// icon='pencilLine'
|
|
||||||
// enabled
|
|
||||||
// />
|
|
||||||
// <CommandButton commandName='removeLink' onSelect={onRemove} icon='linkUnlink' enabled />
|
|
||||||
// </>
|
|
||||||
// ) : (
|
|
||||||
// <CommandButton commandName='updateLink' onSelect={handleClickEdit} icon='link' enabled />
|
|
||||||
// );
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <>
|
|
||||||
// {!isEditing && <FloatingToolbar>{linkEditButtons}</FloatingToolbar>}
|
|
||||||
// {!isEditing && empty && (
|
|
||||||
// <FloatingToolbar positioner={linkPositioner}>{linkEditButtons}</FloatingToolbar>
|
|
||||||
// )}
|
|
||||||
|
|
||||||
// <FloatingWrapper
|
|
||||||
// positioner='always'
|
|
||||||
// placement='bottom'
|
|
||||||
// enabled={isEditing}
|
|
||||||
// renderOutsideEditor
|
|
||||||
// >
|
|
||||||
// <DelayAutoFocusInput
|
|
||||||
// style={{ zIndex: 20 }}
|
|
||||||
// autoFocus
|
|
||||||
// placeholder='Enter link...'
|
|
||||||
// onChange={(event: ChangeEvent<HTMLInputElement>) => setHref(event.target.value)}
|
|
||||||
// value={href}
|
|
||||||
// onKeyPress={(event: KeyboardEvent<HTMLInputElement>) => {
|
|
||||||
// const { code } = event;
|
|
||||||
|
|
||||||
// if (code === 'Enter') {
|
|
||||||
// submitHref();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (code === 'Escape') {
|
|
||||||
// cancelHref();
|
|
||||||
// }
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// </FloatingWrapper>
|
|
||||||
// </>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const EditDialog = (): JSX.Element => {
|
|
||||||
// const { manager, state } = useRemirror({
|
|
||||||
// extensions: () => [new LinkExtension({ autoLink: true })],
|
|
||||||
// content: `Click this <a href="https://remirror.io" target="_blank">link</a> to edit it`,
|
|
||||||
// stringHandler: 'html',
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <ThemeProvider>
|
|
||||||
// <Remirror manager={manager} initialContent={state}>
|
|
||||||
// <EditorComponent />
|
|
||||||
// <FloatingLinkToolbar />
|
|
||||||
// </Remirror>
|
|
||||||
// </ThemeProvider>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export default EditDialog;
|
|
||||||
|
@ -4,6 +4,7 @@ import { useCommands } from "@remirror/react";
|
|||||||
|
|
||||||
export const UndoButton = () => {
|
export const UndoButton = () => {
|
||||||
const { undo } = useCommands();
|
const { undo } = useCommands();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -11,7 +11,11 @@ const nextConfig = {
|
|||||||
reactStrictMode: false,
|
reactStrictMode: false,
|
||||||
swcMinify: true,
|
swcMinify: true,
|
||||||
images: {
|
images: {
|
||||||
domains: ["vinci-web.s3.amazonaws.com", "planefs-staging.s3.ap-south-1.amazonaws.com"],
|
domains: [
|
||||||
|
"vinci-web.s3.amazonaws.com",
|
||||||
|
"planefs-staging.s3.ap-south-1.amazonaws.com",
|
||||||
|
"planefs.s3.amazonaws.com",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
output: "standalone",
|
output: "standalone",
|
||||||
experimental: {
|
experimental: {
|
||||||
|
@ -73,7 +73,7 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: subIssues } = useSWR(
|
const { data: subIssues } = useSWR<IIssue[] | undefined>(
|
||||||
issueId && workspaceSlug && projectId ? SUB_ISSUES(issueId as string) : null,
|
issueId && workspaceSlug && projectId ? SUB_ISSUES(issueId as string) : null,
|
||||||
issueId && workspaceSlug && projectId
|
issueId && workspaceSlug && projectId
|
||||||
? () =>
|
? () =>
|
||||||
@ -126,7 +126,6 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
|
|||||||
issuesService
|
issuesService
|
||||||
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload)
|
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
console.log(res);
|
|
||||||
mutateIssueDetails();
|
mutateIssueDetails();
|
||||||
mutateIssueActivities();
|
mutateIssueActivities();
|
||||||
})
|
})
|
||||||
@ -140,11 +139,16 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
|
|||||||
const handleSubIssueRemove = (issueId: string) => {
|
const handleSubIssueRemove = (issueId: string) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
|
mutate<IIssue[]>(
|
||||||
|
SUB_ISSUES(issueDetails?.id ?? ""),
|
||||||
|
(prevData) => prevData?.filter((i) => i.id !== issueId),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
issuesService
|
issuesService
|
||||||
.patchIssue(workspaceSlug as string, projectId as string, issueId, { parent: null })
|
.patchIssue(workspaceSlug as string, projectId as string, issueId, { parent: null })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate(SUB_ISSUES(issueDetails?.id ?? ""));
|
mutate(SUB_ISSUES(issueDetails?.id ?? ""));
|
||||||
mutateIssueActivities();
|
|
||||||
|
|
||||||
mutate<IssueResponse>(
|
mutate<IssueResponse>(
|
||||||
PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
|
PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
|
||||||
@ -169,7 +173,8 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (issueDetails) {
|
if (!issueDetails) return;
|
||||||
|
|
||||||
mutateIssueActivities();
|
mutateIssueActivities();
|
||||||
reset({
|
reset({
|
||||||
...issueDetails,
|
...issueDetails,
|
||||||
@ -177,14 +182,13 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
|
|||||||
issueDetails.blockers_list ??
|
issueDetails.blockers_list ??
|
||||||
issueDetails.blocker_issues?.map((issue) => issue.blocker_issue_detail?.id),
|
issueDetails.blocker_issues?.map((issue) => issue.blocker_issue_detail?.id),
|
||||||
blocked_list:
|
blocked_list:
|
||||||
issueDetails.blocked_list ??
|
issueDetails.blocks_list ??
|
||||||
issueDetails.blocked_issues?.map((issue) => issue.blocked_issue_detail?.id),
|
issueDetails.blocked_issues?.map((issue) => issue.blocked_issue_detail?.id),
|
||||||
assignees_list:
|
assignees_list:
|
||||||
issueDetails.assignees_list ?? issueDetails.assignee_details?.map((user) => user.id),
|
issueDetails.assignees_list ?? issueDetails.assignee_details?.map((user) => user.id),
|
||||||
labels_list: issueDetails.labels_list ?? issueDetails.labels,
|
labels_list: issueDetails.labels_list ?? issueDetails.labels,
|
||||||
labels: issueDetails.labels_list ?? issueDetails.labels,
|
labels: issueDetails.labels_list ?? issueDetails.labels,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}, [issueDetails, reset, mutateIssueActivities]);
|
}, [issueDetails, reset, mutateIssueActivities]);
|
||||||
|
|
||||||
const isNotAllowed = props.isGuest || props.isViewer;
|
const isNotAllowed = props.isGuest || props.isViewer;
|
||||||
@ -280,9 +284,9 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
|
|||||||
userAuth={props}
|
userAuth={props}
|
||||||
/>
|
/>
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
{issueId && workspaceSlug && projectId && subIssues?.length > 0 ? (
|
{issueId && workspaceSlug && projectId && subIssues && subIssues.length > 0 ? (
|
||||||
<SubIssuesList
|
<SubIssuesList
|
||||||
issues={subIssues}
|
issues={subIssues ?? []}
|
||||||
parentIssue={issueDetails}
|
parentIssue={issueDetails}
|
||||||
projectId={projectId?.toString()}
|
projectId={projectId?.toString()}
|
||||||
workspaceSlug={workspaceSlug?.toString()}
|
workspaceSlug={workspaceSlug?.toString()}
|
||||||
|
@ -401,6 +401,19 @@ img.ProseMirror-separator {
|
|||||||
/* end table styling */
|
/* end table styling */
|
||||||
|
|
||||||
/* link styling */
|
/* link styling */
|
||||||
|
.remirror-floating-popover {
|
||||||
|
z-index: 20 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remirror-floating-popover input {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid #a8a6a6;
|
||||||
|
box-shadow: 1px 1px 5px #c0bebe;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
.remirror-editor-wrapper a {
|
.remirror-editor-wrapper a {
|
||||||
color: blue;
|
color: blue;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
|
Loading…
Reference in New Issue
Block a user