From fa6427f9dcea87ec29d6b530cd0b8c8b3b037ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=9B=BD=E7=92=87?= <37972689+YangGuoXuan-0503@users.noreply.github.com> Date: Fri, 30 Aug 2024 07:00:26 +0800 Subject: [PATCH] feat: metadata longtext editor (#6666) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: metadata longtext editor * feat: optimize code * feat: optimize code * feat: optimize code * feat: delete code * feat: update code * feat: update font * feat: update font * feat: optimize code --------- Co-authored-by: 杨国璇 --- frontend/package-lock.json | 16 +-- frontend/package.json | 4 +- .../components/dialog/insert-file-dialog.js | 2 +- .../src/components/dirent-detail/index.js | 3 +- .../_basic/constants/column/index.js | 6 + .../_basic/constants/column/limit.js | 16 +++ .../metadata-view/_basic/constants/index.js | 75 ++---------- .../metadata/metadata-view/_basic/index.js | 5 + .../_basic/utils/column/index.js | 4 + .../_basic/utils/column/long-text.js | 16 +++ .../metadata-view/_basic/utils/index.js | 2 + .../popup-editor-container.js | 2 +- .../components/cell-editor/editor.js | 18 +-- .../cell-editor/long-text-editor/api.js | 73 +++++++++++ .../cell-editor/long-text-editor/index.css | 3 + .../cell-editor/long-text-editor/index.js | 115 ++++++++++++++++++ .../components/detail-editor/index.js | 4 + .../detail-editor/long-text-editor/index.css | 9 ++ .../detail-editor/long-text-editor/index.js | 55 +++++++++ .../multiple-select-editor/index.js | 7 +- .../filter-popover/widgets/filter-calendar.js | 2 +- .../metadata-view/components/table/index.css | 25 +--- .../metadata-view/model/metadata/column.js | 4 +- .../metadata-view/utils/convert-utils.js | 18 +-- frontend/src/pages/markdown-editor/index.js | 4 +- media/css/seafile-editor-font/iconfont.eot | Bin 13872 -> 15104 bytes media/css/seafile-editor-font/iconfont.svg | 22 +++- media/css/seafile-editor-font/iconfont.ttf | Bin 13704 -> 14936 bytes media/css/seafile-editor-font/iconfont.woff | Bin 8276 -> 8940 bytes media/css/seafile-editor-font/iconfont.woff2 | Bin 7120 -> 7676 bytes .../seafile-editor-font.css | 56 ++++++--- 31 files changed, 414 insertions(+), 152 deletions(-) create mode 100644 frontend/src/metadata/metadata-view/_basic/constants/column/limit.js create mode 100644 frontend/src/metadata/metadata-view/_basic/utils/column/long-text.js create mode 100644 frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/api.js create mode 100644 frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/index.css create mode 100644 frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/index.js create mode 100644 frontend/src/metadata/metadata-view/components/detail-editor/long-text-editor/index.css create mode 100644 frontend/src/metadata/metadata-view/components/detail-editor/long-text-editor/index.js diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ebd3f2f40f..2b74c47a91 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -18,8 +18,8 @@ "@seafile/resumablejs": "1.1.16", "@seafile/sdoc-editor": "^1.0.64", "@seafile/seafile-calendar": "0.0.12", - "@seafile/seafile-editor": "1.0.109", - "@seafile/sf-metadata-ui-component": "^0.0.28", + "@seafile/seafile-editor": "1.0.114", + "@seafile/sf-metadata-ui-component": "^0.0.29", "@uiw/codemirror-extensions-langs": "^4.19.4", "@uiw/react-codemirror": "^4.19.4", "axios": "^1.7.4", @@ -4982,9 +4982,9 @@ } }, "node_modules/@seafile/seafile-editor": { - "version": "1.0.109", - "resolved": "https://registry.npmjs.org/@seafile/seafile-editor/-/seafile-editor-1.0.109.tgz", - "integrity": "sha512-zj5WiflAgiOpW6fXYigFSDB1XHYPHFxET7Gr3Dc0s3UA5S4Vexl9Yjf/oqX0HHu2jHX+fbtYkFoh/F29AGz39A==", + "version": "1.0.114", + "resolved": "https://registry.npmjs.org/@seafile/seafile-editor/-/seafile-editor-1.0.114.tgz", + "integrity": "sha512-4P7wJhNqK8WrJ1+8OPPo9mP/GNnfTv07bq6+B3DJ46syqIAJzy3KF7GC0enVfOaJm7jOEmwdvu3b00/a3ruBSw==", "dependencies": { "@seafile/react-image-lightbox": "2.0.5", "classnames": "2.3.2", @@ -5092,9 +5092,9 @@ } }, "node_modules/@seafile/sf-metadata-ui-component": { - "version": "0.0.28", - "resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.28.tgz", - "integrity": "sha512-jKrA6Q8q+8jS2sMVPEoddhRZ1rWpTL3zWyRryKvYlAPu7A2pW/uqlB9tyw1qumCwkhH8cYtjgKZzmD9pfeBmtQ==", + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.29.tgz", + "integrity": "sha512-sQwlqbdv2qJs/Qh+jyxtSJ57I+FeV51T7JwYXaL29VbB9EC9/Af6EfZ05wiPu+FH0aciNDa1thxQtj8l67JRLA==", "dependencies": { "@seafile/seafile-calendar": "0.0.24", "@seafile/seafile-editor": "~1.0.102", diff --git a/frontend/package.json b/frontend/package.json index 632c94c809..c8209deb42 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,8 +13,8 @@ "@seafile/resumablejs": "1.1.16", "@seafile/sdoc-editor": "^1.0.64", "@seafile/seafile-calendar": "0.0.12", - "@seafile/seafile-editor": "1.0.109", - "@seafile/sf-metadata-ui-component": "^0.0.28", + "@seafile/seafile-editor": "1.0.114", + "@seafile/sf-metadata-ui-component": "^0.0.29", "@uiw/codemirror-extensions-langs": "^4.19.4", "@uiw/react-codemirror": "^4.19.4", "axios": "^1.7.4", diff --git a/frontend/src/components/dialog/insert-file-dialog.js b/frontend/src/components/dialog/insert-file-dialog.js index 0a81f3faed..bd0a961df5 100644 --- a/frontend/src/components/dialog/insert-file-dialog.js +++ b/frontend/src/components/dialog/insert-file-dialog.js @@ -51,7 +51,7 @@ class InsertFileDialog extends React.Component { render() { const toggle = this.props.toggleCancel; return ( - + {gettext('Select File')} { @@ -12,7 +11,7 @@ const Index = React.memo(({ repoID, path, dirent, currentRepoInfo, repoTags, fil // init context const context = new MetadataContext(); window.sfMetadataContext = context; - window.sfMetadataContext.init({ repoID, mediaUrl, repoInfo: currentRepoInfo }); + window.sfMetadataContext.init({ repoID, repoInfo: currentRepoInfo }); return () => { window.sfMetadataContext.destroy(); delete window['sfMetadataContext']; diff --git a/frontend/src/metadata/metadata-view/_basic/constants/column/index.js b/frontend/src/metadata/metadata-view/_basic/constants/column/index.js index bd5a0a419a..77a673ced0 100644 --- a/frontend/src/metadata/metadata-view/_basic/constants/column/index.js +++ b/frontend/src/metadata/metadata-view/_basic/constants/column/index.js @@ -43,3 +43,9 @@ export { NOT_DISPLAY_COLUMN_KEYS, VIEW_NOT_DISPLAY_COLUMN_KEYS, } from './common'; + +export { + INPUT_LENGTH_LIMIT, + LONG_TEXT_EXCEED_LIMIT_MESSAGE, + LONG_TEXT_EXCEED_LIMIT_SUGGEST, +} from './limit'; diff --git a/frontend/src/metadata/metadata-view/_basic/constants/column/limit.js b/frontend/src/metadata/metadata-view/_basic/constants/column/limit.js new file mode 100644 index 0000000000..8a28b4b83b --- /dev/null +++ b/frontend/src/metadata/metadata-view/_basic/constants/column/limit.js @@ -0,0 +1,16 @@ +import CellType from './type'; +import { gettext } from '../../../../../utils/constants'; + +// text value limit +const _TEXT_MAX_LENGTH = 10000; + +// long-text value limit +export const _LONG_TEXT_MAX_LENGTH = 10 * 10000; + +export const INPUT_LENGTH_LIMIT = { + [CellType.TEXT]: _TEXT_MAX_LENGTH, + [CellType.LONG_TEXT]: _LONG_TEXT_MAX_LENGTH +}; + +export const LONG_TEXT_EXCEED_LIMIT_MESSAGE = gettext('The content of the document has exceeded the limit of 100000 characters, and the content cannot be saved'); +export const LONG_TEXT_EXCEED_LIMIT_SUGGEST = gettext('The content of the document has exceeded the limit of 100000 characters, and only the first 100000 characters are saved'); diff --git a/frontend/src/metadata/metadata-view/_basic/constants/index.js b/frontend/src/metadata/metadata-view/_basic/constants/index.js index baf5d82c04..ff0137fd3a 100644 --- a/frontend/src/metadata/metadata-view/_basic/constants/index.js +++ b/frontend/src/metadata/metadata-view/_basic/constants/index.js @@ -1,73 +1,14 @@ import KeyCodes from './key-codes'; import * as Z_INDEX from './z-index'; -export { - CellType, - COLUMNS_ICON_CONFIG, - COLUMNS_ICON_NAME, - COLLABORATOR_COLUMN_TYPES, - DATE_COLUMN_OPTIONS, - NUMERIC_COLUMNS_TYPES, - DEFAULT_DATE_FORMAT, - UTC_FORMAT_DEFAULT, - DATE_UNIT, - DATE_FORMAT_MAP, - DEFAULT_NUMBER_FORMAT, - DATE_DEFAULT_TYPES, - NOT_SUPPORT_EDIT_COLUMN_TYPE, - NOT_SUPPORT_EDIT_COLUMN_TYPE_MAP, - MULTIPLE_CELL_VALUE_COLUMN_TYPE_MAP, - SINGLE_CELL_VALUE_COLUMN_TYPE_MAP, - PRIVATE_COLUMN_KEY, - PRIVATE_COLUMN_KEYS, - NOT_DISPLAY_COLUMN_KEYS, - VIEW_NOT_DISPLAY_COLUMN_KEYS, - PREDEFINED_COLUMN_KEYS, - GEOLOCATION_FORMAT, - EDITABLE_PRIVATE_COLUMN_KEYS, - EDITABLE_DATA_PRIVATE_COLUMN_KEYS, - DELETABLE_PRIVATE_COLUMN_KEY, -} from './column'; -export { - FILTER_CONJUNCTION_TYPE, - FILTER_ERR_MSG, - FILTER_COLUMN_OPTIONS, - FILTER_TERM_MODIFIER_TYPE, - FILTER_TERM_MODIFIER_SHOW, - FILTER_PREDICATE_TYPE, - FILTER_PREDICATE_SHOW, - filterTermModifierIsWithin, - filterTermModifierNotWithin, -} from './filter'; -export { - MAX_GROUP_LEVEL, - GROUP_DATE_GRANULARITY, - DISPLAY_GROUP_DATE_GRANULARITY, - GROUP_GEOLOCATION_GRANULARITY, - DISPLAY_GROUP_GEOLOCATION_GRANULARITY, - SUPPORT_GROUP_COLUMN_TYPES, - GROUPBY_DATE_GRANULARITY_LIST, -} from './group'; -export { - HEADER_HEIGHT_TYPE -} from './grid-header'; -export { - REG_STRING_NUMBER_PARTS, - REG_NUMBER_DIGIT, -} from './reg'; -export { - SELECT_OPTION_COLORS, - HIGHLIGHT_COLORS, -} from './select-option'; -export { - SORT_TYPE, - SORT_COLUMN_OPTIONS, - TEXT_SORTER_COLUMN_TYPES, - NUMBER_SORTER_COLUMN_TYPES, -} from './sort'; -export { - DISPLAY_INTERNAL_ERRORS, -} from './error'; +export * from './column'; +export * from './filter'; +export * from './group'; +export * from './grid-header'; +export * from './reg'; +export * from './select-option'; +export * from './sort'; +export * from './error'; export { KeyCodes, diff --git a/frontend/src/metadata/metadata-view/_basic/index.js b/frontend/src/metadata/metadata-view/_basic/index.js index 79e4c2298c..457dcadf37 100644 --- a/frontend/src/metadata/metadata-view/_basic/index.js +++ b/frontend/src/metadata/metadata-view/_basic/index.js @@ -53,6 +53,9 @@ export { EDITABLE_PRIVATE_COLUMN_KEYS, EDITABLE_DATA_PRIVATE_COLUMN_KEYS, DELETABLE_PRIVATE_COLUMN_KEY, + INPUT_LENGTH_LIMIT, + LONG_TEXT_EXCEED_LIMIT_MESSAGE, + LONG_TEXT_EXCEED_LIMIT_SUGGEST, } from './constants'; export { @@ -156,4 +159,6 @@ export { getCellValueStringResult, getColumnOptionNamesByIds, getColumnOptionIdsByNames, + isLongTextValueExceedLimit, + getValidLongTextValue, } from './utils'; diff --git a/frontend/src/metadata/metadata-view/_basic/utils/column/index.js b/frontend/src/metadata/metadata-view/_basic/utils/column/index.js index b9abe07838..380fcaf2e9 100644 --- a/frontend/src/metadata/metadata-view/_basic/utils/column/index.js +++ b/frontend/src/metadata/metadata-view/_basic/utils/column/index.js @@ -23,4 +23,8 @@ export { generatorCellOption, generatorCellOptions, } from './option'; +export { + isLongTextValueExceedLimit, + getValidLongTextValue, +} from './long-text'; diff --git a/frontend/src/metadata/metadata-view/_basic/utils/column/long-text.js b/frontend/src/metadata/metadata-view/_basic/utils/column/long-text.js new file mode 100644 index 0000000000..3334957b58 --- /dev/null +++ b/frontend/src/metadata/metadata-view/_basic/utils/column/long-text.js @@ -0,0 +1,16 @@ +import { CellType, INPUT_LENGTH_LIMIT } from '../../constants/column'; + +export const isLongTextValueExceedLimit = (value) => { + const limit = INPUT_LENGTH_LIMIT[CellType.LONG_TEXT]; + const { text } = value; + return text ? text.length >= limit : false; +}; + +export const getValidLongTextValue = (value) => { + const limit = INPUT_LENGTH_LIMIT[CellType.LONG_TEXT]; + const newValue = { ...value }; + const { text, preview } = newValue; + newValue.text = text ? text.slice(0, limit) : ''; + newValue.preview = preview ? preview.slice(0, limit) : ''; + return newValue; +}; diff --git a/frontend/src/metadata/metadata-view/_basic/utils/index.js b/frontend/src/metadata/metadata-view/_basic/utils/index.js index 5fad636016..97980624c3 100644 --- a/frontend/src/metadata/metadata-view/_basic/utils/index.js +++ b/frontend/src/metadata/metadata-view/_basic/utils/index.js @@ -44,6 +44,8 @@ export { createOption, generatorCellOption, generatorCellOptions, + isLongTextValueExceedLimit, + getValidLongTextValue, } from './column'; export { getValidFilters, diff --git a/frontend/src/metadata/metadata-view/components/cell-editor/editor-container/popup-editor-container.js b/frontend/src/metadata/metadata-view/components/cell-editor/editor-container/popup-editor-container.js index 45c2d12792..9357cba1a9 100644 --- a/frontend/src/metadata/metadata-view/components/cell-editor/editor-container/popup-editor-container.js +++ b/frontend/src/metadata/metadata-view/components/cell-editor/editor-container/popup-editor-container.js @@ -59,7 +59,7 @@ class PopupEditorContainer extends React.Component { createEditor = () => { const { column, record, height, onPressTab, editorPosition, columns, modifyColumnData } = this.props; - const readOnly = canEditCell(column, record, true) || NOT_SUPPORT_EDITOR_COLUMN_TYPES.includes(column.type); + const readOnly = !canEditCell(column, record, true) || NOT_SUPPORT_EDITOR_COLUMN_TYPES.includes(column.type); const value = this.getInitialValue(readOnly); let editorProps = { diff --git a/frontend/src/metadata/metadata-view/components/cell-editor/editor.js b/frontend/src/metadata/metadata-view/components/cell-editor/editor.js index 506413d00e..1dd025508d 100644 --- a/frontend/src/metadata/metadata-view/components/cell-editor/editor.js +++ b/frontend/src/metadata/metadata-view/components/cell-editor/editor.js @@ -8,32 +8,36 @@ import NumberEditor from './number-editor'; import SingleSelectEditor from './single-select-editor'; import MultipleSelectEditor from './multiple-select-editor'; import CollaboratorEditor from './collaborator-editor'; +import LongTextEditor from './long-text-editor'; +import { lang } from '../../../../utils/constants'; // eslint-disable-next-line react/display-name const Editor = React.forwardRef((props, ref) => { switch (props.column.type) { case CellType.FILE_NAME: { - return (); + return (); } case CellType.TEXT: { - return (); + return (); } case CellType.DATE: { - const lang = window.sfMetadataContext.getSetting('lang'); - return (); + return (); } case CellType.NUMBER: { return (); } case CellType.SINGLE_SELECT: { - return (); + return (); } case CellType.MULTIPLE_SELECT: { - return (); + return (); } case CellType.COLLABORATOR: { - return (); + return (); + } + case CellType.LONG_TEXT: { + return (); } default: { return null; diff --git a/frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/api.js b/frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/api.js new file mode 100644 index 0000000000..6675457507 --- /dev/null +++ b/frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/api.js @@ -0,0 +1,73 @@ +import moment from 'moment'; +import { seafileAPI } from '../../../../../utils/seafile-api'; +import { Utils } from '../../../../../utils/utils'; + +const getImageFileNameWithTimestamp = () => { + var d = Date.now(); + return 'image-' + d.toString() + '.png'; +}; + +class LongtextAPI { + + constructor({ repoID, repoName, server }) { + const { name, username, contactEmail } = window.app.pageOptions; + this.repoID = repoID; + this.repoName = repoName; + this.server = server; + this.name = name; + this.contact_email = contactEmail; + this.userName = username; + this.relativePath = 'metadata'; + } + + _getImageURL(parentPath, fileName) { + return `${this.server}/lib/${this.repoID}/file/${parentPath}/${fileName}?raw=1`; + } + + uploadLocalImage = (imageFile) => { + const month = moment().format('YYYY-MM'); + const parentPath = `images/${this.relativePath}/${month}`; + return ( + seafileAPI.getFileServerUploadLink(this.repoID, '/').then((res) => { + const uploadLink = res.data + '?ret-json=1'; + const name = getImageFileNameWithTimestamp(); + const newFile = new File([imageFile], name, { type: imageFile.type }); + const formData = new FormData(); + formData.append('parent_dir', '/'); + formData.append('relative_path', parentPath); + formData.append('file', newFile); + return seafileAPI.uploadImage(uploadLink, formData); + }).then ((res) => { + return this._getImageURL(parentPath, res.data[0].name); + }) + ); + }; + + getFileURL(fileNode) { + if (fileNode.type !== 'file') { + return this.server + '/library/' + this.repoID + '/' + encodeURIComponent(this.repoName) + Utils.encodePath(fileNode.path()); + } + if (fileNode.isImage()) { + return this.server + '/lib/' + this.repoID + '/file' + Utils.encodePath(fileNode.path()) + '?raw=1'; + } + return this.server + '/lib/' + this.repoID + '/file' + Utils.encodePath(fileNode.path()); + } + + isInternalFileLink(url) { + var re = new RegExp(this.serviceUrl + '/lib/[0-9a-f-]{36}/file.*'); + return re.test(url); + } + + isInternalDirLink(url) { + // eslint-disable-next-line + var re = new RegExp(this.serviceUrl + '/library/' + '[0-9a-f\-]{36}.*'); + return re.test(url); + } + + markdownLint(slateValue) { + return seafileAPI.markdownLint(slateValue); + } + +} + +export default LongtextAPI; diff --git a/frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/index.css b/frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/index.css new file mode 100644 index 0000000000..739dd34b72 --- /dev/null +++ b/frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/index.css @@ -0,0 +1,3 @@ +.sf-metadata-long-text-editor-dialog { + z-index: 1049 !important; +} diff --git a/frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/index.js b/frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/index.js new file mode 100644 index 0000000000..7a520684fa --- /dev/null +++ b/frontend/src/metadata/metadata-view/components/cell-editor/long-text-editor/index.js @@ -0,0 +1,115 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { LongTextEditorDialog, getPreviewContent } from '@seafile/seafile-editor'; +import LongtextAPI from './api'; +import { getValidLongTextValue, isLongTextValueExceedLimit, LONG_TEXT_EXCEED_LIMIT_MESSAGE, + LONG_TEXT_EXCEED_LIMIT_SUGGEST, +} from '../../../_basic'; +import toaster from '../../../../../components/toast'; +import { lang, serviceURL } from '../../../../../utils/constants'; + +import './index.css'; + +class LongTextEditor extends React.PureComponent { + + constructor(props) { + super(props); + this.isLongTextValueChanged = false; + this.repoID = window.sfMetadataContext.getSetting('repoID'); + this.filePath = '/'; + const repoInfo = window.sfMetadataContext.getSetting('repoInfo'); + const { repo_name } = repoInfo; + this.api = new LongtextAPI({ repoID: this.repoID, repoName: repo_name, server: serviceURL }); + this.value = this.initEditorValue(); + } + + initEditorValue = () => { + const value = this.props.value; + if (value) { + if (typeof value === 'object') return value; + if (typeof value === 'string') { + if (value.length === 1) { + this.isLongTextValueChanged = true; + } + const { previewText, images, links, checklist } = getPreviewContent(value); + return Object.assign({}, { text: value, preview: previewText, images, links, checklist }); + } + // When typing fast in a long text, first keystroke should be saved + if (typeof value === 'string' && value.length === 1) { + this.isLongTextValueChanged = true; + return { text: value, preview: value, links: [], images: [] }; + } + } + + return { text: '', preview: '', links: [], images: [], checklist: { completed: 0, count: 0 } }; + }; + + getValue = () => { + const updated = {}; + updated[this.props.column.key] = this.value.text; + return updated; + }; + + onEditorValueChanged = (value) => { + this.value = value; + this.isLongTextValueChanged = true; + }; + + onSaveEditorValue = (value) => { + if (isLongTextValueExceedLimit(value)) { + toaster.closeAll(); + toaster.danger(LONG_TEXT_EXCEED_LIMIT_MESSAGE, { duration: null }); + return; + } + this.props.onCommit(value?.text); + this.isLongTextValueChanged = false; + }; + + onCloseEditorDialog = () => { + const { readOnly } = this.props; + if (!readOnly && this.isLongTextValueChanged) { + if (isLongTextValueExceedLimit(this.value)) { + toaster.closeAll(); + toaster.warning(LONG_TEXT_EXCEED_LIMIT_SUGGEST, { duration: null }); + this.value = getValidLongTextValue(this.value); + } + + this.props.onCommit(this.value?.text); + this.isLongTextValueChanged = false; + } + + this.props.onCommitCancel(); + }; + + render() { + const { column, readOnly } = this.props; + const headerName = column.name; + + return ( + + ); + } +} + +LongTextEditor.propTypes = { + readOnly: PropTypes.bool, + column: PropTypes.object, + onCommit: PropTypes.func, + onCommitCancel: PropTypes.func, +}; + +export default LongTextEditor; diff --git a/frontend/src/metadata/metadata-view/components/detail-editor/index.js b/frontend/src/metadata/metadata-view/components/detail-editor/index.js index 0adbf09e1f..637b57ddf5 100644 --- a/frontend/src/metadata/metadata-view/components/detail-editor/index.js +++ b/frontend/src/metadata/metadata-view/components/detail-editor/index.js @@ -8,6 +8,7 @@ import SingleSelectEditor from './single-select-editor'; import MultipleSelectEditor from './multiple-select-editor'; import CollaboratorEditor from './collaborator-editor'; import DateEditor from './date-editor'; +import LongTextEditor from './long-text-editor'; import { lang } from '../../../../utils/constants'; import './index.css'; @@ -39,6 +40,9 @@ const DetailEditor = ({ field, onChange: onChangeAPI, ...props }) => { case CellType.COLLABORATOR: { return (); } + case CellType.LONG_TEXT: { + return (); + } default: { return null; } diff --git a/frontend/src/metadata/metadata-view/components/detail-editor/long-text-editor/index.css b/frontend/src/metadata/metadata-view/components/detail-editor/long-text-editor/index.css new file mode 100644 index 0000000000..2ef56e158c --- /dev/null +++ b/frontend/src/metadata/metadata-view/components/detail-editor/long-text-editor/index.css @@ -0,0 +1,9 @@ +.sf-metadata-long-text-property-detail-editor { + min-height: 34px; + width: 100%; + padding: 7px 6px 0 6px; +} + +.sf-metadata-long-text-property-detail-editor .sf-metadata-property-detail-formatter { + line-height: 1.5; +} diff --git a/frontend/src/metadata/metadata-view/components/detail-editor/long-text-editor/index.js b/frontend/src/metadata/metadata-view/components/detail-editor/long-text-editor/index.js new file mode 100644 index 0000000000..e4d0760ec7 --- /dev/null +++ b/frontend/src/metadata/metadata-view/components/detail-editor/long-text-editor/index.js @@ -0,0 +1,55 @@ +import React, { useCallback, useState } from 'react'; +import PropTypes from 'prop-types'; +import { LongTextFormatter } from '@seafile/sf-metadata-ui-component'; +import Editor from '../../cell-editor/long-text-editor'; +import { gettext } from '../../../../../utils/constants'; + +import './index.css'; + +const LongTextEditor = ({ field, value: oldValue, onChange }) => { + const [value, setValue] = useState(oldValue); + const [showEditor, setShowEditor] = useState(false); + + const openEditor = useCallback(() => { + setShowEditor(true); + }, []); + + const onCommit = useCallback((newValue) => { + onChange && onChange(newValue); + setValue(newValue); + }, [onChange]); + + const onCommitCancel = useCallback(() => { + setShowEditor(false); + }, []); + + const isEmpty = !value || !value.trim(); + + return ( + <> +
+ {!isEmpty && ()} +
+ {showEditor && ( + + )} + + ); +}; + +LongTextEditor.propTypes = { + field: PropTypes.object.isRequired, + value: PropTypes.string, + onChange: PropTypes.func.isRequired, +}; + +export default LongTextEditor; diff --git a/frontend/src/metadata/metadata-view/components/detail-editor/multiple-select-editor/index.js b/frontend/src/metadata/metadata-view/components/detail-editor/multiple-select-editor/index.js index dbdf235a1a..d06fc2db4e 100644 --- a/frontend/src/metadata/metadata-view/components/detail-editor/multiple-select-editor/index.js +++ b/frontend/src/metadata/metadata-view/components/detail-editor/multiple-select-editor/index.js @@ -8,7 +8,7 @@ import DeleteOptions from '../../cell-editor/multiple-select-editor/delete-optio import './index.css'; -const MultipleSelectEditor = ({ field, value, record, fields, onChange, modifyColumnData }) => { +const MultipleSelectEditor = ({ field, value, onChange, modifyColumnData }) => { const ref = useRef(null); const [showEditor, setShowEditor] = useState(false); const options = useMemo(() => getColumnOptions(field), [field]); @@ -75,14 +75,12 @@ const MultipleSelectEditor = ({ field, value, record, fields, onChange, modifyCo saveImmediately={true} value={value} column={{ ...field, width: Math.max(width - 2, 200) }} - columns={fields} modifyColumnData={modifyColumnData} - record={record} onCommit={onCommit} /> ); - }, [showEditor, onCommit, record, value, modifyColumnData, fields, field]); + }, [showEditor, onCommit, value, modifyColumnData, field]); const isEmpty = useMemo(() => { if (!Array.isArray(value) || value.length === 0) return true; @@ -108,6 +106,7 @@ MultipleSelectEditor.propTypes = { field: PropTypes.object.isRequired, value: PropTypes.array, onChange: PropTypes.func.isRequired, + modifyColumnData: PropTypes.func, }; export default MultipleSelectEditor; diff --git a/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-calendar.js b/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-calendar.js index 4ad5fc8e14..c772349966 100644 --- a/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-calendar.js +++ b/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-calendar.js @@ -2,10 +2,10 @@ import React from 'react'; import PropTypes from 'prop-types'; import { SfFilterCalendar } from '@seafile/sf-metadata-ui-component'; import { getDateColumnFormat } from '../../../../utils/column-utils'; +import { lang } from '../../../../../../utils/constants'; const FilterCalendar = ({ value, filterColumn, readOnly, onChange }) => { const format = getDateColumnFormat(filterColumn).trim(); - const lang = window.sfMetadataContext.getSetting('lang'); return ( { if (PRIVATE_COLUMN_KEYS.includes(key)) return EDITABLE_PRIVATE_COLUMN_KEYS.includes(key); - return type !== CellType.LONG_TEXT; + return true; }; } diff --git a/frontend/src/metadata/metadata-view/utils/convert-utils.js b/frontend/src/metadata/metadata-view/utils/convert-utils.js index c69f4bdc47..923c5fb5dd 100644 --- a/frontend/src/metadata/metadata-view/utils/convert-utils.js +++ b/frontend/src/metadata/metadata-view/utils/convert-utils.js @@ -1,7 +1,6 @@ import { CellType, DEFAULT_DATE_FORMAT, generatorCellOption, getCollaboratorsName, getOptionName, getDateDisplayString, PREDEFINED_COLUMN_KEYS, getFloatNumber, getNumberDisplayString, formatStringToNumber, isNumber, getColumnOptions, - generatorCellOptions, - getColumnOptionNamesByIds, + generatorCellOptions, getColumnOptionNamesByIds, isLongTextValueExceedLimit, getValidLongTextValue, } from '../_basic'; import { formatTextToDate } from './date'; @@ -133,21 +132,6 @@ function convert2SingleSelect(cellValue, oldCellValue, fromColumn, targetColumn) return PREDEFINED_COLUMN_KEYS.includes(targetColumn.key) ? newOption.id : newOption.name; } -const LONG_TEXT_LENGTH_LIMIT = 10 * 10000; - -export const isLongTextValueExceedLimit = (value) => { - const { text } = value; - return text ? text.length >= LONG_TEXT_LENGTH_LIMIT : false; -}; - -export const getValidLongTextValue = (value) => { - const newValue = { ...value }; - const { text, preview } = newValue; - newValue.text = text ? text.slice(0, LONG_TEXT_LENGTH_LIMIT) : ''; - newValue.preview = preview ? preview.slice(0, LONG_TEXT_LENGTH_LIMIT) : ''; - return newValue; -}; - function convert2LongText(cellValue, oldCellValue, fromColumn) { const { type: fromColumnType, data: fromColumnData } = fromColumn; switch (fromColumnType) { diff --git a/frontend/src/pages/markdown-editor/index.js b/frontend/src/pages/markdown-editor/index.js index 99d974cc02..60f7230367 100644 --- a/frontend/src/pages/markdown-editor/index.js +++ b/frontend/src/pages/markdown-editor/index.js @@ -460,7 +460,7 @@ class MarkdownEditor extends React.Component { onSave={this.onSaveEditorContent} onContentChanged={this.onContentChanged} mathJaxSource={mediaUrl + 'js/mathjax/tex-svg.js'} - isSupportInsertSeafileImage={true} + // isSupportInsertSeafileImage={true} > @@ -470,7 +470,7 @@ class MarkdownEditor extends React.Component { isFetching={loading} value={markdownContent} mathJaxSource={mediaUrl + 'js/mathjax/tex-svg.js'} - isSupportInsertSeafileImage={true} + // isSupportInsertSeafileImage={true} isShowOutline={true} > diff --git a/media/css/seafile-editor-font/iconfont.eot b/media/css/seafile-editor-font/iconfont.eot index a948870c6cb20ea52f681a5b86168ff2ac298b67..6b358c0c8661ff6f843d1143303a346645ea7d96 100644 GIT binary patch delta 2517 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 diff --git a/media/css/seafile-editor-font/iconfont.svg b/media/css/seafile-editor-font/iconfont.svg index 47f3df843c..9920f9e4f3 100644 --- a/media/css/seafile-editor-font/iconfont.svg +++ b/media/css/seafile-editor-font/iconfont.svg @@ -14,6 +14,24 @@ /> + + + + + + + + + + + + + + + + + + @@ -24,16 +42,12 @@ - - - - diff --git a/media/css/seafile-editor-font/iconfont.ttf b/media/css/seafile-editor-font/iconfont.ttf index a5cbc33e0315338e1ffd85417b5d802d2d351337..fc687b61d11725fe95bda7598d8bcb94d08b6890 100644 GIT binary patch delta 2540 zcmaKte{54#6vxkbuj^ae^~cutUZK*iYu8S;b&PdufekX!#e^Wgf9Mc&wJU7Wu5&9o z5Z5U}2>uAMQKN~bg7F7`7!nfv2NQyZ_=g%2@J9$i1bvzX4T(rJaj%~H?$D^jmwfK` zocrV4+k4NwJ-GAh!r_Kua>Zr=JKrD80|-|DOlNjvcW=M(jEDf$0e~nB zWm1FlEuTJ1eW@MdLsTJsD}F%sDWY*GSD3h2UHOILT_^u$HlI#)e9?0SKzfV(y}8uH zD6WFj)INv&z(^{WDY}mK90%wM(4;#?^W%j#U)r_;AaRiV&w-{Erz%sh)g)GatK2eK zS*J7sMX(r_KsWSI6bndD1!js*>qqm^r$j7L_Zk+0 z9f$Gtu<#uAJG3SaTbj0#!%E8bPWd_r0Y1~Bwfz|7ZgF;Kn?-5 zq?@lJ2YjR{4){qQ=0H7ZngapSK@K#KW;hTe-Ohm!=?)Gwk`8eoOj;bKf&jMVk8pr( z`A!bpO`7Gve9{~Tnn_1E&_YT#iUF;pqa30=y-kv`6WPSObubdm1nK%8_BhtdwTCpeUVpzY;QDuVVThmsPsNp}8|wCZkh=qMPJ zsh~}9C}%-?ibL58+S44$W6<_-D5F7phC{gx+I|jYIcNtsEZ>c9BOHQv;Vk@!WB3N1 z6Pk;{LE&eySG;7BO-D@Et6Hl*F*lkYG+&Tfr5B}3)t%L^Ro}8Ku}oS{Syx*>w*_sJ zwvTPU)lAz}`THTMMZ{pFtF|-VjUB2|E1N^)FGcSA zkbD7B{hRlPBa!g_&HZN#b9rwrf7GEUj-*qToyor}aUjx2oj#^cjS<6qcwau(yL`s3 zIMB`d7WJPT3cmjLAhuF^m`(T{-ExKHH_B>9yfYFCIYoq}JPxvuyHCt4lt$8c@k!ceeX z){oOWz#b%HY>JJwpz2^_+c1IgJB$@p>BrsejlqR7uB8WskKHIt7uow|L5~F`3pQD3 z^fX42`bDGAZ}g#y6(39zm87{T@hablZ;B1HPtC9#`hhO8yCXh( zTJf$nY{8(J4o!6%XGnW!cyzREL&M}1=|pdLV%0R365w_(m5uGjWyq>SqGI&@D;r8` zL%=<(`bD37Uh(^j?m$5H)ccils?VnilIk~F1M+!yp#BHd?^lQ20lz9zSLL&a_p~=c zMbR6$c=pw!gCj>JrfW}HHd?&$yeLJp@6-&13)lUr){jZR4xi=+>* z60aC`U^x@fX!ye@@#L4yFT2~EHG=EV_O~sPQAq{%-r0r|d!(<#6VKb)g%iKq+rzlD z)EvuZa1k!XCD@HUlsn77HkcVtj}4C&hVvt)Tz)KL863-xMhEkck5s2qW0^v9*Ck!#2?260F8}}l delta 1320 zcmY+DOKcle6o&shGl`#Z?AT37A;eB%r-dYK0c3+(AHEanzc`Pvh_ zc8g>RobcQW>g@#S1; z(GFkEehchdXVZM8e7t%q_3#FpIR-e>M$eL*EM+ z`i|>^chj8|n)Rj_6TMCM8G+T{J}c-BE}xi&9pFAMuov7H1a^h{qQL%eUlQP>?Uy+a z{b$@)1O(`5L2u7}RX`j4nt%{}SU@{HBOpw_E+9hB3h1EU5D=x02sUC2jtba8&k5+H za{_kKZwlbM;?4``q89}0q8A15QM*e59-;FBy6J*|N9ng<>jCIt^0t6DeM~@tE(++S zO9J}nWdZ$kSwNDm2uRWI2pFJO1nj1d3)o{bs0w(DJ|W<7`lNtC`jmhnx+Y+lJ}qD` zeMZ1O`mBKcG{062M(A?_()4@8=73Qh2>J!&aRk>@r}|FaHoV3s#+Dg3$IU;ij8(DR zmhqM^TK;Z5)cUo@>zVSbd4BQEdAEF{zBS)(e!u@-V0YmCz>VP3!E0?3ZN)Y>lnt$i z?zOMAe;*zU7sEFqosreZosP}ubo8Ux#rjI{ck@YpIsCLgH*)$FOD1|#qX$%GWT)y3 zDRb%mXje}}<->a;YAIsGFC>O_5ZV4TIur-$6XE^FK`C(QK>?K+R(*-ykYa@qBdum) z=0NxTsqO(Yre=0z*VS}%B-xjaZC{DjPj;k}D&t%^P*iZvj*a`g^SPD9>d=Xb^W#|3 V?^{?YSB4hKrq00G4S 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 TfADN`hpc1wN%9+Nc+))qV0lBO delta 7854 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 MpzgEmH~6@?@*k}N$^ZZW diff --git a/media/css/seafile-editor-font/iconfont.woff2 b/media/css/seafile-editor-font/iconfont.woff2 index 11d8f109e6bb2444f5371910a81b1a6a82019f99..536312e969a3865d5ec1ed4299e1efd4bb70a44d 100644 GIT binary patch literal 7676 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