at the end of the day, it was inevitable
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { translate } from 'react-i18next';
|
||||
import { Col } from 'reactstrap';
|
||||
|
||||
export class InfoField extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
label: PropTypes.string,
|
||||
labelValue: PropTypes.string,
|
||||
children: PropTypes.oneOfType([PropTypes.string, PropTypes.element])
|
||||
};
|
||||
|
||||
render() {
|
||||
const { t, label, children, labelValue } = this.props;
|
||||
|
||||
return (
|
||||
<li className="row">
|
||||
<Col sm="4">
|
||||
<p className="mb-1">{labelValue || t(label)}</p>
|
||||
</Col>
|
||||
<Col sm="8">
|
||||
<p className="mb-1">{children}</p>
|
||||
</Col>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(InfoField);
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { translate } from 'react-i18next';
|
||||
import PopupLayout from '../../../../common/Popups/PopupLayout';
|
||||
import InfoField from './InfoField';
|
||||
import {
|
||||
capOnlyFirstLetter,
|
||||
getTitle,
|
||||
notNullAndUnd
|
||||
} from '../../../../../common/helper';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faCheckCircle } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
class SourceIndexInfoPopup extends React.Component {
|
||||
static propTypes = {
|
||||
source: PropTypes.object.isRequired,
|
||||
hideSourceInfoPopup: PropTypes.func.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
let { t, source, hideSourceInfoPopup } = this.props;
|
||||
/*
|
||||
const loc = cl(
|
||||
source.city,
|
||||
source.state,
|
||||
source.country && t(`common:country.${source.country}`)
|
||||
)
|
||||
.split(' ')
|
||||
.join(', '); */
|
||||
/*
|
||||
source = {
|
||||
...source,
|
||||
tags: ['Lorem', 'ipsum', 'dolor', 'ipsum', 'dolor', 'ipsum', 'dolor'],
|
||||
verified: true,
|
||||
followers: 3333,
|
||||
following: 33,
|
||||
favorites: 333,
|
||||
title: 'Title',
|
||||
url: 'URL',
|
||||
type: 'Type',
|
||||
subType: 'Sub Type',
|
||||
lang: 'en',
|
||||
location: 'Washington, DC',
|
||||
country: 'US',
|
||||
spam_probability: '20%',
|
||||
likes: 3
|
||||
}; */
|
||||
|
||||
return (
|
||||
<PopupLayout
|
||||
className="source-info-popup"
|
||||
title="sourceIndexTab.sourceInfoPopupTitle"
|
||||
showFooter={false}
|
||||
onHide={hideSourceInfoPopup}
|
||||
>
|
||||
<ul className="container">
|
||||
<InfoField label="sourceIndexTab.titleLabel">
|
||||
<a href={source.url} target="_blank" rel="noopener noreferrer">
|
||||
{getTitle(source.title)}
|
||||
</a>
|
||||
</InfoField>
|
||||
|
||||
{source.url && (
|
||||
<InfoField label="sourceIndexTab.homeUrl">{source.url}</InfoField>
|
||||
)}
|
||||
|
||||
{source.type && (
|
||||
<InfoField label="sourceIndexTab.mediaType">
|
||||
{capOnlyFirstLetter(source.type)}
|
||||
</InfoField>
|
||||
)}
|
||||
|
||||
{source.subType && (
|
||||
<InfoField labelValue="Sub Type">
|
||||
{capOnlyFirstLetter(source.subType)}
|
||||
</InfoField>
|
||||
)}
|
||||
|
||||
{source.verified && (
|
||||
<InfoField labelValue="Verified">
|
||||
<FontAwesomeIcon
|
||||
title="Source Verified"
|
||||
className="text-primary"
|
||||
icon={faCheckCircle}
|
||||
/>
|
||||
</InfoField>
|
||||
)}
|
||||
|
||||
{source.lang && (
|
||||
<InfoField label="sourceIndexTab.lang">
|
||||
{t(`common:language.${source.lang}`, '-')}
|
||||
</InfoField>
|
||||
)}
|
||||
|
||||
{source.location && (
|
||||
<InfoField labelValue="Location">{source.location}</InfoField>
|
||||
)}
|
||||
|
||||
{source.country && (
|
||||
<InfoField label="sourceIndexTab.country">
|
||||
{t(`common:country.${source.country}`)}
|
||||
</InfoField>
|
||||
)}
|
||||
|
||||
{notNullAndUnd(source.followers) && (
|
||||
<InfoField labelValue="Followers">{source.followers}</InfoField>
|
||||
)}
|
||||
|
||||
{notNullAndUnd(source.following) && (
|
||||
<InfoField labelValue="Following">{source.following}</InfoField>
|
||||
)}
|
||||
|
||||
{notNullAndUnd(source.favorites) && (
|
||||
<InfoField labelValue="Favorites">{source.favorites}</InfoField>
|
||||
)}
|
||||
|
||||
{notNullAndUnd(source.likes) && (
|
||||
<InfoField labelValue="Likes">{source.likes}</InfoField>
|
||||
)}
|
||||
|
||||
{source.tags && source.tags.length > 0 && (
|
||||
<InfoField labelValue="Tags">{source.tags.join(', ')}</InfoField>
|
||||
)}
|
||||
|
||||
{source.spam_probability && (
|
||||
<InfoField labelValue="Spam Probability">
|
||||
{source.spam_probability}
|
||||
</InfoField>
|
||||
)}
|
||||
|
||||
{source.source_profiles && (
|
||||
<InfoField labelValue="Source profiles">
|
||||
{source.source_profiles.join(', ')}
|
||||
</InfoField>
|
||||
)}
|
||||
</ul>
|
||||
</PopupLayout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(SourceIndexInfoPopup);
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate } from 'react-i18next'
|
||||
import SourceIndexTable from './SourceIndexTable'
|
||||
import SourceIndexUpdatePopup from './SourceIndexUpdatePopup'
|
||||
import FiltersTable from '../../../../common/FiltersTable/FiltersTable'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import reduxConnect from '../../../../../redux/utils/connect'
|
||||
import { compose } from 'redux'
|
||||
import { Button, ButtonGroup, Input, InputGroup, InputGroupAddon } from 'reactstrap'
|
||||
import { setDocumentData } from '../../../../../common/helper'
|
||||
|
||||
class SourceIndexSubTab extends React.Component {
|
||||
static propTypes = {
|
||||
sourcesState: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
setDocumentData('title', 'Source Index | Search')
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
setDocumentData('title')
|
||||
}
|
||||
|
||||
_sourceIndexesState = () => this.props.sourcesState.sourceIndexesState;
|
||||
_sourceLists = () => this.props.sourcesState.sourceListsState.data;
|
||||
|
||||
loadSourceIndexes = (params) => {
|
||||
this.props.actions.getSourceIndexes(params || null)
|
||||
};
|
||||
|
||||
onSearchSources = () => {
|
||||
this.loadSourceIndexes()
|
||||
};
|
||||
|
||||
onEnterSearchInput = (e) => {
|
||||
if (e.keyCode === 13) this.loadSourceIndexes()
|
||||
};
|
||||
|
||||
onChangeSearchInput = (e) => {
|
||||
this.props.actions.setSourceIndexSearchQuery(e.target.value)
|
||||
};
|
||||
|
||||
onFetchData = (params) => {
|
||||
this.loadSourceIndexes(params)
|
||||
};
|
||||
|
||||
showAddToListPopup = () => {
|
||||
const { actions } = this.props
|
||||
const sourceIndexesState = this._sourceIndexesState()
|
||||
if (sourceIndexesState.selectedIds.length === 0) {
|
||||
actions.addAlert({
|
||||
type: 'notice',
|
||||
transKey: 'noListsSelected',
|
||||
id: 'noListsSelected'
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
actions.toggleAddSourceToListPopup()
|
||||
};
|
||||
|
||||
onSelectFilter = (groupName, filterValue) => {
|
||||
this.props.actions.selectSourcesFilter(groupName, filterValue)
|
||||
};
|
||||
|
||||
onClearFilters = (groupName) => {
|
||||
this.props.actions.clearSourcesFilters(groupName)
|
||||
};
|
||||
|
||||
onClearAllFilters = () => {
|
||||
this.props.actions.clearAllSourcesFilters()
|
||||
};
|
||||
|
||||
onMoreFilters = (groupName) => {
|
||||
this.props.actions.loadMoreSourcesFilters(groupName)
|
||||
};
|
||||
|
||||
onLessFilters = (groupName) => {
|
||||
this.props.actions.loadLessSourcesFilters(groupName)
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t, actions } = this.props
|
||||
const sourceIndexesState = this._sourceIndexesState()
|
||||
const sourceLists = this._sourceLists()
|
||||
const {
|
||||
searchQuery,
|
||||
selectedIds,
|
||||
chosenListsToAddSources,
|
||||
chosenSourceToUpdate,
|
||||
advancedFilters
|
||||
} = sourceIndexesState
|
||||
|
||||
return (
|
||||
<div className="mb-3">
|
||||
<InputGroup className="mb-3">
|
||||
<Input
|
||||
type="text"
|
||||
id="source-index-search"
|
||||
placeholder={t('sourceIndexTab.mainInputPlaceholder')}
|
||||
value={searchQuery}
|
||||
onChange={this.onChangeSearchInput}
|
||||
onKeyUp={this.onEnterSearchInput}
|
||||
/>
|
||||
<InputGroupAddon addonType="append">
|
||||
<Button
|
||||
color="primary"
|
||||
className="btn-icon btn-icon-only"
|
||||
onClick={this.onSearchSources}
|
||||
>
|
||||
<i className="lnr-magnifier btn-icon-wrapper"></i>
|
||||
</Button>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
|
||||
<ButtonGroup className="mb-3">
|
||||
<Button
|
||||
onClick={this.showAddToListPopup}
|
||||
color="secondary"
|
||||
>
|
||||
<i className="fa fa-plus fa-1px for-small mr-1"> </i>{" "}
|
||||
{t('sourceIndexTab.addToSourceListsBtn')}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<div className="search-content">
|
||||
<SourceIndexTable
|
||||
tableState={sourceIndexesState}
|
||||
type="sourceIndexesState"
|
||||
onFetch={this.onFetchData}
|
||||
actions={actions}
|
||||
/>
|
||||
|
||||
<FiltersTable
|
||||
filters={advancedFilters.all}
|
||||
pages={advancedFilters.pages}
|
||||
selectedFilters={advancedFilters.selected}
|
||||
clearPending={advancedFilters.pending}
|
||||
callbacks={{
|
||||
selectFilter: this.onSelectFilter,
|
||||
clearFilters: this.onClearFilters,
|
||||
clearAllFilters: this.onClearAllFilters,
|
||||
moreFilters: this.onMoreFilters,
|
||||
lessFilters: this.onLessFilters,
|
||||
refine: this.onSearchSources
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{sourceIndexesState.isAddPopupVisible && (
|
||||
<SourceIndexUpdatePopup
|
||||
type="add"
|
||||
sourceLists={sourceLists}
|
||||
chosenLists={chosenListsToAddSources}
|
||||
chosenSourceIndexes={selectedIds}
|
||||
actions={actions}
|
||||
/>
|
||||
)}
|
||||
|
||||
{sourceIndexesState.isUpdatePopupVisible && (
|
||||
<SourceIndexUpdatePopup
|
||||
type="update"
|
||||
sourceLists={sourceLists}
|
||||
chosenLists={chosenSourceToUpdate.listIds}
|
||||
chosenSourceIndexes={[chosenSourceToUpdate.id]}
|
||||
updateItemTitle={chosenSourceToUpdate.title}
|
||||
actions={actions}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const applyDecorators = compose(
|
||||
withRouter,
|
||||
reduxConnect('sourcesState', ['appState', 'sourcesState']),
|
||||
translate(['tabsContent'], { wait: true })
|
||||
)
|
||||
|
||||
export default applyDecorators(SourceIndexSubTab)
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate, Interpolate } from 'react-i18next'
|
||||
|
||||
import Table from '../../../../common/Table/Table'
|
||||
import CheckboxCell from '../../../../common/Table/CheckboxCell'
|
||||
import SortableTh from '../../../../common/Table/SortableTh'
|
||||
import SourceIndexInfoPopup from './SourceIndexInfoPopup'
|
||||
import { Button } from 'reactstrap'
|
||||
import { getTitle } from '../../../../../common/helper'
|
||||
|
||||
export class SourceIndexTable extends React.Component {
|
||||
static propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
tableState: PropTypes.object.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
onFetch: PropTypes.func.isRequired,
|
||||
onDeleteIndex: PropTypes.func,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
onFetch = (page, pageSize, sorted) => {
|
||||
const { tableState, onFetch } = this.props
|
||||
const params = {
|
||||
page: page + 1,
|
||||
limit: pageSize,
|
||||
query: tableState.searchQuery
|
||||
}
|
||||
if (sorted.length) {
|
||||
const sortedField = sorted[0]
|
||||
const sort = {
|
||||
field: sortedField.id,
|
||||
direction: sortedField.desc ? 'desc' : 'asc'
|
||||
}
|
||||
params['sort'] = sort
|
||||
}
|
||||
onFetch(params)
|
||||
};
|
||||
|
||||
selectAllAction = (event) => {
|
||||
const { actions } = this.props
|
||||
actions.toggleAllSourceIndexes()
|
||||
};
|
||||
|
||||
selectRowAction = (itemId) => {
|
||||
const { actions } = this.props
|
||||
actions.toggleSourceIndex(itemId) // TODO
|
||||
};
|
||||
|
||||
showUpdateSourcePopup = (source) => (e) => {
|
||||
e.preventDefault()
|
||||
this.props.actions.showUpdateSourcePopup(source)
|
||||
};
|
||||
|
||||
deleteSourceIndex = (source) => (e) => {
|
||||
e.preventDefault()
|
||||
this.props.onDeleteIndex(source)
|
||||
};
|
||||
|
||||
toggleInfoPopup = (source) => () => {
|
||||
const { type, actions } = this.props
|
||||
actions.toggleInfoSourcePopup(type, source)
|
||||
};
|
||||
|
||||
getColumns = () => {
|
||||
const {t, type, tableState} = this.props
|
||||
|
||||
let columns = [
|
||||
{
|
||||
id: 'selectCheckbox',
|
||||
accessor: '',
|
||||
sortable: false,
|
||||
width: 45,
|
||||
className: 'cw-center-cell',
|
||||
headerClassName: 'cw-center-cell',
|
||||
Header: () => {
|
||||
return (
|
||||
<CheckboxCell
|
||||
checked={tableState.isAllSelected}
|
||||
onChange={this.selectAllAction}
|
||||
/>
|
||||
)
|
||||
},
|
||||
Cell: ({original}) => {
|
||||
const isSelected = tableState.selectedIds.includes(original.id)
|
||||
return (
|
||||
<CheckboxCell
|
||||
id={original.id}
|
||||
checked={isSelected}
|
||||
onChange={this.selectRowAction}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}, {
|
||||
Header: <SortableTh title='sourceIndexTab.name' />,
|
||||
accessor: 'name',
|
||||
Cell: ({original}) => {
|
||||
return (
|
||||
<Button
|
||||
color="link"
|
||||
className="btn-anchor"
|
||||
title="Click to see details"
|
||||
onClick={this.toggleInfoPopup(original)}
|
||||
>
|
||||
{getTitle(original.title)}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
}, {
|
||||
id: 'mediaType',
|
||||
Header: <SortableTh title='sourceIndexTab.mediaType' />,
|
||||
accessor: item => t(`searchTab.sourceTypes.${item.type}`)
|
||||
}, {
|
||||
id: 'country',
|
||||
Header: <SortableTh title='sourceIndexTab.country' />,
|
||||
accessor: item => {
|
||||
return item.country ? t(`common:country.${item.country}`) : ''
|
||||
}
|
||||
}, {
|
||||
id: 'action',
|
||||
Header: t('sourceIndexTab.action'),
|
||||
sortable: false,
|
||||
Cell: ({original}) => {
|
||||
return (
|
||||
<Button
|
||||
outline
|
||||
color="info"
|
||||
className="border-0"
|
||||
size="sm"
|
||||
onClick={this.showUpdateSourcePopup(original)}
|
||||
>
|
||||
<Interpolate
|
||||
i18nKey='sourceIndexTab.actionBtn'
|
||||
listsCount={original.listIds.length}
|
||||
/>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
}, {
|
||||
id: 'deleteAction',
|
||||
Header: t('sourceIndexTab.action'),
|
||||
sortable: false,
|
||||
Cell: ({original}) => {
|
||||
return (
|
||||
<Button
|
||||
outline
|
||||
size="sm"
|
||||
color="secondary"
|
||||
className="border-0"
|
||||
onClick={this.deleteSourceIndex(original)}
|
||||
>
|
||||
{t('sourceListsTab.delete')}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const sourceIndexCols = ['selectCheckbox', 'name', 'mediaType', 'country', 'action']
|
||||
const sourceOfListCols = ['name', 'mediaType', 'country', 'deleteAction']
|
||||
let cols = type === 'sourceIndexesState' ? sourceIndexCols : sourceOfListCols
|
||||
return columns.filter(col => cols.includes(col.id) || cols.includes(col.accessor))
|
||||
};
|
||||
|
||||
render () {
|
||||
const {tableState} = this.props
|
||||
const columns = this.getColumns()
|
||||
const infoPopup = tableState.infoPopup
|
||||
|
||||
return (
|
||||
<div className="sources-table">
|
||||
<Table
|
||||
columns={columns}
|
||||
data={tableState.data}
|
||||
totalCount={tableState.totalCount}
|
||||
showTotalCount
|
||||
limit={tableState.limit}
|
||||
page={tableState.page}
|
||||
isLoading={tableState.isLoading}
|
||||
onFetchData={this.onFetch}
|
||||
/>
|
||||
|
||||
{infoPopup.visible && infoPopup.item &&
|
||||
<SourceIndexInfoPopup
|
||||
source={infoPopup.item}
|
||||
hideSourceInfoPopup={this.toggleInfoPopup(null)}
|
||||
/>
|
||||
}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent'], { wait: true })(SourceIndexTable)
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { translate, Interpolate } from 'react-i18next'
|
||||
import PopupLayout from '../../../../common/Popups/PopupLayout'
|
||||
import { CustomInput } from 'reactstrap'
|
||||
import { getTitle } from '../../../../../common/helper'
|
||||
|
||||
export class SourceIndexUpdatePopup extends React.Component {
|
||||
static propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
sourceLists: PropTypes.array.isRequired,
|
||||
chosenLists: PropTypes.array.isRequired,
|
||||
chosenSourceIndexes: PropTypes.array.isRequired,
|
||||
updateItemTitle: PropTypes.string,
|
||||
actions: PropTypes.object.isRequired,
|
||||
t: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
componentWillMount = () => {
|
||||
const { sourceLists, actions } = this.props
|
||||
if (sourceLists.length === 0) {
|
||||
actions.getMainSourceLists({page: 1, limit: 50})
|
||||
}
|
||||
};
|
||||
|
||||
onChoseList = (e) => {
|
||||
const { type, chosenLists, actions } = this.props
|
||||
const isChecked = e.target.checked
|
||||
const listId = parseInt(e.target.dataset.listId)
|
||||
const lists = isChecked ? chosenLists.concat(listId) : chosenLists.filter((id) => listId !== id)
|
||||
const action = type === 'add' ? actions.setChosenListsToAddSources : actions.setChosenListsToUpdateSources
|
||||
|
||||
action(lists)
|
||||
};
|
||||
|
||||
onSubmit = () => {
|
||||
const { actions, chosenSourceIndexes, chosenLists, type } = this.props
|
||||
|
||||
actions.addSourcesToList({
|
||||
sources: chosenSourceIndexes,
|
||||
sourceLists: chosenLists
|
||||
}, type === 'add')
|
||||
};
|
||||
|
||||
getBodyTitle () {
|
||||
const { t, type, updateItemTitle } = this.props
|
||||
if (type === 'add') {
|
||||
return <p className="mb-3">{t('sourceListsTab.popup.addToListDesc')}</p>
|
||||
}
|
||||
else {
|
||||
return (
|
||||
<p className="mb-3">
|
||||
<Interpolate
|
||||
i18nKey='sourceListsTab.popup.updateListDesc'
|
||||
name={getTitle(updateItemTitle)}
|
||||
/>
|
||||
</p>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { type, sourceLists, chosenLists, actions } = this.props
|
||||
const isAdd = type === 'add'
|
||||
const title = isAdd ? 'addToListTitle' : 'updateListTitle'
|
||||
const submitText = isAdd ? 'addBtn' : 'saveBtn'
|
||||
const hideAction = isAdd ? actions.toggleAddSourceToListPopup : actions.hideUpdateSourcePopup
|
||||
|
||||
return (
|
||||
<PopupLayout
|
||||
title={`sourceListsTab.popup.${title}`}
|
||||
submitText={`sourceListsTab.popup.${submitText}`}
|
||||
onHide={hideAction}
|
||||
onSubmit={this.onSubmit}
|
||||
>
|
||||
<div>
|
||||
{this.getBodyTitle()}
|
||||
|
||||
{sourceLists.length > 0 &&
|
||||
<ul className="row">
|
||||
{sourceLists.map((list, i) => {
|
||||
const isListChosen = chosenLists.includes(list.id)
|
||||
return (
|
||||
<li key={i} className="col-md-4 col-sm-6 mb-2">
|
||||
<CustomInput
|
||||
type="checkbox"
|
||||
id={'sourceListCheck-' + i}
|
||||
className="d-flex"
|
||||
data-list-id={list.id}
|
||||
checked={isListChosen}
|
||||
onChange={this.onChoseList}
|
||||
label={list.name}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
</PopupLayout>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(['tabsContent', 'common'], { wait: true })(SourceIndexUpdatePopup)
|
||||
|
||||
Reference in New Issue
Block a user