1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-25 14:50:29 +00:00

feat: metadata property sort (#6755)

Co-authored-by: 杨国璇 <ygx@Hello-word.local>
This commit is contained in:
杨国璇
2024-09-11 17:38:22 +08:00
committed by GitHub
parent 0ec81e4229
commit 61be54517f
17 changed files with 125 additions and 15 deletions

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1726034713002" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15456" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M643.2 777.6c28.8 0 57.6 35.2 57.6 73.6S672 928 643.2 928h-108.8c-28.8 0-57.6-35.2-57.6-73.6s25.6-73.6 57.6-73.6h108.8v-3.2zM195.2 131.2c19.2-25.6 48-32 67.2-19.2 6.4 3.2 12.8 12.8 16 19.2l153.6 224c12.8 22.4 9.6 57.6-12.8 73.6-6.4 6.4-19.2 12.8-28.8 12.8H304v403.2c0 38.4-32 67.2-67.2 67.2s-67.2-32-67.2-67.2V441.6H86.4c-25.6 0-51.2-22.4-54.4-51.2v-3.2c0-12.8 3.2-22.4 9.6-28.8l153.6-227.2z m569.6 422.4c32 0 60.8 35.2 60.8 73.6s-28.8 76.8-60.8 76.8h-233.6c-32 0-60.8-35.2-60.8-73.6s28.8-73.6 60.8-73.6h233.6v-3.2z m99.2-224c28.8 0 57.6 35.2 57.6 73.6 0 38.4-25.6 73.6-57.6 73.6H528c-28.8 0-57.6-35.2-57.6-73.6 0-38.4 25.6-73.6 57.6-73.6H864z m67.2-224v6.4c28.8 0 51.2 35.2 51.2 73.6 0 38.4-25.6 70.4-51.2 70.4H524.8c-28.8 0-51.2-35.2-51.2-73.6s25.6-73.6 51.2-73.6h406.4z" p-id="15457"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1726034718075" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15598" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M643.2 777.6c28.8 0 57.6 35.2 57.6 73.6 0 38.4-25.6 73.6-57.6 73.6h-108.8c-28.8 0-57.6-35.2-57.6-73.6 0-38.4 25.6-73.6 57.6-73.6h108.8zM236.8 92.8c38.4 0 67.2 32 67.2 67.2v425.6h86.4c9.6 0 22.4 3.2 28.8 12.8 25.6 19.2 28.8 51.2 12.8 73.6l-153.6 224c-3.2 6.4-9.6 12.8-16 19.2-22.4 16-51.2 6.4-67.2-19.2l-153.6-224c-6.4-6.4-9.6-19.2-9.6-28.8 0-28.8 25.6-57.6 54.4-57.6h83.2V160c0-38.4 28.8-67.2 67.2-67.2z m528 460.8c32 0 60.8 35.2 60.8 73.6s-28.8 76.8-60.8 76.8h-233.6c-32 0-60.8-35.2-60.8-73.6s28.8-73.6 60.8-73.6h233.6v-3.2z m99.2-224c28.8 0 57.6 35.2 57.6 73.6S892.8 480 864 480H528c-28.8 0-57.6-35.2-57.6-73.6s25.6-73.6 57.6-73.6H864v-3.2z m67.2-224v6.4c28.8 0 51.2 35.2 51.2 73.6S960 256 931.2 256H524.8c-28.8 0-51.2-35.2-51.2-73.6s25.6-73.6 51.2-73.6h406.4z" p-id="15599"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -19,6 +19,13 @@ const SORT_COLUMN_OPTIONS = [
CellType.RATE,
];
const SHOW_DISABLED_SORT_COLUMNS = [
CellType.LONG_TEXT,
CellType.GEOLOCATION,
CellType.CREATOR,
CellType.LAST_MODIFIER,
];
const GALLERY_SORT_COLUMN_OPTIONS = [
CellType.CTIME,
CellType.MTIME,
@@ -38,6 +45,7 @@ const NUMBER_SORTER_COLUMN_TYPES = [CellType.NUMBER, CellType.RATE];
export {
SORT_TYPE,
SORT_COLUMN_OPTIONS,
SHOW_DISABLED_SORT_COLUMNS,
GALLERY_SORT_COLUMN_OPTIONS,
GALLERY_FIRST_SORT_COLUMN_OPTIONS,
TEXT_SORTER_COLUMN_TYPES,

View File

@@ -53,7 +53,7 @@ const RateItem = ({
<Icon iconName={type || 'rate'} />
</div>
{enterIndex !== -1 && (
<UncontrolledTooltip placement='bottom' target={ref} modifiers={{ preventOverflow: { boundariesElement: document.body } }}>
<UncontrolledTooltip placement='bottom' target={ref} modifiers={{ preventOverflow: { boundariesElement: document.body } }} className="sf-metadata-tooltip">
{enterIndex}
</UncontrolledTooltip>
)}

View File

@@ -1,10 +1,11 @@
import React, { useCallback, useState, useMemo } from 'react';
import React, { useCallback, useState, useMemo, useEffect } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { IconBtn } from '@seafile/sf-metadata-ui-component';
import { getValidSorts, CommonlyUsedHotkey } from '../../_basic';
import { gettext } from '../../utils';
import { SortPopover } from '../popover';
import { EVENT_BUS_TYPE } from '../../constants';
const SortSetter = ({ target, type, sorts: propsSorts, readOnly, columns, isNeedSubmit, wrapperClass, modifySorts }) => {
const [isShowSetter, setShowSetter] = useState(false);
@@ -20,6 +21,19 @@ const SortSetter = ({ target, type, sorts: propsSorts, readOnly, columns, isNeed
return isNeedSubmit ? gettext('Preset sort') : gettext('Sort');
}, [isNeedSubmit, sorts]);
const displaySetter = useCallback(() => {
setShowSetter(true);
}, []);
useEffect(() => {
const eventBus = window.sfMetadataContext.eventBus;
const unsubscribeDisplaySorts = eventBus.subscribe(EVENT_BUS_TYPE.DISPLAY_SORTS, displaySetter);
return () => {
unsubscribeDisplaySorts();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const onSetterToggle = useCallback(() => {
setShowSetter(!isShowSetter);
}, [isShowSetter]);

View File

@@ -534,6 +534,7 @@ class FilterItem extends React.Component {
target={this.invalidFilterTip}
placement='bottom'
fade={false}
className="sf-metadata-tooltip"
>
{gettext('Invalid filter')}
</UncontrolledTooltip>
@@ -608,7 +609,7 @@ class FilterItem extends React.Component {
{/* {showToolTip && (
<div className="ml-2" >
<IconBtn id={`filter-tool-tip-${filterColumn.key}`} iconName="exclamation-triangle" />
<UncontrolledTooltip placement="bottom" target={`filter-tool-tip-${filterColumn.key}`} >
<UncontrolledTooltip placement="bottom" target={`filter-tool-tip-${filterColumn.key}`} className="sf-metadata-tooltip">
{gettext('If there are multiple items in the cell, a random one will be chosen and be compared with the filter value.')}
</UncontrolledTooltip>
</div>

View File

@@ -84,7 +84,7 @@ export default class OptionFooter extends React.Component {
return (
<div className='option-editor-footer'>
<span aria-hidden="true" className="sf3-font-help sf3-font option-editor-tips" id="edit-option-tip"></span>
<UncontrolledTooltip delay={{ show: 0, hide: 0 }} target={'edit-option-tip'} placement='bottom'>
<UncontrolledTooltip delay={{ show: 0, hide: 0 }} target="edit-option-tip" placement="bottom" className="sf-metadata-tooltip">
{gettext('Use the import/export function to transfer options quickly. (The export is in JSON format.) By pasting cells, copied from a text column, an Excel or a TXT file, you can also add options quickly.')}
</UncontrolledTooltip>
<input

View File

@@ -204,13 +204,33 @@
background-color: #f9f9f9;
}
.tooltip-inner {
.sf-metadata-tooltip .tooltip-inner {
max-width: 242px;
font-weight: lighter;
text-align: start;
background-color: #303133;
}
.sf-metadata-tooltip .bs-tooltip-right .arrow::before,
.sf-metadata-tooltip .bs-tooltip-auto[x-placement^="right"] .arrow::before {
border-right-color: #303133;
}
.sf-metadata-tooltip .bs-tooltip-top .arrow::before,
.sf-metadata-tooltip .bs-tooltip-auto[x-placement^="top"] .arrow::before {
border-top-color: #303133;
}
.sf-metadata-tooltip .bs-tooltip-bottom .arrow::before,
.sf-metadata-tooltip .bs-tooltip-auto[x-placement^="bottom"] .arrow::before {
border-bottom-color: #303133;
}
.sf-metadata-tooltip .bs-tooltip-left .arrow::before,
.sf-metadata-tooltip .bs-tooltip-auto[x-placement^="left"] .arrow::before {
border-left-color: #303133;
}
/* records count */
.sf-metadata-result.success .sf-metadata-result-footer {
height: 32px;

View File

@@ -28,6 +28,7 @@ const CellOperationBtn = ({ isDir, column, value }) => {
fade={false}
delay={{ show: 0, hide: 0 }}
modifiers={{ preventOverflow: { boundariesElement: document.body } }}
className="sf-metadata-tooltip"
>
{isDir ? gettext('Open folder') : gettext('Open file')}
</UncontrolledTooltip>

View File

@@ -41,7 +41,7 @@ const ColumnDropdownItem = ({ disabled, iconName, target, title, tip, className,
<Icon iconName={iconName} />
<span className="item-text">{title}</span>
{isShowToolTip && (
<UncontrolledTooltip placement="right" target={target} fade={false} delay={{ show: 0, hide: 0 }}>
<UncontrolledTooltip placement="right" target={target} fade={false} delay={{ show: 0, hide: 0 }} className="sf-metadata-tooltip">
{tip}
</UncontrolledTooltip>
)}

View File

@@ -5,12 +5,15 @@ import classnames from 'classnames';
import { ModalPortal, Icon } from '@seafile/sf-metadata-ui-component';
import { isMobile, gettext } from '../../../../../../../../utils';
import DropdownItem from './dropdown-item';
import { CellType, DEFAULT_DATE_FORMAT, getDateDisplayString } from '../../../../../../../../_basic';
import { CellType, DEFAULT_DATE_FORMAT, SORT_COLUMN_OPTIONS, SHOW_DISABLED_SORT_COLUMNS, SORT_TYPE,
getDateDisplayString
} from '../../../../../../../../_basic';
import { RenamePopover, OptionsPopover } from '../../../../../../../popover';
import { EVENT_BUS_TYPE } from '../../../../../../../../constants';
import './index.css';
const HeaderDropdownMenu = ({ column, renameColumn, modifyColumnData, deleteColumn }) => {
const HeaderDropdownMenu = ({ column, view, renameColumn, modifyColumnData, deleteColumn }) => {
const menuRef = createRef();
const dropdownDomRef = createRef();
const [isMenuShow, setMenuShow] = useState(false);
@@ -153,11 +156,38 @@ const HeaderDropdownMenu = ({ column, renameColumn, modifyColumnData, deleteColu
);
}, [today, column, isMenuShow, isSubMenuShow, onChangeDateFormat, openSubMenu]);
const modifySort = useCallback((type, event) => {
const canModifyView = window.sfMetadataContext.canModifyView();
if (!canModifyView) {
event.stopPropagation();
return;
}
const sorts = view.sorts.slice(0);
const { key } = column;
const sortIndex = sorts.findIndex(sort => sort.column_key === key);
const sort = sorts[sortIndex];
const newSort = { column_key: column.key, sort_type: type };
const eventBus = window.sfMetadataContext.eventBus;
if (!sort) {
sorts.push(newSort);
eventBus.dispatch(EVENT_BUS_TYPE.MODIFY_SORTS, sorts, true);
return;
}
if (sort && sort.sort_type !== type) {
sorts.splice(sortIndex, 1, newSort);
eventBus.dispatch(EVENT_BUS_TYPE.MODIFY_SORTS, sorts, true);
return;
}
eventBus.dispatch(EVENT_BUS_TYPE.DISPLAY_SORTS);
}, [view, column]);
const renderDropdownMenu = useCallback(() => {
const { type } = column;
const canModifyColumnData = window.sfMetadataContext.canModifyColumnData(column);
const canDeleteColumn = window.sfMetadataContext.canDeleteColumn(column);
const canRenameColumn = window.sfMetadataContext.canRenameColumn(column);
const canModifyView = window.sfMetadataContext.canModifyView();
return (
<DropdownMenu ref={menuRef} className="sf-metadata-column-dropdown-menu">
<div ref={dropdownDomRef}>
@@ -216,6 +246,28 @@ const HeaderDropdownMenu = ({ column, renameColumn, modifyColumnData, deleteColu
onChange={openRenamePopover}
onMouseEnter={hideSubMenu}
/>
{(SORT_COLUMN_OPTIONS.includes(column.type) || SHOW_DISABLED_SORT_COLUMNS.includes(column.type)) && (
<>
<DropdownItem
disabled={!canModifyView || SHOW_DISABLED_SORT_COLUMNS.includes(column.type)}
target="sf-metadata-sort-ascending-column"
iconName="sort-ascending"
title={gettext('Sort ascending')}
tip={!canModifyView ? gettext('You do not have permission') : gettext('This property does not support sorting')}
onChange={() => modifySort(SORT_TYPE.UP)}
onMouseEnter={hideSubMenu}
/>
<DropdownItem
disabled={!canModifyView || SHOW_DISABLED_SORT_COLUMNS.includes(column.type)}
target="sf-metadata-sort-descending-column"
iconName="sort-descending"
title={gettext('Sort descending')}
tip={!canModifyView ? gettext('You do not have permission') : gettext('This property does not support sorting')}
onChange={() => modifySort(SORT_TYPE.DOWN)}
onMouseEnter={hideSubMenu}
/>
</>
)}
<DropdownItem
disabled={!canDeleteColumn}
target="sf-metadata-delete-column"
@@ -228,7 +280,7 @@ const HeaderDropdownMenu = ({ column, renameColumn, modifyColumnData, deleteColu
</div>
</DropdownMenu>
);
}, [column, openRenamePopover, hideSubMenu, renderDateFormat, openOptionPopover, menuRef, dropdownDomRef, onDelete]);
}, [column, openRenamePopover, hideSubMenu, renderDateFormat, openOptionPopover, menuRef, dropdownDomRef, modifySort, onDelete]);
return (
<>

View File

@@ -89,6 +89,7 @@ const Cell = ({
isHideTriangle,
column,
style: propsStyle,
view,
renameColumn,
deleteColumn,
modifyColumnData,
@@ -99,8 +100,8 @@ const Cell = ({
const canEditColumnInfo = useMemo(() => {
if (isHideTriangle) return false;
return window.sfMetadataContext.canModifyColumn(column);
}, [isHideTriangle, column]);
return window.sfMetadataContext.canModify();
}, [isHideTriangle]);
const style = useMemo(() => {
const { left, width } = column;
@@ -159,7 +160,7 @@ const Cell = ({
<span className="mr-2" id={`header-icon-${key}`}>
<Icon iconName={COLUMNS_ICON_CONFIG[type]} className="sf-metadata-column-icon" />
</span>
<UncontrolledTooltip placement="bottom" target={`header-icon-${key}`} fade={false} trigger="hover">
<UncontrolledTooltip placement="bottom" target={`header-icon-${key}`} fade={false} trigger="hover" className="sf-metadata-tooltip">
{gettext(headerIconTooltip)}
</UncontrolledTooltip>
<div className="header-name d-flex">
@@ -169,6 +170,7 @@ const Cell = ({
{canEditColumnInfo && (
<DropdownMenu
column={column}
view={view}
renameColumn={renameColumn}
deleteColumn={deleteColumn}
modifyColumnData={modifyColumnData}
@@ -213,6 +215,7 @@ Cell.propTypes = {
frozen: PropTypes.bool,
isLastFrozenCell: PropTypes.bool,
isHideTriangle: PropTypes.bool,
view: PropTypes.object,
renameColumn: PropTypes.func,
deleteColumn: PropTypes.func,
modifyColumnData: PropTypes.func,

View File

@@ -114,6 +114,7 @@ const RecordsHeader = ({
isLastFrozenCell={isLastFrozenCell}
frozenColumnsWidth={frozenColumnsWidth}
isHideTriangle={isHideTriangle}
view={table.view}
modifyLocalColumnWidth={modifyLocalColumnWidth}
modifyColumnWidth={modifyColumnWidth}
onMove={modifyColumnOrder}
@@ -131,6 +132,7 @@ const RecordsHeader = ({
groupOffsetLeft={groupOffsetLeft}
height={height}
column={column}
view={table.view}
frozenColumnsWidth={frozenColumnsWidth}
modifyLocalColumnWidth={modifyLocalColumnWidth}
modifyColumnWidth={modifyColumnWidth}

View File

@@ -38,6 +38,7 @@ export const EVENT_BUS_TYPE = {
MODIFY_SORTS: 'modify_sorts',
MODIFY_GROUPBYS: 'modify_groupbys',
MODIFY_HIDDEN_COLUMNS: 'modify_hidden_columns',
DISPLAY_SORTS: 'display_sorts',
// change
VIEW_CHANGED: 'view_changed',

View File

@@ -92,6 +92,11 @@ class Context {
return this.permission;
};
canModify = () => {
if (this.permission === 'r') return false;
return true;
};
canModifyRow = (row) => {
if (this.permission === 'r') return false;
return true;

View File

@@ -49,8 +49,8 @@ export const MetadataProvider = ({
window.sfMetadataStore.modifyFilters(filterConjunction, filters, basicFilters);
}, []);
const modifySorts = useCallback((sorts) => {
window.sfMetadataStore.modifySorts(sorts);
const modifySorts = useCallback((sorts, displaySorts = false) => {
window.sfMetadataStore.modifySorts(sorts, displaySorts);
}, []);
const modifyGroupbys = useCallback((groupbys) => {

View File

@@ -360,7 +360,7 @@ class Store {
this.applyOperation(operation);
}
modifySorts(sorts) {
modifySorts(sorts, displaySorts = false) {
const type = OPERATION_TYPE.MODIFY_SORTS;
const operation = this.createOperation({
type,
@@ -369,6 +369,7 @@ class Store {
view_id: this.viewId,
success_callback: () => {
this.context.eventBus.dispatch(EVENT_BUS_TYPE.RELOAD_DATA);
displaySorts && this.context.eventBus.dispatch(EVENT_BUS_TYPE.DISPLAY_SORTS);
}
});
this.applyOperation(operation);