@addsign/moje-agenda-shared-lib 2.0.60 → 2.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/datatable/DataTableServer.js +93 -54
- package/dist/components/datatable/DataTableServer.js.map +1 -1
- package/dist/components/form/FileInput.d.ts +1 -0
- package/dist/components/form/FileInput.js +13 -4
- package/dist/components/form/FileInput.js.map +1 -1
- package/dist/components/form/FileInputMultiple.d.ts +1 -0
- package/dist/components/form/FileInputMultiple.js +11 -3
- package/dist/components/form/FileInputMultiple.js.map +1 -1
- package/lib/components/datatable/DataTableServer.tsx +124 -66
- package/lib/components/form/FileInput.tsx +15 -2
- package/lib/components/form/FileInputMultiple.tsx +13 -1
- package/package.json +1 -1
|
@@ -35,7 +35,8 @@ const FileInput = ({
|
|
|
35
35
|
description,
|
|
36
36
|
disabled,
|
|
37
37
|
errors = {},
|
|
38
|
-
attachmentName
|
|
38
|
+
attachmentName,
|
|
39
|
+
attachmentType
|
|
39
40
|
}) => {
|
|
40
41
|
var _a, _b, _c, _d;
|
|
41
42
|
const [fileData, setFileData] = useState(
|
|
@@ -63,6 +64,14 @@ const FileInput = ({
|
|
|
63
64
|
return;
|
|
64
65
|
}
|
|
65
66
|
const formData = new FormData();
|
|
67
|
+
const dataObject = {
|
|
68
|
+
...attachmentName && { attachmentName },
|
|
69
|
+
...attachmentType && { attachmentType }
|
|
70
|
+
};
|
|
71
|
+
formData.append(
|
|
72
|
+
"data",
|
|
73
|
+
new Blob([JSON.stringify(dataObject)], { type: "application/json" })
|
|
74
|
+
);
|
|
66
75
|
formData.append("file", file);
|
|
67
76
|
try {
|
|
68
77
|
const response = await federationContext.apiClient.post(
|
|
@@ -71,8 +80,7 @@ const FileInput = ({
|
|
|
71
80
|
{
|
|
72
81
|
headers: {
|
|
73
82
|
"Content-Type": "multipart/form-data"
|
|
74
|
-
}
|
|
75
|
-
params: attachmentName ? { attachmentName } : void 0
|
|
83
|
+
}
|
|
76
84
|
}
|
|
77
85
|
);
|
|
78
86
|
setFileData(response.data);
|
|
@@ -91,7 +99,8 @@ const FileInput = ({
|
|
|
91
99
|
federationContext.emitter,
|
|
92
100
|
onFileChanged,
|
|
93
101
|
name,
|
|
94
|
-
attachmentName
|
|
102
|
+
attachmentName,
|
|
103
|
+
attachmentType
|
|
95
104
|
]
|
|
96
105
|
);
|
|
97
106
|
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileInput.js","sources":["../../../lib/components/form/FileInput.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback } from \"react\";\r\nimport { useDropzone } from \"react-dropzone\";\r\nimport { handleErrors, useFederationContext } from \"../../main\";\r\nimport { MdDeleteOutline, MdInsertDriveFile } from \"react-icons/md\";\r\nimport { AxiosError } from \"axios\";\r\n\r\nexport interface FileData {\r\n id: number;\r\n mimeType: string;\r\n size: number;\r\n filename: string;\r\n createdByEmpId: string;\r\n created: string;\r\n}\r\n\r\ninterface FileInputProps {\r\n name: string;\r\n label?: string;\r\n initialFile?: FileData;\r\n onFileChanged: (e: any) => void;\r\n required?: boolean;\r\n description?: string;\r\n disabled?: boolean;\r\n errors?: { [key: string]: { message: string } };\r\n attachmentName?: string;\r\n}\r\n\r\nconst MAX_FILE_SIZE = 1024 * 1024; // 1MB\r\n\r\nconst FileInput: React.FC<FileInputProps> = ({\r\n initialFile,\r\n onFileChanged,\r\n label,\r\n name,\r\n required,\r\n description,\r\n disabled,\r\n errors = {},\r\n attachmentName,\r\n}) => {\r\n const [fileData, setFileData] = useState<FileData | null>(\r\n initialFile || null\r\n );\r\n const [isFocused, setIsFocused] = useState(false);\r\n\r\n const federationContext = useFederationContext();\r\n useEffect(() => {\r\n if (initialFile) {\r\n setFileData(initialFile);\r\n }\r\n }, [initialFile]);\r\n\r\n const onDrop = useCallback(\r\n async (acceptedFiles: File[]) => {\r\n if (acceptedFiles.length > 0) {\r\n const file = acceptedFiles[0];\r\n\r\n if (file.size > MAX_FILE_SIZE) {\r\n // Handle the case when the file size is exceeded\r\n federationContext.emitter.emit(\"message\", {\r\n title: \"Velikost souboru byla překročena\",\r\n message: `Maximální povolená velikost je ${MAX_FILE_SIZE / (1024 * 1024)} MB.`,\r\n classes: \"bg-danger \",\r\n timeout: 0,\r\n type: \"error\",\r\n });\r\n return;\r\n }\r\n\r\n const formData = new FormData();\r\n formData.append(\"file\", file);\r\n\r\n try {\r\n const response = await federationContext.apiClient.post<FileData>(\r\n \"/files/upload\",\r\n formData,\r\n {\r\n headers: {\r\n \"Content-Type\": \"multipart/form-data\",\r\n },\r\n params: attachmentName ? { attachmentName } : undefined,\r\n }\r\n );\r\n setFileData(response.data);\r\n onFileChanged({\r\n target: { name, value: response.data.id.toString() },\r\n });\r\n setIsFocused(false);\r\n } catch (error) {\r\n handleErrors(error as AxiosError, federationContext.emitter);\r\n console.error(\"There was an error!\", error);\r\n }\r\n }\r\n },\r\n [\r\n federationContext.apiClient,\r\n federationContext.emitter,\r\n onFileChanged,\r\n name,\r\n attachmentName,\r\n ]\r\n );\r\n\r\n const { getRootProps, getInputProps, isDragActive } = useDropzone({\r\n onDrop,\r\n disabled,\r\n multiple: false,\r\n });\r\n\r\n const handleRemove = () => {\r\n setFileData(null);\r\n onFileChanged({ target: { name, value: null } });\r\n };\r\n\r\n return (\r\n <div className=\"w-full min-h-30 flex-col justify-start items-start gap-1.5 inline-flex sharedLibrary\">\r\n <div className=\"self-stretch flex-col justify-start items-start gap-1.5 flex\">\r\n {label && (\r\n <label\r\n className=\"text-slate-700 text-sm leading-tight font-medium\"\r\n htmlFor={name}\r\n >\r\n {label} {required ? \"*\" : \"\"}\r\n </label>\r\n )}\r\n <div\r\n className={\r\n `self-stretch px-2 py-2 rounded-lg justify-start items-center gap-2 inline-flex outline-none border` +\r\n ` ${\r\n isFocused && !errors[name]?.message\r\n ? \"outline-4 outline-indigo-200 outline-offset-0 border-indigo-300\"\r\n : \"\"\r\n }` +\r\n ` ${\r\n isFocused && errors[name]?.message\r\n ? \"outline-4 outline-red-200 outline-offset-0 border-none\"\r\n : \"\"\r\n } ` +\r\n ` ${!isFocused && errors[name]?.message ? \"border-red-200\" : \"\"} ` +\r\n ` ${disabled ? \"bg-gray-100\" : \"bg-transparent\"}`\r\n }\r\n onFocus={() => setIsFocused(true)}\r\n onBlur={() => setIsFocused(false)}\r\n >\r\n <div className=\"flex relative grow shrink basis-0 min-h-5 lg:min-h-[32px] justify-start items-stretch gap-2 max-w-full \">\r\n {!fileData ? (\r\n <div\r\n {...getRootProps()}\r\n className={`w-full p-4 border-dashed border-2 rounded-lg text-center ${\r\n isDragActive\r\n ? \"border-indigo-300 bg-indigo-50\"\r\n : \"border-gray-300\"\r\n }`}\r\n >\r\n <input {...getInputProps()} id={name} />\r\n <p className=\"text-gray-500\">\r\n {isDragActive\r\n ? \"Sem přetáhněte soubor\"\r\n : \"Klikněte pro nahrání, nebo nahrajte přetažením souboru\"}\r\n </p>\r\n </div>\r\n ) : (\r\n <div className=\"w-full flex items-center justify-between\">\r\n <div className=\" flex\">\r\n <MdInsertDriveFile style={{ fontSize: \"2rem\" }} />\r\n <a\r\n href={`/api/files/download/${fileData.id}`}\r\n className=\"pl-2 text-left underline text-primary\"\r\n target=\"_blank\"\r\n >\r\n {fileData.filename}\r\n </a>\r\n </div>\r\n {!disabled && (\r\n <div\r\n onClick={handleRemove}\r\n className=\"text-gray-600 cursor-pointer hover:text-primary hover:bg-gray-200 rounded-full ml-4\"\r\n >\r\n <MdDeleteOutline\r\n style={{ fontSize: \"1.5rem\", margin: \"15px\" }}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n {description && (\r\n <div\r\n className=\"HintText self-stretch text-slate-600 text-sm font-normal leading-tight\"\r\n id={name + \":description\"}\r\n >\r\n {description}\r\n </div>\r\n )}\r\n {errors[name] && (\r\n <div\r\n className=\"HintText self-stretch text-red-600 text-sm font-normal leading-tight\"\r\n id={name + \":error\"}\r\n >\r\n {errors[name]?.message}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nexport default FileInput;\r\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileInput.js","sources":["../../../lib/components/form/FileInput.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback } from \"react\";\r\nimport { useDropzone } from \"react-dropzone\";\r\nimport { handleErrors, useFederationContext } from \"../../main\";\r\nimport { MdDeleteOutline, MdInsertDriveFile } from \"react-icons/md\";\r\nimport { AxiosError } from \"axios\";\r\n\r\nexport interface FileData {\r\n id: number;\r\n mimeType: string;\r\n size: number;\r\n filename: string;\r\n createdByEmpId: string;\r\n created: string;\r\n}\r\n\r\ninterface FileInputProps {\r\n name: string;\r\n label?: string;\r\n initialFile?: FileData;\r\n onFileChanged: (e: any) => void;\r\n required?: boolean;\r\n description?: string;\r\n disabled?: boolean;\r\n errors?: { [key: string]: { message: string } };\r\n attachmentName?: string;\r\n attachmentType?: string;\r\n}\r\n\r\nconst MAX_FILE_SIZE = 1024 * 1024; // 1MB\r\n\r\nconst FileInput: React.FC<FileInputProps> = ({\r\n initialFile,\r\n onFileChanged,\r\n label,\r\n name,\r\n required,\r\n description,\r\n disabled,\r\n errors = {},\r\n attachmentName,\r\n attachmentType,\r\n}) => {\r\n const [fileData, setFileData] = useState<FileData | null>(\r\n initialFile || null\r\n );\r\n const [isFocused, setIsFocused] = useState(false);\r\n\r\n const federationContext = useFederationContext();\r\n useEffect(() => {\r\n if (initialFile) {\r\n setFileData(initialFile);\r\n }\r\n }, [initialFile]);\r\n\r\n const onDrop = useCallback(\r\n async (acceptedFiles: File[]) => {\r\n if (acceptedFiles.length > 0) {\r\n const file = acceptedFiles[0];\r\n\r\n if (file.size > MAX_FILE_SIZE) {\r\n // Handle the case when the file size is exceeded\r\n federationContext.emitter.emit(\"message\", {\r\n title: \"Velikost souboru byla překročena\",\r\n message: `Maximální povolená velikost je ${MAX_FILE_SIZE / (1024 * 1024)} MB.`,\r\n classes: \"bg-danger \",\r\n timeout: 0,\r\n type: \"error\",\r\n });\r\n return;\r\n }\r\n\r\n const formData = new FormData();\r\n\r\n // Add the JSON data object\r\n const dataObject = {\r\n ...(attachmentName && { attachmentName }),\r\n ...(attachmentType && { attachmentType }),\r\n };\r\n\r\n formData.append(\r\n \"data\",\r\n new Blob([JSON.stringify(dataObject)], { type: \"application/json\" })\r\n );\r\n formData.append(\"file\", file);\r\n\r\n try {\r\n const response = await federationContext.apiClient.post<FileData>(\r\n \"/files/upload\",\r\n formData,\r\n {\r\n headers: {\r\n \"Content-Type\": \"multipart/form-data\",\r\n },\r\n }\r\n );\r\n setFileData(response.data);\r\n onFileChanged({\r\n target: { name, value: response.data.id.toString() },\r\n });\r\n setIsFocused(false);\r\n } catch (error) {\r\n handleErrors(error as AxiosError, federationContext.emitter);\r\n console.error(\"There was an error!\", error);\r\n }\r\n }\r\n },\r\n [\r\n federationContext.apiClient,\r\n federationContext.emitter,\r\n onFileChanged,\r\n name,\r\n attachmentName,\r\n attachmentType,\r\n ]\r\n );\r\n\r\n const { getRootProps, getInputProps, isDragActive } = useDropzone({\r\n onDrop,\r\n disabled,\r\n multiple: false,\r\n });\r\n\r\n const handleRemove = () => {\r\n setFileData(null);\r\n onFileChanged({ target: { name, value: null } });\r\n };\r\n\r\n return (\r\n <div className=\"w-full min-h-30 flex-col justify-start items-start gap-1.5 inline-flex sharedLibrary\">\r\n <div className=\"self-stretch flex-col justify-start items-start gap-1.5 flex\">\r\n {label && (\r\n <label\r\n className=\"text-slate-700 text-sm leading-tight font-medium\"\r\n htmlFor={name}\r\n >\r\n {label} {required ? \"*\" : \"\"}\r\n </label>\r\n )}\r\n <div\r\n className={\r\n `self-stretch px-2 py-2 rounded-lg justify-start items-center gap-2 inline-flex outline-none border` +\r\n ` ${\r\n isFocused && !errors[name]?.message\r\n ? \"outline-4 outline-indigo-200 outline-offset-0 border-indigo-300\"\r\n : \"\"\r\n }` +\r\n ` ${\r\n isFocused && errors[name]?.message\r\n ? \"outline-4 outline-red-200 outline-offset-0 border-none\"\r\n : \"\"\r\n } ` +\r\n ` ${!isFocused && errors[name]?.message ? \"border-red-200\" : \"\"} ` +\r\n ` ${disabled ? \"bg-gray-100\" : \"bg-transparent\"}`\r\n }\r\n onFocus={() => setIsFocused(true)}\r\n onBlur={() => setIsFocused(false)}\r\n >\r\n <div className=\"flex relative grow shrink basis-0 min-h-5 lg:min-h-[32px] justify-start items-stretch gap-2 max-w-full \">\r\n {!fileData ? (\r\n <div\r\n {...getRootProps()}\r\n className={`w-full p-4 border-dashed border-2 rounded-lg text-center ${\r\n isDragActive\r\n ? \"border-indigo-300 bg-indigo-50\"\r\n : \"border-gray-300\"\r\n }`}\r\n >\r\n <input {...getInputProps()} id={name} />\r\n <p className=\"text-gray-500\">\r\n {isDragActive\r\n ? \"Sem přetáhněte soubor\"\r\n : \"Klikněte pro nahrání, nebo nahrajte přetažením souboru\"}\r\n </p>\r\n </div>\r\n ) : (\r\n <div className=\"w-full flex items-center justify-between\">\r\n <div className=\" flex\">\r\n <MdInsertDriveFile style={{ fontSize: \"2rem\" }} />\r\n <a\r\n href={`/api/files/download/${fileData.id}`}\r\n className=\"pl-2 text-left underline text-primary\"\r\n target=\"_blank\"\r\n >\r\n {fileData.filename}\r\n </a>\r\n </div>\r\n {!disabled && (\r\n <div\r\n onClick={handleRemove}\r\n className=\"text-gray-600 cursor-pointer hover:text-primary hover:bg-gray-200 rounded-full ml-4\"\r\n >\r\n <MdDeleteOutline\r\n style={{ fontSize: \"1.5rem\", margin: \"15px\" }}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n {description && (\r\n <div\r\n className=\"HintText self-stretch text-slate-600 text-sm font-normal leading-tight\"\r\n id={name + \":description\"}\r\n >\r\n {description}\r\n </div>\r\n )}\r\n {errors[name] && (\r\n <div\r\n className=\"HintText self-stretch text-red-600 text-sm font-normal leading-tight\"\r\n id={name + \":error\"}\r\n >\r\n {errors[name]?.message}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nexport default FileInput;\r\n"],"names":[],"mappings":"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"}
|
|
@@ -36,7 +36,8 @@ const FileInputMultiple = ({
|
|
|
36
36
|
disabled,
|
|
37
37
|
errors = {},
|
|
38
38
|
initialFilesReadOnly = true,
|
|
39
|
-
attachmentName
|
|
39
|
+
attachmentName,
|
|
40
|
+
attachmentType
|
|
40
41
|
}) => {
|
|
41
42
|
var _a, _b;
|
|
42
43
|
const [fileDataList, setFileDataList] = useState(
|
|
@@ -76,6 +77,14 @@ const FileInputMultiple = ({
|
|
|
76
77
|
return null;
|
|
77
78
|
}
|
|
78
79
|
const formData = new FormData();
|
|
80
|
+
const dataObject = {
|
|
81
|
+
...attachmentName && { attachmentName },
|
|
82
|
+
...attachmentType && { attachmentType }
|
|
83
|
+
};
|
|
84
|
+
formData.append(
|
|
85
|
+
"data",
|
|
86
|
+
new Blob([JSON.stringify(dataObject)], { type: "application/json" })
|
|
87
|
+
);
|
|
79
88
|
formData.append("file", file);
|
|
80
89
|
try {
|
|
81
90
|
const response = await federationContext.apiClient.post(
|
|
@@ -84,8 +93,7 @@ const FileInputMultiple = ({
|
|
|
84
93
|
{
|
|
85
94
|
headers: {
|
|
86
95
|
"Content-Type": "multipart/form-data"
|
|
87
|
-
}
|
|
88
|
-
params: attachmentName ? { attachmentName } : void 0
|
|
96
|
+
}
|
|
89
97
|
}
|
|
90
98
|
);
|
|
91
99
|
return response.data;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileInputMultiple.js","sources":["../../../lib/components/form/FileInputMultiple.tsx"],"sourcesContent":["import React, { useState, useCallback, useEffect } from \"react\";\r\nimport { useDropzone } from \"react-dropzone\";\r\nimport { MdDeleteOutline, MdInsertDriveFile } from \"react-icons/md\";\r\nimport { IAttachment } from \"../../types\";\r\nimport { handleErrors, useFederationContext } from \"../../main\";\r\nimport { AxiosError } from \"axios\";\r\n\r\ninterface FileInputMultipleProps {\r\n name: string;\r\n label?: string;\r\n initialFiles?: IAttachment[];\r\n onFilesChanged: (e: any) => void;\r\n required?: boolean;\r\n description?: string;\r\n disabled?: boolean;\r\n errors?: { [key: string]: { message: string } };\r\n initialFilesReadOnly?: boolean;\r\n attachmentName?: string;\r\n}\r\n\r\ninterface IAttachmentReadOnly extends IAttachment {\r\n readonly?: boolean;\r\n}\r\n\r\nconst MAX_FILE_SIZE = 1024 * 1024; // 1MB\r\n\r\nconst FileInputMultiple: React.FC<FileInputMultipleProps> = ({\r\n initialFiles,\r\n onFilesChanged,\r\n label,\r\n name,\r\n required,\r\n description,\r\n disabled,\r\n errors = {},\r\n initialFilesReadOnly = true,\r\n attachmentName,\r\n}) => {\r\n const [fileDataList, setFileDataList] = useState<IAttachmentReadOnly[]>(\r\n initialFiles\r\n ? [...initialFiles].map((file) => ({\r\n ...file,\r\n readonly: initialFilesReadOnly,\r\n }))\r\n : []\r\n );\r\n const federationContext = useFederationContext();\r\n\r\n useEffect(() => {\r\n console.log(\r\n \"%clibcomponents\\formFileInputMultiple.tsx:40 initialFiles\",\r\n \"color: #007acc;\",\r\n initialFiles\r\n );\r\n if (!initialFiles || initialFiles.length === 0) return;\r\n setFileDataList(\r\n [...initialFiles].map((file) => ({\r\n ...file,\r\n readonly: initialFilesReadOnly,\r\n }))\r\n );\r\n }, [initialFiles, initialFilesReadOnly]);\r\n\r\n const onDrop = useCallback(\r\n async (acceptedFiles: File[]) => {\r\n const uploadedFiles = await Promise.all(\r\n acceptedFiles.map(async (file) => {\r\n if (file.size > MAX_FILE_SIZE) {\r\n // Handle the case when the file size is exceeded\r\n\r\n federationContext.emitter.emit(\"message\", {\r\n title: \"Velikost souboru byla překročena\",\r\n message: `Maximální povolená velikost je ${MAX_FILE_SIZE / (1024 * 1024)} MB.`,\r\n classes: \"bg-danger \",\r\n timeout: 0,\r\n type: \"error\",\r\n });\r\n\r\n return null;\r\n }\r\n\r\n const formData = new FormData();\r\n formData.append(\"file\", file);\r\n\r\n try {\r\n const response =\r\n await federationContext.apiClient.post<IAttachment>(\r\n \"/files/upload\",\r\n formData,\r\n {\r\n headers: {\r\n \"Content-Type\": \"multipart/form-data\",\r\n },\r\n params: attachmentName ? { attachmentName } : undefined,\r\n }\r\n );\r\n return response.data;\r\n } catch (error) {\r\n handleErrors(error as AxiosError, federationContext.emitter);\r\n console.error(\"There was an error!\", error);\r\n return null;\r\n }\r\n })\r\n );\r\n\r\n const validFiles = uploadedFiles.filter(\r\n (file) => file !== null\r\n ) as IAttachment[];\r\n const updatedFileDataList = [...fileDataList, ...validFiles];\r\n setFileDataList(updatedFileDataList);\r\n onFilesChanged({\r\n target: {\r\n name,\r\n value: updatedFileDataList.map((file) => file.id.toString()),\r\n },\r\n });\r\n },\r\n [federationContext, fileDataList, onFilesChanged, name, attachmentName]\r\n );\r\n\r\n const { getRootProps, getInputProps, isDragActive } = useDropzone({\r\n onDrop,\r\n disabled,\r\n });\r\n\r\n const handleRemove = (fileId: number) => {\r\n const updatedFileDataList = fileDataList.filter(\r\n (file) => file.id !== fileId\r\n );\r\n setFileDataList(updatedFileDataList);\r\n onFilesChanged({\r\n target: {\r\n name,\r\n value: updatedFileDataList.map((file) => file.id.toString()),\r\n },\r\n });\r\n };\r\n if (disabled === true && fileDataList.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <div className=\"w-full min-h-30 flex-col justify-start items-start gap-1.5 inline-flex sharedLibrary\">\r\n <div className=\"self-stretch flex-col justify-start items-start gap-1.5 flex\">\r\n {label && (\r\n <label\r\n className=\"text-slate-700 text-sm leading-tight font-medium\"\r\n htmlFor={name}\r\n >\r\n {label} {required ? \"*\" : \"\"}\r\n </label>\r\n )}\r\n <div\r\n className={\r\n `self-stretch px-3 py-2 rounded-lg justify-start items-center gap-2 outline-none border bg-transparent ` +\r\n ` ${errors[name]?.message ? \"border-red-200\" : \"border-gray-300\"} `\r\n }\r\n >\r\n {!disabled && (\r\n <div\r\n {...getRootProps()}\r\n className={`w-full p-4 border-dashed cursor-pointer \r\n border-2 rounded-lg text-center hover:bg-gray-100\r\n ${isDragActive ? \"border-indigo-300 bg-indigo-50\" : \"border-gray-300\"}`}\r\n >\r\n <input {...getInputProps()} id={name} />\r\n <p className=\"text-gray-500\">\r\n {isDragActive\r\n ? \"Sem přetáhněte soubory\"\r\n : \"Klikněte pro nahrání, nebo nahrajte přetažením souborů\"}\r\n </p>\r\n </div>\r\n )}\r\n <div className=\"w-full\">\r\n {fileDataList.map((file) => (\r\n <div\r\n key={file.id}\r\n className=\"w-full flex items-center justify-between py-2 border-b \"\r\n >\r\n <div className=\"flex items-center content-center\">\r\n <MdInsertDriveFile style={{ fontSize: \"2rem\" }} />\r\n <a\r\n href={`/api/files/download/${file.id}`}\r\n className=\"pl-2 text-left underline text-primary\"\r\n target=\"_blank\"\r\n >\r\n {file.filename}\r\n </a>\r\n </div>\r\n {!disabled && file.readonly !== true && (\r\n <div\r\n onClick={() => handleRemove(file.id)}\r\n className=\"text-gray-600 cursor-pointer hover:text-primary hover:bg-gray-200 rounded-full ml-4\"\r\n >\r\n <MdDeleteOutline\r\n style={{ fontSize: \"1.5rem\", margin: \"10px\" }}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n </div>\r\n {description && (\r\n <div\r\n className=\"HintText self-stretch text-slate-600 text-sm font-normal leading-tight\"\r\n id={name + \":description\"}\r\n >\r\n {description}\r\n </div>\r\n )}\r\n {errors[name] && (\r\n <div\r\n className=\"HintText self-stretch text-red-600 text-sm font-normal leading-tight\"\r\n id={name + \":error\"}\r\n >\r\n {errors[name]?.message}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nexport default FileInputMultiple;\r\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileInputMultiple.js","sources":["../../../lib/components/form/FileInputMultiple.tsx"],"sourcesContent":["import React, { useState, useCallback, useEffect } from \"react\";\r\nimport { useDropzone } from \"react-dropzone\";\r\nimport { MdDeleteOutline, MdInsertDriveFile } from \"react-icons/md\";\r\nimport { IAttachment } from \"../../types\";\r\nimport { handleErrors, useFederationContext } from \"../../main\";\r\nimport { AxiosError } from \"axios\";\r\n\r\ninterface FileInputMultipleProps {\r\n name: string;\r\n label?: string;\r\n initialFiles?: IAttachment[];\r\n onFilesChanged: (e: any) => void;\r\n required?: boolean;\r\n description?: string;\r\n disabled?: boolean;\r\n errors?: { [key: string]: { message: string } };\r\n initialFilesReadOnly?: boolean;\r\n attachmentName?: string;\r\n attachmentType?: string;\r\n}\r\n\r\ninterface IAttachmentReadOnly extends IAttachment {\r\n readonly?: boolean;\r\n}\r\n\r\nconst MAX_FILE_SIZE = 1024 * 1024; // 1MB\r\n\r\nconst FileInputMultiple: React.FC<FileInputMultipleProps> = ({\r\n initialFiles,\r\n onFilesChanged,\r\n label,\r\n name,\r\n required,\r\n description,\r\n disabled,\r\n errors = {},\r\n initialFilesReadOnly = true,\r\n attachmentName,\r\n attachmentType,\r\n}) => {\r\n const [fileDataList, setFileDataList] = useState<IAttachmentReadOnly[]>(\r\n initialFiles\r\n ? [...initialFiles].map((file) => ({\r\n ...file,\r\n readonly: initialFilesReadOnly,\r\n }))\r\n : []\r\n );\r\n const federationContext = useFederationContext();\r\n\r\n useEffect(() => {\r\n console.log(\r\n \"%clibcomponents\\formFileInputMultiple.tsx:40 initialFiles\",\r\n \"color: #007acc;\",\r\n initialFiles\r\n );\r\n if (!initialFiles || initialFiles.length === 0) return;\r\n setFileDataList(\r\n [...initialFiles].map((file) => ({\r\n ...file,\r\n readonly: initialFilesReadOnly,\r\n }))\r\n );\r\n }, [initialFiles, initialFilesReadOnly]);\r\n\r\n const onDrop = useCallback(\r\n async (acceptedFiles: File[]) => {\r\n const uploadedFiles = await Promise.all(\r\n acceptedFiles.map(async (file) => {\r\n if (file.size > MAX_FILE_SIZE) {\r\n // Handle the case when the file size is exceeded\r\n\r\n federationContext.emitter.emit(\"message\", {\r\n title: \"Velikost souboru byla překročena\",\r\n message: `Maximální povolená velikost je ${MAX_FILE_SIZE / (1024 * 1024)} MB.`,\r\n classes: \"bg-danger \",\r\n timeout: 0,\r\n type: \"error\",\r\n });\r\n\r\n return null;\r\n }\r\n\r\n const formData = new FormData();\r\n\r\n // Add the JSON data object\r\n const dataObject = {\r\n ...(attachmentName && { attachmentName }),\r\n ...(attachmentType && { attachmentType }),\r\n };\r\n\r\n formData.append(\r\n \"data\",\r\n new Blob([JSON.stringify(dataObject)], { type: \"application/json\" })\r\n );\r\n formData.append(\"file\", file);\r\n\r\n try {\r\n const response =\r\n await federationContext.apiClient.post<IAttachment>(\r\n \"/files/upload\",\r\n formData,\r\n {\r\n headers: {\r\n \"Content-Type\": \"multipart/form-data\",\r\n },\r\n }\r\n );\r\n return response.data;\r\n } catch (error) {\r\n handleErrors(error as AxiosError, federationContext.emitter);\r\n console.error(\"There was an error!\", error);\r\n return null;\r\n }\r\n })\r\n );\r\n\r\n const validFiles = uploadedFiles.filter(\r\n (file) => file !== null\r\n ) as IAttachment[];\r\n const updatedFileDataList = [...fileDataList, ...validFiles];\r\n setFileDataList(updatedFileDataList);\r\n onFilesChanged({\r\n target: {\r\n name,\r\n value: updatedFileDataList.map((file) => file.id.toString()),\r\n },\r\n });\r\n },\r\n [federationContext, fileDataList, onFilesChanged, name, attachmentName]\r\n );\r\n\r\n const { getRootProps, getInputProps, isDragActive } = useDropzone({\r\n onDrop,\r\n disabled,\r\n });\r\n\r\n const handleRemove = (fileId: number) => {\r\n const updatedFileDataList = fileDataList.filter(\r\n (file) => file.id !== fileId\r\n );\r\n setFileDataList(updatedFileDataList);\r\n onFilesChanged({\r\n target: {\r\n name,\r\n value: updatedFileDataList.map((file) => file.id.toString()),\r\n },\r\n });\r\n };\r\n if (disabled === true && fileDataList.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <div className=\"w-full min-h-30 flex-col justify-start items-start gap-1.5 inline-flex sharedLibrary\">\r\n <div className=\"self-stretch flex-col justify-start items-start gap-1.5 flex\">\r\n {label && (\r\n <label\r\n className=\"text-slate-700 text-sm leading-tight font-medium\"\r\n htmlFor={name}\r\n >\r\n {label} {required ? \"*\" : \"\"}\r\n </label>\r\n )}\r\n <div\r\n className={\r\n `self-stretch px-3 py-2 rounded-lg justify-start items-center gap-2 outline-none border bg-transparent ` +\r\n ` ${errors[name]?.message ? \"border-red-200\" : \"border-gray-300\"} `\r\n }\r\n >\r\n {!disabled && (\r\n <div\r\n {...getRootProps()}\r\n className={`w-full p-4 border-dashed cursor-pointer \r\n border-2 rounded-lg text-center hover:bg-gray-100\r\n ${isDragActive ? \"border-indigo-300 bg-indigo-50\" : \"border-gray-300\"}`}\r\n >\r\n <input {...getInputProps()} id={name} />\r\n <p className=\"text-gray-500\">\r\n {isDragActive\r\n ? \"Sem přetáhněte soubory\"\r\n : \"Klikněte pro nahrání, nebo nahrajte přetažením souborů\"}\r\n </p>\r\n </div>\r\n )}\r\n <div className=\"w-full\">\r\n {fileDataList.map((file) => (\r\n <div\r\n key={file.id}\r\n className=\"w-full flex items-center justify-between py-2 border-b \"\r\n >\r\n <div className=\"flex items-center content-center\">\r\n <MdInsertDriveFile style={{ fontSize: \"2rem\" }} />\r\n <a\r\n href={`/api/files/download/${file.id}`}\r\n className=\"pl-2 text-left underline text-primary\"\r\n target=\"_blank\"\r\n >\r\n {file.filename}\r\n </a>\r\n </div>\r\n {!disabled && file.readonly !== true && (\r\n <div\r\n onClick={() => handleRemove(file.id)}\r\n className=\"text-gray-600 cursor-pointer hover:text-primary hover:bg-gray-200 rounded-full ml-4\"\r\n >\r\n <MdDeleteOutline\r\n style={{ fontSize: \"1.5rem\", margin: \"10px\" }}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n </div>\r\n {description && (\r\n <div\r\n className=\"HintText self-stretch text-slate-600 text-sm font-normal leading-tight\"\r\n id={name + \":description\"}\r\n >\r\n {description}\r\n </div>\r\n )}\r\n {errors[name] && (\r\n <div\r\n className=\"HintText self-stretch text-red-600 text-sm font-normal leading-tight\"\r\n id={name + \":error\"}\r\n >\r\n {errors[name]?.message}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nexport default FileInputMultiple;\r\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAM,gBAAgB,OAAO;AAE7B,MAAM,oBAAsD,CAAC;AAAA,EAC3D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,CAAC;AAAA,EACV,uBAAuB;AAAA,EACvB;AAAA,EACA;AACF,MAAM;;AACE,QAAA,CAAC,cAAc,eAAe,IAAI;AAAA,IACtC,eACI,CAAC,GAAG,YAAY,EAAE,IAAI,CAAC,UAAU;AAAA,MAC/B,GAAG;AAAA,MACH,UAAU;AAAA,IACZ,EAAE,IACF,CAAC;AAAA,EAAA;AAEP,QAAM,oBAAoB;AAE1B,YAAU,MAAM;AACN,YAAA;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAEE,QAAA,CAAC,gBAAgB,aAAa,WAAW;AAAG;AAChD;AAAA,MACE,CAAC,GAAG,YAAY,EAAE,IAAI,CAAC,UAAU;AAAA,QAC/B,GAAG;AAAA,QACH,UAAU;AAAA,MAAA,EACV;AAAA,IAAA;AAAA,EACJ,GACC,CAAC,cAAc,oBAAoB,CAAC;AAEvC,QAAM,SAAS;AAAA,IACb,OAAO,kBAA0B;AACzB,YAAA,gBAAgB,MAAM,QAAQ;AAAA,QAClC,cAAc,IAAI,OAAO,SAAS;AAC5B,cAAA,KAAK,OAAO,eAAe;AAGX,8BAAA,QAAQ,KAAK,WAAW;AAAA,cACxC,OAAO;AAAA,cACP,SAAS,kCAAkC,iBAAiB,OAAO,KAAK;AAAA,cACxE,SAAS;AAAA,cACT,SAAS;AAAA,cACT,MAAM;AAAA,YAAA,CACP;AAEM,mBAAA;AAAA,UACT;AAEM,gBAAA,WAAW,IAAI;AAGrB,gBAAM,aAAa;AAAA,YACjB,GAAI,kBAAkB,EAAE,eAAe;AAAA,YACvC,GAAI,kBAAkB,EAAE,eAAe;AAAA,UAAA;AAGhC,mBAAA;AAAA,YACP;AAAA,YACA,IAAI,KAAK,CAAC,KAAK,UAAU,UAAU,CAAC,GAAG,EAAE,MAAM,oBAAoB;AAAA,UAAA;AAE5D,mBAAA,OAAO,QAAQ,IAAI;AAExB,cAAA;AACI,kBAAA,WACJ,MAAM,kBAAkB,UAAU;AAAA,cAChC;AAAA,cACA;AAAA,cACA;AAAA,gBACE,SAAS;AAAA,kBACP,gBAAgB;AAAA,gBAClB;AAAA,cACF;AAAA,YAAA;AAEJ,mBAAO,SAAS;AAAA,mBACT,OAAO;AACD,yBAAA,OAAqB,kBAAkB,OAAO;AACnD,oBAAA,MAAM,uBAAuB,KAAK;AACnC,mBAAA;AAAA,UACT;AAAA,QAAA,CACD;AAAA,MAAA;AAGH,YAAM,aAAa,cAAc;AAAA,QAC/B,CAAC,SAAS,SAAS;AAAA,MAAA;AAErB,YAAM,sBAAsB,CAAC,GAAG,cAAc,GAAG,UAAU;AAC3D,sBAAgB,mBAAmB;AACpB,qBAAA;AAAA,QACb,QAAQ;AAAA,UACN;AAAA,UACA,OAAO,oBAAoB,IAAI,CAAC,SAAS,KAAK,GAAG,UAAU;AAAA,QAC7D;AAAA,MAAA,CACD;AAAA,IACH;AAAA,IACA,CAAC,mBAAmB,cAAc,gBAAgB,MAAM,cAAc;AAAA,EAAA;AAGxE,QAAM,EAAE,cAAc,eAAe,aAAA,IAAiB,YAAY;AAAA,IAChE;AAAA,IACA;AAAA,EAAA,CACD;AAEK,QAAA,eAAe,CAAC,WAAmB;AACvC,UAAM,sBAAsB,aAAa;AAAA,MACvC,CAAC,SAAS,KAAK,OAAO;AAAA,IAAA;AAExB,oBAAgB,mBAAmB;AACpB,mBAAA;AAAA,MACb,QAAQ;AAAA,QACN;AAAA,QACA,OAAO,oBAAoB,IAAI,CAAC,SAAS,KAAK,GAAG,UAAU;AAAA,MAC7D;AAAA,IAAA,CACD;AAAA,EAAA;AAEH,MAAI,aAAa,QAAQ,aAAa,WAAW,GAAG;AAC3C,WAAA;AAAA,EACT;AAGE,SAAA,qBAAC,OAAI,EAAA,WAAU,wFACb,UAAA;AAAA,IAAC,qBAAA,OAAA,EAAI,WAAU,gEACZ,UAAA;AAAA,MACC,SAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS;AAAA,UAER,UAAA;AAAA,YAAA;AAAA,YAAM;AAAA,YAAE,WAAW,MAAM;AAAA,UAAA;AAAA,QAAA;AAAA,MAC5B;AAAA,MAEF;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WACE,6GACI,YAAO,IAAI,MAAX,mBAAc,WAAU,mBAAmB,iBAAiB;AAAA,UAGjE,UAAA;AAAA,YAAA,CAAC,YACA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACE,GAAG,aAAa;AAAA,gBACjB,WAAW;AAAA;AAAA,kBAEP,eAAe,mCAAmC,iBAAiB;AAAA,gBAEvE,UAAA;AAAA,kBAAA,oBAAC,SAAO,EAAA,GAAG,cAAc,GAAG,IAAI,MAAM;AAAA,sCACrC,KAAE,EAAA,WAAU,iBACV,UAAA,eACG,2BACA,0DACN;AAAA,gBAAA;AAAA,cAAA;AAAA,YACF;AAAA,gCAED,OAAI,EAAA,WAAU,UACZ,UAAa,aAAA,IAAI,CAAC,SACjB;AAAA,cAAC;AAAA,cAAA;AAAA,gBAEC,WAAU;AAAA,gBAEV,UAAA;AAAA,kBAAC,qBAAA,OAAA,EAAI,WAAU,oCACb,UAAA;AAAA,oBAAA,oBAAC,mBAAkB,EAAA,OAAO,EAAE,UAAU,UAAU;AAAA,oBAChD;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACC,MAAM,uBAAuB,KAAK,EAAE;AAAA,wBACpC,WAAU;AAAA,wBACV,QAAO;AAAA,wBAEN,UAAK,KAAA;AAAA,sBAAA;AAAA,oBACR;AAAA,kBAAA,GACF;AAAA,kBACC,CAAC,YAAY,KAAK,aAAa,QAC9B;AAAA,oBAAC;AAAA,oBAAA;AAAA,sBACC,SAAS,MAAM,aAAa,KAAK,EAAE;AAAA,sBACnC,WAAU;AAAA,sBAEV,UAAA;AAAA,wBAAC;AAAA,wBAAA;AAAA,0BACC,OAAO,EAAE,UAAU,UAAU,QAAQ,OAAO;AAAA,wBAAA;AAAA,sBAC9C;AAAA,oBAAA;AAAA,kBACF;AAAA,gBAAA;AAAA,cAAA;AAAA,cArBG,KAAK;AAAA,YAwBb,CAAA,GACH;AAAA,UAAA;AAAA,QAAA;AAAA,MACF;AAAA,IAAA,GACF;AAAA,IACC,eACC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,IAAI,OAAO;AAAA,QAEV,UAAA;AAAA,MAAA;AAAA,IACH;AAAA,IAED,OAAO,IAAI,KACV;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,IAAI,OAAO;AAAA,QAEV,WAAA,YAAO,IAAI,MAAX,mBAAc;AAAA,MAAA;AAAA,IACjB;AAAA,EAEJ,EAAA,CAAA;AAEJ;"}
|
|
@@ -128,7 +128,7 @@ function DataTableServer<T extends DataTableInternalItems>({
|
|
|
128
128
|
const tableRef = useRef<HTMLTableElement | null>(null);
|
|
129
129
|
const syncWidthRef = useRef<HTMLDivElement | null>(null);
|
|
130
130
|
|
|
131
|
-
const [itemsPerPageLocal, setItemsPerPageLocal] = useState<number>();
|
|
131
|
+
const [itemsPerPageLocal, setItemsPerPageLocal] = useState<number>(10);
|
|
132
132
|
const federationContext = useFederationContext();
|
|
133
133
|
const [data, setData] = useState<IPageable<T>>();
|
|
134
134
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -137,15 +137,17 @@ function DataTableServer<T extends DataTableInternalItems>({
|
|
|
137
137
|
|
|
138
138
|
const [hasMounted, setHasMounted] = useState(false);
|
|
139
139
|
|
|
140
|
-
const [currentPage, setCurrentPage] = useState<number>();
|
|
140
|
+
const [currentPage, setCurrentPage] = useState<number>(0);
|
|
141
141
|
const [selectedItems, setSelectedItems] = useState<T[]>([]);
|
|
142
142
|
const [fulltextSearch, setFulltextSearch] = useState("");
|
|
143
143
|
const [filterOptions, setFilterOptions] = useState<Record<string, any[]>>({});
|
|
144
144
|
const [columnFilters, setColumnFilters] = useState<{ [key: string]: any }>(
|
|
145
145
|
{}
|
|
146
146
|
);
|
|
147
|
-
const [showColFilters, setShowColFilters] = useState<boolean>();
|
|
147
|
+
const [showColFilters, setShowColFilters] = useState<boolean>(false);
|
|
148
148
|
const [sortConfig, setSortConfig] = useState<ISortConfig | null>(null);
|
|
149
|
+
const prevDepsRef = useRef<any[]>([]);
|
|
150
|
+
const prevFilterDepsRef = useRef<any[]>([]);
|
|
149
151
|
|
|
150
152
|
const createDataPageable = (
|
|
151
153
|
response: any,
|
|
@@ -171,24 +173,53 @@ function DataTableServer<T extends DataTableInternalItems>({
|
|
|
171
173
|
const mergedFilters: { [key: string]: any } = useMemo(() => {
|
|
172
174
|
return showColFilters ? { ...columnFilters, ...filters } : filters || {};
|
|
173
175
|
}, [columnFilters, filters, showColFilters]);
|
|
174
|
-
|
|
175
176
|
useEffect(() => {
|
|
176
|
-
|
|
177
|
+
const currentDeps = [
|
|
178
|
+
url,
|
|
179
|
+
showColFilters,
|
|
180
|
+
columnFilters,
|
|
181
|
+
itemsPerPageLocal,
|
|
182
|
+
currentPage,
|
|
183
|
+
sortConfig,
|
|
184
|
+
filters,
|
|
185
|
+
tableKey,
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
// Kontrola, jestli se skutečně něco změnilo
|
|
189
|
+
const hasChanged = currentDeps.some((dep, index) => {
|
|
190
|
+
return JSON.stringify(dep) !== JSON.stringify(prevDepsRef.current[index]);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
if (hasChanged) {
|
|
194
|
+
console.log(
|
|
195
|
+
"setting reloadData - actual change detected",
|
|
196
|
+
url,
|
|
197
|
+
showColFilters,
|
|
198
|
+
columnFilters,
|
|
199
|
+
itemsPerPageLocal,
|
|
200
|
+
currentPage,
|
|
201
|
+
sortConfig,
|
|
202
|
+
filters,
|
|
203
|
+
tableKey,
|
|
204
|
+
reloadData
|
|
205
|
+
);
|
|
206
|
+
setReloadData(true);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
prevDepsRef.current = currentDeps;
|
|
177
210
|
}, [
|
|
178
211
|
url,
|
|
179
212
|
showColFilters,
|
|
180
|
-
// id,
|
|
181
213
|
columnFilters,
|
|
182
214
|
itemsPerPageLocal,
|
|
183
215
|
currentPage,
|
|
184
216
|
sortConfig,
|
|
185
|
-
federationContext.apiClient,
|
|
186
|
-
federationContext.emitter,
|
|
187
217
|
filters,
|
|
188
218
|
tableKey,
|
|
189
219
|
]);
|
|
190
220
|
|
|
191
221
|
useEffect(() => {
|
|
222
|
+
console.log("reloadData", reloadData);
|
|
192
223
|
if (reloadData) {
|
|
193
224
|
if (abortControllerRef.current) {
|
|
194
225
|
abortControllerRef.current.abort();
|
|
@@ -307,66 +338,92 @@ function DataTableServer<T extends DataTableInternalItems>({
|
|
|
307
338
|
}, [id]);
|
|
308
339
|
|
|
309
340
|
useEffect(() => {
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const options = response.data.map((item: any) => ({
|
|
320
|
-
value: item[column.filterValueKey as keyof typeof item]?.toString(),
|
|
321
|
-
label: item[column.filterLabelKey as keyof typeof item]?.toString(),
|
|
322
|
-
}));
|
|
323
|
-
return options;
|
|
324
|
-
} catch (error) {
|
|
325
|
-
console.error("Error fetching filter options:", error);
|
|
326
|
-
return [];
|
|
327
|
-
}
|
|
341
|
+
const currentFilterDeps = [columns, federationContext.apiClient];
|
|
342
|
+
|
|
343
|
+
// Kontrola, jestli se skutečně něco změnilo
|
|
344
|
+
const hasFilterChanged = currentFilterDeps.some((dep, index) => {
|
|
345
|
+
const prev = prevFilterDepsRef.current[index];
|
|
346
|
+
if (index === 1) {
|
|
347
|
+
// federationContext.apiClient (index 1) - referenční porovnání
|
|
348
|
+
return dep !== prev;
|
|
328
349
|
} else {
|
|
329
|
-
|
|
350
|
+
// columns (index 0) - deep porovnání
|
|
351
|
+
return JSON.stringify(dep) !== JSON.stringify(prev);
|
|
330
352
|
}
|
|
331
|
-
};
|
|
353
|
+
});
|
|
332
354
|
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if (
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
column.filterValueKey &&
|
|
342
|
-
column.filterLabelKey &&
|
|
343
|
-
column.filterParam
|
|
344
|
-
) {
|
|
345
|
-
const options = await fetchFilterOptions(column);
|
|
346
|
-
|
|
347
|
-
if (options && column.filterType === "select") {
|
|
348
|
-
// Filter out empty values and add a "clear" option
|
|
349
|
-
const filteredOptions = options.filter(
|
|
350
|
-
(option: IOptionItem) =>
|
|
351
|
-
option.value !== null &&
|
|
352
|
-
option.value !== undefined &&
|
|
353
|
-
option.value !== ""
|
|
355
|
+
if (hasFilterChanged) {
|
|
356
|
+
const fetchFilterOptions = async (column: DataTableColumn<T>) => {
|
|
357
|
+
if (column.filterOptions) {
|
|
358
|
+
return column.filterOptions;
|
|
359
|
+
} else if (column.filterSource) {
|
|
360
|
+
try {
|
|
361
|
+
const response = await federationContext.apiClient.get(
|
|
362
|
+
column.filterSource
|
|
354
363
|
);
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
364
|
+
|
|
365
|
+
const options = response.data.map((item: any) => ({
|
|
366
|
+
value:
|
|
367
|
+
item[column.filterValueKey as keyof typeof item]?.toString(),
|
|
368
|
+
label:
|
|
369
|
+
item[column.filterLabelKey as keyof typeof item]?.toString(),
|
|
370
|
+
}));
|
|
371
|
+
return options;
|
|
372
|
+
} catch (error) {
|
|
373
|
+
console.error("Error fetching filter options:", error);
|
|
374
|
+
return [];
|
|
375
|
+
}
|
|
376
|
+
} else {
|
|
377
|
+
return [];
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
const updateFilterOptions = async () => {
|
|
382
|
+
const newFilterOptions: Record<string, any[]> = {};
|
|
383
|
+
|
|
384
|
+
for (const column of columns) {
|
|
385
|
+
if (
|
|
386
|
+
(column.filterType === "select" ||
|
|
387
|
+
column.filterType === "multi-select") &&
|
|
388
|
+
(column.filterSource || column.filterOptions) &&
|
|
389
|
+
column.filterValueKey &&
|
|
390
|
+
column.filterLabelKey &&
|
|
391
|
+
column.filterParam
|
|
392
|
+
) {
|
|
393
|
+
const options = await fetchFilterOptions(column);
|
|
394
|
+
|
|
395
|
+
if (options && column.filterType === "select") {
|
|
396
|
+
// Filter out empty values and add a "clear" option
|
|
397
|
+
const filteredOptions = options.filter(
|
|
398
|
+
(option: IOptionItem) =>
|
|
399
|
+
option.value !== null &&
|
|
400
|
+
option.value !== undefined &&
|
|
401
|
+
option.value !== ""
|
|
402
|
+
);
|
|
403
|
+
newFilterOptions[column.filterParam as string] = [
|
|
404
|
+
{ value: "__clear__", label: "Všechny" },
|
|
405
|
+
...filteredOptions,
|
|
406
|
+
];
|
|
407
|
+
} else if (options && column.filterType === "multi-select") {
|
|
408
|
+
newFilterOptions[column.filterParam as string] = options;
|
|
409
|
+
}
|
|
361
410
|
}
|
|
362
411
|
}
|
|
363
|
-
}
|
|
364
412
|
|
|
365
|
-
|
|
366
|
-
|
|
413
|
+
setFilterOptions(newFilterOptions);
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
console.log(
|
|
417
|
+
"updateFilterOptions - actual change detected",
|
|
418
|
+
columns,
|
|
419
|
+
federationContext.apiClient
|
|
420
|
+
);
|
|
421
|
+
updateFilterOptions();
|
|
422
|
+
}
|
|
367
423
|
|
|
368
|
-
|
|
424
|
+
prevFilterDepsRef.current = currentFilterDeps;
|
|
369
425
|
}, [columns, federationContext.apiClient]);
|
|
426
|
+
|
|
370
427
|
const hasSomeColFilters = useMemo(() => {
|
|
371
428
|
return columns.some((column) => !!column.filterParam);
|
|
372
429
|
}, [columns]);
|
|
@@ -848,7 +905,12 @@ function DataTableServer<T extends DataTableInternalItems>({
|
|
|
848
905
|
<div
|
|
849
906
|
className="p-0 m-0 pb-2"
|
|
850
907
|
onClick={(e) => e.stopPropagation()}
|
|
851
|
-
data-cy={
|
|
908
|
+
data-cy={
|
|
909
|
+
"datatable-filter-container-" +
|
|
910
|
+
id +
|
|
911
|
+
"-" +
|
|
912
|
+
String(key)
|
|
913
|
+
}
|
|
852
914
|
>
|
|
853
915
|
{filterType === "select" ? (
|
|
854
916
|
<Select
|
|
@@ -867,15 +929,11 @@ function DataTableServer<T extends DataTableInternalItems>({
|
|
|
867
929
|
String(filterParam)
|
|
868
930
|
]?.toString() || "__clear__"
|
|
869
931
|
}
|
|
870
|
-
|
|
871
932
|
disabled={Object.keys(
|
|
872
933
|
(filters as object) || {}
|
|
873
934
|
).includes(String(filterParam))}
|
|
874
935
|
>
|
|
875
|
-
<SelectTrigger
|
|
876
|
-
|
|
877
|
-
className="flex-1 w-full px-2 font-normal placeholder-muted-foreground"
|
|
878
|
-
>
|
|
936
|
+
<SelectTrigger className="flex-1 w-full px-2 font-normal placeholder-muted-foreground">
|
|
879
937
|
<SelectValue placeholder="Zadejte filtr" />
|
|
880
938
|
</SelectTrigger>
|
|
881
939
|
<SelectContent>
|
|
@@ -921,7 +979,7 @@ function DataTableServer<T extends DataTableInternalItems>({
|
|
|
921
979
|
).includes(String(filterParam))}
|
|
922
980
|
variant="secondary"
|
|
923
981
|
maxCount={0}
|
|
924
|
-
|
|
982
|
+
/>
|
|
925
983
|
) : filterType === "dateRange" ? (
|
|
926
984
|
<DateRangeField
|
|
927
985
|
// key={JSON.stringify(mergedFilters)}
|
|
@@ -23,6 +23,7 @@ interface FileInputProps {
|
|
|
23
23
|
disabled?: boolean;
|
|
24
24
|
errors?: { [key: string]: { message: string } };
|
|
25
25
|
attachmentName?: string;
|
|
26
|
+
attachmentType?: string;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
const MAX_FILE_SIZE = 1024 * 1024; // 1MB
|
|
@@ -37,6 +38,7 @@ const FileInput: React.FC<FileInputProps> = ({
|
|
|
37
38
|
disabled,
|
|
38
39
|
errors = {},
|
|
39
40
|
attachmentName,
|
|
41
|
+
attachmentType,
|
|
40
42
|
}) => {
|
|
41
43
|
const [fileData, setFileData] = useState<FileData | null>(
|
|
42
44
|
initialFile || null
|
|
@@ -47,7 +49,7 @@ const FileInput: React.FC<FileInputProps> = ({
|
|
|
47
49
|
useEffect(() => {
|
|
48
50
|
if (initialFile) {
|
|
49
51
|
setFileData(initialFile);
|
|
50
|
-
|
|
52
|
+
}
|
|
51
53
|
}, [initialFile]);
|
|
52
54
|
|
|
53
55
|
const onDrop = useCallback(
|
|
@@ -68,6 +70,17 @@ const FileInput: React.FC<FileInputProps> = ({
|
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
const formData = new FormData();
|
|
73
|
+
|
|
74
|
+
// Add the JSON data object
|
|
75
|
+
const dataObject = {
|
|
76
|
+
...(attachmentName && { attachmentName }),
|
|
77
|
+
...(attachmentType && { attachmentType }),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
formData.append(
|
|
81
|
+
"data",
|
|
82
|
+
new Blob([JSON.stringify(dataObject)], { type: "application/json" })
|
|
83
|
+
);
|
|
71
84
|
formData.append("file", file);
|
|
72
85
|
|
|
73
86
|
try {
|
|
@@ -78,7 +91,6 @@ const FileInput: React.FC<FileInputProps> = ({
|
|
|
78
91
|
headers: {
|
|
79
92
|
"Content-Type": "multipart/form-data",
|
|
80
93
|
},
|
|
81
|
-
params: attachmentName ? { attachmentName } : undefined,
|
|
82
94
|
}
|
|
83
95
|
);
|
|
84
96
|
setFileData(response.data);
|
|
@@ -98,6 +110,7 @@ const FileInput: React.FC<FileInputProps> = ({
|
|
|
98
110
|
onFileChanged,
|
|
99
111
|
name,
|
|
100
112
|
attachmentName,
|
|
113
|
+
attachmentType,
|
|
101
114
|
]
|
|
102
115
|
);
|
|
103
116
|
|
|
@@ -16,6 +16,7 @@ interface FileInputMultipleProps {
|
|
|
16
16
|
errors?: { [key: string]: { message: string } };
|
|
17
17
|
initialFilesReadOnly?: boolean;
|
|
18
18
|
attachmentName?: string;
|
|
19
|
+
attachmentType?: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
interface IAttachmentReadOnly extends IAttachment {
|
|
@@ -35,6 +36,7 @@ const FileInputMultiple: React.FC<FileInputMultipleProps> = ({
|
|
|
35
36
|
errors = {},
|
|
36
37
|
initialFilesReadOnly = true,
|
|
37
38
|
attachmentName,
|
|
39
|
+
attachmentType,
|
|
38
40
|
}) => {
|
|
39
41
|
const [fileDataList, setFileDataList] = useState<IAttachmentReadOnly[]>(
|
|
40
42
|
initialFiles
|
|
@@ -80,6 +82,17 @@ const FileInputMultiple: React.FC<FileInputMultipleProps> = ({
|
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
const formData = new FormData();
|
|
85
|
+
|
|
86
|
+
// Add the JSON data object
|
|
87
|
+
const dataObject = {
|
|
88
|
+
...(attachmentName && { attachmentName }),
|
|
89
|
+
...(attachmentType && { attachmentType }),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
formData.append(
|
|
93
|
+
"data",
|
|
94
|
+
new Blob([JSON.stringify(dataObject)], { type: "application/json" })
|
|
95
|
+
);
|
|
83
96
|
formData.append("file", file);
|
|
84
97
|
|
|
85
98
|
try {
|
|
@@ -91,7 +104,6 @@ const FileInputMultiple: React.FC<FileInputMultipleProps> = ({
|
|
|
91
104
|
headers: {
|
|
92
105
|
"Content-Type": "multipart/form-data",
|
|
93
106
|
},
|
|
94
|
-
params: attachmentName ? { attachmentName } : undefined,
|
|
95
107
|
}
|
|
96
108
|
);
|
|
97
109
|
return response.data;
|