mirror of
https://github.com/Shadowfita/docmost.git
synced 2025-11-16 17:51:06 +10:00
Merge branch 'docmost:main' into main
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "client",
|
"name": "client",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.2.10",
|
"version": "0.3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
@ -14,26 +14,26 @@
|
|||||||
"@emoji-mart/data": "^1.2.1",
|
"@emoji-mart/data": "^1.2.1",
|
||||||
"@emoji-mart/react": "^1.1.1",
|
"@emoji-mart/react": "^1.1.1",
|
||||||
"@excalidraw/excalidraw": "^0.17.6",
|
"@excalidraw/excalidraw": "^0.17.6",
|
||||||
"@mantine/core": "^7.11.0",
|
"@mantine/core": "^7.12.2",
|
||||||
"@mantine/form": "^7.11.0",
|
"@mantine/form": "^7.12.2",
|
||||||
"@mantine/hooks": "^7.11.0",
|
"@mantine/hooks": "^7.12.2",
|
||||||
"@mantine/modals": "^7.11.0",
|
"@mantine/modals": "^7.12.2",
|
||||||
"@mantine/notifications": "^7.11.0",
|
"@mantine/notifications": "^7.12.2",
|
||||||
"@mantine/spotlight": "^7.11.0",
|
"@mantine/spotlight": "^7.12.2",
|
||||||
"@tabler/icons-react": "^3.7.0",
|
"@tabler/icons-react": "^3.14.0",
|
||||||
"@tanstack/react-query": "^5.48.0",
|
"@tanstack/react-query": "^5.53.2",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.7",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"emoji-mart": "^5.6.0",
|
"emoji-mart": "^5.6.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"jotai": "^2.8.3",
|
"jotai": "^2.9.3",
|
||||||
"jotai-optics": "^0.4.0",
|
"jotai-optics": "^0.4.0",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"katex": "^0.16.10",
|
"katex": "^0.16.11",
|
||||||
"lowlight": "^3.1.0",
|
"lowlight": "^3.1.0",
|
||||||
"mermaid": "^11.0.1",
|
"mermaid": "^11.0.2",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-arborist": "^3.4.0",
|
"react-arborist": "^3.4.0",
|
||||||
"react-clear-modal": "^2.0.9",
|
"react-clear-modal": "^2.0.9",
|
||||||
@ -42,32 +42,32 @@
|
|||||||
"react-error-boundary": "^4.0.13",
|
"react-error-boundary": "^4.0.13",
|
||||||
"react-helmet-async": "^2.0.5",
|
"react-helmet-async": "^2.0.5",
|
||||||
"react-moveable": "^0.56.0",
|
"react-moveable": "^0.56.0",
|
||||||
"react-router-dom": "^6.24.0",
|
"react-router-dom": "^6.26.1",
|
||||||
"socket.io-client": "^4.7.5",
|
"socket.io-client": "^4.7.5",
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"tiptap-extension-global-drag-handle": "^0.1.10",
|
"tiptap-extension-global-drag-handle": "^0.1.12",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tanstack/eslint-plugin-query": "^5.47.0",
|
"@tanstack/eslint-plugin-query": "^5.53.0",
|
||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/katex": "^0.16.7",
|
"@types/katex": "^0.16.7",
|
||||||
"@types/node": "20.14.9",
|
"@types/node": "22.5.2",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.5",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.14.1",
|
"@typescript-eslint/eslint-plugin": "^8.3.0",
|
||||||
"@typescript-eslint/parser": "^7.14.1",
|
"@typescript-eslint/parser": "^8.3.0",
|
||||||
"@vitejs/plugin-react": "^4.3.1",
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
"eslint": "^9.5.0",
|
"eslint": "^9.9.1",
|
||||||
"eslint-plugin-react-hooks": "^4.6.2",
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
"eslint-plugin-react-refresh": "^0.4.7",
|
"eslint-plugin-react-refresh": "^0.4.11",
|
||||||
"optics-ts": "^2.4.1",
|
"optics-ts": "^2.4.1",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.43",
|
||||||
"postcss-preset-mantine": "^1.15.0",
|
"postcss-preset-mantine": "^1.17.0",
|
||||||
"postcss-simple-vars": "^7.0.1",
|
"postcss-simple-vars": "^7.0.1",
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.3.3",
|
||||||
"typescript": "^5.5.2",
|
"typescript": "^5.5.4",
|
||||||
"vite": "^5.3.1"
|
"vite": "^5.4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from "react";
|
||||||
import { Group, Text, ScrollArea, ActionIcon, rem } from '@mantine/core';
|
import { Group, Text, ScrollArea, ActionIcon, rem } from "@mantine/core";
|
||||||
import {
|
import {
|
||||||
IconUser,
|
IconUser,
|
||||||
IconSettings,
|
IconSettings,
|
||||||
@ -8,9 +8,9 @@ import {
|
|||||||
IconUsersGroup,
|
IconUsersGroup,
|
||||||
IconSpaces,
|
IconSpaces,
|
||||||
IconBrush,
|
IconBrush,
|
||||||
} from '@tabler/icons-react';
|
} from "@tabler/icons-react";
|
||||||
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||||
import classes from './settings.module.css';
|
import classes from "./settings.module.css";
|
||||||
|
|
||||||
interface DataItem {
|
interface DataItem {
|
||||||
label: string;
|
label: string;
|
||||||
@ -25,27 +25,27 @@ interface DataGroup {
|
|||||||
|
|
||||||
const groupedData: DataGroup[] = [
|
const groupedData: DataGroup[] = [
|
||||||
{
|
{
|
||||||
heading: 'Account',
|
heading: "Account",
|
||||||
items: [
|
items: [
|
||||||
{ label: 'Profile', icon: IconUser, path: '/settings/account/profile' },
|
{ label: "Profile", icon: IconUser, path: "/settings/account/profile" },
|
||||||
{
|
{
|
||||||
label: 'Preferences',
|
label: "Preferences",
|
||||||
icon: IconBrush,
|
icon: IconBrush,
|
||||||
path: '/settings/account/preferences',
|
path: "/settings/account/preferences",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: 'Workspace',
|
heading: "Workspace",
|
||||||
items: [
|
items: [
|
||||||
{ label: 'General', icon: IconSettings, path: '/settings/workspace' },
|
{ label: "General", icon: IconSettings, path: "/settings/workspace" },
|
||||||
{
|
{
|
||||||
label: 'Members',
|
label: "Members",
|
||||||
icon: IconUsers,
|
icon: IconUsers,
|
||||||
path: '/settings/members',
|
path: "/settings/members",
|
||||||
},
|
},
|
||||||
{ label: 'Groups', icon: IconUsersGroup, path: '/settings/groups' },
|
{ label: "Groups", icon: IconUsersGroup, path: "/settings/groups" },
|
||||||
{ label: 'Spaces', icon: IconSpaces, path: '/settings/spaces' },
|
{ label: "Spaces", icon: IconSpaces, path: "/settings/spaces" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -96,6 +96,7 @@ export default function SettingsSidebar() {
|
|||||||
<div className={classes.version}>
|
<div className={classes.version}>
|
||||||
<Text
|
<Text
|
||||||
className={classes.version}
|
className={classes.version}
|
||||||
|
size="sm"
|
||||||
c="dimmed"
|
c="dimmed"
|
||||||
component="a"
|
component="a"
|
||||||
href="https://github.com/docmost/docmost/releases"
|
href="https://github.com/docmost/docmost/releases"
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from 'react';
|
||||||
import data from "@emoji-mart/data";
|
|
||||||
import Picker from "@emoji-mart/react";
|
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
Popover,
|
Popover,
|
||||||
Button,
|
Button,
|
||||||
useMantineColorScheme,
|
useMantineColorScheme,
|
||||||
} from "@mantine/core";
|
} from '@mantine/core';
|
||||||
import { useDisclosure } from "@mantine/hooks";
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
|
const Picker = React.lazy(() => import('@emoji-mart/react'));
|
||||||
|
|
||||||
export interface EmojiPickerInterface {
|
export interface EmojiPickerInterface {
|
||||||
onEmojiSelect: (emoji: any) => void;
|
onEmojiSelect: (emoji: any) => void;
|
||||||
@ -48,23 +49,25 @@ function EmojiPicker({
|
|||||||
{icon}
|
{icon}
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown bg="000" style={{ border: "none" }}>
|
<Popover.Dropdown bg="000" style={{ border: 'none' }}>
|
||||||
|
<Suspense fallback={null}>
|
||||||
<Picker
|
<Picker
|
||||||
data={data}
|
data={async () => (await import('@emoji-mart/data')).default}
|
||||||
onEmojiSelect={handleEmojiSelect}
|
onEmojiSelect={handleEmojiSelect}
|
||||||
perLine={8}
|
perLine={8}
|
||||||
skinTonePosition="search"
|
skinTonePosition="search"
|
||||||
theme={colorScheme}
|
theme={colorScheme}
|
||||||
/>
|
/>
|
||||||
|
</Suspense>
|
||||||
<Button
|
<Button
|
||||||
variant="default"
|
variant="default"
|
||||||
c="gray"
|
c="gray"
|
||||||
size="xs"
|
size="xs"
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
bottom: "1rem",
|
bottom: '1rem',
|
||||||
right: "1rem",
|
right: '1rem',
|
||||||
}}
|
}}
|
||||||
onClick={handleRemoveEmoji}
|
onClick={handleRemoveEmoji}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,15 +1,21 @@
|
|||||||
import { NodeViewContent, NodeViewProps, NodeViewWrapper } from "@tiptap/react";
|
import { NodeViewContent, NodeViewProps, NodeViewWrapper } from '@tiptap/react';
|
||||||
import { ActionIcon, CopyButton, Group, Select, Tooltip } from "@mantine/core";
|
import { ActionIcon, CopyButton, Group, Select, Tooltip } from '@mantine/core';
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from 'react';
|
||||||
import { IconCheck, IconCopy } from "@tabler/icons-react";
|
import { IconCheck, IconCopy } from '@tabler/icons-react';
|
||||||
import MermaidView from "@/features/editor/components/code-block/mermaid-view.tsx";
|
//import MermaidView from "@/features/editor/components/code-block/mermaid-view.tsx";
|
||||||
import classes from "./code-block.module.css";
|
import classes from './code-block.module.css';
|
||||||
|
import React from 'react';
|
||||||
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
|
const MermaidView = React.lazy(
|
||||||
|
() => import('@/features/editor/components/code-block/mermaid-view.tsx')
|
||||||
|
);
|
||||||
|
|
||||||
export default function CodeBlockView(props: NodeViewProps) {
|
export default function CodeBlockView(props: NodeViewProps) {
|
||||||
const { node, updateAttributes, extension, editor, getPos } = props;
|
const { node, updateAttributes, extension, editor, getPos } = props;
|
||||||
const { language } = node.attrs;
|
const { language } = node.attrs;
|
||||||
const [languageValue, setLanguageValue] = useState<string | null>(
|
const [languageValue, setLanguageValue] = useState<string | null>(
|
||||||
language || null,
|
language || null
|
||||||
);
|
);
|
||||||
const [isSelected, setIsSelected] = useState(false);
|
const [isSelected, setIsSelected] = useState(false);
|
||||||
|
|
||||||
@ -24,9 +30,9 @@ export default function CodeBlockView(props: NodeViewProps) {
|
|||||||
setIsSelected(isNodeSelected);
|
setIsSelected(isNodeSelected);
|
||||||
};
|
};
|
||||||
|
|
||||||
editor.on("selectionUpdate", updateSelection);
|
editor.on('selectionUpdate', updateSelection);
|
||||||
return () => {
|
return () => {
|
||||||
editor.off("selectionUpdate", updateSelection);
|
editor.off('selectionUpdate', updateSelection);
|
||||||
};
|
};
|
||||||
}, [editor, getPos(), node.nodeSize]);
|
}, [editor, getPos(), node.nodeSize]);
|
||||||
|
|
||||||
@ -47,7 +53,7 @@ export default function CodeBlockView(props: NodeViewProps) {
|
|||||||
value={languageValue}
|
value={languageValue}
|
||||||
onChange={changeLanguage}
|
onChange={changeLanguage}
|
||||||
searchable
|
searchable
|
||||||
style={{ maxWidth: "130px" }}
|
style={{ maxWidth: '130px' }}
|
||||||
classNames={{ input: classes.selectInput }}
|
classNames={{ input: classes.selectInput }}
|
||||||
disabled={!editor.isEditable}
|
disabled={!editor.isEditable}
|
||||||
/>
|
/>
|
||||||
@ -55,12 +61,12 @@ export default function CodeBlockView(props: NodeViewProps) {
|
|||||||
<CopyButton value={node?.textContent} timeout={2000}>
|
<CopyButton value={node?.textContent} timeout={2000}>
|
||||||
{({ copied, copy }) => (
|
{({ copied, copy }) => (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
label={copied ? "Copied" : "Copy"}
|
label={copied ? 'Copied' : 'Copy'}
|
||||||
withArrow
|
withArrow
|
||||||
position="right"
|
position="right"
|
||||||
>
|
>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
color={copied ? "teal" : "gray"}
|
color={copied ? 'teal' : 'gray'}
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
onClick={copy}
|
onClick={copy}
|
||||||
>
|
>
|
||||||
@ -74,15 +80,19 @@ export default function CodeBlockView(props: NodeViewProps) {
|
|||||||
<pre
|
<pre
|
||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
hidden={
|
hidden={
|
||||||
((language === "mermaid" && !editor.isEditable) ||
|
((language === 'mermaid' && !editor.isEditable) ||
|
||||||
(language === "mermaid" && !isSelected)) &&
|
(language === 'mermaid' && !isSelected)) &&
|
||||||
node.textContent.length > 0
|
node.textContent.length > 0
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<NodeViewContent as="code" className={`language-${language}`} />
|
<NodeViewContent as="code" className={`language-${language}`} />
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
{language === "mermaid" && <MermaidView props={props} />}
|
{language === 'mermaid' && (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<MermaidView props={props} />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
</NodeViewWrapper>
|
</NodeViewWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import {
|
|||||||
useComputedColorScheme,
|
useComputedColorScheme,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Excalidraw, exportToSvg, loadFromBlob } from '@excalidraw/excalidraw';
|
|
||||||
import { uploadFile } from '@/features/page/services/page-service.ts';
|
import { uploadFile } from '@/features/page/services/page-service.ts';
|
||||||
import { svgStringToFile } from '@/lib';
|
import { svgStringToFile } from '@/lib';
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
@ -19,6 +18,14 @@ import { IAttachment } from '@/lib/types';
|
|||||||
import ReactClearModal from 'react-clear-modal';
|
import ReactClearModal from 'react-clear-modal';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { IconEdit } from '@tabler/icons-react';
|
import { IconEdit } from '@tabler/icons-react';
|
||||||
|
import { lazy } from 'react';
|
||||||
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
|
const Excalidraw = lazy(() =>
|
||||||
|
import('@excalidraw/excalidraw').then((module) => ({
|
||||||
|
default: module.Excalidraw,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
export default function ExcalidrawView(props: NodeViewProps) {
|
export default function ExcalidrawView(props: NodeViewProps) {
|
||||||
const { node, updateAttributes, editor, selected } = props;
|
const { node, updateAttributes, editor, selected } = props;
|
||||||
@ -43,6 +50,8 @@ export default function ExcalidrawView(props: NodeViewProps) {
|
|||||||
cache: 'no-store',
|
cache: 'no-store',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { loadFromBlob } = await import('@excalidraw/excalidraw');
|
||||||
|
|
||||||
const data = await loadFromBlob(await request.blob(), null, null);
|
const data = await loadFromBlob(await request.blob(), null, null);
|
||||||
setExcalidrawData(data);
|
setExcalidrawData(data);
|
||||||
}
|
}
|
||||||
@ -58,6 +67,8 @@ export default function ExcalidrawView(props: NodeViewProps) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { exportToSvg } = await import('@excalidraw/excalidraw');
|
||||||
|
|
||||||
const svg = await exportToSvg({
|
const svg = await exportToSvg({
|
||||||
elements: excalidrawAPI?.getSceneElements(),
|
elements: excalidrawAPI?.getSceneElements(),
|
||||||
appState: {
|
appState: {
|
||||||
@ -129,6 +140,7 @@ export default function ExcalidrawView(props: NodeViewProps) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
<div style={{ height: '90vh' }}>
|
<div style={{ height: '90vh' }}>
|
||||||
|
<Suspense fallback={null}>
|
||||||
<Excalidraw
|
<Excalidraw
|
||||||
excalidrawAPI={(api) => setExcalidrawAPI(api)}
|
excalidrawAPI={(api) => setExcalidrawAPI(api)}
|
||||||
initialData={{
|
initialData={{
|
||||||
@ -136,6 +148,7 @@ export default function ExcalidrawView(props: NodeViewProps) {
|
|||||||
scrollToContent: true,
|
scrollToContent: true,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
</ReactClearModal>
|
</ReactClearModal>
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import {
|
|||||||
IconH2,
|
IconH2,
|
||||||
IconH3,
|
IconH3,
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
IconLetterY,
|
|
||||||
IconList,
|
IconList,
|
||||||
IconListNumbers,
|
IconListNumbers,
|
||||||
IconListTree,
|
IconListTree,
|
||||||
@ -18,6 +17,7 @@ import {
|
|||||||
IconPhoto,
|
IconPhoto,
|
||||||
IconTable,
|
IconTable,
|
||||||
IconTypography,
|
IconTypography,
|
||||||
|
IconMenu4
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
import {
|
import {
|
||||||
CommandProps,
|
CommandProps,
|
||||||
@ -139,12 +139,20 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Code",
|
title: "Code",
|
||||||
description: "Capture a code snippet.",
|
description: "Insert code snippet.",
|
||||||
searchTerms: ["codeblock"],
|
searchTerms: ["codeblock"],
|
||||||
icon: IconCode,
|
icon: IconCode,
|
||||||
command: ({ editor, range }: CommandProps) =>
|
command: ({ editor, range }: CommandProps) =>
|
||||||
editor.chain().focus().deleteRange(range).toggleCodeBlock().run(),
|
editor.chain().focus().deleteRange(range).toggleCodeBlock().run(),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Divider",
|
||||||
|
description: "Insert horizontal rule divider",
|
||||||
|
searchTerms: ["horizontal rule", "hr"],
|
||||||
|
icon: IconMenu4,
|
||||||
|
command: ({ editor, range }: CommandProps) =>
|
||||||
|
editor.chain().focus().deleteRange(range).setHorizontalRule().run(),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "Image",
|
title: "Image",
|
||||||
description: "Upload any image from your device.",
|
description: "Upload any image from your device.",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.2.10",
|
"version": "0.3.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"author": "",
|
"author": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
@ -28,40 +28,38 @@
|
|||||||
"test:e2e": "jest --config test/jest-e2e.json"
|
"test:e2e": "jest --config test/jest-e2e.json"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.600.0",
|
"@aws-sdk/client-s3": "^3.637.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.600.0",
|
"@aws-sdk/s3-request-presigner": "^3.637.0",
|
||||||
"@casl/ability": "^6.7.1",
|
"@casl/ability": "^6.7.1",
|
||||||
"@fastify/cookie": "^9.3.1",
|
"@fastify/cookie": "^9.4.0",
|
||||||
"@fastify/multipart": "^8.3.0",
|
"@fastify/multipart": "^8.3.0",
|
||||||
"@fastify/static": "^7.0.4",
|
"@fastify/static": "^7.0.4",
|
||||||
"@nestjs/bullmq": "^10.1.1",
|
"@nestjs/bullmq": "^10.2.1",
|
||||||
"@nestjs/common": "^10.3.9",
|
"@nestjs/common": "^10.4.1",
|
||||||
"@nestjs/config": "^3.2.2",
|
"@nestjs/config": "^3.2.3",
|
||||||
"@nestjs/core": "^10.3.9",
|
"@nestjs/core": "^10.4.1",
|
||||||
"@nestjs/event-emitter": "^2.0.4",
|
"@nestjs/event-emitter": "^2.0.4",
|
||||||
"@nestjs/jwt": "^10.2.0",
|
"@nestjs/jwt": "^10.2.0",
|
||||||
"@nestjs/mapped-types": "^2.0.5",
|
"@nestjs/mapped-types": "^2.0.5",
|
||||||
"@nestjs/passport": "^10.0.3",
|
"@nestjs/passport": "^10.0.3",
|
||||||
"@nestjs/platform-fastify": "^10.3.9",
|
"@nestjs/platform-fastify": "^10.4.1",
|
||||||
"@nestjs/platform-socket.io": "^10.3.9",
|
"@nestjs/platform-socket.io": "^10.4.1",
|
||||||
"@nestjs/terminus": "^10.2.3",
|
"@nestjs/terminus": "^10.2.3",
|
||||||
"@nestjs/websockets": "^10.3.9",
|
"@nestjs/websockets": "^10.4.1",
|
||||||
"@react-email/components": "0.0.19",
|
"@react-email/components": "0.0.24",
|
||||||
"@react-email/render": "^0.0.15",
|
"@react-email/render": "^1.0.1",
|
||||||
"@socket.io/redis-adapter": "^8.3.0",
|
"@socket.io/redis-adapter": "^8.3.0",
|
||||||
"@types/pg": "^8.11.6",
|
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"bullmq": "^5.8.2",
|
"bullmq": "^5.12.12",
|
||||||
"bytes": "^3.1.2",
|
"bytes": "^3.1.2",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.1",
|
"class-validator": "^0.14.1",
|
||||||
"fastify": "^4.28.0",
|
|
||||||
"fix-esm": "^1.0.1",
|
"fix-esm": "^1.0.1",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"happy-dom": "^14.12.3",
|
"happy-dom": "^15.7.3",
|
||||||
"kysely": "^0.27.3",
|
"kysely": "^0.27.4",
|
||||||
"kysely-migration-cli": "^0.4.2",
|
"kysely-migration-cli": "^0.4.2",
|
||||||
"marked": "^13.0.2",
|
"marked": "^13.0.3",
|
||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
"nanoid": "^5.0.7",
|
"nanoid": "^5.0.7",
|
||||||
"nestjs-kysely": "^1.0.0",
|
"nestjs-kysely": "^1.0.0",
|
||||||
@ -69,46 +67,47 @@
|
|||||||
"passport-jwt": "^4.0.1",
|
"passport-jwt": "^4.0.1",
|
||||||
"pg": "^8.12.0",
|
"pg": "^8.12.0",
|
||||||
"pg-tsquery": "^8.4.2",
|
"pg-tsquery": "^8.4.2",
|
||||||
"postmark": "^4.0.4",
|
"postmark": "^4.0.5",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"redis": "^4.6.14",
|
"redis": "^4.7.0",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"sanitize-filename-ts": "^1.0.2",
|
"sanitize-filename-ts": "^1.0.2",
|
||||||
"socket.io": "^4.7.5",
|
"socket.io": "^4.7.5",
|
||||||
"ws": "^8.17.1"
|
"ws": "^8.18.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nestjs/cli": "^10.3.2",
|
"@nestjs/cli": "^10.4.5",
|
||||||
"@nestjs/schematics": "^10.1.1",
|
"@nestjs/schematics": "^10.1.4",
|
||||||
"@nestjs/testing": "^10.3.9",
|
"@nestjs/testing": "^10.4.1",
|
||||||
"@types/bcrypt": "^5.0.2",
|
"@types/bcrypt": "^5.0.2",
|
||||||
"@types/bytes": "^3.1.4",
|
"@types/bytes": "^3.1.4",
|
||||||
"@types/debounce": "^1.2.4",
|
"@types/debounce": "^1.2.4",
|
||||||
"@types/fs-extra": "^11.0.4",
|
"@types/fs-extra": "^11.0.4",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/mime-types": "^2.1.4",
|
"@types/mime-types": "^2.1.4",
|
||||||
"@types/node": "^20.14.9",
|
"@types/node": "^22.5.2",
|
||||||
"@types/nodemailer": "^6.4.15",
|
"@types/nodemailer": "^6.4.15",
|
||||||
"@types/passport-jwt": "^4.0.1",
|
"@types/passport-jwt": "^4.0.1",
|
||||||
|
"@types/pg": "^8.11.8",
|
||||||
"@types/supertest": "^6.0.2",
|
"@types/supertest": "^6.0.2",
|
||||||
"@types/ws": "^8.5.10",
|
"@types/ws": "^8.5.12",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.14.1",
|
"@typescript-eslint/eslint-plugin": "^8.3.0",
|
||||||
"@typescript-eslint/parser": "^7.14.1",
|
"@typescript-eslint/parser": "^8.3.0",
|
||||||
"eslint": "^9.5.0",
|
"eslint": "^9.9.1",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"kysely-codegen": "^0.15.0",
|
"kysely-codegen": "^0.16.3",
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.3.3",
|
||||||
"react-email": "^2.1.4",
|
"react-email": "^3.0.1",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"supertest": "^7.0.0",
|
"supertest": "^7.0.0",
|
||||||
"ts-jest": "^29.1.5",
|
"ts-jest": "^29.2.5",
|
||||||
"ts-loader": "^9.5.1",
|
"ts-loader": "^9.5.1",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"tsconfig-paths": "^4.2.0",
|
"tsconfig-paths": "^4.2.0",
|
||||||
"typescript": "^5.5.2"
|
"typescript": "^5.5.4"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"moduleFileExtensions": [
|
"moduleFileExtensions": [
|
||||||
|
|||||||
@ -10,10 +10,7 @@ export function generateJSON(
|
|||||||
const schema = getSchema(extensions);
|
const schema = getSchema(extensions);
|
||||||
|
|
||||||
const window = new Window();
|
const window = new Window();
|
||||||
const dom = new HappyDomParser(window).parseFromString(
|
const dom = new HappyDomParser().parseFromString(html, 'text/html').body;
|
||||||
html,
|
|
||||||
'text/html',
|
|
||||||
).body;
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return DOMParser.fromSchema(schema).parse(dom, options).toJSON();
|
return DOMParser.fromSchema(schema).parse(dom, options).toJSON();
|
||||||
|
|||||||
@ -5,10 +5,10 @@ export enum AttachmentType {
|
|||||||
File = 'file',
|
File = 'file',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const validImageExtensions = ['.jpg', '.png', '.jpeg', 'gif'];
|
export const validImageExtensions = ['.jpg', '.png', '.jpeg'];
|
||||||
export const MAX_AVATAR_SIZE = '5MB';
|
export const MAX_AVATAR_SIZE = '5MB';
|
||||||
|
|
||||||
export const InlineFileExtensions = [
|
export const inlineFileExtensions = [
|
||||||
'.jpg',
|
'.jpg',
|
||||||
'.png',
|
'.png',
|
||||||
'.jpeg',
|
'.jpeg',
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import {
|
|||||||
import { getMimeType } from '../../common/helpers';
|
import { getMimeType } from '../../common/helpers';
|
||||||
import {
|
import {
|
||||||
AttachmentType,
|
AttachmentType,
|
||||||
|
inlineFileExtensions,
|
||||||
MAX_AVATAR_SIZE,
|
MAX_AVATAR_SIZE,
|
||||||
MAX_FILE_SIZE,
|
MAX_FILE_SIZE,
|
||||||
} from './attachment.constants';
|
} from './attachment.constants';
|
||||||
@ -177,6 +178,14 @@ export class AttachmentController {
|
|||||||
'Content-Type': attachment.mimeType,
|
'Content-Type': attachment.mimeType,
|
||||||
'Cache-Control': 'public, max-age=3600',
|
'Cache-Control': 'public, max-age=3600',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!inlineFileExtensions.includes(attachment.fileExt)) {
|
||||||
|
res.header(
|
||||||
|
'Content-Disposition',
|
||||||
|
`attachment; filename="${attachment.fileName}"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return res.send(fileStream);
|
return res.send(fileStream);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.error(err);
|
this.logger.error(err);
|
||||||
|
|||||||
@ -19,8 +19,8 @@ export class MailService {
|
|||||||
async sendEmail(message: MailMessage): Promise<void> {
|
async sendEmail(message: MailMessage): Promise<void> {
|
||||||
if (message.template) {
|
if (message.template) {
|
||||||
// in case this method is used directly. we do not send the tsx template from queue
|
// in case this method is used directly. we do not send the tsx template from queue
|
||||||
message.html = render(message.template, { pretty: true });
|
message.html = await render(message.template, { pretty: true });
|
||||||
message.text = render(message.template, { plainText: true });
|
message.text = await render(message.template, { plainText: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const sender = `${this.environmentService.getMailFromName()} <${this.environmentService.getMailFromAddress()}> `;
|
const sender = `${this.environmentService.getMailFromName()} <${this.environmentService.getMailFromAddress()}> `;
|
||||||
@ -30,8 +30,8 @@ export class MailService {
|
|||||||
async sendToQueue(message: MailMessage): Promise<void> {
|
async sendToQueue(message: MailMessage): Promise<void> {
|
||||||
if (message.template) {
|
if (message.template) {
|
||||||
// transform the React object because it gets lost when sent via the queue
|
// transform the React object because it gets lost when sent via the queue
|
||||||
message.html = render(message.template, { pretty: true });
|
message.html = await render(message.template, { pretty: true });
|
||||||
message.text = render(message.template, {
|
message.text = await render(message.template, {
|
||||||
plainText: true,
|
plainText: true,
|
||||||
});
|
});
|
||||||
delete message.template;
|
delete message.template;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "docmost",
|
"name": "docmost",
|
||||||
"homepage": "https://docmost.com",
|
"homepage": "https://docmost.com",
|
||||||
"version": "0.2.10",
|
"version": "0.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "nx run-many -t build",
|
"build": "nx run-many -t build",
|
||||||
|
|||||||
4812
pnpm-lock.yaml
generated
4812
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user