antd#Transfer TypeScript Examples
The following examples show how to use
antd#Transfer.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: data-task-creation.tsx From erda-ui with GNU Affero General Public License v3.0 | 6 votes |
render() {
const { isFetching, onCancel } = this.props;
const { targetKeys, sourceFiles, selectedKeys } = this.state;
return (
<div className="data-task">
<Spin spinning={isFetching}>
<Transfer
rowKey={(record) => record.title}
showSearch
className="data-task-transfer"
dataSource={sourceFiles}
targetKeys={targetKeys}
selectedKeys={selectedKeys}
onChange={this.handleChange}
render={this.renderItem}
listStyle={{ width: 352, height: 482 }}
onSelectChange={this.onSelectChange}
/>
<section className="footer flex justify-between items-center mt-5">
<span>
<CustomIcon type="jg" />
{i18n.t('dop:can only add up to 10 files at a time')}
</span>
<div>
<Button className="ml-2" onClick={onCancel}>
{i18n.t('Cancel')}
</Button>
<Button className="ml-2" type="primary" onClick={this.onOk}>
{i18n.t('OK')}
</Button>
</div>
</section>
</Spin>
</div>
);
}
Example #2
Source File: GeneralTransfer.spec.tsx From next-basics with GNU General Public License v3.0 | 5 votes |
describe("GeneralTransfer", () => {
it("should work", () => {
const changeFn = jest.fn();
const selectFn = jest.fn();
const wrapper = shallow(
<GeneralTransfer
dataSource={[]}
onChange={changeFn}
onSelectedChange={selectFn}
/>
);
let transfer = wrapper.find(Transfer).first();
transfer.invoke("onChange")([], "", []);
expect(changeFn).toBeCalledWith([]);
transfer.invoke("onSelectChange")([], []);
expect(selectFn).toBeCalledWith([], []);
transfer.invoke("filterOption")("x", {
key: "host.disk.used_total",
title: "disk used total",
});
wrapper.setProps({ maxSelected: 10 });
transfer = wrapper.find(Transfer).first();
expect(transfer.invoke("footer")(null)).toBeTruthy();
expect(transfer.invoke("render")({ key: "x", title: "title" })).toBe(
"title"
);
});
it("should work and maxSelected", () => {
const changeFn = jest.fn();
const selectFn = jest.fn();
const wrapper = shallow(
<GeneralTransfer
dataSource={[
{
key: "1",
title: "test1",
},
{
key: "2",
title: "test2",
},
{
key: "3",
title: "test3",
},
{
key: "4",
title: "test3",
},
]}
onChange={changeFn}
onSelectedChange={selectFn}
maxSelected={2}
/>
);
const transfer = wrapper.find(Transfer).first();
transfer.invoke("onChange")(["1", "2", "3"], "right", []);
expect(changeFn).not.toHaveBeenCalled();
});
});
Example #3
Source File: GeneralTransfer.tsx From next-basics with GNU General Public License v3.0 | 5 votes |
export function GeneralTransfer(
props: GeneralTransferProps
): React.ReactElement {
const { t } = useTranslation(NS_PRESENTATIONAL_BRICKS);
const onChange = (
targetKeys: string[],
direction: "left" | "right",
moveKeys: string[]
): void => {
if (
direction === "left" ||
!props.maxSelected ||
targetKeys.length <= props.maxSelected
) {
props.onChange(targetKeys);
} else {
Modal.warning({
title: "提示",
content: `所选数量超过最大限制(${props.maxSelected}),请重新选择`,
okText: "知道了",
});
}
};
const onSelectChange = (
sourceSelectedKeys: string[],
targetSelectedKeys: string[]
): void => {
props.onSelectedChange?.(sourceSelectedKeys, targetSelectedKeys);
};
const filterOption = (inputValue: string, item: TransferItem): boolean => {
const q = inputValue.trim().toLowerCase();
return item.title.toLowerCase().includes(q);
};
const footer = (): React.ReactNode => {
return (
<div className={cssStyle.footer}>最多选择 {props.maxSelected} 个</div>
);
};
return (
<div className={cssStyle.container}>
<Transfer
lazy={false}
dataSource={props.dataSource}
render={(item) => item.title}
targetKeys={props.targetKeys}
onChange={onChange}
onSelectChange={onSelectChange}
locale={props.locale}
listStyle={props.listStyle}
titles={props.titles}
operations={props.operations}
selectedKeys={props.selectedKeys}
disabled={props.disabled}
filterOption={filterOption}
showSearch={props.showSearch}
showSelectAll={props.showSelectAll}
footer={props.maxSelected && footer}
/>
</div>
);
}
Example #4
Source File: MemberForm.tsx From datart with Apache License 2.0 | 5 votes |
MemberForm = memo(
({ initialValues, onChange, onCancel, ...modalProps }: MemberFormProps) => {
const [targetKeys, setTargetKeys] = useState<string[]>([]);
const dispatch = useDispatch();
const formRef = useRef<FormInstance>();
const members = useSelector(selectMembers);
const memberListLoading = useSelector(selectMemberListLoading);
const orgId = useSelector(selectOrgId);
const dataSource = useMemo(
() => members.map(m => ({ ...m, key: m.id })),
[members],
);
useEffect(() => {
if (modalProps.visible) {
dispatch(getMembers(orgId));
}
}, [dispatch, orgId, modalProps.visible]);
useEffect(() => {
setTargetKeys(initialValues.map(({ id }) => id));
}, [initialValues]);
const save = useCallback(() => {
onChange(targetKeys.map(id => members.find(m => m.id === id)!));
onCancel && onCancel(null as any);
}, [targetKeys, members, onCancel, onChange]);
const renderTitle = useCallback(
({ name, username, email }) => (
<ItemTitle>
{name && <span>{name}</span>}
{username && <span>{` (${username})`}</span>}
{email && <span className="email">{email}</span>}
</ItemTitle>
),
[],
);
const filterMemberListOptions = useCallback(
(inputValue, option: User) =>
[option.email, option.name, option.username].some(text =>
text?.includes(inputValue.trim()),
),
[],
);
return (
<ModalForm
{...modalProps}
onSave={save}
onCancel={onCancel}
ref={formRef}
>
<TransferWrapper>
<LoadingMask loading={memberListLoading}>
<Transfer
dataSource={dataSource}
targetKeys={targetKeys}
render={renderTitle}
onChange={setTargetKeys}
filterOption={filterMemberListOptions}
showSearch
/>
</LoadingMask>
</TransferWrapper>
</ModalForm>
);
},
)
Example #5
Source File: CreateForm.tsx From anew-server with MIT License | 5 votes |
CreateForm: React.FC<CreateFormProps> = (props) => {
const { actionRef, modalVisible, handleChange } = props;
const [hostData, setHostData] = useState<TransferItem[]>([]);
const [targetKeys, setTargetKeys] = useState<string[]>([]);
const transferChange = (keys: string[]) => {
setTargetKeys(keys);
};
useEffect(() => {
queryHosts({ all: true }).then((res) => {
if (Array.isArray(res.data.data)) {
setHostData(
res.data.data.map((item: API.HostList) => ({
key: item.id,
title: item.host_name,
description: item.ip_address,
})),
);
}
});
}, []);
return (
<ModalForm
title="新建主机组"
visible={modalVisible}
onVisibleChange={handleChange}
onFinish={async (v) => {
createHostGroup(v as API.HostGroupParams).then((res) => {
if (res.code === 200 && res.status === true) {
message.success(res.message);
if (actionRef.current) {
actionRef.current.reload();
}
}
});
return true;
}}
>
<ProForm.Group>
<ProFormText name="name" label="名称" width="md" rules={[{ required: true }]} />
<ProFormText name="desc" label="说明" width="md" />
<Form.Item label="选择主机" name="hosts">
<Transfer
dataSource={hostData}
showSearch
listStyle={{
width: 320,
height: 280,
}}
//operations={['加入', '退出']}
targetKeys={targetKeys}
onChange={transferChange}
render={(item) => `${item.title}(${item.description})`}
/>
</Form.Item>
</ProForm.Group>
</ModalForm>
);
}
Example #6
Source File: UpdateForm.tsx From anew-server with MIT License | 5 votes |
UpdateForm: React.FC<UpdateFormProps> = (props) => {
const { actionRef, modalVisible, handleChange, values } = props;
const [hostData, setHostData] = useState<TransferItem[]>([]);
const [targetKeys, setTargetKeys] = useState<string[]>([]);
const transferChange = (keys: string[]) => {
setTargetKeys(keys);
};
useEffect(() => {
console.log(hostData)
},[hostData]);
useEffect(() => {
queryHosts({ all: true }).then((res) => {
if (Array.isArray(res.data.data)) {
setHostData(
res.data.data.map((item: API.HostList) => ({
key: item.id,
title: item.host_name,
description: item.ip_address,
})),
);
}
});
transferChange(values?.hosts_id as unknown as string[])
}, []);
return (
<ModalForm
title="更新主机组"
visible={modalVisible}
onVisibleChange={handleChange}
onFinish={async (v) => {
updateHostGroup(v as API.HostGroupParams, values?.id).then((res) => {
if (res.code === 200 && res.status === true) {
message.success(res.message);
if (actionRef.current) {
actionRef.current.reload();
}
}
});
return true;
}}
>
<ProForm.Group>
<ProFormText
name="name"
label="名称"
width="md"
initialValue={values?.name}
rules={[{ required: true }]}
/>
<ProFormText name="desc" label="说明" width="md" initialValue={values?.desc} />
<Form.Item label="选择主机" name="hosts">
<Transfer
dataSource={hostData}
showSearch
listStyle={{
width: 320,
height: 280,
}}
//operations={['加入', '退出']}
targetKeys={targetKeys ? targetKeys : []}
onChange={transferChange}
render={(item) => `${item.title}(${item.description})`}
/>
</Form.Item>
</ProForm.Group>
</ModalForm>
);
}
Example #7
Source File: change-permission-form.tsx From erda-ui with GNU Affero General Public License v3.0 | 4 votes |
ChangePermissionForm = (props: IProps) => {
const { visible, data, onClose, handleSubmit } = props;
const RDSDatabaseList = cloudServiceStore.useStore((s) => s.RDSDatabaseList);
const [rdsID, query] = routeInfoStore.useStore((s) => [s.params.rdsID, s.query]);
const { getRDSDatabaseList } = cloudServiceStore.effects;
const [{ targetKeys, permissionChoose }, updater, update] = useUpdate({
targetKeys: [],
permissionChoose: {},
});
useMount(() => {
getRDSDatabaseList({
id: rdsID,
query,
});
});
useEffect(() => {
const newKeys: string[] = [];
const newChoose = {};
forEach(get(data, 'databasePrivileges'), (item) => {
newKeys.push(item.dBName);
newChoose[item.dBName] = item.accountPrivilege;
});
update({
targetKeys: newKeys,
permissionChoose: newChoose,
});
}, [data, update]);
const handleChange = (keys: string[]) => {
update({
targetKeys: keys,
permissionChoose: reduce(
keys,
(acc, key) => {
const newPermissionChoose = {
...acc,
[key]: permissionChoose[key] || rdsAccountType[0].value,
};
return newPermissionChoose;
},
{},
),
});
};
const renderTransferItem = (item: TransferItem) => {
const { key } = item;
const label = (
<>
{item.key}
<span className="permission-select" onClick={(e: any) => e.stopPropagation()}>
<RadioGroup
onChange={(e: any) => {
updater.permissionChoose({
...permissionChoose,
[key]: e.target.value,
});
}}
value={permissionChoose[key]}
>
{rdsAccountType.map((per) => (
<Radio key={per.value} value={per.value}>
{per.name}
</Radio>
))}
</RadioGroup>
</span>
</>
);
return {
label,
value: item.key,
};
};
const fieldsList = [
{
getComp: () => {
return (
<span>
{i18n.t('cmp:database account')}: {get(data, 'AccountName')}
</span>
);
},
},
{
label: i18n.t('cmp:authorization database'),
getComp: () => {
return (
<Transfer
dataSource={map(RDSDatabaseList, (db) => ({
key: db.dBName,
title: db.dBName,
}))}
className="permission-transfer"
targetKeys={targetKeys}
onChange={handleChange}
render={renderTransferItem}
titles={[i18n.t('cmp:unauthorized database'), i18n.t('cmp:authorized database')]}
/>
);
},
},
];
return (
<FormModal
title={i18n.t('change account permissions')}
visible={visible}
fieldsList={fieldsList}
width={800}
onCancel={onClose}
onOk={() => handleSubmit(permissionChoose)}
/>
);
}
Example #8
Source File: CategoryConditionConfiguration.tsx From datart with Apache License 2.0 | 4 votes |
CategoryConditionConfiguration: ForwardRefRenderFunction<
FilterOptionForwardRef,
{
colName: string;
dataView?: ChartDataView;
condition?: ChartFilterCondition;
onChange: (condition: ChartFilterCondition) => void;
fetchDataByField?: (fieldId) => Promise<string[]>;
} & I18NComponentProps
> = (
{
colName,
i18nPrefix,
condition,
dataView,
onChange: onConditionChange,
fetchDataByField,
},
ref,
) => {
const t = useI18NPrefix(i18nPrefix);
const [curTab, setCurTab] = useState<FilterConditionType>(() => {
if (
[
FilterConditionType.List,
FilterConditionType.Condition,
FilterConditionType.Customize,
].includes(condition?.type!)
) {
return condition?.type!;
}
return FilterConditionType.List;
});
const [targetKeys, setTargetKeys] = useState<string[]>(() => {
let values;
if (condition?.operator === FilterSqlOperator.In) {
values = condition?.value;
if (Array.isArray(condition?.value)) {
const firstValues =
(condition?.value as [])?.filter(n => {
if (IsKeyIn(n as RelationFilterValue, 'key')) {
return (n as RelationFilterValue).isSelected;
}
return false;
}) || [];
values = firstValues?.map((n: RelationFilterValue) => n.key);
}
}
return values || [];
});
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
const [isTree, setIsTree] = useState(isTreeModel(condition?.value));
const [treeOptions, setTreeOptions] = useState<string[]>([]);
const [listDatas, setListDatas] = useState<RelationFilterValue[]>([]);
const [treeDatas, setTreeDatas] = useState<RelationFilterValue[]>([]);
useImperativeHandle(ref, () => ({
onValidate: (args: ChartFilterCondition) => {
if (isEmpty(args?.operator)) {
return false;
}
if (args?.operator === FilterSqlOperator.In) {
return !isEmptyArray(args?.value);
} else if (
[
FilterSqlOperator.Contain,
FilterSqlOperator.PrefixContain,
FilterSqlOperator.SuffixContain,
FilterSqlOperator.Equal,
FilterSqlOperator.NotContain,
FilterSqlOperator.NotPrefixContain,
FilterSqlOperator.NotSuffixContain,
FilterSqlOperator.NotEqual,
].includes(args?.operator as FilterSqlOperator)
) {
return !isEmpty(args?.value);
} else if (
[FilterSqlOperator.Null, FilterSqlOperator.NotNull].includes(
args?.operator as FilterSqlOperator,
)
) {
return true;
}
return false;
},
}));
useMount(() => {
if (curTab === FilterConditionType.List) {
handleFetchData();
}
});
const getDataOptionFields = () => {
return dataView?.meta || [];
};
const isChecked = (selectedKeys, eventKey) =>
selectedKeys.indexOf(eventKey) !== -1;
const fetchNewDataset = async (viewId, colName: string) => {
const fieldDataset = await getDistinctFields(
viewId,
[colName],
undefined,
undefined,
);
return fieldDataset;
};
const setListSelectedState = (
list?: RelationFilterValue[],
keys?: string[],
) => {
return (list || []).map(c =>
Object.assign(c, { isSelected: isChecked(keys, c.key) }),
);
};
const setTreeCheckableState = (
treeList?: RelationFilterValue[],
keys?: string[],
) => {
return (treeList || []).map(c => {
c.isSelected = isChecked(keys, c.key);
c.children = setTreeCheckableState(c.children, keys);
return c;
});
};
const handleGeneralListChange = async selectedKeys => {
const items = setListSelectedState(listDatas, selectedKeys);
setTargetKeys(selectedKeys);
setListDatas(items);
const generalTypeItems = items?.filter(i => i.isSelected);
const filter = new ConditionBuilder(condition)
.setOperator(FilterSqlOperator.In)
.setValue(generalTypeItems)
.asGeneral();
onConditionChange(filter);
};
const filterGeneralListOptions = useCallback(
(inputValue, option) => option.label?.includes(inputValue) || false,
[],
);
const handleGeneralTreeChange = async treeSelectedKeys => {
const selectedKeys = treeSelectedKeys.checked;
const treeItems = setTreeCheckableState(treeDatas, selectedKeys);
setTargetKeys(selectedKeys);
setTreeDatas(treeItems);
const filter = new ConditionBuilder(condition)
.setOperator(FilterSqlOperator.In)
.setValue(treeItems)
.asTree();
onConditionChange(filter);
};
const onSelectChange = (
sourceSelectedKeys: string[],
targetSelectedKeys: string[],
) => {
const newSelectedKeys = [...sourceSelectedKeys, ...targetSelectedKeys];
setSelectedKeys(newSelectedKeys);
};
const handleTreeOptionChange = (
associateField: string,
labelField: string,
) => {
setTreeOptions([associateField, labelField]);
};
const handleFetchData = () => {
fetchNewDataset?.(dataView?.id, colName).then(dataset => {
if (isTree) {
// setTreeDatas(convertToTree(dataset?.columns, selectedKeys));
// setListDatas(convertToList(dataset?.columns, selectedKeys));
} else {
setListDatas(convertToList(dataset?.rows, selectedKeys));
}
});
};
const convertToList = (collection, selectedKeys) => {
const items: string[] = (collection || []).flatMap(c => c);
const uniqueKeys = Array.from(new Set(items));
return uniqueKeys.map(item => ({
key: item,
label: item,
isSelected: selectedKeys.includes(item),
}));
};
const convertToTree = (collection, selectedKeys) => {
const associateField = treeOptions?.[0];
const labelField = treeOptions?.[1];
if (!associateField || !labelField) {
return [];
}
const associateKeys = Array.from(
new Set(collection?.map(c => c[associateField])),
);
const treeNodes = associateKeys
.map(key => {
const associateItem = collection?.find(c => c[colName] === key);
if (!associateItem) {
return null;
}
const associateChildren = collection
.filter(c => c[associateField] === key)
.map(c => {
const itemKey = c[labelField];
return {
key: itemKey,
label: itemKey,
isSelected: isChecked(selectedKeys, itemKey),
};
});
const itemKey = associateItem?.[colName];
return {
key: itemKey,
label: itemKey,
isSelected: isChecked(selectedKeys, itemKey),
children: associateChildren,
};
})
.filter(i => Boolean(i)) as RelationFilterValue[];
return treeNodes;
};
const handleTabChange = (activeKey: string) => {
const conditionType = +activeKey;
setCurTab(conditionType);
const filter = new ConditionBuilder(condition)
.setOperator(null!)
.setValue(null)
.asFilter(conditionType);
setTreeDatas([]);
setTargetKeys([]);
setListDatas([]);
onConditionChange(filter);
};
return (
<StyledTabs activeKey={curTab.toString()} onChange={handleTabChange}>
<Tabs.TabPane
tab={t('general')}
key={FilterConditionType.List.toString()}
>
<Row>
<Space>
<Button type="primary" onClick={handleFetchData}>
{t('load')}
</Button>
{/* <Checkbox
checked={isTree}
disabled
onChange={e => setIsTree(e.target.checked)}
>
{t('useTree')}
</Checkbox> */}
</Space>
</Row>
<Row>
<Space>
{isTree && (
<>
{t('associateField')}
<Select
value={treeOptions?.[0]}
options={getDataOptionFields()?.map(f => ({
label: f.name,
value: f.id,
}))}
onChange={value =>
handleTreeOptionChange(value, treeOptions?.[1])
}
/>
{t('labelField')}
<Select
value={treeOptions?.[1]}
options={getDataOptionFields()?.map(f => ({
label: f.name,
value: f.id,
}))}
onChange={value =>
handleTreeOptionChange(treeOptions?.[0], value)
}
/>
</>
)}
</Space>
</Row>
{isTree && (
<Tree
blockNode
checkable
checkStrictly
defaultExpandAll
checkedKeys={targetKeys}
treeData={treeDatas}
onCheck={handleGeneralTreeChange}
onSelect={handleGeneralTreeChange}
/>
)}
{!isTree && (
<Transfer
operations={[t('moveToRight'), t('moveToLeft')]}
dataSource={listDatas}
titles={[`${t('sourceList')}`, `${t('targetList')}`]}
targetKeys={targetKeys}
selectedKeys={selectedKeys}
onChange={handleGeneralListChange}
onSelectChange={onSelectChange}
render={item => item.label}
filterOption={filterGeneralListOptions}
showSearch
pagination
/>
)}
</Tabs.TabPane>
<Tabs.TabPane
tab={t('customize')}
key={FilterConditionType.Customize.toString()}
>
<CategoryConditionEditableTable
dataView={dataView}
i18nPrefix={i18nPrefix}
condition={condition}
onConditionChange={onConditionChange}
fetchDataByField={fetchDataByField}
/>
</Tabs.TabPane>
<Tabs.TabPane
tab={t('condition')}
key={FilterConditionType.Condition.toString()}
>
<CategoryConditionRelationSelector
condition={condition}
onConditionChange={onConditionChange}
/>
</Tabs.TabPane>
</StyledTabs>
);
}
Example #9
Source File: DomainAccess.tsx From wildduck-ui with MIT License | 4 votes |
DomainAccess: React.FC = () => {
const { Search } = Input;
const { setBlockedList, setTag, setAllowedList, setAddDomainModalVisiblity, setDataSource } = useActions(
domainAccessLogic,
);
const { blockedList, tag, allowedList, addDomainModalVisiblity, dataSource } = useValues(domainAccessLogic);
const { data: allowedListData, isLoading: allowedListLoading } = useAllowedList(tag);
const { data: blockedListData, isLoading: blockedListLoading } = useBlockedList(tag);
const { mutate } = useDeleteDomain();
const { mutate: addDomainToAllowList } = useCreateAllowedDomain();
const { mutate: addDomainToBlockList } = useCreateBlockedDomain();
const onSearch = (value: string) => {
if (value.length > 0) {
setTag(value);
}
};
const renderFooter = () => (
<Button size='small' style={{ float: 'right', margin: 5 }} onClick={() => setAddDomainModalVisiblity(true)}>
Add Domain
</Button>
);
const onChange = (targetKeys: string[], direction: string, moveKeys: string[]) => {
const blockList = _.filter(dataSource, (domain) => targetKeys.includes(domain.id));
const moveList = _.filter(dataSource, (domain) => moveKeys.includes(domain.id));
if (direction === 'right') {
_.forEach(moveList, (domain) => addDomainToBlockList({ tag: tag, domain: domain.domain }));
setAllowedList(_.filter(allowedList, (domain) => !moveKeys.includes(domain.id)));
} else {
_.forEach(moveList, (domain) => addDomainToAllowList({ tag: tag, domain: domain.domain }));
setAllowedList(_.concat(allowedList, moveList));
}
setBlockedList(blockList);
};
useEffect(() => {
setAllowedList(_.uniq(allowedListData));
setBlockedList(_.uniq(blockedListData));
setDataSource(_.uniqBy(_.concat(allowedListData, blockedListData), 'id'));
}, [allowedListData, blockedListData]);
const Content = ({ item }: { item: any }) => (
<Row style={{ display: 'flex', justifyContent: 'space-between' }}>
<Col>{item.domain}</Col>
<Col>
<DeleteOutlined onClick={() => showConfirm(() => mutate(item.id))} />
</Col>
</Row>
);
const AddDomains = () => {
const onFinish = (values: any) => {
values.action === 'allow'
? addDomainToAllowList({ tag: tag, domain: values.domain })
: addDomainToBlockList({ tag: tag, domain: values.domain });
};
return (
<Form {...layout} onFinish={onFinish} initialValues={{ action: 'allow' }}>
<Form.Item
label='Domain'
name='domain'
wrapperCol={{ span: '10' }}
rules={[
{
required: true,
message: 'Please input the Domain!',
},
]}
>
<Input placeholder='Domain name' />
</Form.Item>
<Form.Item label='Add To' name='action'>
<Select style={{ width: 120 }}>
<Select.Option value='allow'>Allow List</Select.Option>
<Select.Option value='block'>Block List</Select.Option>
</Select>
</Form.Item>
<Form.Item {...tailLayout}>
<Button type='primary' htmlType='submit'>
Add
</Button>
</Form.Item>
</Form>
);
};
return (
<Page title='Domain Access' loading={allowedListLoading || blockedListLoading}>
<Search
size='large'
placeholder='Enter a Tag'
defaultValue={tag}
allowClear
enterButton='Search'
onSearch={onSearch}
/>
{!_.isEmpty(tag) && !allowedListLoading && !blockedListLoading && (
<Transfer
dataSource={_.map(_.uniqBy(_.concat(allowedListData, blockedListData), 'id'), (domain) => ({
...domain,
key: domain.id,
}))}
targetKeys={_.map(blockedList, (domain) => domain.id)}
titles={['Allowed List', 'Blocked List']}
style={{ paddingTop: '5px' }}
showSearch
listStyle={{
width: '90%',
height: '90%',
}}
operations={['to right', 'to left']}
render={(item: any) => ({ value: item.domain, label: <Content item={item} /> })}
footer={renderFooter}
onChange={onChange}
/>
)}
<Modal
title='Add Domain'
visible={addDomainModalVisiblity}
onCancel={() => setAddDomainModalVisiblity(false)}
footer={null}
>
<AddDomains />
</Modal>
</Page>
);
}