* start moving ui to redux tlk * remove unused reducer * changes for gdpr and site types * ui: migrating duck/roles to mobx * ui: drop unreferenced types * ui: drop unreferenced types * ui: move player slice reducer to mobx family * ui: move assignments to issueReportingStore.ts * remove issues store * some fixes after issues store * remove errors reducer, drop old components * finish removing errors reducer * start moving integrations state to mobx * change(ui): funnel duck cleanup * change(ui): custom fields * change(ui): customMetrics cleanup * change(ui): customMetrics cleanup * change(ui): duck/filters minor cleanup * change(ui): duck/filters cleanup * change(ui): duck/customMetrics cleanup and upgrades * fix integrations service, fix babel config to >.25 + not ie * refactoring integrations reducers etc WIP * finish removing integrations state * some fixes for integrated check * start of projects refactoring * move api and "few" files to new project store * new batch for site -> projects * fix setid context * move all critical components, drop site duck * remove all duck/site refs, remove old components * fixup for SessionTags.tsx, remove duck/sources (?) * move session store * init sessionstore outside of context * fix userfilter * replace simple actions for session store * sessions sotre * Rtm temp (#2597) * change(ui): duck/search wip * change(ui): duck/search wip * change(ui): duck/search wip * change(ui): duck/searchLive wip * change(ui): duck/searchLive wip * change(ui): duck/searchLive wip * change(ui): duck/searchLive wip * change(ui): search states * change(ui): search states * change(ui): search states * change(ui): fix savedSearch store * change(ui): fix savedSearch store * some fixes for session connector * change(ui): fix savedSearch store * change(ui): fix searchLive * change(ui): fix searchLive * fixes for session replay * change(ui): bookmark fetch * last components for sessions * add fetchautoplaylist * finish session reducer, remove deleted reducers * change(ui): fix the search fetch * change(ui): fix the search fetch * fix integrations call ctx * ensure ctx for sessionstore * fix(ui): checking for latest sessions path * start removing user reducer * removing user reducer pt2... * finish user store * remove rand log * fix crashes * tinkering workflow file for tracker test * making sure prefetched sessions work properly * fix conflict * fix router redirects during loading --------- Co-authored-by: Shekar Siri <sshekarsiri@gmail.com>
137 lines
4.5 KiB
JavaScript
137 lines
4.5 KiB
JavaScript
import React, { useEffect } from 'react';
|
|
import cn from 'classnames';
|
|
import { connect } from 'react-redux';
|
|
import withPageTitle from 'HOCs/withPageTitle';
|
|
import { Button, Loader, NoContent, Icon, Tooltip, Divider } from 'UI';
|
|
import { init, fetchList, save, remove } from 'Duck/customField';
|
|
import SiteDropdown from 'Shared/SiteDropdown';
|
|
import styles from './customFields.module.css';
|
|
import CustomFieldForm from './CustomFieldForm';
|
|
import ListItem from './ListItem';
|
|
import { confirm } from 'UI';
|
|
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
|
|
import { useModal } from 'App/components/Modal';
|
|
import { toast } from 'react-toastify';
|
|
|
|
function CustomFields(props) {
|
|
const [currentSite, setCurrentSite] = React.useState(props.sites.get(0));
|
|
const [deletingItem, setDeletingItem] = React.useState(null);
|
|
const { showModal, hideModal } = useModal();
|
|
|
|
useEffect(() => {
|
|
const activeSite = props.sites.get(0);
|
|
if (!activeSite) return;
|
|
|
|
props.fetchList(activeSite.id);
|
|
}, []);
|
|
|
|
const save = (field) => {
|
|
props.save(currentSite.id, field).then((response) => {
|
|
if (!response || !response.errors || response.errors.size === 0) {
|
|
hideModal();
|
|
toast.success('Metadata added successfully!');
|
|
} else {
|
|
toast.error(response.errors[0]);
|
|
}
|
|
});
|
|
};
|
|
|
|
const init = (field) => {
|
|
props.init(field);
|
|
showModal(<CustomFieldForm onClose={hideModal} onSave={save} onDelete={() => removeMetadata(field)} />);
|
|
};
|
|
|
|
const onChangeSelect = ({ value }) => {
|
|
const site = props.sites.find((s) => s.id === value.value);
|
|
setCurrentSite(site);
|
|
props.fetchList(site.id);
|
|
};
|
|
|
|
const removeMetadata = async (field) => {
|
|
if (
|
|
await confirm({
|
|
header: 'Metadata',
|
|
confirmation: `Are you sure you want to remove?`
|
|
})
|
|
) {
|
|
setDeletingItem(field.index);
|
|
props
|
|
.remove(currentSite.id, field.index)
|
|
.then(() => {
|
|
hideModal();
|
|
})
|
|
.finally(() => {
|
|
setDeletingItem(null);
|
|
});
|
|
}
|
|
};
|
|
|
|
const { fields, loading } = props;
|
|
return (
|
|
<div className="bg-white rounded-lg shadow-sm border p-5 ">
|
|
<div className={cn(styles.tabHeader)}>
|
|
<h3 className={cn(styles.tabTitle, 'text-2xl')}>{'Metadata'}</h3>
|
|
<div style={{ marginRight: '15px' }}>
|
|
<SiteDropdown value={currentSite && currentSite.id} onChange={onChangeSelect} />
|
|
</div>
|
|
<div className="ml-auto">
|
|
<Tooltip title="You've reached the limit of 10 metadata." disabled={fields.size < 10}>
|
|
<Button disabled={fields.size >= 10} variant="primary" onClick={() => init()}>Add Metadata</Button>
|
|
</Tooltip>
|
|
</div>
|
|
</div>
|
|
<div className="text-base text-disabled-text flex px-5 items-center my-3">
|
|
<Icon name="info-circle-fill" className="mr-2" size={16} />
|
|
See additonal user information in sessions.
|
|
<a href="https://docs.openreplay.com/installation/metadata" className="link ml-1" target="_blank">Learn more</a>
|
|
</div>
|
|
|
|
<Loader loading={loading}>
|
|
<NoContent
|
|
title={
|
|
<div className="flex flex-col items-center justify-center">
|
|
<AnimatedSVG name={ICONS.NO_METADATA} size={60} />
|
|
{/* <div className="mt-4" /> */}
|
|
<div className="text-center my-4">None added yet</div>
|
|
</div>
|
|
}
|
|
size="small"
|
|
show={fields.size === 0}
|
|
>
|
|
<div className={styles.list}>
|
|
{fields
|
|
.filter((i) => i.index)
|
|
.map((field) => (
|
|
<>
|
|
<ListItem
|
|
disabled={deletingItem && deletingItem === field.index}
|
|
key={field._key}
|
|
field={field}
|
|
onEdit={init}
|
|
// onDelete={ () => removeMetadata(field) }
|
|
/>
|
|
<Divider className="m-0" />
|
|
</>
|
|
))}
|
|
</div>
|
|
</NoContent>
|
|
</Loader>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default connect(
|
|
(state) => ({
|
|
fields: state.getIn(['customFields', 'list']).sortBy((i) => i.index),
|
|
field: state.getIn(['customFields', 'instance']),
|
|
loading: state.getIn(['customFields', 'fetchRequest', 'loading']),
|
|
sites: state.getIn(['site', 'list']),
|
|
errors: state.getIn(['customFields', 'saveRequest', 'errors'])
|
|
}),
|
|
{
|
|
init,
|
|
fetchList,
|
|
save,
|
|
remove
|
|
}
|
|
)(withPageTitle('Metadata - OpenReplay Preferences')(CustomFields));
|