Skip to content

Commit

Permalink
Merge branch 'feature-issue-table' into 'master-0.24.0'
Browse files Browse the repository at this point in the history
[IMP]拆分issue table和搜索

See merge request hzero-agile/agile-service!1026
  • Loading branch information
王坤奇 committed Sep 14, 2020
2 parents 8fc6bfa + 2f8678d commit 666bd6d
Show file tree
Hide file tree
Showing 42 changed files with 1,029 additions and 815 deletions.
Original file line number Diff line number Diff line change
@@ -1,94 +1,67 @@
/* eslint-disable camelcase */
import React, {
useContext, useEffect, useState,
} from 'react';
import { withRouter } from 'react-router-dom';
import React, { useState, useContext } from 'react';
import {
Select, Icon,
} from 'choerodon-ui';
import { Button } from 'choerodon-ui/pro';
import {
find, remove, map,
} from 'lodash';
import { find, remove } from 'lodash';
import { observer } from 'mobx-react-lite';
import IssueStore, { flattenObject, isFilterSame } from '@/stores/project/issue/IssueStore';
import { quickFilterApi } from '@/api';
import { linkUrl } from '@/utils/to';
import LINK_URL, { getParams } from '@/constants/LINK_URL';
import { Button } from 'choerodon-ui/pro';
import { SelectMode } from 'choerodon-ui/lib/select/enum';
import { FuncType, ButtonColor } from 'choerodon-ui/pro/lib/button/enum';
import { LabeledValue } from 'choerodon-ui/lib/select';
import { flattenObject, isFilterSame } from './utils';
import IssueSearchContext from './context';
import SummaryField from './custom-fields/field/SummaryField';
import Store from '../../stores';
import CustomFields from './custom-fields';
import { getSelectStyle } from './custom-fields/utils';
import './index.less';
import useQuickFilters from './useQuickFilters';

const { Option, OptGroup } = Select;

export default withRouter(observer(({
urlFilter, onClear, history, location,
}) => {
const SearchArea: React.FC = () => {
const prefixCls = 'c7n-issue';
const {
prefixCls, projectId, userId,
} = useContext(Store);
store, onClear, urlFilter, onClickSaveFilter,
} = useContext(IssueSearchContext);
const { data: quickFilters } = useQuickFilters();
const { isHasFilter } = store;
const myFilters = store.getMyFilters;
const [selectedQuickFilters, setSelectedQuickFilters] = useState<LabeledValue[]>([]);

const filters = IssueStore.getMyFilters;
const editFilterInfo = IssueStore.getEditFilterInfo;
const { isHasFilter } = IssueStore;
const [quickFilters, setQuickFilters] = useState([]);
const [selectedQuickFilters, setSelectedQuickFilters] = useState([]);
const loadFilters = async () => {
IssueStore.axiosGetMyFilterList();
const QuickFilters = await quickFilterApi.loadAll();
setQuickFilters(QuickFilters);
};

useEffect(() => {
loadFilters();
IssueStore.loadCustomFields();
}, []);
const reset = () => {
const {
paramChoose, paramCurrentVersion, paramCurrentSprint, paramId,
paramType, paramIssueId, paramName, paramOpenIssueId, ...otherArgs
} = getParams(location.search);
setSelectedQuickFilters([]);
if (paramOpenIssueId || paramIssueId || paramChoose || paramType) {
history.replace(linkUrl(LINK_URL.workListIssue));
}
onClear();
IssueStore.clearAllFilter();
IssueStore.query();
store.clearAllFilter();
store.query();
};
const handleSelect = (v) => {
const handleSelect = (v: LabeledValue) => {
const { key: k } = v;
const [type, id] = k.split('|');
if (type === 'quick') {
const newSelectedQuickFilters = [...selectedQuickFilters, v];
setSelectedQuickFilters([...selectedQuickFilters, v]);
const quickFilterIds = newSelectedQuickFilters.map((filter) => filter.key.split('|')[1]);
IssueStore.handleFilterChange('quickFilterIds', quickFilterIds);
store.handleFilterChange('quickFilterIds', quickFilterIds);
} else if (type === 'my') {
const targetMyFilter = find(filters, { filterId: id });
const filterObject = flattenObject(JSON.parse(targetMyFilter.filterJson));
const targetMyFilter = find(myFilters, { filterId: id });
const filterObject = flattenObject(JSON.parse(targetMyFilter?.filterJson || '{}'));
// 先清除筛选
IssueStore.clearAllFilter();
store.clearAllFilter();
for (const [key, value] of Object.entries(filterObject)) {
// 自定义字段保存的时候只保存了id,这里要找到code
if (value.isCustom) {
const code = IssueStore.getFieldCodeById(key);
const code = store.getFieldCodeById(key);
if (code) {
IssueStore.handleFilterChange(code, value.value);
store.handleFilterChange(code, value.value);
}
} else if (key === 'createEndDate' || key === 'createStartDate') {
IssueStore.handleFilterChange('createDate', [filterObject.createStartDate, filterObject.createEndDate]);
store.handleFilterChange('createDate', [filterObject.createStartDate, filterObject.createEndDate]);
} else if (key === 'updateEndDate' || key === 'updateStartDate') {
IssueStore.handleFilterChange('updateDate', [filterObject.updateStartDate, filterObject.updateEndDate]);
store.handleFilterChange('updateDate', [filterObject.updateStartDate, filterObject.updateEndDate]);
} else {
IssueStore.handleFilterChange(key, value);
store.handleFilterChange(key, value);
}
}
}
};
const handleDeselect = (v) => {
const handleDeselect = (v: LabeledValue) => {
// clear
if (!v) {
setSelectedQuickFilters([]);
Expand All @@ -101,67 +74,64 @@ export default withRouter(observer(({
remove(selectedQuickFilters, { key });
setSelectedQuickFilters([...selectedQuickFilters]);
} else if (type === 'my') {
IssueStore.clearAllFilter();
IssueStore.query();
store.clearAllFilter();
store.query();
}
const quickFilterIds = selectedQuickFilters.map((filter) => filter.key.split('|')[1]);
IssueStore.handleFilterChange('quickFilterIds', quickFilterIds);
store.handleFilterChange('quickFilterIds', quickFilterIds);
};

const findSameFilter = () => {
const currentFilterDTO = IssueStore.getCustomFieldFilters()
? flattenObject(IssueStore.getCustomFieldFilters()) : {};
const currentFilterDTO = store.getCustomFieldFilters()
? flattenObject(store.getCustomFieldFilters()) : {};
// console.log(currentFilterDTO);
// 找到与当前筛选相同条件的我的筛选
const targetMyFilter = find(filters,
const targetMyFilter = find(myFilters,
(filter) => isFilterSame(flattenObject(JSON.parse(filter.filterJson)), currentFilterDTO));
return targetMyFilter;
};
const getMyFilterSelectValue = () => {
const targetMyFilter = findSameFilter();
return targetMyFilter ? selectedQuickFilters.concat({ key: `my|${targetMyFilter.filterId}`, label: targetMyFilter.name }) : selectedQuickFilters;
};
const handleClickSaveFilter = () => {
IssueStore.setSaveFilterVisible(true);
IssueStore.setFilterListVisible(false);
IssueStore.setEditFilterInfo(map(editFilterInfo,
(item) => Object.assign(item, { isEditing: false })));
};
const handleInputChange = (value) => {
const handleInputChange = (value: string) => {
if (value) {
IssueStore.handleFilterChange('contents', [value]);
store.handleFilterChange('contents', [value]);
} else {
IssueStore.handleFilterChange('contents', []);
store.handleFilterChange('contents', []);
}
IssueStore.handleFilterChange('issueIds', []);
store.handleFilterChange('issueIds', []);
};
const myFilterSelectValue = getMyFilterSelectValue();
const renderSearch = () => (
<>
<div style={{ marginTop: 4 }}>
<SummaryField
onChange={handleInputChange}
value={IssueStore.getFilterValueByCode('contents') ? IssueStore.getFilterValueByCode('contents')[0] : undefined}
value={store.getFilterValueByCode('contents') ? store.getFilterValueByCode('contents')[0] : undefined}
/>
</div>
<div className={`${prefixCls}-search-left`}>
<CustomFields>
<div style={{ margin: '4px 5px' }}>
<Select
mode="multiple"
mode={'multiple' as SelectMode}
showCheckAll={false}
allowClear
className="SelectTheme"
dropdownMatchSelectWidth={false}
placeholder="快速筛选"
maxTagCount={0}
labelInValue
maxTagPlaceholder={(ommittedValues) => `${ommittedValues.map((item) => item.label).join(', ')}`}
style={{ ...getSelectStyle({ name: '快速筛选' }, getMyFilterSelectValue()), height: 34 }}
maxTagPlaceholder={(ommittedValues : LabeledValue[]) => `${ommittedValues.map((item) => item.label).join(', ')}`}
style={{ ...getSelectStyle({ name: '快速筛选' }, myFilterSelectValue), height: 34 }}
onSelect={handleSelect}
onDeselect={handleDeselect}
onClear={handleDeselect}
value={getMyFilterSelectValue()}
getPopupContainer={(triggerNode) => triggerNode.parentNode}
onClear={() => {
setSelectedQuickFilters([]);
reset();
}}
value={myFilterSelectValue}
// getPopupContainer={(triggerNode) => triggerNode.parentNode}
>
<OptGroup key="quick" label="快速筛选">
{quickFilters.map((filter) => (
Expand All @@ -170,7 +140,7 @@ export default withRouter(observer(({
</OptGroup>
<OptGroup key="my" label="我的筛选">
{
filters.map((filter) => (
myFilters.map((filter) => (
<Option value={`my|${filter.filterId}`}>{filter.name}</Option>
))
}
Expand All @@ -180,8 +150,24 @@ export default withRouter(observer(({
</CustomFields>
</div>
<div className={`${prefixCls}-search-right`}>
{isHasFilter && <Button onClick={reset} funcType="flat" color="blue">重置</Button>}
{!findSameFilter() && isHasFilter && <Button onClick={handleClickSaveFilter} funcType="raised" color="blue">保存筛选</Button>}
{isHasFilter && (
<Button
onClick={reset}
funcType={'flat' as FuncType}
color={'blue' as ButtonColor}
>
重置
</Button>
)}
{!findSameFilter() && isHasFilter && (
<Button
onClick={onClickSaveFilter}
funcType={'raised' as FuncType}
color={'blue' as ButtonColor}
>
保存筛选
</Button>
)}
</div>
</>
);
Expand All @@ -194,7 +180,7 @@ export default withRouter(observer(({
</div>
</div>
<div className={`${prefixCls}-search-right`}>
<Button onClick={reset} funcType="flat" color="blue">重置</Button>
<Button onClick={reset} funcType={'flat' as FuncType} color={'blue' as ButtonColor}>重置</Button>
</div>
</>
);
Expand All @@ -203,4 +189,5 @@ export default withRouter(observer(({
{urlFilter ? renderUrlFilter() : renderSearch()}
</div>
);
}));
};
export default observer(SearchArea);
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import React, { useState } from 'react';
import React, { useState, useContext } from 'react';
import { observer } from 'mobx-react-lite';
import {
CheckBox, Button, TextField, Icon,
} from 'choerodon-ui/pro';
import IssueStore, { getSystemFields } from '@/stores/project/issue/IssueStore';
import { getSystemFields } from '@/stores/project/issue/IssueStore';
import IssueSearchContext from '../context';
import './FieldList.less';

const prefix = 'c7nagile-choose-field-list';
function FieldList() {
const { store } = useContext(IssueSearchContext);
const {
fields, chosenFields, handleChosenFieldChange,
} = IssueStore;
} = store;
const systemFields = getSystemFields();
const selectableSystemFields = systemFields.filter((field) => !field.defaultShow);
const defaultShowSystemFields = systemFields.filter((field) => field.defaultShow);
Expand Down Expand Up @@ -42,9 +44,9 @@ function FieldList() {
checked={checked}
onChange={(checkAll) => {
if (checkAll) {
IssueStore.chooseAll([...filteredFields, ...filteredSystemFields]);
store.chooseAll([...filteredFields, ...filteredSystemFields]);
} else {
IssueStore.unChooseAll();
store.unChooseAll();
}
}}
>
Expand All @@ -53,7 +55,7 @@ function FieldList() {
<Button
style={{ display: checked || indeterminate ? 'inline-block' : 'none' }}
onClick={() => {
IssueStore.unChooseAll();
store.unChooseAll();
}}
>
清除筛选项
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {
useState, useCallback, useRef, useEffect,
} from 'react';
import {
Button, Icon,
Button, Icon,
} from 'choerodon-ui/pro';
import { Dropdown } from 'choerodon-ui';
import { observer } from 'mobx-react-lite';
Expand All @@ -24,8 +24,8 @@ function useClickOut(onClickOut) {
return ref;
}

function ChooseField() {
const [hidden, setHidden] = useState(true);
function ChooseField() {
const [hidden, setHidden] = useState(true);
const handleClickOut = useCallback(() => {
setHidden(true);
}, []);
Expand All @@ -35,10 +35,11 @@ function ChooseField() {
style={{ marginLeft: 5, display: 'flex', alignItems: 'center' }}
>
<Dropdown
getPopupContainer={trigger => trigger.parentNode}
getPopupContainer={(trigger) => trigger.parentNode}
visible={!hidden}
overlay={(
<div
<div
role="none"
ref={ref}
onClick={(e) => {
e.stopPropagation();
Expand All @@ -59,7 +60,7 @@ function ChooseField() {
<Icon type="arrow_drop_down" />
</Button>
</Dropdown>
</div>
</div>
);
}
export default observer(ChooseField);
11 changes: 11 additions & 0 deletions react/components/issue-search/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { createContext } from 'react';
import IssueSearchStore from './store';
import { IssueSearchProps } from './index';

export interface IIssueSearchContext extends Omit<IssueSearchProps, 'onChange'> {
store: IssueSearchStore

}

const context = createContext<IIssueSearchContext>({} as IIssueSearchContext);
export default context;
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React from 'react';
import { observer } from 'mobx-react-lite';
import { Input, Icon } from 'choerodon-ui';

function SummaryField({ field, value, onChange }) {
function SummaryField({ value, onChange }) {
return (
<Input
value={value}
onChange={e => onChange(e.target.value)}
onChange={(e) => onChange(e.target.value)}
className="hidden-label"
prefix={<Icon type="search" style={{ color: 'rgba(0, 0, 0, 0.45)', marginLeft: 2 }} />}
style={{ width: 180, marginRight: 5 }}
Expand Down
Loading

0 comments on commit 666bd6d

Please sign in to comment.