diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json
index 174d5c0a62..d0708c4bf9 100644
--- a/frontend/.eslintrc.json
+++ b/frontend/.eslintrc.json
@@ -18,7 +18,6 @@
"no-prototype-builtins": "off",
"no-restricted-globals": "off",
"brace-style": "off",
- "no-console": "off",
"no-cond-assign": "off",
"no-var": "off",
"no-case-declarations": "off",
diff --git a/frontend/src/components/dir-view-mode/dir-column-file.js b/frontend/src/components/dir-view-mode/dir-column-file.js
index c47eb884c5..54ec0a5170 100644
--- a/frontend/src/components/dir-view-mode/dir-column-file.js
+++ b/frontend/src/components/dir-view-mode/dir-column-file.js
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { SeafileMetadata } from '../../metadata';
import { Utils } from '../../utils/utils';
-import { gettext, siteRoot, lang, mediaUrl } from '../../utils/constants';
+import { gettext, siteRoot, mediaUrl } from '../../utils/constants';
import SeafileMarkdownViewer from '../seafile-markdown-viewer';
const propTypes = {
@@ -54,13 +54,8 @@ class DirColumnFile extends React.Component {
if (this.props.content === '__sf-metadata') {
const { repoID, currentRepoInfo, metadataViewId } = this.props;
- window.sfMetadata = {
- siteRoot,
- lang,
- mediaUrl,
- };
- return ();
+ return ();
}
return (
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 f056524dd2..bd5a0a419a 100644
--- a/frontend/src/metadata/metadata-view/_basic/constants/column/index.js
+++ b/frontend/src/metadata/metadata-view/_basic/constants/column/index.js
@@ -27,7 +27,10 @@ export {
export {
PRIVATE_COLUMN_KEY,
- PRIVATE_COLUMN_KEYS
+ PRIVATE_COLUMN_KEYS,
+ EDITABLE_PRIVATE_COLUMN_KEYS,
+ EDITABLE_DATA_PRIVATE_COLUMN_KEYS,
+ DELETABLE_PRIVATE_COLUMN_KEY,
} from './private';
export {
diff --git a/frontend/src/metadata/metadata-view/_basic/constants/column/private.js b/frontend/src/metadata/metadata-view/_basic/constants/column/private.js
index ef72ea42bc..be882e5fe0 100644
--- a/frontend/src/metadata/metadata-view/_basic/constants/column/private.js
+++ b/frontend/src/metadata/metadata-view/_basic/constants/column/private.js
@@ -46,3 +46,25 @@ export const PRIVATE_COLUMN_KEYS = [
PRIVATE_COLUMN_KEY.FILE_STATUS,
PRIVATE_COLUMN_KEY.LOCATION,
];
+
+export const EDITABLE_PRIVATE_COLUMN_KEYS = [
+ PRIVATE_COLUMN_KEY.FILE_COLLABORATORS,
+ PRIVATE_COLUMN_KEY.FILE_EXPIRE_TIME,
+ PRIVATE_COLUMN_KEY.FILE_KEYWORDS,
+ PRIVATE_COLUMN_KEY.FILE_SUMMARY,
+ PRIVATE_COLUMN_KEY.FILE_EXPIRED,
+ PRIVATE_COLUMN_KEY.FILE_STATUS,
+];
+
+export const EDITABLE_DATA_PRIVATE_COLUMN_KEYS = [
+
+];
+
+export const DELETABLE_PRIVATE_COLUMN_KEY = [
+ PRIVATE_COLUMN_KEY.FILE_COLLABORATORS,
+ PRIVATE_COLUMN_KEY.FILE_EXPIRE_TIME,
+ PRIVATE_COLUMN_KEY.FILE_KEYWORDS,
+ PRIVATE_COLUMN_KEY.FILE_SUMMARY,
+ PRIVATE_COLUMN_KEY.FILE_EXPIRED,
+ PRIVATE_COLUMN_KEY.FILE_STATUS,
+];
diff --git a/frontend/src/metadata/metadata-view/_basic/constants/index.js b/frontend/src/metadata/metadata-view/_basic/constants/index.js
index 7855f0d936..baf5d82c04 100644
--- a/frontend/src/metadata/metadata-view/_basic/constants/index.js
+++ b/frontend/src/metadata/metadata-view/_basic/constants/index.js
@@ -24,6 +24,9 @@ export {
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,
diff --git a/frontend/src/metadata/metadata-view/_basic/index.js b/frontend/src/metadata/metadata-view/_basic/index.js
index 1294ca30c0..3775b327bf 100644
--- a/frontend/src/metadata/metadata-view/_basic/index.js
+++ b/frontend/src/metadata/metadata-view/_basic/index.js
@@ -50,6 +50,9 @@ export {
NOT_DISPLAY_COLUMN_KEYS,
VIEW_NOT_DISPLAY_COLUMN_KEYS,
PREDEFINED_COLUMN_KEYS,
+ EDITABLE_PRIVATE_COLUMN_KEYS,
+ EDITABLE_DATA_PRIVATE_COLUMN_KEYS,
+ DELETABLE_PRIVATE_COLUMN_KEY,
} from './constants';
export {
diff --git a/frontend/src/metadata/metadata-view/_basic/utils/validate/filter.js b/frontend/src/metadata/metadata-view/_basic/utils/validate/filter.js
index 68b4f90d8d..46c556814e 100644
--- a/frontend/src/metadata/metadata-view/_basic/utils/validate/filter.js
+++ b/frontend/src/metadata/metadata-view/_basic/utils/validate/filter.js
@@ -8,6 +8,7 @@ import {
FILTER_ERR_MSG,
} from '../../constants/filter';
import { isDateColumn } from '../column/date';
+import { getColumnOptions } from '../column';
const TERM_TYPE_MAP = {
NUMBER: 'number',
@@ -16,6 +17,11 @@ const TERM_TYPE_MAP = {
ARRAY: 'array',
};
+const PREDICATES_REQUIRE_ARRAY_TERM = [
+ FILTER_PREDICATE_TYPE.IS_ANY_OF,
+ FILTER_PREDICATE_TYPE.IS_NONE_OF,
+];
+
const TEXT_COLUMN_TYPES = [CellType.TEXT, CellType.FILE_NAME];
const CHECK_EMPTY_PREDICATES = [FILTER_PREDICATE_TYPE.EMPTY, FILTER_PREDICATE_TYPE.NOT_EMPTY];
@@ -142,7 +148,7 @@ class ValidateFilter {
if (CHECK_EMPTY_PREDICATES.includes(predicate)) {
return true;
}
- if (array_type === CellType.SINGLE_SELECT || array_type === CellType.DEPARTMENT_SINGLE_SELECT) {
+ if (array_type === CellType.SINGLE_SELECT) {
return this.validatePredicate(predicate, { type: CellType.MULTIPLE_SELECT });
}
if (COLLABORATOR_COLUMN_TYPES.includes(array_type)) {
@@ -223,9 +229,13 @@ class ValidateFilter {
static isValidTerm(term, predicate, modifier, filterColumn) {
switch (filterColumn.type) {
case CellType.TEXT:
+ case CellType.GEOLOCATION:
case CellType.FILE_NAME: {
return this.isValidTermType(term, TERM_TYPE_MAP.STRING);
}
+ case CellType.NUMBER: {
+ return this.isValidTermType(term, TERM_TYPE_MAP.NUMBER);
+ }
case CellType.CHECKBOX:
case CellType.BOOL: {
@@ -244,6 +254,24 @@ class ValidateFilter {
}
return this.isValidTermType(term, TERM_TYPE_MAP.STRING);
}
+ case CellType.SINGLE_SELECT: {
+ const options = getColumnOptions(filterColumn);
+ if (PREDICATES_REQUIRE_ARRAY_TERM.includes(predicate)) {
+ if (!this.isValidTermType(term, TERM_TYPE_MAP.ARRAY)) {
+ return false;
+ }
+
+ // contains deleted option(s)
+ return this.isValidSelectedOptions(term, options);
+ }
+
+ if (!this.isValidTermType(term, TERM_TYPE_MAP.STRING)) {
+ return false;
+ }
+
+ // invalid filter_term if selected option is deleted
+ return !!options.find((option) => term === option.id);
+ }
default: {
return false;
}
diff --git a/frontend/src/metadata/metadata-view/components/cell-editor/file-name-editor.js b/frontend/src/metadata/metadata-view/components/cell-editor/file-name-editor.js
index 4d04cf9743..90ca378ecd 100644
--- a/frontend/src/metadata/metadata-view/components/cell-editor/file-name-editor.js
+++ b/frontend/src/metadata/metadata-view/components/cell-editor/file-name-editor.js
@@ -57,7 +57,7 @@ const FileNameEditor = ({ column, record, onCommitCancel }) => {
if (fileType === 'image') {
const fileExt = fileName.substr(fileName.lastIndexOf('.') + 1).toLowerCase();
const isGIF = fileExt === 'gif';
- const useThumbnail = window.sfMetadataContext.getSetting('currentRepoInfo')?.encrypted;
+ const useThumbnail = window.sfMetadataContext.getSetting('repoInfo')?.encrypted;
let src = '';
if (useThumbnail && !isGIF) {
src = `${siteRoot}thumbnail/${repoID}/${thumbnailSizeForOriginal}${path}`;
diff --git a/frontend/src/metadata/metadata-view/components/popover/column-popover/index.js b/frontend/src/metadata/metadata-view/components/popover/column-popover/index.js
index 858f012fa0..30de575607 100644
--- a/frontend/src/metadata/metadata-view/components/popover/column-popover/index.js
+++ b/frontend/src/metadata/metadata-view/components/popover/column-popover/index.js
@@ -2,7 +2,7 @@ import React, { useCallback, useMemo, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { Button, UncontrolledPopover } from 'reactstrap';
import classnames from 'classnames';
-import { CellType, DEFAULT_DATE_FORMAT } from '../../../_basic';
+import { CellType, DEFAULT_DATE_FORMAT, PRIVATE_COLUMN_KEY } from '../../../_basic';
import { gettext } from '../../../utils';
import ObjectUtils from '../../../utils/object-utils';
import { ValidateColumnFormFields } from './utils';
@@ -11,6 +11,7 @@ import { useMetadata } from '../../../hooks';
import Name from './name';
import Type from './type';
import Data from './data';
+import { getDefaultFileStatusOptions } from '../../../utils/column-utils';
import './index.css';
@@ -73,6 +74,10 @@ const ColumnPopover = ({ target, onChange }) => {
} else if (column.type === CellType.DATE) {
data = { format: DEFAULT_DATE_FORMAT };
}
+ } else {
+ if (column.type === CellType.SINGLE_SELECT && column.key === PRIVATE_COLUMN_KEY.FILE_STATUS) {
+ data = { options: getDefaultFileStatusOptions() };
+ }
}
}
onChange(columnName, column.type, { key: column.unique ? column.key : '', data });
diff --git a/frontend/src/metadata/metadata-view/components/popover/filter-popover/index.css b/frontend/src/metadata/metadata-view/components/popover/filter-popover/index.css
index 1ba5b5fe23..a8bf97c0de 100644
--- a/frontend/src/metadata/metadata-view/components/popover/filter-popover/index.css
+++ b/frontend/src/metadata/metadata-view/components/popover/filter-popover/index.css
@@ -1,4 +1,4 @@
-.filter-popover .popover {
+.sf-metadata-filter-popover .popover {
max-width: none;
min-width: 300px;
}
diff --git a/frontend/src/metadata/metadata-view/components/popover/filter-popover/index.js b/frontend/src/metadata/metadata-view/components/popover/filter-popover/index.js
index 88745738eb..4fc10d4c78 100644
--- a/frontend/src/metadata/metadata-view/components/popover/filter-popover/index.js
+++ b/frontend/src/metadata/metadata-view/components/popover/filter-popover/index.js
@@ -155,7 +155,7 @@ class FilterPopover extends Component {
target={target}
fade={false}
hideArrow={true}
- className="filter-popover"
+ className="sf-metadata-filter-popover"
boundariesElement={document.body}
>
{({ scheduleUpdate }) => (
@@ -180,7 +180,7 @@ class FilterPopover extends Component {
addIconClassName="popover-add-icon"
/>
{this.isNeedSubmit() && (
-
+
diff --git a/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-item-utils.js b/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-item-utils.js
index fac862b915..9360c46dd4 100644
--- a/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-item-utils.js
+++ b/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-item-utils.js
@@ -40,7 +40,7 @@ class FilterItemUtils {
{option.name}
- {selectedOption?.id === option.id && }
+ {selectedOption?.id === option.id && ()}
)
@@ -54,7 +54,7 @@ class FilterItemUtils {
{option.name}
- {filterTerm.indexOf(option.id) > -1 && }
+ {filterTerm.indexOf(option.id) > -1 && ()}
)
diff --git a/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-item/collaborator-filter/index.css b/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-item/collaborator-filter/index.css
new file mode 100644
index 0000000000..051577140d
--- /dev/null
+++ b/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-item/collaborator-filter/index.css
@@ -0,0 +1,13 @@
+.sf-metadata-selector-collaborator.sf-metadata-select .option {
+ line-height: 20px;
+ padding: 5px 10px 5px 10px !important;
+}
+
+.sf-metadata-selector-collaborator.sf-metadata-select .option:hover {
+ background-color: #f7f7f7;
+ color: #212529;
+}
+
+.sf-metadata-selector-collaborator.sf-metadata-select .selected-option-show {
+ text-overflow: clip;
+}
diff --git a/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/collaborator-filter.js b/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-item/collaborator-filter/index.js
similarity index 95%
rename from frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/collaborator-filter.js
rename to frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-item/collaborator-filter/index.js
index 26daa087ed..b96c2faf09 100644
--- a/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/collaborator-filter.js
+++ b/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/filter-item/collaborator-filter/index.js
@@ -1,8 +1,10 @@
import React, { Fragment, useMemo } from 'react';
import PropTypes from 'prop-types';
import { CustomizeSelect, Icon } from '@seafile/sf-metadata-ui-component';
-import { FILTER_PREDICATE_TYPE } from '../../../../_basic';
-import { gettext } from '../../../../utils';
+import { FILTER_PREDICATE_TYPE } from '../../../../../../_basic';
+import { gettext } from '../../../../../../utils';
+
+import './index.css';
const CollaboratorFilter = ({ isLocked, filterIndex, filterTerm, collaborators, placeholder, filter_predicate, onSelectCollaborator }) => {
const supportMultipleSelectOptions = useMemo(() => {
@@ -73,7 +75,7 @@ const CollaboratorFilter = ({ isLocked, filterIndex, filterTerm, collaborators,
return (
{
+ const collaborators = window.sfMetadata.collaborators;
+ const collaboratorsCache = window.sfMetadata.collaboratorsCache;
+ return [...collaborators, ...Object.values(collaboratorsCache)];
+ };
+
renderFilterTerm = (filterColumn) => {
const { index, filter, collaborators } = this.props;
const { type } = filterColumn;
@@ -410,6 +419,57 @@ class FilterItem extends React.Component {
case CellType.CHECKBOX: {
return this.getInputComponent('checkbox');
}
+ case CellType.SINGLE_SELECT: {
+ // get options
+ const options = getSelectColumnOptions(filterColumn);
+ if ([FILTER_PREDICATE_TYPE.IS_ANY_OF, FILTER_PREDICATE_TYPE.IS_NONE_OF].includes(filter_predicate)) {
+ return this.renderMultipleSelectOption(options, filter_term);
+ }
+ let selectedOptionDom = { label: null };
+ if (filter_term) {
+ let selectedOption = options.find(option => option.id === filter_term);
+ const className = 'select-option-name single-select-option';
+ const style = selectedOption ?
+ { background: selectedOption.color, color: selectedOption.textColor || null } :
+ { background: DELETED_OPTION_BACKGROUND_COLOR };
+ const selectedOptionName = selectedOption ? selectedOption.name : gettext('deleted option');
+ selectedOptionDom = { label: (
+ {selectedOptionName}
+ ) };
+ }
+
+ let dataOptions = options.map(option => {
+ return FilterItemUtils.generatorSingleSelectOption(option);
+ });
+
+ return (
+
+ );
+ }
+ case CellType.COLLABORATOR: {
+ if (filter_predicate === FILTER_PREDICATE_TYPE.INCLUDE_ME) return null;
+ const allCollaborators = this.getAllCollaborators();
+ return (
+
+ );
+ }
default: {
return null;
}
diff --git a/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/index.css b/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/index.css
index 39aa36be77..abf84abb67 100644
--- a/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/index.css
+++ b/frontend/src/metadata/metadata-view/components/popover/filter-popover/widgets/index.css
@@ -226,8 +226,8 @@
.filters-list .multiple-check-icon .sf-metadata-icon-check-mark,
.filters-list .collaborator-check-icon .sf-metadata-icon-check-mark {
+ fill: #798d99;
font-size: 12px;
- color: #798d99;
}
.user-select-item,
diff --git a/frontend/src/metadata/metadata-view/components/popover/index.css b/frontend/src/metadata/metadata-view/components/popover/index.css
index 15854b6c09..6e80d5ecd8 100644
--- a/frontend/src/metadata/metadata-view/components/popover/index.css
+++ b/frontend/src/metadata/metadata-view/components/popover/index.css
@@ -1,4 +1,4 @@
-.filter-popover-footer {
+.sf-metadata-filter-popover-footer {
display: flex;
align-items: center;
justify-content: flex-end;
@@ -25,6 +25,6 @@
fill: #c2c2c2;
}
-.filter-popover .popover-add-tool.disabled {
+.sf-metadata-filter-popover .popover-add-tool.disabled {
color: #c2c2c2;
}
diff --git a/frontend/src/metadata/metadata-view/components/popover/options-popover/index.css b/frontend/src/metadata/metadata-view/components/popover/options-popover/index.css
index d794abb766..6b033ca688 100644
--- a/frontend/src/metadata/metadata-view/components/popover/options-popover/index.css
+++ b/frontend/src/metadata/metadata-view/components/popover/options-popover/index.css
@@ -1,3 +1,9 @@
+.sf-metadata-edit-column-options-popover .popover {
+ margin-left: -4px;
+ margin-top: 4px;
+ max-width: 600px;
+}
+
.sf-metadata-edit-column-options-container {
min-width: 400px;
height: auto;
@@ -12,6 +18,13 @@
color: #212529;
}
+.sf-metadata-edit-column-options-container .none-search-result {
+ height: 100px;
+ opacity: .5;
+ padding: 10px;
+ width: 100%;
+}
+
.sf-metadata-edit-column-options-container .sf-metadata-select-options-list {
margin-bottom: 0;
margin-top: 1rem;
@@ -19,3 +32,13 @@
overflow: auto;
padding: 0;
}
+
+.sf-metadata-edit-column-options-container .sf-metadata-add-option {
+ border-top: none;
+ color: #666;
+}
+
+.sf-metadata-edit-column-options-container .sf-metadata-add-option .sf-metadata-add-option-icon {
+ fill: #666;
+ font-weight: 600;
+}
diff --git a/frontend/src/metadata/metadata-view/components/popover/options-popover/index.js b/frontend/src/metadata/metadata-view/components/popover/options-popover/index.js
index 538849b6b2..a68399c244 100644
--- a/frontend/src/metadata/metadata-view/components/popover/options-popover/index.js
+++ b/frontend/src/metadata/metadata-view/components/popover/options-popover/index.js
@@ -157,7 +157,7 @@ const OptionsPopover = ({ target, column, onToggle, onSubmit }) => {
<>
this.sortPopoverRef = ref} onClick={this.onPopoverInsideClick}>
@@ -264,7 +264,7 @@ class SortPopover extends Component {
/>
}
{(this.isNeedSubmit() && !readonly) && (
-
+
diff --git a/frontend/src/metadata/metadata-view/components/table/index.css b/frontend/src/metadata/metadata-view/components/table/index.css
index e7ab6bb39e..4051c37a21 100644
--- a/frontend/src/metadata/metadata-view/components/table/index.css
+++ b/frontend/src/metadata/metadata-view/components/table/index.css
@@ -49,122 +49,6 @@
box-shadow: inset 0 0 0 2px rgb(0 0 0 / 10%);
}
-.sf-metadata-wrapper .table-right-operations .new-record-btn button {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 23px;
- font-weight: 400;
- border-color: rgba(0, 0, 0, 0.05);
-}
-
-.sf-metadata-wrapper .table-right-operations .more-operation-add-record {
- padding: 0;
-}
-
-.sf-metadata-wrapper .table-right-operations .more-operation-add-record:not(:disabled):not(.disabled):active:focus {
- box-shadow: none;
-}
-
-.sf-metadata-wrapper .table-right-operations .more-operation-add-record .dropdown {
- display: inline-block;
- width: 100%;
- height: 100%;
-}
-
-.sf-metadata-wrapper .table-right-operations .add-record-dropdown-menu {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 100%;
- width: 100%;
-}
-
-.sf-metadata-dropdown-menu.add-record {
- margin-top: 4px;
-}
-
-.sf-metadata-wrapper .table-right-operations .more-operation-add-record .dropdown .sf-metadata-dropdown-menu {
- margin-top: 2px;
-}
-
-.sf-metadata-wrapper .table-right-operations .more-operation-add-record .toggle-icon {
- display: inline-block;
- font-size: 12px;
- transform: scale(0.8);
- margin-top: 1px;
-}
-
-.sf-metadata-wrapper .table-right-operations .new-record {
- font-size: 14px;
- line-height: 1.5rem;
-}
-
-.sf-metadata-wrapper .table-right-operations .table-search-box .input-icon-addon.search-poll-button {
- display: flex;
- right: 25px;
- height: 30px;
- line-height: 30px;
- left: auto;
- text-align: center;
- font-size: 12px;
- min-width: 35px;
- pointer-events: all;
-}
-
-.sf-metadata-wrapper .table-right-operations .table-search-box .search-poll-button .search-description {
- height: 30px;
- line-height: 30px;
- color: #666666;
-}
-
-.search-poll-button .sf-metadata-font {
- font-size: 12px;
- cursor: pointer;
- color: #212529;
-}
-
-.mobile-search-exchange-btn {
- width: 30px;
- height: 30px;
- line-height: 30px;
- background-color: #e5e5e5;
- color: #212529;
- display: block;
-}
-
-.mobile-search-exchange-btn:hover {
- background-color: #ededed;
- color: #666666;
-}
-
-.mobile-search-exchange-btn.mobile-search-upward {
- border-radius: 2px 0 0 2px;
- transform: scale(0.8, 0.8) translateX(8px);
-}
-
-.mobile-search-exchange-btn.mobile-search-backward {
- border-radius: 0 2px 2px 0;
- transform: scale(0.8, 0.8);
-}
-
-.search-text-clear {
- cursor: pointer;
- min-width: 25px;
- pointer-events: all;
- font-style: normal;
- font-size: 18px;
- font-weight: 700;
- text-align: center;
- line-height: 30px;
- height: 30px;
- color: #999;
-}
-
-.search-text-clear:hover {
- color: #212529;
-}
-
.sf-metadata-result.success {
display: flex;
flex-direction: column;
diff --git a/frontend/src/metadata/metadata-view/components/table/table-main/records/record/cell/index.js b/frontend/src/metadata/metadata-view/components/table/table-main/records/record/cell/index.js
index 92ca54138b..d2d4a7101e 100644
--- a/frontend/src/metadata/metadata-view/components/table/table-main/records/record/cell/index.js
+++ b/frontend/src/metadata/metadata-view/components/table/table-main/records/record/cell/index.js
@@ -28,13 +28,12 @@ const Cell = React.memo(({
const className = useMemo(() => {
const { type } = column;
const canEditable = window.sfMetadataContext.canModifyCell(column);
- return classnames('sf-metadata-result-table-cell', `sf-metadata-result-table-${type}-cell`, {
+ return classnames('sf-metadata-result-table-cell', `sf-metadata-result-table-${type}-cell`, highlightClassName, {
'table-cell-uneditable': !canEditable || !TABLE_SUPPORT_EDIT_TYPE_MAP[type],
- [highlightClassName]: highlightClassName,
'last-cell': isLastCell,
'table-last--frozen': isLastFrozenCell,
'cell-selected': isCellSelected,
- // 'draging-file-to-cell': ,
+ // 'dragging-file-to-cell': ,
// 'row-comment-cell': ,
});
}, [column, highlightClassName, isLastCell, isLastFrozenCell, isCellSelected]);
diff --git a/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/dropdown-item.js b/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/dropdown-item.js
index 155f4de4cd..4ce2033f0d 100644
--- a/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/dropdown-item.js
+++ b/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/dropdown-item.js
@@ -1,18 +1,28 @@
-import React, { useCallback } from 'react';
+import React, { useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { UncontrolledTooltip, DropdownItem } from 'reactstrap';
import classnames from 'classnames';
import { Icon } from '@seafile/sf-metadata-ui-component';
const ColumnDropdownItem = ({ disabled, iconName, target, title, tip, className, onChange, onMouseEnter }) => {
+ const [isShowToolTip, setToolTipShow] = useState(false);
+
+ useEffect(() => {
+ if (disabled) {
+ setToolTipShow(true);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
const onClick = useCallback((event) => {
event.preventDefault();
+ event.nativeEvent.stopImmediatePropagation();
+ event.stopPropagation();
}, []);
if (!disabled) {
return (
-
+
{title}
@@ -20,21 +30,23 @@ const ColumnDropdownItem = ({ disabled, iconName, target, title, tip, className,
}
return (
-
-
- {title}
- {disabled &&
-
- {tip}
-
- }
-
+ <>
+
+
+ {title}
+ {isShowToolTip && (
+
+ {tip}
+
+ )}
+
+ >
);
};
diff --git a/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/index.css b/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/index.css
index 008e3404d8..c8b46895c3 100644
--- a/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/index.css
+++ b/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/index.css
@@ -1,3 +1,7 @@
+.sf-metadata-column-dropdown-menu {
+ margin-top: 20px;
+}
+
.sf-metadata-column-dropdown-menu .dropdown-item .sf-metadata-icon {
margin-right: 10px;
font-size: 14px;
@@ -20,3 +24,18 @@
.sf-metadata-column-dropdown-menu .dropdown-toggle:hover::after {
color: #fff;
}
+
+.sf-metadata-column-dropdown-menu .dropdown-item.disabled,
+.sf-metadata-column-dropdown-menu .dropdown-item:disabled {
+ pointer-events: unset !important;
+}
+
+.sf-metadata-column-dropdown-menu .disabled.dropdown-item:hover {
+ background-color: unset;
+ cursor: default;
+ color: #c2c2c2;
+}
+
+.sf-metadata-column-dropdown-menu .disabled.dropdown-item .sf-metadata-icon {
+ fill: #c2c2c2;
+}
diff --git a/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/index.js b/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/index.js
index f95af5b0bb..3db9987281 100644
--- a/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/index.js
+++ b/frontend/src/metadata/metadata-view/components/table/table-main/records/records-header/cell/dropdown-menu/index.js
@@ -4,7 +4,6 @@ import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem as DefaultDropdown
import classnames from 'classnames';
import { ModalPortal, Icon } from '@seafile/sf-metadata-ui-component';
import { isMobile, gettext } from '../../../../../../../utils';
-import { isFrozen } from '../../../../../../../utils/column-utils';
import DropdownItem from './dropdown-item';
import { CellType, DEFAULT_DATE_FORMAT, getDateDisplayString } from '../../../../../../../_basic';
import { RenamePopover, OptionsPopover } from '../../../../../../popover';
@@ -153,15 +152,12 @@ const HeaderDropdownMenu = ({ column, renameColumn, modifyColumnData, deleteColu
}, [today, column, isMenuShow, isSubMenuShow, onChangeDateFormat, openSubMenu]);
const renderDropdownMenu = useCallback(() => {
- let menuStyle = { transform: 'none' };
const { type } = column;
- if (!isFrozen(column)) {
- menuStyle['top'] = -5; // - (container padding + menu margin)
- menuStyle['left'] = - (column.width - 30); // column width - container width - padding
- }
- const canModifyColumnData = window.sfMetadataContext.canModifyColumn(column);
+ const canModifyColumnData = window.sfMetadataContext.canModifyColumnData(column);
+ const canDeleteColumn = window.sfMetadataContext.canDeleteColumn(column);
+ const canRenameColumn = window.sfMetadataContext.canRenameColumn(column);
return (
-
+
{type === CellType.SINGLE_SELECT && (
<>
@@ -200,7 +196,7 @@ const HeaderDropdownMenu = ({ column, renameColumn, modifyColumnData, deleteColu
)}
{
if (isHideTriangle) return false;
- if (PRIVATE_COLUMN_KEYS.includes(column.key)) return false;
return window.sfMetadataContext.canModifyColumn(column);
}, [isHideTriangle, column]);
diff --git a/frontend/src/metadata/metadata-view/context.js b/frontend/src/metadata/metadata-view/context.js
index 14badafe18..eb81ccdbf1 100644
--- a/frontend/src/metadata/metadata-view/context.js
+++ b/frontend/src/metadata/metadata-view/context.js
@@ -1,5 +1,6 @@
import metadataAPI from '../api';
-import { UserService, LocalStorage } from './_basic';
+import { UserService, LocalStorage, PRIVATE_COLUMN_KEYS, EDITABLE_DATA_PRIVATE_COLUMN_KEYS,
+ EDITABLE_PRIVATE_COLUMN_KEYS, PREDEFINED_COLUMN_KEYS } from './_basic';
import EventBus from '../../components/common/event-bus';
import { username } from '../../utils/constants';
@@ -12,6 +13,7 @@ class Context {
this.userService = null;
this.eventBus = null;
this.hasInit = false;
+ this.permission = 'r';
}
async init({ otherSettings }) {
@@ -21,7 +23,7 @@ class Context {
this.settings = otherSettings || {};
// init metadataAPI
- const { mediaUrl } = this.settings;
+ const { mediaUrl, repoInfo } = this.settings;
this.metadataAPI = metadataAPI;
// init localStorage
@@ -34,6 +36,8 @@ class Context {
const eventBus = new EventBus();
this.eventBus = eventBus;
+ this.permission = repoInfo.permission !== 'admin' && repoInfo.permission !== 'rw' ? 'r' : 'rw';
+
this.hasInit = true;
}
@@ -44,6 +48,7 @@ class Context {
this.userService = null;
this.eventBus = null;
this.hasInit = false;
+ this.permission = 'r';
};
getSetting = (key) => {
@@ -81,22 +86,46 @@ class Context {
return this.metadataAPI.getView(repoID, viewId);
};
+ getPermission = () => {
+ return this.permission;
+ };
+
canModifyCell = (column) => {
+ if (this.permission === 'r') return false;
const { editable } = column;
if (!editable) return false;
return true;
};
canModifyRow = (row) => {
+ if (this.permission === 'r') return false;
return true;
};
canModifyColumn = (column) => {
+ if (this.permission === 'r') return false;
+ if (PRIVATE_COLUMN_KEYS.includes(column.key) && !EDITABLE_PRIVATE_COLUMN_KEYS.includes(column.key)) return false;
return true;
};
- getPermission = () => {
- return 'rw';
+ canRenameColumn = (column) => {
+ if (this.permission === 'r') return false;
+ if (PRIVATE_COLUMN_KEYS.includes(column.key)) return false;
+ return true;
+ };
+
+ canModifyColumnData = (column) => {
+ if (this.permission === 'r') return false;
+ const { key } = column;
+ if (PRIVATE_COLUMN_KEYS.includes(key)) return EDITABLE_DATA_PRIVATE_COLUMN_KEYS.includes(key);
+ return true;
+ };
+
+ canDeleteColumn = (column) => {
+ if (this.permission === 'r') return false;
+ const { key } = column;
+ if (PRIVATE_COLUMN_KEYS.includes(key)) return PREDEFINED_COLUMN_KEYS.includes(key);
+ return true;
};
getCollaboratorsFromCache = () => {
diff --git a/frontend/src/metadata/metadata-view/hooks/collaborators.js b/frontend/src/metadata/metadata-view/hooks/collaborators.js
index 9b6b935ba7..73df4a3e02 100644
--- a/frontend/src/metadata/metadata-view/hooks/collaborators.js
+++ b/frontend/src/metadata/metadata-view/hooks/collaborators.js
@@ -19,6 +19,12 @@ export const CollaboratorsProvider = ({
setCollaborators(store?.collaborators || []);
}, [store?.collaborators]);
+ useEffect(() => {
+ if (!window.sfMetadata) return;
+ window.sfMetadata.collaborators = collaborators;
+ window.sfMetadata.collaboratorsCache = collaboratorsCache;
+ }, [collaborators, collaboratorsCache]);
+
const updateCollaboratorsCache = useCallback((user) => {
const newCollaboratorsCache = { ...collaboratorsCacheRef.current, [user.email]: user };
collaboratorsCacheRef.current = newCollaboratorsCache;
diff --git a/frontend/src/metadata/metadata-view/hooks/metadata.js b/frontend/src/metadata/metadata-view/hooks/metadata.js
index aeb4a3d4cf..231d314c39 100644
--- a/frontend/src/metadata/metadata-view/hooks/metadata.js
+++ b/frontend/src/metadata/metadata-view/hooks/metadata.js
@@ -12,7 +12,6 @@ export const MetadataProvider = ({
children,
repoID,
viewID,
- currentRepoInfo,
...params
}) => {
const [isLoading, setLoading] = useState(true);
@@ -37,11 +36,11 @@ export const MetadataProvider = ({
setLoading(true);
// init context
const context = new Context();
+ window.sfMetadata = {};
window.sfMetadataContext = context;
window.sfMetadataContext.init({ otherSettings: params });
window.sfMetadataContext.setSetting('viewID', viewID);
window.sfMetadataContext.setSetting('repoID', repoID);
- window.sfMetadataContext.setSetting('currentRepoInfo', currentRepoInfo);
storeRef.current = new Store({ context: window.sfMetadataContext, repoId: repoID, viewId: viewID });
window.sfMetadataStore = storeRef.current;
storeRef.current.initStartIndex();
@@ -59,6 +58,7 @@ export const MetadataProvider = ({
const unsubscribeUpdateRows = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_TABLE_ROWS, updateMetadata);
return () => {
+ window.sfMetadata = {};
window.sfMetadataContext.destroy();
window.sfMetadataStore.destroy();
unsubscribeServerTableChanged();
@@ -67,7 +67,7 @@ export const MetadataProvider = ({
unsubscribeUpdateRows();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [repoID, viewID, currentRepoInfo]);
+ }, [repoID, viewID]);
return (
diff --git a/frontend/src/metadata/metadata-view/model/metadata/column.js b/frontend/src/metadata/metadata-view/model/metadata/column.js
index 0f8b001114..7083338f12 100644
--- a/frontend/src/metadata/metadata-view/model/metadata/column.js
+++ b/frontend/src/metadata/metadata-view/model/metadata/column.js
@@ -1,5 +1,5 @@
import { normalizeColumnData } from '../../utils/column-utils';
-import { CellType } from '../../_basic';
+import { CellType, PRIVATE_COLUMN_KEYS, EDITABLE_PRIVATE_COLUMN_KEYS } from '../../_basic';
class Column {
constructor(object) {
@@ -8,10 +8,15 @@ class Column {
this.type = object.type || '';
this.data = object.data || null;
this.width = object.width || 200;
- this.editable = object.editable || !this.key.startsWith('_') && this.type !== CellType.LONG_TEXT || false;
+ this.editable = this.enable_edit(this.key, this.type);
this.data = normalizeColumnData(this);
}
+ enable_edit = (key, type) => {
+ if (PRIVATE_COLUMN_KEYS.includes(key)) return EDITABLE_PRIVATE_COLUMN_KEYS.includes(key);
+ return type !== CellType.LONG_TEXT;
+ };
+
}
export default Column;
diff --git a/frontend/src/metadata/metadata-view/utils/column-utils.js b/frontend/src/metadata/metadata-view/utils/column-utils.js
index 6a7a3a4887..2678af898a 100644
--- a/frontend/src/metadata/metadata-view/utils/column-utils.js
+++ b/frontend/src/metadata/metadata-view/utils/column-utils.js
@@ -255,26 +255,25 @@ const getFileTypeColumnData = (column) => {
'_audio': { name: gettext('Audio'), color: '#FBD44A', textColor: '#FFFFFF', borderColor: '#E5C142', id: '_audio' },
'_code': { name: gettext('Code'), color: '#4ad8fb', textColor: '#FFFFFF', borderColor: '#4283e5', id: '_code' },
};
-
let newData = { ...data };
- newData.options = Array.isArray(newData.options) ? newData.options.map(o => {
- return { ..._OPTIONS[o.name] };
- }) : Object.keys(_OPTIONS);
+ newData.options = Array.isArray(data.options) ? data.options.map(o => {
+ return _OPTIONS[o.name];
+ }) : Object.values(_OPTIONS);
return newData;
};
+export const getDefaultFileStatusOptions = () => {
+ return [
+ { name: gettext('Draft'), color: '#EED5FF', textColor: '#202428', id: '_draft' },
+ { name: gettext('In review'), color: '#FFFDCF', textColor: '#202428', id: '_in_review' },
+ { name: gettext('Done'), color: '#59CB74', textColor: '#FFFFFF', borderColor: '#844BD2', id: '_done' },
+ ];
+};
+
const getFileStatusColumnData = (column) => {
const { data } = column;
- const _OPTIONS = {
- '_draft': { name: gettext('Draft'), color: '#EED5FF', textColor: '#202428', id: '_draft' },
- '_in_review': { name: gettext('In review'), color: '#FFFDCF', textColor: '#202428', id: '_in_review' },
- '_done': { name: gettext('Done'), color: '#59CB74', textColor: '#FFFFFF', borderColor: '#844BD2', id: '_done' },
- };
-
let newData = { ...data };
- newData.options = Array.isArray(newData.options) ? newData.options.map(o => {
- return { ..._OPTIONS[o.name] };
- }) : Object.keys(_OPTIONS);
+ newData.options = Array.isArray(data?.options) ? data.options : getDefaultFileStatusOptions();
return newData;
};
@@ -305,7 +304,6 @@ export const normalizeColumns = (columns) => {
type: columnType,
name: getColumnName(key, name),
width: columnsWidth[key] || 200,
- editable: !key.startsWith('_') && columnType !== CellType.LONG_TEXT
};
}).filter(column => !NOT_DISPLAY_COLUMN_KEYS.includes(column.key));
let displayColumns = [];
@@ -332,7 +330,6 @@ export function canEdit(col, record, enableCellSelect) {
if (col.editable != null && typeof (col.editable) === 'function') {
return enableCellSelect === true && col.editable(record);
}
- console.log(col);
return enableCellSelect === true && !!col.editable;
}