Skip to content

Commit

Permalink
Feature/filter by file type (#6852)
Browse files Browse the repository at this point in the history
* update basic filters, add file type filter

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code

---------

Co-authored-by: 杨国璇 <[email protected]>
  • Loading branch information
Aries-0331 and 杨国璇 authored Sep 29, 2024
1 parent 2a4949f commit 77b4664
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { FilterPopover } from '../popover';
import { getValidFilters } from '../../utils/filter';
import { gettext } from '../../../utils/constants';
import { isEnter, isSpace } from '../../utils/hotkey';
import { VIEW_TYPE } from '../../constants';

const FilterSetter = ({
readOnly,
Expand All @@ -20,7 +21,8 @@ const FilterSetter = ({
target,
filterConjunction,
basicFilters,
modifyFilters
modifyFilters,
viewType,
}) => {
const [isShowSetter, setShowSetter] = useState(false);

Expand Down Expand Up @@ -84,6 +86,7 @@ const FilterSetter = ({
hidePopover={onSetterToggle}
update={onChange}
isPre={isPre}
viewType={viewType}
/>
}
</>
Expand All @@ -104,12 +107,14 @@ FilterSetter.propTypes = {
collaborators: PropTypes.array,
isPre: PropTypes.bool,
basicFilters: PropTypes.array,
viewType: PropTypes.string,
};

FilterSetter.defaultProps = {
target: 'sf-metadata-filter-popover',
isNeedSubmit: false,
basicFilters: [],
viewType: VIEW_TYPE.TABLE,
};

export default FilterSetter;
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const OPTIONS = [
{ value: 'all', name: gettext('Pictures and videos') },
];

const FileTypeFilter = ({ readOnly, value = 'picture', onChange: onChangeAPI }) => {
const GalleryFileTypeFilter = ({ readOnly, value = 'picture', onChange: onChangeAPI }) => {

const options = useMemo(() => {
return OPTIONS.map(o => {
Expand Down Expand Up @@ -60,10 +60,10 @@ const FileTypeFilter = ({ readOnly, value = 'picture', onChange: onChangeAPI })
);
};

FileTypeFilter.propTypes = {
GalleryFileTypeFilter.propTypes = {
readOnly: PropTypes.bool,
value: PropTypes.string,
onChange: PropTypes.func,
};

export default FileTypeFilter;
export default GalleryFileTypeFilter;
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
margin-right: 8px;
}

.sf-metadata-basic-filters-select .selected-option .custom-select-dropdown-icon {
margin-left: 0;
}

.select-basic-filter-option {
width: 100%;
display: flex;
Expand Down Expand Up @@ -52,10 +56,22 @@
fill: #fff;
}

.sf-metadata-basic-filters-select .sf-metadata-option-group {
margin-left: 6px;
}

.filter-group-basic .sf-metadata-filters-list {
min-height: unset;
display: flex;
}

.sf-metadata-table-view-basic-filter-file-type-select .sf-metadata-option {
padding: 0.25rem 1rem;
}

.sf-metadata-table-view-basic-filter-file-type-select .select-basic-filter-option .select-basic-filter-option-checkbox {
display: inline-flex;
align-items: center;
flex-shrink: 0;
}

.sf-metadata-table-view-basic-filter-file-type-select .select-basic-filter-option .select-basic-filter-option-checkbox,
.sf-metadata-table-view-basic-filter-file-type-select .select-basic-filter-option .select-basic-filter-option-checkbox input {
cursor: inherit;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import { FormGroup, Label } from 'reactstrap';
import FileOrFolderFilter from './file-folder-filter';
import FileTypeFilter from './file-type-filter';
import TableFileTypeFilter from './table-file-type-filter';
import GalleryFileTypeFilter from './gallery-file-type-filter';
import { gettext } from '../../../../../utils/constants';
import { PRIVATE_COLUMN_KEY } from '../../../../constants';
import { PRIVATE_COLUMN_KEY, VIEW_TYPE } from '../../../../constants';

import './index.css';

const BasicFilters = ({ readOnly, filters = [], onChange }) => {
const BasicFilters = ({ readOnly, filters = [], onChange, viewType }) => {

const onChangeFileOrFolderFilter = useCallback((newValue) => {
const filterIndex = filters.findIndex(filter => filter.column_key === PRIVATE_COLUMN_KEY.IS_DIR);
Expand All @@ -31,17 +32,16 @@ const BasicFilters = ({ readOnly, filters = [], onChange }) => {
<Label className="filter-group-name">{gettext('Basic')}</Label>
<div className="filter-group-container">
<div className="sf-metadata-filters-list">
{filters.map((filter, index) => {
{filters.map((filter) => {
const { column_key, filter_term } = filter;
if (column_key === PRIVATE_COLUMN_KEY.IS_DIR) {
return (
<FileOrFolderFilter key={column_key} readOnly={readOnly} value={filter_term} onChange={onChangeFileOrFolderFilter} />
);
}
if (column_key === PRIVATE_COLUMN_KEY.FILE_TYPE) {
return (
<FileTypeFilter key={column_key} readOnly={readOnly} value={filter_term} onChange={onChangeFileTypeFilter} />
);
const FileTypeFilter = viewType === VIEW_TYPE.GALLERY ? GalleryFileTypeFilter : TableFileTypeFilter;
return (<FileTypeFilter key={column_key} readOnly={readOnly} value={filter_term} onChange={onChangeFileTypeFilter} />);
}
return null;
})}
Expand All @@ -56,6 +56,7 @@ BasicFilters.propTypes = {
filters: PropTypes.array,
columns: PropTypes.array,
onChange: PropTypes.func,
viewType: PropTypes.oneOf(Object.values(VIEW_TYPE)),
};

export default BasicFilters;
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { CustomizeSelect } from '@seafile/sf-metadata-ui-component';
import { gettext } from '../../../../../utils/constants';
import { getFileTypeColumnOptions } from '../../../../utils/column';

const TableFileTypeFilter = ({ readOnly, value, onChange: onChangeAPI }) => {

const OPTIONS = useMemo(() => {
const optionsMap = getFileTypeColumnOptions();
let options = [];
for (const [key, option] of Object.entries(optionsMap)) {
options.push({ value: key, name: option.name });
}
return options;
}, []);

const options = useMemo(() => {
return OPTIONS.map(o => {
const { name } = o;
return {
value: o.value,
label: (
<div className="select-basic-filter-option">
<div className="select-basic-filter-option-checkbox mr-2">
<input type="checkbox" checked={value.includes(o.value)} readOnly />
</div>
<div className="select-basic-filter-option-name" title={name} aria-label={name}>{name}</div>
</div>
)
};
});
}, [OPTIONS, value]);

const displayValue = useMemo(() => {
const selectedOptions = OPTIONS.filter(o => value.includes(o.value));
return {
label: (
<div className="select-basic-filter-display-name">
{selectedOptions.length > 0 ? selectedOptions.map(o => o.name).join(', ') : gettext('File type')}
</div>
)
};
}, [OPTIONS, value]);

const onChange = useCallback((newValue) => {
if (value.includes(newValue)) {
onChangeAPI(value.filter(v => v !== newValue));
} else {
onChangeAPI([...value, newValue]);
}
}, [value, onChangeAPI]);

return (
<CustomizeSelect
readOnly={readOnly}
className="sf-metadata-basic-filters-select sf-metadata-table-view-basic-filter-file-type-select ml-4"
value={displayValue}
options={options}
onSelectOption={onChange}
supportMultipleSelect={true}
component={{
DropDownIcon: (
<i className="sf3-font sf3-font-down"></i>
)
}}
/>
);
};

TableFileTypeFilter.propTypes = {
readOnly: PropTypes.bool,
value: PropTypes.array,
onChange: PropTypes.func,
};

export default TableFileTypeFilter;
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class FilterPopover extends Component {
};

render() {
const { readOnly, target, columns, placement } = this.props;
const { readOnly, target, columns, placement, viewType } = this.props;
const { filters, filterConjunction, basicFilters } = this.state;
const canAddFilter = columns.length > 0;
return (
Expand All @@ -168,7 +168,7 @@ class FilterPopover extends Component {
>
{({ scheduleUpdate }) => (
<div ref={ref => this.dtablePopoverRef = ref} onClick={this.onPopoverInsideClick} className={this.props.filtersClassName}>
<BasicFilters filters={basicFilters} onChange={this.onBasicFilterChange} />
<BasicFilters filters={basicFilters} onChange={this.onBasicFilterChange} viewType={viewType}/>
<FormGroup className="filter-group-advanced filter-group mb-0">
<Label className="filter-group-name">{gettext('Advanced')}</Label>
<div className="filter-group-container">
Expand Down Expand Up @@ -222,6 +222,7 @@ FilterPopover.propTypes = {
basicFilters: PropTypes.array,
hidePopover: PropTypes.func,
update: PropTypes.func,
viewType: PropTypes.string,
};

export default FilterPopover;
9 changes: 7 additions & 2 deletions frontend/src/metadata/components/view-toolbar/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import { GalleryGroupBySetter, GallerySliderSetter, FilterSetter, GroupbySetter, SortSetter, HideColumnSetter } from '../data-process-setter';
import { EVENT_BUS_TYPE, VIEW_TYPE } from '../../constants';
import { EVENT_BUS_TYPE, PRIVATE_COLUMN_KEY, VIEW_TYPE } from '../../constants';

import './index.css';

Expand All @@ -14,6 +14,10 @@ const ViewToolBar = ({ viewId }) => {
return view.columns;
}, [view]);

const filterColumns = useMemo(() => {
return viewColumns.filter(c => c.key !== PRIVATE_COLUMN_KEY.FILE_TYPE);
}, [viewColumns]);

const onHeaderClick = useCallback(() => {
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.SELECT_NONE);
}, []);
Expand Down Expand Up @@ -86,9 +90,10 @@ const ViewToolBar = ({ viewId }) => {
filterConjunction={view.filter_conjunction}
basicFilters={view.basic_filters}
filters={view.filters}
columns={viewColumns}
columns={filterColumns}
modifyFilters={modifyFilters}
collaborators={collaborators}
viewType={viewType}
/>
<SortSetter
isNeedSubmit={true}
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/metadata/constants/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ export const VIEW_TYPE_DEFAULT_BASIC_FILTER = {
column_key: PRIVATE_COLUMN_KEY.IS_DIR,
filter_predicate: FILTER_PREDICATE_TYPE.IS,
filter_term: 'file'
}
}, {
column_key: PRIVATE_COLUMN_KEY.FILE_TYPE,
filter_predicate: FILTER_PREDICATE_TYPE.IS_ANY_OF,
filter_term: []
},
],
[VIEW_TYPE.GALLERY]: [
{
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/metadata/model/metadata/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ class View {
this.filters = object.filters || [];
this.filter_conjunction = object.filter_conjunction || 'Or';

this.basic_filters = object.basic_filters && object.basic_filters.length > 0 ? object.basic_filters : VIEW_TYPE_DEFAULT_BASIC_FILTER[this.type];
const defaultBasicFilters = VIEW_TYPE_DEFAULT_BASIC_FILTER[this.type];
this.basic_filters = object.basic_filters && object.basic_filters.length > 0 ? object.basic_filters : defaultBasicFilters;
if (this.basic_filters.length !== defaultBasicFilters.length) {
this.basic_filters = [...this.basic_filters, ...defaultBasicFilters.slice(this.basic_filters.length)];
}

// sort
this.sorts = object.sorts && object.sorts.length > 0 ? object.sorts : VIEW_TYPE_DEFAULT_SORTS[this.type];
Expand Down
10 changes: 7 additions & 3 deletions frontend/src/metadata/utils/column/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,16 +262,20 @@ export const getNormalizedColumnType = (key, type) => {
}
};

const getFileTypeColumnData = (column) => {
const { data } = column;
const _OPTIONS = {
export const getFileTypeColumnOptions = () => {
return {
[PREDEFINED_FILE_TYPE_OPTION_KEY.PICTURE]: { name: gettext('Picture'), color: '#FFFCB5', textColor: '#202428' },
[PREDEFINED_FILE_TYPE_OPTION_KEY.DOCUMENT]: { name: gettext('Document'), color: '#B7CEF9', textColor: '#202428' },
[PREDEFINED_FILE_TYPE_OPTION_KEY.VIDEO]: { name: gettext('Video'), color: '#9860E5', textColor: '#FFFFFF', borderColor: '#844BD2' },
[PREDEFINED_FILE_TYPE_OPTION_KEY.AUDIO]: { name: gettext('Audio'), color: '#FBD44A', textColor: '#FFFFFF', borderColor: '#E5C142' },
[PREDEFINED_FILE_TYPE_OPTION_KEY.CODE]: { name: gettext('Code'), color: '#4ad8fb', textColor: '#FFFFFF', borderColor: '#4283e5' },
[PREDEFINED_FILE_TYPE_OPTION_KEY.COMPRESSED]: { name: gettext('Compressed'), color: '#4a9afb', textColor: '#FFFFFF', borderColor: '#da42e5' },
};
};

const getFileTypeColumnData = (column) => {
const { data } = column;
const _OPTIONS = getFileTypeColumnOptions();
let newData = { ...data };
newData.options = Array.isArray(data.options) ? data.options.map(o => {
return { ...o, ..._OPTIONS[o.id] };
Expand Down

0 comments on commit 77b4664

Please sign in to comment.