fix: Image restoration fixed (marks/unmarks an image to be deleted after a week) (#2859)
* image restoration fixed (marks an image to be deleted after a week) * removed clgs * added image constraints * formatted editor-core package using yarn format * lite-text-editor nothing to format * rich-text-editor nothing to format * formatted document-editor with prettier * modified file service to follow api change * fixed more formatting in document editor * fixed all instances of types with that from the package * fixed delete to work consistently (minor optimizations turned off) * stop duplicate images inside editor * restore image on editor creation say if user A deletes image number 2, user B was also in the same issue and in their screen the image was there, if user B makes certain changes and that gets saved in backend, according to user B image 2 should exist but since user A deleted it, it'll not get restored and get deleted in 7 days, hence I've added a check such that whenever a issue loads we restore all images by default * added restore image function with types * replaced all instances to have restore image logic * fixed issue detail for peek view * disabled option to insert table inside a table
This commit is contained in:
parent
0fcadca53a
commit
e01ca97fc9
63 changed files with 471 additions and 225 deletions
|
|
@ -155,6 +155,7 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
|||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
debouncedUpdatesEnabled={false}
|
||||
value={!value || value === "" ? "<p></p>" : value}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ export const AddComment: React.FC<Props> = ({ disabled = false, onSubmit, showAc
|
|||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
||||
customClassName="p-2 h-full"
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ export const CommentCard: React.FC<Props> = ({
|
|||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
value={watch("comment_html")}
|
||||
debouncedUpdatesEnabled={false}
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = (props) => {
|
|||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
value={value}
|
||||
setShouldShowAlert={setShowAlert}
|
||||
setIsSubmitting={setIsSubmitting}
|
||||
|
|
|
|||
|
|
@ -425,6 +425,7 @@ export const DraftIssueForm: FC<IssueFormProps> = observer((props) => {
|
|||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
debouncedUpdatesEnabled={false}
|
||||
value={
|
||||
|
|
|
|||
|
|
@ -379,6 +379,7 @@ export const IssueForm: FC<IssueFormProps> = observer((props) => {
|
|||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
debouncedUpdatesEnabled={false}
|
||||
value={
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ export const IssueCommentCard: React.FC<IIssueCommentCard> = (props) => {
|
|||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
value={watch("comment_html")}
|
||||
debouncedUpdatesEnabled={false}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
|
|||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
||||
customClassName="p-2 h-full"
|
||||
|
|
|
|||
|
|
@ -66,11 +66,15 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) =
|
|||
[issue, issueUpdate]
|
||||
);
|
||||
|
||||
const debouncedIssueDescription = useDebouncedCallback(async (_data: any) => {
|
||||
issueUpdate({ ...issue, description_html: _data });
|
||||
}, 1500);
|
||||
const [localTitleValue, setLocalTitleValue] = useState("");
|
||||
const issueTitleCurrentValue = watch("name");
|
||||
useEffect(() => {
|
||||
if (localTitleValue === "" && issueTitleCurrentValue !== "") {
|
||||
setLocalTitleValue(issueTitleCurrentValue);
|
||||
}
|
||||
}, [issueTitleCurrentValue, localTitleValue]);
|
||||
|
||||
const debouncedTitleSave = useDebouncedCallback(async () => {
|
||||
const debouncedFormSave = useDebouncedCallback(async () => {
|
||||
handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted"));
|
||||
}, 1500);
|
||||
|
||||
|
|
@ -105,18 +109,19 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) =
|
|||
<Controller
|
||||
name="name"
|
||||
control={control}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
render={({ field: { onChange } }) => (
|
||||
<TextArea
|
||||
id="name"
|
||||
name="name"
|
||||
value={value}
|
||||
value={localTitleValue}
|
||||
placeholder="Enter issue name"
|
||||
onFocus={() => setCharacterLimit(true)}
|
||||
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setCharacterLimit(false);
|
||||
setIsSubmitting("submitting");
|
||||
debouncedTitleSave();
|
||||
setLocalTitleValue(e.target.value);
|
||||
onChange(e.target.value);
|
||||
debouncedFormSave();
|
||||
}}
|
||||
required={true}
|
||||
className="min-h-10 block w-full resize-none overflow-hidden rounded border-none bg-transparent text-xl outline-none ring-0 focus:ring-1 focus:ring-custom-primary !p-0 focus:!px-3 focus:!py-2"
|
||||
|
|
@ -139,20 +144,41 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) =
|
|||
)}
|
||||
</div>
|
||||
<span>{errors.name ? errors.name.message : null}</span>
|
||||
<RichTextEditor
|
||||
dragDropEnabled
|
||||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
value={issue?.description_html}
|
||||
debouncedUpdatesEnabled={false}
|
||||
onChange={(description: Object, description_html: string) => {
|
||||
debouncedIssueDescription(description_html);
|
||||
}}
|
||||
customClassName="mt-0"
|
||||
mentionSuggestions={editorSuggestions.mentionSuggestions}
|
||||
mentionHighlights={editorSuggestions.mentionHighlights}
|
||||
/>
|
||||
<div className="relative">
|
||||
<Controller
|
||||
name="description_html"
|
||||
control={control}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<RichTextEditor
|
||||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
value={value}
|
||||
setShouldShowAlert={setShowAlert}
|
||||
setIsSubmitting={setIsSubmitting}
|
||||
dragDropEnabled
|
||||
customClassName={isAllowed ? "min-h-[150px] shadow-sm" : "!p-0 !pt-2 text-custom-text-200"}
|
||||
noBorder={!isAllowed}
|
||||
onChange={(description: Object, description_html: string) => {
|
||||
setShowAlert(true);
|
||||
setIsSubmitting("submitting");
|
||||
onChange(description_html);
|
||||
debouncedFormSave();
|
||||
}}
|
||||
mentionSuggestions={editorSuggestions.mentionSuggestions}
|
||||
mentionHighlights={editorSuggestions.mentionHighlights}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<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"
|
||||
}`}
|
||||
>
|
||||
{isSubmitting === "submitting" ? "Saving..." : "Saved"}
|
||||
</div>
|
||||
</div>
|
||||
<IssueReaction
|
||||
issueReactions={issueReactions}
|
||||
user={user}
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ export const CreateUpdateBlockInline: FC<Props> = (props) => {
|
|||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
value={"<p></p>"}
|
||||
debouncedUpdatesEnabled={false}
|
||||
|
|
@ -293,6 +294,7 @@ export const CreateUpdateBlockInline: FC<Props> = (props) => {
|
|||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
value={
|
||||
value && value !== "" && Object.keys(value).length > 0
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
|||
}}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
debouncedUpdatesEnabled={false}
|
||||
setIsSubmitting={setIsSubmitting}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ export class FileService extends APIService {
|
|||
super(API_BASE_URL);
|
||||
this.uploadFile = this.uploadFile.bind(this);
|
||||
this.deleteImage = this.deleteImage.bind(this);
|
||||
this.restoreImage = this.restoreImage.bind(this);
|
||||
this.cancelUpload = this.cancelUpload.bind(this);
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +82,17 @@ export class FileService extends APIService {
|
|||
});
|
||||
}
|
||||
|
||||
async restoreImage(assetUrlWithWorkspaceId: string): Promise<any> {
|
||||
return this.post(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/restore/`, {
|
||||
headers: this.getHeaders(),
|
||||
"Content-Type": "application/json",
|
||||
})
|
||||
.then((response) => response?.status)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data;
|
||||
});
|
||||
}
|
||||
|
||||
async deleteFile(workspaceId: string, assetUrl: string): Promise<any> {
|
||||
const lastIndex = assetUrl.lastIndexOf("/");
|
||||
const assetId = assetUrl.substring(lastIndex + 1);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
/* Custom image styles */
|
||||
|
||||
.ProseMirror img {
|
||||
min-width: 100px;
|
||||
min-height: 100px;
|
||||
transition: filter 0.1s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue