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
|
||||
import { Button } from "components/ui";
|
||||
// icons
|
||||
import { FolderIcon, MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||
import { MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||
import { BlockerIcon, LayerDiagonalIcon } from "components/icons";
|
||||
// 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";
|
||||
|
||||
@ -113,29 +113,35 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
});
|
||||
};
|
||||
|
||||
const handleCycleChange = (cycleDetail: ICycle) => {
|
||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
||||
const handleCycleChange = useCallback(
|
||||
(cycleDetail: ICycle) => {
|
||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
||||
|
||||
issuesServices
|
||||
.addIssueToCycle(workspaceSlug as string, projectId as string, cycleDetail.id, {
|
||||
issues: [issueDetail.id],
|
||||
})
|
||||
.then((res) => {
|
||||
mutate(ISSUE_DETAILS(issueId as string));
|
||||
});
|
||||
};
|
||||
issuesServices
|
||||
.addIssueToCycle(workspaceSlug as string, projectId as string, cycleDetail.id, {
|
||||
issues: [issueDetail.id],
|
||||
})
|
||||
.then((res) => {
|
||||
mutate(ISSUE_DETAILS(issueId as string));
|
||||
});
|
||||
},
|
||||
[workspaceSlug, projectId, issueId, issueDetail]
|
||||
);
|
||||
|
||||
const handleModuleChange = (moduleDetail: IModule) => {
|
||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
||||
const handleModuleChange = useCallback(
|
||||
(moduleDetail: IModule) => {
|
||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
||||
|
||||
modulesService
|
||||
.addIssuesToModule(workspaceSlug as string, projectId as string, moduleDetail.id, {
|
||||
issues: [issueDetail.id],
|
||||
})
|
||||
.then((res) => {
|
||||
mutate(ISSUE_DETAILS(issueId as string));
|
||||
});
|
||||
};
|
||||
modulesService
|
||||
.addIssuesToModule(workspaceSlug as string, projectId as string, moduleDetail.id, {
|
||||
issues: [issueDetail.id],
|
||||
})
|
||||
.then((res) => {
|
||||
mutate(ISSUE_DETAILS(issueId as string));
|
||||
});
|
||||
},
|
||||
[workspaceSlug, projectId, issueId, issueDetail]
|
||||
);
|
||||
|
||||
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";
|
||||
// services
|
||||
import issuesServices from "services/issues.service";
|
||||
// helpers
|
||||
import { orderArrayBy } from "helpers/array.helper";
|
||||
// types
|
||||
import { IIssue, IssueResponse } from "types";
|
||||
// constants
|
||||
@ -47,11 +49,24 @@ export const SubIssuesListModal: React.FC<Props> = ({ isOpen, handleClose, paren
|
||||
setQuery("");
|
||||
};
|
||||
|
||||
const addAsSubIssue = (issueId: string) => {
|
||||
const addAsSubIssue = (issue: IIssue) => {
|
||||
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
|
||||
.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) => {
|
||||
mutate(SUB_ISSUES(parent?.id ?? ""));
|
||||
mutate<IssueResponse>(
|
||||
@ -146,7 +161,7 @@ export const SubIssuesListModal: React.FC<Props> = ({ isOpen, handleClose, paren
|
||||
}`
|
||||
}
|
||||
onClick={() => {
|
||||
addAsSubIssue(issue.id);
|
||||
addAsSubIssue(issue);
|
||||
handleClose();
|
||||
}}
|
||||
>
|
||||
|
@ -36,6 +36,7 @@ import { Spinner } from "components/ui";
|
||||
// components
|
||||
import { RichTextToolbar } from "./toolbar";
|
||||
import { MentionAutoComplete } from "./mention-autocomplete";
|
||||
import { FloatingLinkToolbar } from "./toolbar/link";
|
||||
|
||||
export interface IRemirrorRichTextEditor {
|
||||
placeholder?: string;
|
||||
@ -125,7 +126,7 @@ const RemirrorRichTextEditor: FC<IRemirrorRichTextEditor> = (props) => {
|
||||
new CalloutExtension({ defaultType: "warn" }),
|
||||
new CodeBlockExtension(),
|
||||
new CodeExtension(),
|
||||
new PlaceholderExtension({ placeholder: placeholder || `Enter text...` }),
|
||||
new PlaceholderExtension({ placeholder: placeholder || "Enter text..." }),
|
||||
new HistoryExtension(),
|
||||
new LinkExtension({ autoLink: true }),
|
||||
new ImageExtension({
|
||||
@ -165,6 +166,7 @@ const RemirrorRichTextEditor: FC<IRemirrorRichTextEditor> = (props) => {
|
||||
setJsonValue(json);
|
||||
onJSONChange(json);
|
||||
};
|
||||
|
||||
const handleHTMLChange = (value: string) => {
|
||||
setHtmlValue(value);
|
||||
onHTMLChange(value);
|
||||
@ -194,6 +196,7 @@ const RemirrorRichTextEditor: FC<IRemirrorRichTextEditor> = (props) => {
|
||||
</div>
|
||||
)}
|
||||
{/* <TableComponents /> */}
|
||||
<FloatingLinkToolbar />
|
||||
<MentionAutoComplete mentions={mentions} tags={tags} />
|
||||
{<OnChangeJSON onChange={handleJSONChange} />}
|
||||
{<OnChangeHTML onChange={handleHTMLChange} />}
|
||||
|
@ -6,7 +6,6 @@ import { BoldButton } from "./bold";
|
||||
import { ItalicButton } from "./italic";
|
||||
import { UnderlineButton } from "./underline";
|
||||
import { StrikeButton } from "./strike";
|
||||
import { LinkButton } from "./link";
|
||||
// headings
|
||||
import HeadingControls from "./heading-controls";
|
||||
// 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 = () => {
|
||||
const { focus } = useCommands();
|
||||
import { createMarkPositioner, LinkExtension, ShortcutHandlerProps } from "remirror/extensions";
|
||||
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 (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
// toggleLink();
|
||||
focus();
|
||||
}}
|
||||
className={`${active.link() ? "bg-gray-200" : "hover:bg-gray-100"} rounded p-1`}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="18"
|
||||
width="18"
|
||||
fill="black"
|
||||
viewBox="0 0 48 48"
|
||||
>
|
||||
<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>
|
||||
useExtensionEvent(
|
||||
LinkExtension,
|
||||
"onShortcut",
|
||||
useCallback(
|
||||
(props) => {
|
||||
if (!isEditing) {
|
||||
setIsEditing(true);
|
||||
}
|
||||
|
||||
return setLinkShortcut(props);
|
||||
},
|
||||
[isEditing]
|
||||
)
|
||||
);
|
||||
|
||||
return { linkShortcut, isEditing, setIsEditing };
|
||||
};
|
||||
|
||||
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';
|
||||
// import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
// import { createMarkPositioner, LinkExtension, ShortcutHandlerProps } from 'remirror/extensions';
|
||||
// import {
|
||||
// CommandButton,
|
||||
// EditorComponent,
|
||||
// FloatingToolbar,
|
||||
// FloatingWrapper,
|
||||
// Remirror,
|
||||
// ThemeProvider,
|
||||
// useActive,
|
||||
// useAttrs,
|
||||
// useChainedCommands,
|
||||
// useCurrentSelection,
|
||||
// useExtensionEvent,
|
||||
// useRemirror,
|
||||
// useUpdateReason,
|
||||
// } from '@remirror/react';
|
||||
const DelayAutoFocusInput = ({ autoFocus, ...rest }: HTMLProps<HTMLInputElement>) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
// function useLinkShortcut() {
|
||||
// const [linkShortcut, setLinkShortcut] = useState<ShortcutHandlerProps | undefined>();
|
||||
// const [isEditing, setIsEditing] = useState(false);
|
||||
useEffect(() => {
|
||||
if (!autoFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// useExtensionEvent(
|
||||
// LinkExtension,
|
||||
// 'onShortcut',
|
||||
// useCallback(
|
||||
// (props) => {
|
||||
// if (!isEditing) {
|
||||
// setIsEditing(true);
|
||||
// }
|
||||
const frame = window.requestAnimationFrame(() => {
|
||||
inputRef.current?.focus();
|
||||
});
|
||||
|
||||
// return setLinkShortcut(props);
|
||||
// },
|
||||
// [isEditing],
|
||||
// ),
|
||||
// );
|
||||
return () => {
|
||||
window.cancelAnimationFrame(frame);
|
||||
};
|
||||
}, [autoFocus]);
|
||||
|
||||
// return { linkShortcut, isEditing, setIsEditing };
|
||||
// }
|
||||
return <input ref={inputRef} {...rest} />;
|
||||
};
|
||||
|
||||
// function useFloatingLinkState() {
|
||||
// const chain = useChainedCommands();
|
||||
// const { isEditing, linkShortcut, setIsEditing } = useLinkShortcut();
|
||||
// const { to, empty } = useCurrentSelection();
|
||||
export const FloatingLinkToolbar = () => {
|
||||
const { isEditing, linkPositioner, clickEdit, onRemove, submitHref, href, setHref, cancelHref } =
|
||||
useFloatingLinkState();
|
||||
const active = useActive();
|
||||
const activeLink = active.link();
|
||||
const { empty } = useCurrentSelection();
|
||||
|
||||
// const url = (useAttrs().link()?.href as string) ?? '';
|
||||
// const [href, setHref] = useState<string>(url);
|
||||
const handleClickEdit = useCallback(() => {
|
||||
clickEdit();
|
||||
}, [clickEdit]);
|
||||
|
||||
// // A positioner which only shows for links.
|
||||
// const linkPositioner = useMemo(() => createMarkPositioner({ type: 'link' }), []);
|
||||
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 />
|
||||
);
|
||||
|
||||
// const onRemove = useCallback(() => {
|
||||
// return chain.removeLink().focus().run();
|
||||
// }, [chain]);
|
||||
return (
|
||||
<>
|
||||
{!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 (!isEditing) {
|
||||
// return;
|
||||
// }
|
||||
if (code === "Enter") {
|
||||
submitHref();
|
||||
}
|
||||
|
||||
// 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],
|
||||
// );
|
||||
// }
|
||||
|
||||
// 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;
|
||||
if (code === "Escape") {
|
||||
cancelHref();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</FloatingWrapper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -4,6 +4,7 @@ import { useCommands } from "@remirror/react";
|
||||
|
||||
export const UndoButton = () => {
|
||||
const { undo } = useCommands();
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
|
@ -11,7 +11,11 @@ const nextConfig = {
|
||||
reactStrictMode: false,
|
||||
swcMinify: true,
|
||||
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",
|
||||
experimental: {
|
||||
|
@ -73,7 +73,7 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
|
||||
: null
|
||||
);
|
||||
|
||||
const { data: subIssues } = useSWR(
|
||||
const { data: subIssues } = useSWR<IIssue[] | undefined>(
|
||||
issueId && workspaceSlug && projectId ? SUB_ISSUES(issueId as string) : null,
|
||||
issueId && workspaceSlug && projectId
|
||||
? () =>
|
||||
@ -126,7 +126,6 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
|
||||
issuesService
|
||||
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload)
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
mutateIssueDetails();
|
||||
mutateIssueActivities();
|
||||
})
|
||||
@ -140,11 +139,16 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
|
||||
const handleSubIssueRemove = (issueId: string) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
||||
mutate<IIssue[]>(
|
||||
SUB_ISSUES(issueDetails?.id ?? ""),
|
||||
(prevData) => prevData?.filter((i) => i.id !== issueId),
|
||||
false
|
||||
);
|
||||
|
||||
issuesService
|
||||
.patchIssue(workspaceSlug as string, projectId as string, issueId, { parent: null })
|
||||
.then((res) => {
|
||||
mutate(SUB_ISSUES(issueDetails?.id ?? ""));
|
||||
mutateIssueActivities();
|
||||
|
||||
mutate<IssueResponse>(
|
||||
PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
|
||||
@ -169,22 +173,22 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (issueDetails) {
|
||||
mutateIssueActivities();
|
||||
reset({
|
||||
...issueDetails,
|
||||
blockers_list:
|
||||
issueDetails.blockers_list ??
|
||||
issueDetails.blocker_issues?.map((issue) => issue.blocker_issue_detail?.id),
|
||||
blocked_list:
|
||||
issueDetails.blocked_list ??
|
||||
issueDetails.blocked_issues?.map((issue) => issue.blocked_issue_detail?.id),
|
||||
assignees_list:
|
||||
issueDetails.assignees_list ?? issueDetails.assignee_details?.map((user) => user.id),
|
||||
labels_list: issueDetails.labels_list ?? issueDetails.labels,
|
||||
labels: issueDetails.labels_list ?? issueDetails.labels,
|
||||
});
|
||||
}
|
||||
if (!issueDetails) return;
|
||||
|
||||
mutateIssueActivities();
|
||||
reset({
|
||||
...issueDetails,
|
||||
blockers_list:
|
||||
issueDetails.blockers_list ??
|
||||
issueDetails.blocker_issues?.map((issue) => issue.blocker_issue_detail?.id),
|
||||
blocked_list:
|
||||
issueDetails.blocks_list ??
|
||||
issueDetails.blocked_issues?.map((issue) => issue.blocked_issue_detail?.id),
|
||||
assignees_list:
|
||||
issueDetails.assignees_list ?? issueDetails.assignee_details?.map((user) => user.id),
|
||||
labels_list: issueDetails.labels_list ?? issueDetails.labels,
|
||||
labels: issueDetails.labels_list ?? issueDetails.labels,
|
||||
});
|
||||
}, [issueDetails, reset, mutateIssueActivities]);
|
||||
|
||||
const isNotAllowed = props.isGuest || props.isViewer;
|
||||
@ -280,9 +284,9 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
|
||||
userAuth={props}
|
||||
/>
|
||||
<div className="mt-2">
|
||||
{issueId && workspaceSlug && projectId && subIssues?.length > 0 ? (
|
||||
{issueId && workspaceSlug && projectId && subIssues && subIssues.length > 0 ? (
|
||||
<SubIssuesList
|
||||
issues={subIssues}
|
||||
issues={subIssues ?? []}
|
||||
parentIssue={issueDetails}
|
||||
projectId={projectId?.toString()}
|
||||
workspaceSlug={workspaceSlug?.toString()}
|
||||
|
@ -401,6 +401,19 @@ img.ProseMirror-separator {
|
||||
/* end table 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 {
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
|
Loading…
Reference in New Issue
Block a user