mirror of
https://github.com/docmost/docmost.git
synced 2025-11-14 15:11:09 +10:00
Compare commits
8 Commits
v0.20.4
...
1c200dbd0f
| Author | SHA1 | Date | |
|---|---|---|---|
| 1c200dbd0f | |||
| fb7e4a7956 | |||
| 1413033568 | |||
| 00f4588c21 | |||
| 3a75251e75 | |||
| c6bca6a602 | |||
| 55d1a2c932 | |||
| bc3cb2d63f |
@ -15,7 +15,7 @@ export default function EnforceSso() {
|
|||||||
<Text size="md">{t("Enforce SSO")}</Text>
|
<Text size="md">{t("Enforce SSO")}</Text>
|
||||||
<Text size="sm" c="dimmed">
|
<Text size="sm" c="dimmed">
|
||||||
{t(
|
{t(
|
||||||
"Once enforced, members will not able to login with email and password.",
|
"Once enforced, members will not be able to login with email and password.",
|
||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import { asideStateAtom } from "@/components/layouts/global/hooks/atoms/sidebar-
|
|||||||
import { useEditor } from "@tiptap/react";
|
import { useEditor } from "@tiptap/react";
|
||||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useQueryEmit } from "@/features/websocket/use-query-emit";
|
||||||
|
|
||||||
interface CommentDialogProps {
|
interface CommentDialogProps {
|
||||||
editor: ReturnType<typeof useEditor>;
|
editor: ReturnType<typeof useEditor>;
|
||||||
@ -35,6 +36,8 @@ function CommentDialog({ editor, pageId }: CommentDialogProps) {
|
|||||||
const createCommentMutation = useCreateCommentMutation();
|
const createCommentMutation = useCreateCommentMutation();
|
||||||
const { isPending } = createCommentMutation;
|
const { isPending } = createCommentMutation;
|
||||||
|
|
||||||
|
const emit = useQueryEmit();
|
||||||
|
|
||||||
const handleDialogClose = () => {
|
const handleDialogClose = () => {
|
||||||
setShowCommentPopup(false);
|
setShowCommentPopup(false);
|
||||||
editor.chain().focus().unsetCommentDecoration().run();
|
editor.chain().focus().unsetCommentDecoration().run();
|
||||||
@ -63,11 +66,23 @@ function CommentDialog({ editor, pageId }: CommentDialogProps) {
|
|||||||
.run();
|
.run();
|
||||||
setActiveCommentId(createdComment.id);
|
setActiveCommentId(createdComment.id);
|
||||||
|
|
||||||
|
//unselect text to close bubble menu
|
||||||
|
editor.commands.setTextSelection({ from: editor.view.state.selection.from, to: editor.view.state.selection.from });
|
||||||
|
|
||||||
setAsideState({ tab: "comments", isAsideOpen: true });
|
setAsideState({ tab: "comments", isAsideOpen: true });
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const selector = `div[data-comment-id="${createdComment.id}"]`;
|
const selector = `div[data-comment-id="${createdComment.id}"]`;
|
||||||
const commentElement = document.querySelector(selector);
|
const commentElement = document.querySelector(selector);
|
||||||
commentElement?.scrollIntoView();
|
commentElement?.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||||
|
|
||||||
|
editor.view.dispatch(
|
||||||
|
editor.state.tr.scrollIntoView()
|
||||||
|
);
|
||||||
|
}, 400);
|
||||||
|
|
||||||
|
emit({
|
||||||
|
operation: "invalidateComment",
|
||||||
|
pageId: pageId,
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setShowCommentPopup(false);
|
setShowCommentPopup(false);
|
||||||
|
|||||||
@ -53,6 +53,10 @@ const CommentEditor = forwardRef(
|
|||||||
autofocus: (autofocus && "end") || false,
|
autofocus: (autofocus && "end") || false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
commentEditor.commands.setContent(defaultContent);
|
||||||
|
}, [defaultContent]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (autofocus) {
|
if (autofocus) {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Group, Text, Box } from "@mantine/core";
|
import { Group, Text, Box } from "@mantine/core";
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import classes from "./comment.module.css";
|
import classes from "./comment.module.css";
|
||||||
import { useAtom, useAtomValue } from "jotai";
|
import { useAtom, useAtomValue } from "jotai";
|
||||||
import { timeAgo } from "@/lib/time";
|
import { timeAgo } from "@/lib/time";
|
||||||
@ -15,12 +15,14 @@ import {
|
|||||||
import { IComment } from "@/features/comment/types/comment.types";
|
import { IComment } from "@/features/comment/types/comment.types";
|
||||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||||
import { currentUserAtom } from "@/features/user/atoms/current-user-atom.ts";
|
import { currentUserAtom } from "@/features/user/atoms/current-user-atom.ts";
|
||||||
|
import { useQueryEmit } from "@/features/websocket/use-query-emit";
|
||||||
|
|
||||||
interface CommentListItemProps {
|
interface CommentListItemProps {
|
||||||
comment: IComment;
|
comment: IComment;
|
||||||
|
pageId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function CommentListItem({ comment }: CommentListItemProps) {
|
function CommentListItem({ comment, pageId }: CommentListItemProps) {
|
||||||
const { hovered, ref } = useHover();
|
const { hovered, ref } = useHover();
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
@ -29,6 +31,11 @@ function CommentListItem({ comment }: CommentListItemProps) {
|
|||||||
const updateCommentMutation = useUpdateCommentMutation();
|
const updateCommentMutation = useUpdateCommentMutation();
|
||||||
const deleteCommentMutation = useDeleteCommentMutation(comment.pageId);
|
const deleteCommentMutation = useDeleteCommentMutation(comment.pageId);
|
||||||
const [currentUser] = useAtom(currentUserAtom);
|
const [currentUser] = useAtom(currentUserAtom);
|
||||||
|
const emit = useQueryEmit();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setContent(comment.content)
|
||||||
|
}, [comment]);
|
||||||
|
|
||||||
async function handleUpdateComment() {
|
async function handleUpdateComment() {
|
||||||
try {
|
try {
|
||||||
@ -39,6 +46,11 @@ function CommentListItem({ comment }: CommentListItemProps) {
|
|||||||
};
|
};
|
||||||
await updateCommentMutation.mutateAsync(commentToUpdate);
|
await updateCommentMutation.mutateAsync(commentToUpdate);
|
||||||
setIsEditing(false);
|
setIsEditing(false);
|
||||||
|
|
||||||
|
emit({
|
||||||
|
operation: "invalidateComment",
|
||||||
|
pageId: pageId,
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to update comment:", error);
|
console.error("Failed to update comment:", error);
|
||||||
} finally {
|
} finally {
|
||||||
@ -50,11 +62,27 @@ function CommentListItem({ comment }: CommentListItemProps) {
|
|||||||
try {
|
try {
|
||||||
await deleteCommentMutation.mutateAsync(comment.id);
|
await deleteCommentMutation.mutateAsync(comment.id);
|
||||||
editor?.commands.unsetComment(comment.id);
|
editor?.commands.unsetComment(comment.id);
|
||||||
|
|
||||||
|
emit({
|
||||||
|
operation: "invalidateComment",
|
||||||
|
pageId: pageId,
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to delete comment:", error);
|
console.error("Failed to delete comment:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCommentClick(comment: IComment) {
|
||||||
|
const el = document.querySelector(`.comment-mark[data-comment-id="${comment.id}"]`);
|
||||||
|
if (el) {
|
||||||
|
el.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||||
|
el.classList.add("comment-highlight");
|
||||||
|
setTimeout(() => {
|
||||||
|
el.classList.remove("comment-highlight");
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleEditToggle() {
|
function handleEditToggle() {
|
||||||
setIsEditing(true);
|
setIsEditing(true);
|
||||||
}
|
}
|
||||||
@ -99,7 +127,7 @@ function CommentListItem({ comment }: CommentListItemProps) {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
{!comment.parentCommentId && comment?.selection && (
|
{!comment.parentCommentId && comment?.selection && (
|
||||||
<Box className={classes.textSelection}>
|
<Box className={classes.textSelection} onClick={() => handleCommentClick(comment)}>
|
||||||
<Text size="sm">{comment?.selection}</Text>
|
<Text size="sm">{comment?.selection}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { usePageQuery } from "@/features/page/queries/page-query.ts";
|
|||||||
import { IPagination } from "@/lib/types.ts";
|
import { IPagination } from "@/lib/types.ts";
|
||||||
import { extractPageSlugId } from "@/lib";
|
import { extractPageSlugId } from "@/lib";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useQueryEmit } from "@/features/websocket/use-query-emit";
|
||||||
|
|
||||||
function CommentList() {
|
function CommentList() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -26,6 +27,7 @@ function CommentList() {
|
|||||||
} = useCommentsQuery({ pageId: page?.id, limit: 100 });
|
} = useCommentsQuery({ pageId: page?.id, limit: 100 });
|
||||||
const createCommentMutation = useCreateCommentMutation();
|
const createCommentMutation = useCreateCommentMutation();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const emit = useQueryEmit();
|
||||||
|
|
||||||
const handleAddReply = useCallback(
|
const handleAddReply = useCallback(
|
||||||
async (commentId: string, content: string) => {
|
async (commentId: string, content: string) => {
|
||||||
@ -38,6 +40,11 @@ function CommentList() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
await createCommentMutation.mutateAsync(commentData);
|
await createCommentMutation.mutateAsync(commentData);
|
||||||
|
|
||||||
|
emit({
|
||||||
|
operation: "invalidateComment",
|
||||||
|
pageId: page?.id,
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to post comment:", error);
|
console.error("Failed to post comment:", error);
|
||||||
} finally {
|
} finally {
|
||||||
@ -59,8 +66,8 @@ function CommentList() {
|
|||||||
data-comment-id={comment.id}
|
data-comment-id={comment.id}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<CommentListItem comment={comment} />
|
<CommentListItem comment={comment} pageId={page?.id} />
|
||||||
<MemoizedChildComments comments={comments} parentId={comment.id} />
|
<MemoizedChildComments comments={comments} parentId={comment.id} pageId={page?.id} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider my={4} />
|
<Divider my={4} />
|
||||||
@ -99,8 +106,9 @@ function CommentList() {
|
|||||||
interface ChildCommentsProps {
|
interface ChildCommentsProps {
|
||||||
comments: IPagination<IComment>;
|
comments: IPagination<IComment>;
|
||||||
parentId: string;
|
parentId: string;
|
||||||
|
pageId: string;
|
||||||
}
|
}
|
||||||
const ChildComments = ({ comments, parentId }: ChildCommentsProps) => {
|
const ChildComments = ({ comments, parentId, pageId }: ChildCommentsProps) => {
|
||||||
const getChildComments = useCallback(
|
const getChildComments = useCallback(
|
||||||
(parentId: string) =>
|
(parentId: string) =>
|
||||||
comments.items.filter(
|
comments.items.filter(
|
||||||
@ -113,10 +121,11 @@ const ChildComments = ({ comments, parentId }: ChildCommentsProps) => {
|
|||||||
<div>
|
<div>
|
||||||
{getChildComments(parentId).map((childComment) => (
|
{getChildComments(parentId).map((childComment) => (
|
||||||
<div key={childComment.id}>
|
<div key={childComment.id}>
|
||||||
<CommentListItem comment={childComment} />
|
<CommentListItem comment={childComment} pageId={pageId} />
|
||||||
<MemoizedChildComments
|
<MemoizedChildComments
|
||||||
comments={comments}
|
comments={comments}
|
||||||
parentId={childComment.id}
|
parentId={childComment.id}
|
||||||
|
pageId={pageId}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
border-left: 2px solid var(--mantine-color-gray-6);
|
border-left: 2px solid var(--mantine-color-gray-6);
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
background: var(--mantine-color-gray-light);
|
background: var(--mantine-color-gray-light);
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commentEditor {
|
.commentEditor {
|
||||||
|
|||||||
@ -219,9 +219,12 @@ export default function PageEditor({
|
|||||||
setActiveCommentId(commentId);
|
setActiveCommentId(commentId);
|
||||||
setAsideState({ tab: "comments", isAsideOpen: true });
|
setAsideState({ tab: "comments", isAsideOpen: true });
|
||||||
|
|
||||||
|
//wait if aside is closed
|
||||||
|
setTimeout(() => {
|
||||||
const selector = `div[data-comment-id="${commentId}"]`;
|
const selector = `div[data-comment-id="${commentId}"]`;
|
||||||
const commentElement = document.querySelector(selector);
|
const commentElement = document.querySelector(selector);
|
||||||
commentElement?.scrollIntoView();
|
commentElement?.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||||
|
}, 400);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -144,6 +144,19 @@
|
|||||||
border-bottom: 2px solid rgb(166, 158, 12);
|
border-bottom: 2px solid rgb(166, 158, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment-highlight {
|
||||||
|
animation: flash-highlight 3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes flash-highlight {
|
||||||
|
0% {
|
||||||
|
background-color: #ff4d4d;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-color: rgba(255, 215, 0, 0.14);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.resize-cursor {
|
.resize-cursor {
|
||||||
cursor: ew-resize;
|
cursor: ew-resize;
|
||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
|
|||||||
@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
.column-resize-handle {
|
.column-resize-handle {
|
||||||
background-color: #adf;
|
background-color: #adf;
|
||||||
bottom: -2px;
|
bottom: -1px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -2px;
|
right: -2px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import {
|
|||||||
pageEditorAtom,
|
pageEditorAtom,
|
||||||
titleEditorAtom,
|
titleEditorAtom,
|
||||||
} from "@/features/editor/atoms/editor-atoms";
|
} from "@/features/editor/atoms/editor-atoms";
|
||||||
import { useUpdatePageMutation } from "@/features/page/queries/page-query";
|
import { updatePageData, useUpdateTitlePageMutation } from "@/features/page/queries/page-query";
|
||||||
import { useDebouncedCallback } from "@mantine/hooks";
|
import { useDebouncedCallback } from "@mantine/hooks";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { useQueryEmit } from "@/features/websocket/use-query-emit.ts";
|
import { useQueryEmit } from "@/features/websocket/use-query-emit.ts";
|
||||||
@ -38,7 +38,7 @@ export function TitleEditor({
|
|||||||
editable,
|
editable,
|
||||||
}: TitleEditorProps) {
|
}: TitleEditorProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { mutateAsync: updatePageMutationAsync } = useUpdatePageMutation();
|
const { mutateAsync: updateTitlePageMutationAsync } = useUpdateTitlePageMutation();
|
||||||
const pageEditor = useAtomValue(pageEditorAtom);
|
const pageEditor = useAtomValue(pageEditorAtom);
|
||||||
const [, setTitleEditor] = useAtom(titleEditorAtom);
|
const [, setTitleEditor] = useAtom(titleEditorAtom);
|
||||||
const emit = useQueryEmit();
|
const emit = useQueryEmit();
|
||||||
@ -94,7 +94,7 @@ export function TitleEditor({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePageMutationAsync({
|
updateTitlePageMutationAsync({
|
||||||
pageId: pageId,
|
pageId: pageId,
|
||||||
title: titleEditor.getText(),
|
title: titleEditor.getText(),
|
||||||
}).then((page) => {
|
}).then((page) => {
|
||||||
@ -106,6 +106,10 @@ export function TitleEditor({
|
|||||||
payload: { title: page.title, slugId: page.slugId },
|
payload: { title: page.title, slugId: page.slugId },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (page.title !== titleEditor.getText()) return;
|
||||||
|
|
||||||
|
updatePageData(page);
|
||||||
|
|
||||||
localEmitter.emit("message", event);
|
localEmitter.emit("message", event);
|
||||||
emit(event);
|
emit(event);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -63,12 +63,7 @@ export function useCreatePageMutation() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useUpdatePageMutation() {
|
export function updatePageData(data: IPage) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
return useMutation<IPage, Error, Partial<IPageInput>>({
|
|
||||||
mutationFn: (data) => updatePage(data),
|
|
||||||
onSuccess: (data) => {
|
|
||||||
const pageBySlug = queryClient.getQueryData<IPage>([
|
const pageBySlug = queryClient.getQueryData<IPage>([
|
||||||
"pages",
|
"pages",
|
||||||
data.slugId,
|
data.slugId,
|
||||||
@ -85,6 +80,19 @@ export function useUpdatePageMutation() {
|
|||||||
if (pageById) {
|
if (pageById) {
|
||||||
queryClient.setQueryData(["pages", data.id], { ...pageById, ...data });
|
queryClient.setQueryData(["pages", data.id], { ...pageById, ...data });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useUpdateTitlePageMutation() {
|
||||||
|
return useMutation<IPage, Error, Partial<IPageInput>>({
|
||||||
|
mutationFn: (data) => updatePage(data),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useUpdatePageMutation() {
|
||||||
|
return useMutation<IPage, Error, Partial<IPageInput>>({
|
||||||
|
mutationFn: (data) => updatePage(data),
|
||||||
|
onSuccess: (data) => {
|
||||||
|
updatePage(data);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,7 @@ export function SpaceSelect({
|
|||||||
nothingFoundMessage={t("No space found")}
|
nothingFoundMessage={t("No space found")}
|
||||||
limit={50}
|
limit={50}
|
||||||
checkIconPosition="right"
|
checkIconPosition="right"
|
||||||
comboboxProps={{ width, withinPortal: false }}
|
comboboxProps={{ width, withinPortal: true, position: "bottom" }}
|
||||||
dropdownOpened={opened}
|
dropdownOpened={opened}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -7,6 +7,11 @@ export type InvalidateEvent = {
|
|||||||
id?: string;
|
id?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type InvalidateCommentsEvent = {
|
||||||
|
operation: "invalidateComment";
|
||||||
|
pageId: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type UpdateEvent = {
|
export type UpdateEvent = {
|
||||||
operation: "updateOne";
|
operation: "updateOne";
|
||||||
spaceId: string;
|
spaceId: string;
|
||||||
@ -52,4 +57,4 @@ export type DeleteTreeNodeEvent = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export type WebSocketEvent = InvalidateEvent | UpdateEvent | DeleteEvent | AddTreeNodeEvent | MoveTreeNodeEvent | DeleteTreeNodeEvent;
|
export type WebSocketEvent = InvalidateEvent | InvalidateCommentsEvent | UpdateEvent | DeleteEvent | AddTreeNodeEvent | MoveTreeNodeEvent | DeleteTreeNodeEvent;
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { socketAtom } from "@/features/websocket/atoms/socket-atom.ts";
|
|||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { WebSocketEvent } from "@/features/websocket/types";
|
import { WebSocketEvent } from "@/features/websocket/types";
|
||||||
|
import { RQ_KEY } from "../comment/queries/comment-query";
|
||||||
|
|
||||||
export const useQuerySubscription = () => {
|
export const useQuerySubscription = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@ -21,6 +22,11 @@ export const useQuerySubscription = () => {
|
|||||||
queryKey: [...data.entity, data.id].filter(Boolean),
|
queryKey: [...data.entity, data.id].filter(Boolean),
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case "invalidateComment":
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: RQ_KEY(data.pageId),
|
||||||
|
});
|
||||||
|
break;
|
||||||
case "updateOne":
|
case "updateOne":
|
||||||
entity = data.entity[0];
|
entity = data.entity[0];
|
||||||
if (entity === "pages") {
|
if (entity === "pages") {
|
||||||
|
|||||||
@ -46,7 +46,7 @@ export const tiptapExtensions = [
|
|||||||
codeBlock: false,
|
codeBlock: false,
|
||||||
}),
|
}),
|
||||||
Comment,
|
Comment,
|
||||||
TextAlign,
|
TextAlign.configure({ types: ["heading", "paragraph"] }),
|
||||||
TaskList,
|
TaskList,
|
||||||
TaskItem,
|
TaskItem,
|
||||||
Underline,
|
Underline,
|
||||||
|
|||||||
@ -387,14 +387,14 @@ export class WorkspaceService {
|
|||||||
.replace(/[^a-z0-9]/g, '')
|
.replace(/[^a-z0-9]/g, '')
|
||||||
.substring(0, 20);
|
.substring(0, 20);
|
||||||
// Ensure we leave room for a random suffix.
|
// Ensure we leave room for a random suffix.
|
||||||
const maxSuffixLength = 3;
|
const maxSuffixLength = 6;
|
||||||
|
|
||||||
if (subdomain.length < 4) {
|
if (subdomain.length < 4) {
|
||||||
subdomain = `${subdomain}-${generateRandomSuffix(maxSuffixLength)}`;
|
subdomain = `${subdomain}-${generateRandomSuffix(maxSuffixLength)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DISALLOWED_HOSTNAMES.includes(subdomain)) {
|
if (DISALLOWED_HOSTNAMES.includes(subdomain)) {
|
||||||
subdomain = `myworkspace-${generateRandomSuffix(maxSuffixLength)}`;
|
subdomain = `workspace-${generateRandomSuffix(maxSuffixLength)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let uniqueHostname = subdomain;
|
let uniqueHostname = subdomain;
|
||||||
|
|||||||
@ -70,7 +70,7 @@ export class UserTokenRepo {
|
|||||||
.where('userId', '=', userId)
|
.where('userId', '=', userId)
|
||||||
.where('workspaceId', '=', workspaceId)
|
.where('workspaceId', '=', workspaceId)
|
||||||
.where('type', '=', tokenType)
|
.where('type', '=', tokenType)
|
||||||
.orderBy('expiresAt desc')
|
.orderBy('expiresAt', 'desc')
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -70,7 +70,7 @@ export class WorkspaceRepo {
|
|||||||
return await this.db
|
return await this.db
|
||||||
.selectFrom('workspaces')
|
.selectFrom('workspaces')
|
||||||
.selectAll()
|
.selectAll()
|
||||||
.orderBy('createdAt asc')
|
.orderBy('createdAt', 'asc')
|
||||||
.limit(1)
|
.limit(1)
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user