mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-04 16:31:13 +00:00
feat: metadata view permission (#6500)
Co-authored-by: 杨国璇 <ygx@Hello-word.local>
This commit is contained in:
@@ -7,7 +7,9 @@ import { getValidFilters, CommonlyUsedHotkey } from '../../_basic';
|
||||
import { gettext } from '../../../../utils/constants';
|
||||
import { FilterPopover } from '../popover';
|
||||
|
||||
const FilterSetter = ({ columns,
|
||||
const FilterSetter = ({
|
||||
readOnly,
|
||||
columns,
|
||||
wrapperClass,
|
||||
filters: propsFilters,
|
||||
isNeedSubmit,
|
||||
@@ -67,6 +69,7 @@ const FilterSetter = ({ columns,
|
||||
placement="bottom-end"
|
||||
filtersClassName={filtersClassName}
|
||||
target={target}
|
||||
readOnly={readOnly}
|
||||
isNeedSubmit={isNeedSubmit}
|
||||
columns={columns}
|
||||
collaborators={collaborators}
|
||||
@@ -83,6 +86,7 @@ const FilterSetter = ({ columns,
|
||||
};
|
||||
|
||||
FilterSetter.propTypes = {
|
||||
readOnly: PropTypes.bool,
|
||||
wrapperClass: PropTypes.string,
|
||||
filtersClassName: PropTypes.string,
|
||||
target: PropTypes.string,
|
||||
|
@@ -6,7 +6,7 @@ import { CommonlyUsedHotkey, getValidGroupbys, SUPPORT_GROUP_COLUMN_TYPES } from
|
||||
import { gettext } from '../../utils';
|
||||
import { GroupbysPopover } from '../popover';
|
||||
|
||||
const GroupbySetter = ({ columns: allColumns, groupbys: propsGroupbys, wrapperClass, target, modifyGroupbys }) => {
|
||||
const GroupbySetter = ({ columns: allColumns, readOnly, groupbys: propsGroupbys, wrapperClass, target, modifyGroupbys }) => {
|
||||
const [isShowSetter, setShowSetter] = useState(false);
|
||||
|
||||
const columns = useMemo(() => {
|
||||
@@ -56,6 +56,7 @@ const GroupbySetter = ({ columns: allColumns, groupbys: propsGroupbys, wrapperCl
|
||||
/>
|
||||
{isShowSetter && (
|
||||
<GroupbysPopover
|
||||
readOnly={readOnly}
|
||||
groupbys={groupbys}
|
||||
target={target}
|
||||
placement="bottom-end"
|
||||
@@ -75,6 +76,7 @@ GroupbySetter.defaultProps = {
|
||||
};
|
||||
|
||||
GroupbySetter.propTypes = {
|
||||
readOnly: PropTypes.bool,
|
||||
wrapperClass: PropTypes.string,
|
||||
columns: PropTypes.array,
|
||||
groupbys: PropTypes.array, // valid groupbys
|
||||
|
@@ -6,7 +6,7 @@ import { CommonlyUsedHotkey } from '../../_basic';
|
||||
import { gettext } from '../../utils';
|
||||
import { HideColumnPopover } from '../popover';
|
||||
|
||||
const HideColumnSetter = ({ columns, wrapperClass, target, hiddenColumns, modifyHiddenColumns }) => {
|
||||
const HideColumnSetter = ({ readOnly, columns, wrapperClass, target, hiddenColumns, modifyHiddenColumns }) => {
|
||||
const [isShowSetter, setShowSetter] = useState(false);
|
||||
|
||||
const validHiddenColumns = useMemo(() => {
|
||||
@@ -50,6 +50,7 @@ const HideColumnSetter = ({ columns, wrapperClass, target, hiddenColumns, modify
|
||||
/>
|
||||
{isShowSetter && (
|
||||
<HideColumnPopover
|
||||
readOnly={readOnly}
|
||||
hiddenColumns={validHiddenColumns}
|
||||
target={target}
|
||||
placement="bottom-end"
|
||||
@@ -63,6 +64,7 @@ const HideColumnSetter = ({ columns, wrapperClass, target, hiddenColumns, modify
|
||||
};
|
||||
|
||||
HideColumnSetter.propTypes = {
|
||||
readOnly: PropTypes.bool,
|
||||
wrapperClass: PropTypes.string,
|
||||
target: PropTypes.string,
|
||||
hiddenColumns: PropTypes.array,
|
||||
|
@@ -6,7 +6,7 @@ import { getValidSorts, CommonlyUsedHotkey } from '../../_basic';
|
||||
import { gettext } from '../../utils';
|
||||
import { SortPopover } from '../popover';
|
||||
|
||||
const SortSetter = ({ target, sorts: propsSorts, columns, isNeedSubmit, wrapperClass, modifySorts }) => {
|
||||
const SortSetter = ({ target, sorts: propsSorts, readOnly, columns, isNeedSubmit, wrapperClass, modifySorts }) => {
|
||||
const [isShowSetter, setShowSetter] = useState(false);
|
||||
|
||||
const sorts = useMemo(() => {
|
||||
@@ -53,6 +53,7 @@ const SortSetter = ({ target, sorts: propsSorts, columns, isNeedSubmit, wrapperC
|
||||
{isShowSetter && (
|
||||
<SortPopover
|
||||
isNeedSubmit={isNeedSubmit}
|
||||
readOnly={readOnly}
|
||||
target={target}
|
||||
columns={columns}
|
||||
sorts={sorts}
|
||||
@@ -67,6 +68,7 @@ const SortSetter = ({ target, sorts: propsSorts, columns, isNeedSubmit, wrapperC
|
||||
|
||||
|
||||
const propTypes = {
|
||||
readOnly: PropTypes.bool,
|
||||
wrapperClass: PropTypes.string,
|
||||
target: PropTypes.string,
|
||||
isNeedSubmit: PropTypes.bool,
|
||||
|
@@ -145,7 +145,7 @@ class FilterPopover extends Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { target, columns, placement } = this.props;
|
||||
const { readOnly, target, columns, placement } = this.props;
|
||||
const { filters, filterConjunction } = this.state;
|
||||
const canAddFilter = columns.length > 0;
|
||||
return (
|
||||
@@ -169,17 +169,19 @@ class FilterPopover extends Component {
|
||||
deleteFilter={this.deleteFilter}
|
||||
updateFilterConjunction={this.updateFilterConjunction}
|
||||
collaborators={this.props.collaborators}
|
||||
readOnly={false}
|
||||
readOnly={readOnly}
|
||||
scheduleUpdate={scheduleUpdate}
|
||||
isPre={this.props.isPre}
|
||||
/>
|
||||
<CustomizeAddTool
|
||||
className={`popover-add-tool ${canAddFilter ? '' : 'disabled'}`}
|
||||
callBack={canAddFilter ? () => this.addFilter(scheduleUpdate) : () => {}}
|
||||
footerName={gettext('Add filter')}
|
||||
addIconClassName="popover-add-icon"
|
||||
/>
|
||||
{this.isNeedSubmit() && (
|
||||
{!readOnly && (
|
||||
<CustomizeAddTool
|
||||
className={`popover-add-tool ${canAddFilter ? '' : 'disabled'}`}
|
||||
callBack={canAddFilter ? () => this.addFilter(scheduleUpdate) : () => {}}
|
||||
footerName={gettext('Add filter')}
|
||||
addIconClassName="popover-add-icon"
|
||||
/>
|
||||
)}
|
||||
{!readOnly && this.isNeedSubmit() && (
|
||||
<div className='sf-metadata-filter-popover-footer'>
|
||||
<Button className='mr-2' onClick={this.onClosePopover}>{gettext('Cancel')}</Button>
|
||||
<Button color="primary" disabled={this.state.isSubmitDisabled} onClick={this.onSubmitFilters}>{gettext('Submit')}</Button>
|
||||
@@ -197,7 +199,7 @@ FilterPopover.propTypes = {
|
||||
filtersClassName: PropTypes.string,
|
||||
target: PropTypes.string.isRequired,
|
||||
isNeedSubmit: PropTypes.bool,
|
||||
isLocked: PropTypes.bool,
|
||||
readOnly: PropTypes.bool,
|
||||
columns: PropTypes.array.isRequired,
|
||||
filterConjunction: PropTypes.string,
|
||||
filters: PropTypes.array,
|
||||
|
@@ -3,12 +3,12 @@ import PropTypes from 'prop-types';
|
||||
import { SfFilterCalendar } from '@seafile/sf-metadata-ui-component';
|
||||
import { getDateColumnFormat } from '../../../../utils/column-utils';
|
||||
|
||||
const FilterCalendar = ({ value, filterColumn, isReadOnly, onChange }) => {
|
||||
const FilterCalendar = ({ value, filterColumn, readOnly, onChange }) => {
|
||||
const format = getDateColumnFormat(filterColumn).trim();
|
||||
const lang = window.sfMetadataContext.getSetting('lang');
|
||||
return (
|
||||
<SfFilterCalendar
|
||||
isReadOnly={isReadOnly}
|
||||
isReadOnly={readOnly}
|
||||
format={format}
|
||||
lang={lang}
|
||||
value={value}
|
||||
@@ -22,7 +22,7 @@ FilterCalendar.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
filterColumn: PropTypes.object.isRequired,
|
||||
isReadOnly: PropTypes.bool,
|
||||
readOnly: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default FilterCalendar;
|
||||
|
@@ -6,7 +6,7 @@ import { gettext } from '../../../../../../utils';
|
||||
|
||||
import './index.css';
|
||||
|
||||
const CollaboratorFilter = ({ isLocked, filterIndex, filterTerm, collaborators, placeholder, filter_predicate, onSelectCollaborator }) => {
|
||||
const CollaboratorFilter = ({ readOnly, filterIndex, filterTerm, collaborators, placeholder, filter_predicate, onSelectCollaborator }) => {
|
||||
const supportMultipleSelectOptions = useMemo(() => {
|
||||
return [
|
||||
FILTER_PREDICATE_TYPE.HAS_ANY_OF,
|
||||
@@ -80,7 +80,7 @@ const CollaboratorFilter = ({ isLocked, filterIndex, filterTerm, collaborators,
|
||||
onSelectOption={onSelectCollaborator}
|
||||
options={options}
|
||||
placeholder={placeholder}
|
||||
isLocked={isLocked}
|
||||
readOnly={readOnly}
|
||||
supportMultipleSelect={isSupportMultipleSelect}
|
||||
searchable={true}
|
||||
searchPlaceholder={gettext('Search collaborator')}
|
||||
@@ -96,7 +96,7 @@ CollaboratorFilter.propTypes = {
|
||||
filter_predicate: PropTypes.string,
|
||||
collaborators: PropTypes.array,
|
||||
onSelectCollaborator: PropTypes.func,
|
||||
isLocked: PropTypes.bool,
|
||||
readOnly: PropTypes.bool,
|
||||
placeholder: PropTypes.string,
|
||||
};
|
||||
|
||||
|
@@ -25,6 +25,7 @@ import { DELETED_OPTION_BACKGROUND_COLOR, DELETED_OPTION_TIPS } from '../../../.
|
||||
import './index.css';
|
||||
|
||||
const propTypes = {
|
||||
readOnly: PropTypes.bool,
|
||||
index: PropTypes.number.isRequired,
|
||||
filter: PropTypes.object.isRequired,
|
||||
filterColumn: PropTypes.object.isRequired,
|
||||
@@ -245,6 +246,7 @@ class FilterItem extends React.Component {
|
||||
};
|
||||
|
||||
getInputComponent = (type) => {
|
||||
const { readOnly } = this.props;
|
||||
const { filterTerm } = this.state;
|
||||
if (type === 'text') {
|
||||
return (
|
||||
@@ -252,13 +254,16 @@ class FilterItem extends React.Component {
|
||||
value={filterTerm}
|
||||
onChange={this.onFilterTermTextChanged}
|
||||
autoFocus={false}
|
||||
disabled={readOnly}
|
||||
className='text-truncate'
|
||||
/>
|
||||
);
|
||||
} else if (type === 'checkbox') {
|
||||
const { readOnly } = this.props;
|
||||
return (
|
||||
<input
|
||||
type="checkbox"
|
||||
disabled={readOnly}
|
||||
checked={filterTerm}
|
||||
onChange={this.onFilterTermCheckboxChanged}
|
||||
/>
|
||||
@@ -267,7 +272,7 @@ class FilterItem extends React.Component {
|
||||
};
|
||||
|
||||
renderConjunction = () => {
|
||||
const { index, filterConjunction, conjunctionOptions } = this.props;
|
||||
const { index, readOnly, filterConjunction, conjunctionOptions } = this.props;
|
||||
switch (index) {
|
||||
case 0: {
|
||||
return null;
|
||||
@@ -276,6 +281,7 @@ class FilterItem extends React.Component {
|
||||
const activeConjunction = FilterItemUtils.getActiveConjunctionOption(filterConjunction);
|
||||
return (
|
||||
<CustomizeSelect
|
||||
readOnly={readOnly}
|
||||
value={activeConjunction}
|
||||
options={conjunctionOptions}
|
||||
onSelectOption={this.onSelectConjunction}
|
||||
@@ -356,7 +362,7 @@ class FilterItem extends React.Component {
|
||||
};
|
||||
|
||||
renderFilterTerm = (filterColumn) => {
|
||||
const { index, filter, collaborators } = this.props;
|
||||
const { index, filter, collaborators, readOnly } = this.props;
|
||||
const { type } = filterColumn;
|
||||
const { filter_term, filter_predicate, filter_term_modifier } = filter;
|
||||
// predicate is empty or not empty
|
||||
@@ -381,6 +387,7 @@ class FilterItem extends React.Component {
|
||||
if (filter_term_modifier === 'exact_date') {
|
||||
return (
|
||||
<FilterCalendar
|
||||
readOnly={readOnly}
|
||||
onChange={this.onFilterExactDateChanged}
|
||||
value={this.state.filterTerm}
|
||||
filterColumn={filterColumn}
|
||||
@@ -409,6 +416,7 @@ class FilterItem extends React.Component {
|
||||
const creators = collaborators;
|
||||
return (
|
||||
<CollaboratorFilter
|
||||
readOnly={readOnly}
|
||||
filterIndex={index}
|
||||
filterTerm={filter_term || []}
|
||||
collaborators={creators}
|
||||
@@ -444,6 +452,7 @@ class FilterItem extends React.Component {
|
||||
|
||||
return (
|
||||
<CustomizeSelect
|
||||
readOnly={readOnly}
|
||||
className="sf-metadata-selector-single-select"
|
||||
value={selectedOptionDom}
|
||||
options={dataOptions || []}
|
||||
@@ -461,6 +470,7 @@ class FilterItem extends React.Component {
|
||||
const allCollaborators = this.getAllCollaborators();
|
||||
return (
|
||||
<CollaboratorFilter
|
||||
readOnly={readOnly}
|
||||
filterIndex={index}
|
||||
filterTerm={filter_term || []}
|
||||
filter_predicate={filter_predicate}
|
||||
@@ -501,7 +511,7 @@ class FilterItem extends React.Component {
|
||||
|
||||
render() {
|
||||
const { filterPredicateOptions, filterTermModifierOptions } = this;
|
||||
const { filter, filterColumn, filterColumnOptions } = this.props;
|
||||
const { filter, filterColumn, filterColumnOptions, readOnly } = this.props;
|
||||
const { filter_predicate, filter_term_modifier } = filter;
|
||||
const activeColumn = FilterItemUtils.generatorColumnOption(filterColumn);
|
||||
const activePredicate = FilterItemUtils.generatorPredicateOption(filter_predicate);
|
||||
@@ -521,9 +531,11 @@ class FilterItem extends React.Component {
|
||||
|
||||
return (
|
||||
<div className="filter-item">
|
||||
<div className="delete-filter" onClick={this.onDeleteFilter}>
|
||||
<Icon iconName="fork-number"/>
|
||||
</div>
|
||||
{!readOnly && (
|
||||
<div className="delete-filter" onClick={this.onDeleteFilter}>
|
||||
<Icon iconName="fork-number"/>
|
||||
</div>
|
||||
)}
|
||||
<div className="condition">
|
||||
<div className="filter-conjunction">
|
||||
{this.renderConjunction()}
|
||||
@@ -531,6 +543,7 @@ class FilterItem extends React.Component {
|
||||
<div className="filter-container">
|
||||
<div className="filter-column">
|
||||
<CustomizeSelect
|
||||
readOnly={readOnly}
|
||||
value={activeColumn}
|
||||
options={filterColumnOptions}
|
||||
onSelectOption={this.onSelectColumn}
|
||||
@@ -541,6 +554,7 @@ class FilterItem extends React.Component {
|
||||
</div>
|
||||
<div className={`filter-predicate ml-2 ${_isCheckboxColumn ? 'filter-checkbox-predicate' : ''}`}>
|
||||
<CustomizeSelect
|
||||
readOnly={readOnly}
|
||||
value={activePredicate}
|
||||
options={filterPredicateOptions}
|
||||
onSelectOption={this.onSelectPredicate}
|
||||
@@ -549,6 +563,7 @@ class FilterItem extends React.Component {
|
||||
{isDateColumn(filterColumn) && isNeedShowTermModifier && (
|
||||
<div className="filter-term-modifier ml-2">
|
||||
<CustomizeSelect
|
||||
readOnly={readOnly}
|
||||
value={activeTermModifier}
|
||||
options={filterTermModifierOptions}
|
||||
onSelectOption={this.onSelectTermModifier}
|
||||
|
@@ -67,6 +67,10 @@
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.filters-list .sf-metadata-select.disabled .selected-option-show {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.filters-list .sf-metadata-select .selected-option {
|
||||
width: auto;
|
||||
overflow-x: auto;
|
||||
@@ -147,7 +151,7 @@
|
||||
border-color: rgb(179, 179, 179);
|
||||
}
|
||||
|
||||
.filters-list .filter-term input.disabled:hover {
|
||||
.filters-list .filter-term input:disabled:hover {
|
||||
border-color: rgba(0, 40, 100, 0.12);
|
||||
}
|
||||
|
||||
|
@@ -12,7 +12,7 @@ import FilterItem from './filter-item';
|
||||
import './index.css';
|
||||
|
||||
const propTypes = {
|
||||
isLocked: PropTypes.bool,
|
||||
readOnly: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
filters: PropTypes.array,
|
||||
columns: PropTypes.array.isRequired,
|
||||
@@ -81,13 +81,13 @@ class FiltersList extends Component {
|
||||
};
|
||||
|
||||
renderFilterItem = (filter, index, errMsg, filterColumn) => {
|
||||
const { filterConjunction, value } = this.props;
|
||||
const { readOnly, filterConjunction, value } = this.props;
|
||||
const conjunctionOptions = this.getConjunctionOptions();
|
||||
const columnOptions = this.getColumnOptions();
|
||||
return (
|
||||
<FilterItem
|
||||
key={index}
|
||||
isLocked={this.props.isLocked}
|
||||
readOnly={readOnly}
|
||||
index={index}
|
||||
filter={filter}
|
||||
errMsg={errMsg}
|
||||
|
@@ -60,7 +60,7 @@ const dropCollect = (connect, monitor) => ({
|
||||
*/
|
||||
const GroupbyItem = memo(({
|
||||
isOver, isDragging, canDrop, connectDragSource, connectDragPreview, connectDropTarget,
|
||||
showDragBtn, index, groupby, columns, onDelete, onUpdate
|
||||
showDragBtn, index, readOnly, groupby, columns, onDelete, onUpdate
|
||||
}) => {
|
||||
const column = useMemo(() => {
|
||||
return getColumnByKey(columns, groupby.column_key);
|
||||
@@ -162,12 +162,15 @@ const GroupbyItem = memo(({
|
||||
{ 'group-can-drop': isOver && canDrop && !isDragging }
|
||||
)}
|
||||
>
|
||||
<div className="delete-groupby" onClick={deleteGroupby} aria-label={gettext('Delete')}>
|
||||
<Icon iconName="fork-number"/>
|
||||
</div>
|
||||
{!readOnly && (
|
||||
<div className="delete-groupby" onClick={deleteGroupby} aria-label={gettext('Delete')}>
|
||||
<Icon iconName="fork-number"/>
|
||||
</div>
|
||||
)}
|
||||
<div className="condition">
|
||||
<div className="groupby-column">
|
||||
<CustomizeSelect
|
||||
readOnly={readOnly}
|
||||
value={selectedColumn}
|
||||
options={columnsOptions}
|
||||
onSelectOption={selectColumn}
|
||||
@@ -179,6 +182,7 @@ const GroupbyItem = memo(({
|
||||
{isShowGroupCountType(column) && (
|
||||
<div className="groupby-count-type">
|
||||
<CustomizeSelect
|
||||
readOnly={readOnly}
|
||||
value={selectedCountType}
|
||||
onSelectOption={selectCountType}
|
||||
options={countTypeOptions}
|
||||
@@ -188,6 +192,7 @@ const GroupbyItem = memo(({
|
||||
<div className="groupby-predicate">
|
||||
{(!column.key || SORT_COLUMN_OPTIONS.includes(column.type)) && (
|
||||
<CustomizeSelect
|
||||
readOnly={readOnly}
|
||||
value={selectedSortType}
|
||||
options={sortOptions}
|
||||
onSelectOption={selectSortType}
|
||||
@@ -195,7 +200,7 @@ const GroupbyItem = memo(({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{showDragBtn && connectDragSource(
|
||||
{!readOnly && showDragBtn && connectDragSource(
|
||||
<div className="groupby-drag">
|
||||
<Icon iconName="drag" />
|
||||
</div>
|
||||
@@ -217,6 +222,7 @@ const GroupbyItem = memo(({
|
||||
|
||||
GroupbyItem.propTypes = {
|
||||
index: PropTypes.number,
|
||||
readOnly: PropTypes.bool,
|
||||
groupby: PropTypes.object,
|
||||
columns: PropTypes.array,
|
||||
onDelete: PropTypes.func,
|
||||
|
@@ -6,15 +6,16 @@ import html5DragDropContext from '../../../../../../pages/wiki2/wiki-nav/html5Dr
|
||||
import { gettext } from '../../../../utils';
|
||||
import GroupbyItem from './groupby-item';
|
||||
|
||||
const Groupbys = ({ groupbys, columns, onDelete, onUpdate, onMove }) => {
|
||||
const Groupbys = ({ readOnly, groupbys, columns, onDelete, onUpdate, onMove }) => {
|
||||
const isEmpty = useMemo(() => {
|
||||
if (!Array.isArray(groupbys) || groupbys.length === 0) return true;
|
||||
return false;
|
||||
}, [groupbys]);
|
||||
const showDragBtn = useMemo(() => {
|
||||
if (readOnly) return false;
|
||||
if (!Array.isArray(groupbys) || groupbys.length === 0) return false;
|
||||
return groupbys.length > 1;
|
||||
}, [groupbys]);
|
||||
}, [readOnly, groupbys]);
|
||||
|
||||
return (
|
||||
<div className={classnames('groupbys-list', { 'empty-groupbys-container': isEmpty })}>
|
||||
@@ -24,6 +25,7 @@ const Groupbys = ({ groupbys, columns, onDelete, onUpdate, onMove }) => {
|
||||
<GroupbyItem
|
||||
key={index}
|
||||
index={index}
|
||||
readOnly={readOnly}
|
||||
showDragBtn={showDragBtn}
|
||||
groupby={groupby}
|
||||
columns={columns}
|
||||
|
@@ -13,7 +13,7 @@ import Groupbys from './groupbys';
|
||||
|
||||
import './index.css';
|
||||
|
||||
const GroupbysPopover = ({ groupbys: propsGroupBys, hidePopover, onChange, target, placement, columns }) => {
|
||||
const GroupbysPopover = ({ groupbys: propsGroupBys, readOnly, hidePopover, onChange, target, placement, columns }) => {
|
||||
const [groupbys, setGroupbys] = useState(propsGroupBys);
|
||||
const isSelectOpenRef = useState(false);
|
||||
const popoverRef = useRef(null);
|
||||
@@ -107,8 +107,8 @@ const GroupbysPopover = ({ groupbys: propsGroupBys, hidePopover, onChange, targe
|
||||
boundariesElement={document.body}
|
||||
>
|
||||
<div ref={popoverRef} onClick={onPopoverInsideClick} className="sf-metadata-groupbys">
|
||||
<Groupbys groupbys={groupbys} columns={columns} onDelete={deleteGroup} onUpdate={updateGroup} onMove={moveGroupbys} />
|
||||
{(groupbys.length < MAX_GROUP_LEVEL) && (
|
||||
<Groupbys readOnly={readOnly} groupbys={groupbys} columns={columns} onDelete={deleteGroup} onUpdate={updateGroup} onMove={moveGroupbys} />
|
||||
{!readOnly && (groupbys.length < MAX_GROUP_LEVEL) && (
|
||||
<CustomizeAddTool
|
||||
className="popover-add-tool"
|
||||
callBack={addGroupby}
|
||||
@@ -128,6 +128,7 @@ const GroupbysPopover = ({ groupbys: propsGroupBys, hidePopover, onChange, targe
|
||||
};
|
||||
|
||||
GroupbysPopover.propTypes = {
|
||||
readOnly: PropTypes.bool,
|
||||
target: PropTypes.oneOfType([PropTypes.string, PropTypes.object, PropTypes.node]),
|
||||
groupbys: PropTypes.array,
|
||||
columns: PropTypes.array,
|
||||
|
@@ -2,16 +2,19 @@ import React, { useCallback } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Icon, Switch } from '@seafile/sf-metadata-ui-component';
|
||||
import { COLUMNS_ICON_CONFIG } from '../../../../_basic';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const HideColumnItem = ({ column, isHidden, onChange }) => {
|
||||
const HideColumnItem = ({ readOnly, column, isHidden, onChange }) => {
|
||||
|
||||
const update = useCallback(() => {
|
||||
if (readOnly) return;
|
||||
onChange(column.key);
|
||||
}, [column, onChange]);
|
||||
}, [readOnly, column, onChange]);
|
||||
|
||||
return (
|
||||
<div className="hide-column-item">
|
||||
<div className={classNames('hide-column-item', { 'disabled': readOnly })}>
|
||||
<Switch
|
||||
disabled={readOnly}
|
||||
checked={isHidden}
|
||||
placeholder={(
|
||||
<>
|
||||
@@ -27,6 +30,7 @@ const HideColumnItem = ({ column, isHidden, onChange }) => {
|
||||
};
|
||||
|
||||
HideColumnItem.propTypes = {
|
||||
readOnly: PropTypes.bool,
|
||||
isHidden: PropTypes.bool,
|
||||
column: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
|
@@ -4,7 +4,7 @@ import classnames from 'classnames';
|
||||
import { gettext } from '../../../../utils';
|
||||
import HideColumn from './hide-column';
|
||||
|
||||
const HiddenColumns = ({ columns, hiddenColumns, onChange }) => {
|
||||
const HiddenColumns = ({ readOnly, columns, hiddenColumns, onChange }) => {
|
||||
const isEmpty = useMemo(() => {
|
||||
if (!Array.isArray(columns) || columns.length === 0) return true;
|
||||
return false;
|
||||
@@ -17,6 +17,7 @@ const HiddenColumns = ({ columns, hiddenColumns, onChange }) => {
|
||||
return (
|
||||
<HideColumn
|
||||
key={column.key}
|
||||
readOnly={readOnly}
|
||||
isHidden={hiddenColumns.includes(column.key)}
|
||||
column={column}
|
||||
onChange={onChange}
|
||||
@@ -28,6 +29,7 @@ const HiddenColumns = ({ columns, hiddenColumns, onChange }) => {
|
||||
};
|
||||
|
||||
HiddenColumns.propTypes = {
|
||||
readOnly: PropTypes.bool,
|
||||
hiddenColumns: PropTypes.array,
|
||||
columns: PropTypes.array,
|
||||
onChange: PropTypes.func,
|
||||
|
@@ -57,10 +57,10 @@
|
||||
|
||||
.sf-metadata-hide-columns-popover .hide-columns-list .hide-column-item:hover {
|
||||
background: #f5f5f5;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sf-metadata-hide-columns-popover .hide-columns-list .hide-column-item:hover * {
|
||||
.sf-metadata-hide-columns-popover .hide-columns-list .hide-column-item:not(.disabled):hover
|
||||
.sf-metadata-hide-columns-popover .hide-columns-list .hide-column-item:not(.disabled):hover * {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,7 @@ import { getEventClassName, gettext } from '../../../utils';
|
||||
|
||||
import './index.css';
|
||||
|
||||
const HideColumnPopover = ({ hidePopover, onChange, target, placement, columns, hiddenColumns: oldHiddenColumns }) => {
|
||||
const HideColumnPopover = ({ hidePopover, onChange, readOnly, target, placement, columns, hiddenColumns: oldHiddenColumns }) => {
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const [hiddenColumns, setHiddenColumns] = useState(oldHiddenColumns);
|
||||
const displayColumns = useMemo(() => {
|
||||
@@ -104,8 +104,8 @@ const HideColumnPopover = ({ hidePopover, onChange, target, placement, columns,
|
||||
<div className="sf-metadata-hide-columns-search-container">
|
||||
<SearchInput placeholder={gettext('Search column')} onKeyDown={onKeyDown} onChange={onChangeSearch} autoFocus={true}/>
|
||||
</div>
|
||||
<HiddenColumns columns={displayColumns} hiddenColumns={hiddenColumns} onChange={hideColumn} />
|
||||
{!searchValue && (
|
||||
<HiddenColumns readOnly={readOnly} columns={displayColumns} hiddenColumns={hiddenColumns} onChange={hideColumn} />
|
||||
{!readOnly && !searchValue && (
|
||||
<div className="sf-metadata-hide-columns-operations">
|
||||
<div className="sf-metadata-hide-columns-operation px-2" onClick={hideAll} aria-label={gettext('Hide all')}>{gettext('Hide all')}</div>
|
||||
<div className="sf-metadata-hide-columns-operation px-2" onClick={showAll} aria-label={gettext('Show all')}>{gettext('Show all')}</div>
|
||||
@@ -118,6 +118,7 @@ const HideColumnPopover = ({ hidePopover, onChange, target, placement, columns,
|
||||
};
|
||||
|
||||
HideColumnPopover.propTypes = {
|
||||
readOnly: PropTypes.bool,
|
||||
placement: PropTypes.string.isRequired,
|
||||
target: PropTypes.string.isRequired,
|
||||
hiddenColumns: PropTypes.array.isRequired,
|
||||
|
@@ -18,19 +18,19 @@ import './index.css';
|
||||
const SORT_TYPES = [SORT_TYPE.UP, SORT_TYPE.DOWN];
|
||||
|
||||
const propTypes = {
|
||||
readOnly: PropTypes.bool,
|
||||
target: PropTypes.string.isRequired,
|
||||
isNeedSubmit: PropTypes.bool,
|
||||
sorts: PropTypes.array,
|
||||
columns: PropTypes.array.isRequired,
|
||||
onSortComponentToggle: PropTypes.func,
|
||||
update: PropTypes.func,
|
||||
readonly: PropTypes.bool,
|
||||
};
|
||||
|
||||
class SortPopover extends Component {
|
||||
|
||||
static defaultProps = {
|
||||
readonly: false,
|
||||
readOnly: false,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
@@ -183,7 +183,7 @@ class SortPopover extends Component {
|
||||
|
||||
renderSortItem = (column, sort, index) => {
|
||||
let { name, type } = column;
|
||||
const { readonly } = this.props;
|
||||
const { readOnly } = this.props;
|
||||
let selectedColumn = {
|
||||
label: (
|
||||
<Fragment>
|
||||
@@ -200,7 +200,7 @@ class SortPopover extends Component {
|
||||
|
||||
return (
|
||||
<div key={'sort-item-' + index} className="sort-item">
|
||||
{!readonly &&
|
||||
{!readOnly &&
|
||||
<div className="delete-sort" onClick={(event) => this.deleteSort(event, index)}>
|
||||
<Icon iconName="fork-number"/>
|
||||
</div>
|
||||
@@ -208,7 +208,7 @@ class SortPopover extends Component {
|
||||
<div className="condition">
|
||||
<div className="sort-column">
|
||||
<CustomizeSelect
|
||||
isLocked={readonly}
|
||||
readOnly={readOnly}
|
||||
value={selectedColumn}
|
||||
onSelectOption={(value) => this.onSelectColumn(value, index)}
|
||||
options={this.columnsOptions}
|
||||
@@ -219,7 +219,7 @@ class SortPopover extends Component {
|
||||
</div>
|
||||
<div className="sort-predicate ml-2">
|
||||
<CustomizeSelect
|
||||
isLocked={readonly}
|
||||
readOnly={readOnly}
|
||||
value={selectedSortType}
|
||||
onSelectOption={(value) => this.onSelectSortType(value, index)}
|
||||
options={this.sortTypeOptions}
|
||||
@@ -235,7 +235,7 @@ class SortPopover extends Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { target, readonly } = this.props;
|
||||
const { target, readOnly } = this.props;
|
||||
const { sorts } = this.state;
|
||||
const isEmpty = isSortsEmpty(sorts);
|
||||
return (
|
||||
@@ -255,7 +255,7 @@ class SortPopover extends Component {
|
||||
this.renderSortsList()
|
||||
}
|
||||
</div>
|
||||
{!readonly &&
|
||||
{!readOnly &&
|
||||
<CustomizeAddTool
|
||||
callBack={this.addSort}
|
||||
footerName={gettext('Add sort')}
|
||||
@@ -263,7 +263,7 @@ class SortPopover extends Component {
|
||||
addIconClassName="popover-add-icon"
|
||||
/>
|
||||
}
|
||||
{(this.isNeedSubmit() && !readonly) && (
|
||||
{(this.isNeedSubmit() && !readOnly) && (
|
||||
<div className='sf-metadata-sort-popover-footer'>
|
||||
<Button className='mr-2' onClick={this.onClosePopover}>{gettext('Cancel')}</Button>
|
||||
<Button color="primary" disabled={this.state.isSubmitDisabled} onClick={this.onSubmitSorts}>{gettext('Submit')}</Button>
|
||||
|
@@ -63,6 +63,8 @@ const ViewToolBar = ({ metadataViewId }) => {
|
||||
|
||||
if (!view) return null;
|
||||
|
||||
const readOnly = !window.sfMetadataContext.canModifyView(view);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="sf-metadata-tool"
|
||||
@@ -73,6 +75,7 @@ const ViewToolBar = ({ metadataViewId }) => {
|
||||
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-filter"
|
||||
filtersClassName="sf-metadata-filters"
|
||||
target="sf-metadata-filter-popover"
|
||||
readOnly={readOnly}
|
||||
filterConjunction={view.filter_conjunction}
|
||||
filters={view.filters}
|
||||
columns={availableColumns}
|
||||
@@ -82,6 +85,7 @@ const ViewToolBar = ({ metadataViewId }) => {
|
||||
<SortSetter
|
||||
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-sort"
|
||||
target="sf-metadata-sort-popover"
|
||||
readOnly={readOnly}
|
||||
sorts={view.sorts}
|
||||
columns={viewColumns}
|
||||
modifySorts={modifySorts}
|
||||
@@ -89,6 +93,7 @@ const ViewToolBar = ({ metadataViewId }) => {
|
||||
<GroupbySetter
|
||||
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-groupby"
|
||||
target="sf-metadata-groupby-popover"
|
||||
readOnly={readOnly}
|
||||
columns={viewColumns}
|
||||
groupbys={view.groupbys}
|
||||
modifyGroupbys={modifyGroupbys}
|
||||
@@ -96,6 +101,7 @@ const ViewToolBar = ({ metadataViewId }) => {
|
||||
<HideColumnSetter
|
||||
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-hide-column"
|
||||
target="sf-metadata-hide-column-popover"
|
||||
readOnly={readOnly}
|
||||
columns={viewColumns.slice(1)}
|
||||
hiddenColumns={view.hidden_columns || []}
|
||||
modifyHiddenColumns={modifyHiddenColumns}
|
||||
|
@@ -130,6 +130,11 @@ class Context {
|
||||
return true;
|
||||
};
|
||||
|
||||
canModifyView = (view) => {
|
||||
if (this.permission === 'r') return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
getCollaboratorFromCache(email) {
|
||||
return this.collaboratorsCache[email];
|
||||
}
|
||||
|
Reference in New Issue
Block a user