mirror of
https://github.com/makeplane/plane.git
synced 2026-05-11 19:39:31 -05:00
feat: support .md and .mdx file uploads
Plain-text files have no magic bytes, so the file-type signature detector returned an empty MIME type and the backend rejected them. Add an extension-based fallback for markdown/mdx, allow text/mdx in the API and editor allow-lists, and pick a file icon for these extensions.
This commit is contained in:
@@ -402,6 +402,7 @@ ATTACHMENT_MIME_TYPES = [
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
"text/plain",
|
||||
"text/markdown",
|
||||
"text/mdx",
|
||||
"application/rtf",
|
||||
"application/vnd.oasis.opendocument.spreadsheet",
|
||||
"application/vnd.oasis.opendocument.text",
|
||||
@@ -469,8 +470,6 @@ ATTACHMENT_MIME_TYPES = [
|
||||
"application/x-sql",
|
||||
# Gzip
|
||||
"application/x-gzip",
|
||||
# Markdown
|
||||
"text/markdown",
|
||||
]
|
||||
|
||||
# Seed directory path
|
||||
|
||||
@@ -47,6 +47,9 @@ export const getFileIcon = (fileType: string, size: number = 28) => {
|
||||
case "js":
|
||||
return <JavaScriptIcon height={size} width={size} />;
|
||||
case "txt":
|
||||
case "md":
|
||||
case "markdown":
|
||||
case "mdx":
|
||||
return <TxtIcon height={size} width={size} />;
|
||||
case "svg":
|
||||
return <SvgIcon height={size} width={size} />;
|
||||
|
||||
@@ -33,6 +33,7 @@ export const ACCEPTED_ATTACHMENT_MIME_TYPES = [
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
"text/plain",
|
||||
"text/markdown",
|
||||
"text/mdx",
|
||||
"application/rtf",
|
||||
"audio/mpeg",
|
||||
"audio/wav",
|
||||
|
||||
@@ -10,6 +10,28 @@ import { fileTypeFromBuffer } from "file-type";
|
||||
import type { TFileMetaDataLite, TFileSignedURLResponse } from "@plane/types";
|
||||
import { DANGEROUS_EXTENSIONS } from "@plane/constants";
|
||||
|
||||
/**
|
||||
* @description Map of file extensions to MIME types for plain-text formats that
|
||||
* file-type signature detection cannot identify (no magic bytes).
|
||||
*/
|
||||
const EXTENSION_MIME_TYPE_MAP: Record<string, string> = {
|
||||
md: "text/markdown",
|
||||
markdown: "text/markdown",
|
||||
mdx: "text/mdx",
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Resolve a MIME type from the file extension for known text formats.
|
||||
* @param {string} filename
|
||||
* @returns {string} MIME type if extension is known, empty string otherwise
|
||||
*/
|
||||
const detectMimeTypeFromExtension = (filename: string): string => {
|
||||
const parts = filename.split(".");
|
||||
if (parts.length < 2) return "";
|
||||
const extension = parts[parts.length - 1]?.toLowerCase() || "";
|
||||
return EXTENSION_MIME_TYPE_MAP[extension] || "";
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Filename validation - checks for double extensions and dangerous patterns
|
||||
* @param {string} filename
|
||||
@@ -103,6 +125,12 @@ const validateAndDetectFileType = async (file: File): Promise<string> => {
|
||||
console.warn("Error detecting file type from signature:", _error);
|
||||
}
|
||||
|
||||
// Plain-text formats (markdown, mdx, …) have no magic bytes — fall back to extension.
|
||||
const extensionType = detectMimeTypeFromExtension(file.name);
|
||||
if (extensionType) {
|
||||
return extensionType;
|
||||
}
|
||||
|
||||
// fallback for unknown files
|
||||
return "";
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user