balibabu commited on
Commit
8d2a400
·
1 Parent(s): d684fd5

fix: fix uploaded file time error #680 (#690)

Browse files

### What problem does this PR solve?

fix: fix uploaded file time error #680
feat: support preview of word and excel #684

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)

web/src/components/new-document-link.tsx CHANGED
@@ -1,22 +1,24 @@
1
- import { api_host } from '@/utils/api';
2
  import React from 'react';
3
 
4
  interface IProps extends React.PropsWithChildren {
5
- documentId: string;
6
  preventDefault?: boolean;
 
7
  }
8
 
9
  const NewDocumentLink = ({
10
  children,
11
- documentId,
12
  preventDefault = false,
 
13
  }: IProps) => {
14
  return (
15
  <a
16
  target="_blank"
17
  onClick={!preventDefault ? undefined : (e) => e.preventDefault()}
18
- href={`${api_host}/document/get/${documentId}`}
19
  rel="noreferrer"
 
20
  >
21
  {children}
22
  </a>
 
 
1
  import React from 'react';
2
 
3
  interface IProps extends React.PropsWithChildren {
4
+ link: string;
5
  preventDefault?: boolean;
6
+ color?: string;
7
  }
8
 
9
  const NewDocumentLink = ({
10
  children,
11
+ link,
12
  preventDefault = false,
13
+ color = 'rgb(15, 79, 170)',
14
  }: IProps) => {
15
  return (
16
  <a
17
  target="_blank"
18
  onClick={!preventDefault ? undefined : (e) => e.preventDefault()}
19
+ href={link}
20
  rel="noreferrer"
21
+ style={{ color }}
22
  >
23
  {children}
24
  </a>
web/src/constants/common.ts CHANGED
@@ -68,3 +68,23 @@ export const FileMimeTypeMap = {
68
  xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
69
  mp4: 'video/mp4',
70
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
69
  mp4: 'video/mp4',
70
  };
71
+
72
+ //#region file preview
73
+ export const Images = [
74
+ 'jpg',
75
+ 'jpeg',
76
+ 'png',
77
+ 'gif',
78
+ 'bmp',
79
+ 'tif',
80
+ 'tiff',
81
+ 'webp',
82
+ // 'svg',
83
+ 'ico',
84
+ ];
85
+
86
+ // Without FileViewer
87
+ export const ExceptiveType = ['xlsx', 'xls', 'pdf', ...Images];
88
+
89
+ export const SupportedPreviewDocumentTypes = ['docx', 'csv', ...ExceptiveType];
90
+ //#endregion
web/src/hooks/documentHooks.ts CHANGED
@@ -9,12 +9,15 @@ import { useDispatch, useSelector } from 'umi';
9
  import { useGetKnowledgeSearchParams } from './routeHook';
10
  import { useOneNamespaceEffectsLoading } from './storeHooks';
11
 
12
- export const useGetDocumentUrl = (documentId: string) => {
13
- const url = useMemo(() => {
14
- return `${api_host}/document/get/${documentId}`;
15
- }, [documentId]);
 
 
 
16
 
17
- return url;
18
  };
19
 
20
  export const useGetChunkHighlights = (selectedChunk: IChunk) => {
 
9
  import { useGetKnowledgeSearchParams } from './routeHook';
10
  import { useOneNamespaceEffectsLoading } from './storeHooks';
11
 
12
+ export const useGetDocumentUrl = (documentId?: string) => {
13
+ const getDocumentUrl = useCallback(
14
+ (id?: string) => {
15
+ return `${api_host}/document/get/${documentId || id}`;
16
+ },
17
+ [documentId],
18
+ );
19
 
20
+ return getDocumentUrl;
21
  };
22
 
23
  export const useGetChunkHighlights = (selectedChunk: IChunk) => {
web/src/locales/en.ts CHANGED
@@ -505,6 +505,7 @@ export default {
505
  'Support for a single or bulk upload. Strictly prohibited from uploading company data or other banned files.',
506
  local: 'Local uploads',
507
  s3: 'S3 uploads',
 
508
  },
509
  footer: {
510
  profile: 'All rights reserved @ React',
 
505
  'Support for a single or bulk upload. Strictly prohibited from uploading company data or other banned files.',
506
  local: 'Local uploads',
507
  s3: 'S3 uploads',
508
+ preview: 'Preview',
509
  },
510
  footer: {
511
  profile: 'All rights reserved @ React',
web/src/locales/zh-traditional.ts CHANGED
@@ -468,6 +468,7 @@ export default {
468
  directory: '文件夾',
469
  local: '本地上傳',
470
  s3: 'S3 上傳',
 
471
  },
472
  footer: {
473
  profile: '“保留所有權利 @ react”',
 
468
  directory: '文件夾',
469
  local: '本地上傳',
470
  s3: 'S3 上傳',
471
+ preview: '預覽',
472
  },
473
  footer: {
474
  profile: '“保留所有權利 @ react”',
web/src/locales/zh.ts CHANGED
@@ -486,6 +486,7 @@ export default {
486
  directory: '文件夹',
487
  local: '本地上传',
488
  s3: 'S3 上传',
 
489
  },
490
  footer: {
491
  profile: 'All rights reserved @ React',
 
486
  directory: '文件夹',
487
  local: '本地上传',
488
  s3: 'S3 上传',
489
+ preview: '预览',
490
  },
491
  footer: {
492
  profile: 'All rights reserved @ React',
web/src/pages/add-knowledge/components/knowledge-file/index.tsx CHANGED
@@ -106,8 +106,8 @@ const KnowledgeFile = () => {
106
  },
107
  {
108
  title: t('uploadDate'),
109
- dataIndex: 'create_date',
110
- key: 'create_date',
111
  render(value) {
112
  return formatDate(value);
113
  },
 
106
  },
107
  {
108
  title: t('uploadDate'),
109
+ dataIndex: 'create_time',
110
+ key: 'create_time',
111
  render(value) {
112
  return formatDate(value);
113
  },
web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx CHANGED
@@ -1,5 +1,6 @@
1
  import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg';
2
  import NewDocumentLink from '@/components/new-document-link';
 
3
  import { ITestingDocument } from '@/interfaces/database/knowledge';
4
  import { isPdf } from '@/utils/documentUtils';
5
  import { Table, TableProps } from 'antd';
@@ -15,6 +16,7 @@ const SelectFiles = ({ handleTesting }: IProps) => {
15
  );
16
 
17
  const dispatch = useDispatch();
 
18
 
19
  const columns: TableProps<ITestingDocument>['columns'] = [
20
  {
@@ -35,7 +37,10 @@ const SelectFiles = ({ handleTesting }: IProps) => {
35
  key: 'view',
36
  width: 50,
37
  render: (_, { doc_id, doc_name }) => (
38
- <NewDocumentLink documentId={doc_id} preventDefault={!isPdf(doc_name)}>
 
 
 
39
  <NavigationPointerIcon />
40
  </NewDocumentLink>
41
  ),
 
1
  import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg';
2
  import NewDocumentLink from '@/components/new-document-link';
3
+ import { useGetDocumentUrl } from '@/hooks/documentHooks';
4
  import { ITestingDocument } from '@/interfaces/database/knowledge';
5
  import { isPdf } from '@/utils/documentUtils';
6
  import { Table, TableProps } from 'antd';
 
16
  );
17
 
18
  const dispatch = useDispatch();
19
+ const getDocumentUrl = useGetDocumentUrl();
20
 
21
  const columns: TableProps<ITestingDocument>['columns'] = [
22
  {
 
37
  key: 'view',
38
  width: 50,
39
  render: (_, { doc_id, doc_name }) => (
40
+ <NewDocumentLink
41
+ link={getDocumentUrl(doc_id)}
42
+ preventDefault={!isPdf(doc_name)}
43
+ >
44
  <NavigationPointerIcon />
45
  </NewDocumentLink>
46
  ),
web/src/pages/chat/chat-container/index.tsx CHANGED
@@ -30,6 +30,7 @@ import MarkdownContent from '../markdown-content';
30
 
31
  import SvgIcon from '@/components/svg-icon';
32
  import { useTranslate } from '@/hooks/commonHooks';
 
33
  import { getExtension, isPdf } from '@/utils/documentUtils';
34
  import styles from './index.less';
35
 
@@ -44,6 +45,7 @@ const MessageItem = ({
44
  }) => {
45
  const userInfo = useSelectUserInfo();
46
  const fileThumbnails = useSelectFileThumbnails();
 
47
 
48
  const isAssistant = item.role === MessageType.Assistant;
49
 
@@ -113,7 +115,7 @@ const MessageItem = ({
113
  )}
114
 
115
  <NewDocumentLink
116
- documentId={item.doc_id}
117
  preventDefault={!isPdf(item.doc_name)}
118
  >
119
  {item.doc_name}
 
30
 
31
  import SvgIcon from '@/components/svg-icon';
32
  import { useTranslate } from '@/hooks/commonHooks';
33
+ import { useGetDocumentUrl } from '@/hooks/documentHooks';
34
  import { getExtension, isPdf } from '@/utils/documentUtils';
35
  import styles from './index.less';
36
 
 
45
  }) => {
46
  const userInfo = useSelectUserInfo();
47
  const fileThumbnails = useSelectFileThumbnails();
48
+ const getDocumentUrl = useGetDocumentUrl();
49
 
50
  const isAssistant = item.role === MessageType.Assistant;
51
 
 
115
  )}
116
 
117
  <NewDocumentLink
118
+ link={getDocumentUrl(item.doc_id)}
119
  preventDefault={!isPdf(item.doc_name)}
120
  >
121
  {item.doc_name}
web/src/pages/document-viewer/index.less CHANGED
@@ -1,8 +1,13 @@
1
  .viewerWrapper {
2
  width: 100%;
 
3
  :global {
4
  .pdf-canvas {
5
  text-align: center;
6
  }
7
  }
 
 
 
 
8
  }
 
1
  .viewerWrapper {
2
  width: 100%;
3
+ height: 100%;
4
  :global {
5
  .pdf-canvas {
6
  text-align: center;
7
  }
8
  }
9
+ .image {
10
+ width: 100%;
11
+ height: 100%;
12
+ }
13
  }
web/src/pages/document-viewer/index.tsx CHANGED
@@ -1,10 +1,17 @@
 
1
  import { api_host } from '@/utils/api';
 
2
  import FileViewer from 'react-file-viewer';
3
  import { useParams, useSearchParams } from 'umi';
4
  import Excel from './excel';
 
5
 
6
  import styles from './index.less';
7
 
 
 
 
 
8
  const DocumentViewer = () => {
9
  const { id: documentId } = useParams();
10
  const api = `${api_host}/file/get/${documentId}`;
@@ -17,8 +24,14 @@ const DocumentViewer = () => {
17
 
18
  return (
19
  <section className={styles.viewerWrapper}>
20
- {ext === 'xlsx' && <Excel filePath={api}></Excel>}
21
- {ext !== 'xlsx' && (
 
 
 
 
 
 
22
  <FileViewer fileType={ext} filePath={api} onError={onError} />
23
  )}
24
  </section>
 
1
+ import { ExceptiveType, Images } from '@/constants/common';
2
  import { api_host } from '@/utils/api';
3
+ import { Flex, Image } from 'antd';
4
  import FileViewer from 'react-file-viewer';
5
  import { useParams, useSearchParams } from 'umi';
6
  import Excel from './excel';
7
+ import Pdf from './pdf';
8
 
9
  import styles from './index.less';
10
 
11
+ // TODO: The interface returns an incorrect content-type for the SVG.
12
+
13
+ const isNotExceptiveType = (ext: string) => ExceptiveType.indexOf(ext) === -1;
14
+
15
  const DocumentViewer = () => {
16
  const { id: documentId } = useParams();
17
  const api = `${api_host}/file/get/${documentId}`;
 
24
 
25
  return (
26
  <section className={styles.viewerWrapper}>
27
+ {Images.includes(ext!) && (
28
+ <Flex className={styles.image} align="center" justify="center">
29
+ <Image src={api} preview={false}></Image>
30
+ </Flex>
31
+ )}
32
+ {ext === 'pdf' && <Pdf url={api}></Pdf>}
33
+ {(ext === 'xlsx' || ext === 'xls') && <Excel filePath={api}></Excel>}
34
+ {isNotExceptiveType(ext!) && (
35
  <FileViewer fileType={ext} filePath={api} onError={onError} />
36
  )}
37
  </section>
web/src/pages/document-viewer/pdf/index.tsx ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Skeleton } from 'antd';
2
+ import { PdfHighlighter, PdfLoader } from 'react-pdf-highlighter';
3
+
4
+ interface IProps {
5
+ url: string;
6
+ }
7
+
8
+ const DocumentPreviewer = ({ url }: IProps) => {
9
+ const resetHash = () => {};
10
+
11
+ return (
12
+ <div style={{ width: '100%' }}>
13
+ <PdfLoader
14
+ url={url}
15
+ beforeLoad={<Skeleton active />}
16
+ workerSrc="/pdfjs-dist/pdf.worker.min.js"
17
+ >
18
+ {(pdfDocument) => {
19
+ return (
20
+ <PdfHighlighter
21
+ pdfDocument={pdfDocument}
22
+ enableAreaSelection={(event) => event.altKey}
23
+ onScrollChange={resetHash}
24
+ scrollRef={() => {}}
25
+ onSelectionFinished={() => null}
26
+ highlightTransform={() => {
27
+ return <div></div>;
28
+ }}
29
+ highlights={[]}
30
+ />
31
+ );
32
+ }}
33
+ </PdfLoader>
34
+ </div>
35
+ );
36
+ };
37
+
38
+ export default DocumentPreviewer;
web/src/pages/file-manager/action-cell/index.tsx CHANGED
@@ -6,13 +6,21 @@ import {
6
  DeleteOutlined,
7
  DownloadOutlined,
8
  EditOutlined,
 
9
  LinkOutlined,
10
  } from '@ant-design/icons';
11
  import { Button, Space, Tooltip } from 'antd';
12
- import { useHandleDeleteFile, useNavigateToDocument } from '../hooks';
13
 
 
 
 
14
  import styles from './index.less';
15
 
 
 
 
 
16
  interface IProps {
17
  record: IFile;
18
  setCurrentRecord: (record: any) => void;
@@ -35,7 +43,7 @@ const ActionCell = ({
35
  [documentId],
36
  setSelectedRowKeys,
37
  );
38
- const navigateToDocument = useNavigateToDocument(record.id, record.name);
39
 
40
  const onDownloadDocument = () => {
41
  downloadFile({
@@ -59,15 +67,6 @@ const ActionCell = ({
59
 
60
  return (
61
  <Space size={0}>
62
- {/* <Tooltip title={t('addToKnowledge')}>
63
- <Button
64
- type="text"
65
- className={styles.iconButton}
66
- onClick={navigateToDocument}
67
- >
68
- <EyeOutlined size={20} />
69
- </Button>
70
- </Tooltip> */}
71
  <Tooltip title={t('addToKnowledge')}>
72
  <Button
73
  type="text"
@@ -110,6 +109,18 @@ const ActionCell = ({
110
  </Button>
111
  </Tooltip>
112
  )}
 
 
 
 
 
 
 
 
 
 
 
 
113
  </Space>
114
  );
115
  };
 
6
  DeleteOutlined,
7
  DownloadOutlined,
8
  EditOutlined,
9
+ EyeOutlined,
10
  LinkOutlined,
11
  } from '@ant-design/icons';
12
  import { Button, Space, Tooltip } from 'antd';
13
+ import { useHandleDeleteFile } from '../hooks';
14
 
15
+ import NewDocumentLink from '@/components/new-document-link';
16
+ import { SupportedPreviewDocumentTypes } from '@/constants/common';
17
+ import { getExtension } from '@/utils/documentUtils';
18
  import styles from './index.less';
19
 
20
+ const isSupportedPreviewDocumentType = (fileExtension: string) => {
21
+ return SupportedPreviewDocumentTypes.includes(fileExtension);
22
+ };
23
+
24
  interface IProps {
25
  record: IFile;
26
  setCurrentRecord: (record: any) => void;
 
43
  [documentId],
44
  setSelectedRowKeys,
45
  );
46
+ const extension = getExtension(record.name);
47
 
48
  const onDownloadDocument = () => {
49
  downloadFile({
 
67
 
68
  return (
69
  <Space size={0}>
 
 
 
 
 
 
 
 
 
70
  <Tooltip title={t('addToKnowledge')}>
71
  <Button
72
  type="text"
 
109
  </Button>
110
  </Tooltip>
111
  )}
112
+ {isSupportedPreviewDocumentType(extension) && (
113
+ <NewDocumentLink
114
+ color="black"
115
+ link={`/document/${documentId}?ext=${extension}`}
116
+ >
117
+ <Tooltip title={t('preview')}>
118
+ <Button type="text" className={styles.iconButton}>
119
+ <EyeOutlined size={20} />
120
+ </Button>
121
+ </Tooltip>
122
+ </NewDocumentLink>
123
+ )}
124
  </Space>
125
  );
126
  };
web/src/pages/file-manager/hooks.ts CHANGED
@@ -13,7 +13,6 @@ import {
13
  import { useGetPagination, useSetPagination } from '@/hooks/logicHooks';
14
  import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
15
  import { IFile } from '@/interfaces/database/file-manager';
16
- import { getExtension } from '@/utils/documentUtils';
17
  import { PaginationProps } from 'antd';
18
  import { UploadFile } from 'antd/lib';
19
  import { useCallback, useEffect, useMemo, useState } from 'react';
@@ -339,12 +338,3 @@ export const useHandleBreadcrumbClick = () => {
339
 
340
  return { handleBreadcrumbClick };
341
  };
342
-
343
- export const useNavigateToDocument = (documentId: string, name: string) => {
344
- const navigate = useNavigate();
345
- const navigateToDocument = () => {
346
- navigate(`/document/${documentId}?ext=${getExtension(name)}`);
347
- };
348
-
349
- return navigateToDocument;
350
- };
 
13
  import { useGetPagination, useSetPagination } from '@/hooks/logicHooks';
14
  import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
15
  import { IFile } from '@/interfaces/database/file-manager';
 
16
  import { PaginationProps } from 'antd';
17
  import { UploadFile } from 'antd/lib';
18
  import { useCallback, useEffect, useMemo, useState } from 'react';
 
338
 
339
  return { handleBreadcrumbClick };
340
  };
 
 
 
 
 
 
 
 
 
web/src/pages/file-manager/index.tsx CHANGED
@@ -96,8 +96,8 @@ const FileManager = () => {
96
  },
97
  {
98
  title: t('uploadDate'),
99
- dataIndex: 'create_date',
100
- key: 'create_date',
101
  render(text) {
102
  return formatDate(text);
103
  },
 
96
  },
97
  {
98
  title: t('uploadDate'),
99
+ dataIndex: 'create_time',
100
+ key: 'create_time',
101
  render(text) {
102
  return formatDate(text);
103
  },
web/src/pages/knowledge/knowledge-card/index.tsx CHANGED
@@ -100,7 +100,7 @@ const KnowledgeCard = ({ item }: IProps) => {
100
  <div className={styles.bottomLeft}>
101
  <CalendarOutlined className={styles.leftIcon} />
102
  <span className={styles.rightText}>
103
- {formatDate(item.update_date)}
104
  </span>
105
  </div>
106
  {/* <Avatar.Group size={25}>
 
100
  <div className={styles.bottomLeft}>
101
  <CalendarOutlined className={styles.leftIcon} />
102
  <span className={styles.rightText}>
103
+ {formatDate(item.update_time)}
104
  </span>
105
  </div>
106
  {/* <Avatar.Group size={25}>
web/src/routes.ts CHANGED
@@ -88,12 +88,13 @@ const routes = [
88
  path: '/flow',
89
  component: '@/pages/flow',
90
  },
91
- {
92
- path: 'document/:id',
93
- component: '@/pages/document-viewer',
94
- },
95
  ],
96
  },
 
 
 
 
 
97
  {
98
  path: '/*',
99
  component: '@/pages/404',
 
88
  path: '/flow',
89
  component: '@/pages/flow',
90
  },
 
 
 
 
91
  ],
92
  },
93
+ {
94
+ path: 'document/:id',
95
+ component: '@/pages/document-viewer',
96
+ layout: false,
97
+ },
98
  {
99
  path: '/*',
100
  component: '@/pages/404',
web/src/utils/date.ts CHANGED
@@ -16,5 +16,5 @@ export function formatDate(date: any) {
16
  if (!date) {
17
  return '';
18
  }
19
- return dayjs(date).format('DD/MM/YYYY');
20
  }
 
16
  if (!date) {
17
  return '';
18
  }
19
+ return dayjs(date).format('DD/MM/YYYY HH:mm:ss');
20
  }