lodash#findIndex JavaScript Examples
The following examples show how to use
lodash#findIndex.
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: notification.js From haven with MIT License | 6 votes |
getNotificationType = (type) => {
const order = findIndex(orderNotificationTypes, o => o === type);
if (order >= 0) {
return 'order';
}
const peer = findIndex(peerNotificationTypes, o => o === type);
if (peer >= 0) {
return 'peer';
}
const dispute = findIndex(disputeNotificationTypes, o => o === type);
if (dispute >= 0) {
return 'dispute';
}
return 'unknown';
}
Example #2
Source File: index.js From hzero-front with Apache License 2.0 | 6 votes |
@Bind()
handleConfig() {
const {
dataSource: { dataSourceDetail = {}, extConfigs = [] },
} = this.props;
const { extConfig = '{}' } = dataSourceDetail;
const columnList = [];
// 获取参数
forIn(JSON.parse(extConfig), (value, key) => {
if (
findIndex(extConfigs, (o) => {
return o.itemCode === key;
}) === -1
) {
columnList.push({
name: key,
value,
columnId: uuid(),
_status: '',
});
}
});
this.setState({
dataSource: columnList,
});
}
Example #3
Source File: menuTab.js From hzero-front with Apache License 2.0 | 6 votes |
/**
* 判断是不是合法的tabPathname
* '' / 登录,登出 其他的都认为合法的pathname
* '' / /user/login /user/logout
* @param {!String} pathname - 切换的pathname
*/
function isValidTabPathname(pathname) {
return (
isString(pathname) &&
findIndex(
['', '/', '/user/login', '/user/logout'],
(invalidPathname) => invalidPathname === pathname
) === -1
);
}
Example #4
Source File: ComposeTableEditModal.js From hzero-front with Apache License 2.0 | 6 votes |
dataSourceRemove() {
const { dataSource, selectedRowKeys } = this.state;
const { rowKey } = this.props;
const nextDataSource = [];
forEach(dataSource, r => {
if (findIndex(selectedRowKeys, rowId => rowId === r[rowKey]) === -1) {
nextDataSource.push(r);
}
});
this.setState({
selectedRowKeys: [],
selectedRows: [],
dataSource: nextDataSource,
removeLoading: false,
});
}
Example #5
Source File: ComposeTableEditModal.js From hzero-front with Apache License 2.0 | 6 votes |
handleRemove() {
const { dataSource, selectedRowKeys } = this.state;
const { rowKey } = this.props;
const removeRows = [];
forEach(dataSource, r => {
if (findIndex(selectedRowKeys, rowId => rowId === r[rowKey]) !== -1) {
if (!r.isCreate) {
removeRows.push(r);
}
}
});
if (removeRows.length > 0) {
// 调用 父组件 传进来的 方法
const { onRemove } = this.props;
if (isFunction(onRemove)) {
this.setState({
removeLoading: true,
});
onRemove(map(removeRows, row => row[rowKey]), removeRows, { onOk: this.dataSourceRemove });
}
} else {
this.dataSourceRemove();
}
}
Example #6
Source File: diff.js From hivemind with Apache License 2.0 | 6 votes |
async function getReversedDiff(nid, eid, fctime, lctime) {
const until = lctime + 0.0001
const response = await rg.get('/event/diff', {
path: `/n/${nid}`,
reverse: true,
since: fctime,
until,
})
const result = response.body[0]
const idx = findIndex(result.events, { _id: eid })
return result.commands[idx]
}
Example #7
Source File: addModerators.js From haven with MIT License | 6 votes |
getProfileList() {
const { storeModerators } = this.props;
const { options } = this.state;
const filteredOptions = filter(options, (val) => {
const idx = findIndex(storeModerators, o => o === val);
return idx === -1;
});
return filteredOptions || [];
}
Example #8
Source File: addModerators.js From haven with MIT License | 6 votes |
onChangeState(peerID) {
const { selected } = this.state;
const idx = findIndex(selected, o => o === peerID);
if (idx >= 0) {
const newArray = filter(selected, o => o !== peerID);
this.setState({
selected: newArray,
});
} else {
this.setState({
selected: [...selected, peerID],
});
}
}
Example #9
Source File: MultiFilter.js From haven with MIT License | 6 votes |
onChange(val, idx, isExclusive) {
const { selected, options } = this.props;
const exclusiveIdx = findIndex(options, val => get(val, 'exclusive', false));
const exclusiveVal = get(options, `[${exclusiveIdx}].value`, 'exclusive_value');
if (idx === -1) {
if (isExclusive) {
selected.length = 0;
selected.push(val);
} else {
selected.push(val);
remove(selected, o => o === exclusiveVal);
}
} else {
remove(selected, o => o === val);
}
this.props.onChange(selected);
}
Example #10
Source File: parseMobilityData.js From covid with GNU General Public License v3.0 | 6 votes |
parseMobilityData = (selectedGeoid, weightData, centroids) => {
let sourceCenter = findIndex(centroids, o => o[0]===selectedGeoid)
let sourceX = centroids[sourceCenter][1];
let sourceY = centroids[sourceCenter][2];
let length = weightData.length
let n = 0;
while (n < length-1) {
centroids[n] = [centroids[n][0], centroids[n][1], centroids[n][2], sourceX, sourceY, weightData[n]]
n++;
}
return centroids;
}
Example #11
Source File: bulk-commands-functions.js From OctoFarm with GNU Affero General Public License v3.0 | 6 votes |
//REFACTOR this should come from printer select to save the extra call, re-iteration and matching.
async function getCurrentlySelectedPrinterList(disabled) {
try {
const currentPrinterList = await OctoFarmClient.listPrinters(disabled);
const matchedPrinters = [];
//Grab all check boxes
const selectedPrinters = PrinterSelectionService.getSelected();
selectedPrinters.forEach((element) => {
const printerID = element.id.split("-");
const index = findIndex(currentPrinterList, function (o) {
return o._id === printerID[1];
});
if (index > -1) {
matchedPrinters.push(currentPrinterList[index]);
}
});
return matchedPrinters;
} catch (e) {
console.error(e);
UI.createAlert(
"error",
`Couldn't get selected printer list: ${e}`,
0,
"clicked"
);
return [];
}
}
Example #12
Source File: SelectorModal.js From haven with MIT License | 6 votes |
getOptionLabel(val) {
const {
options, valueKey, getTitleLabel, getLabel,
} = this.props;
const idx = findIndex(options, o => o[valueKey] === val);
return idx >= 0 ? (
getTitleLabel ? getTitleLabel(options[idx]) : getLabel(options[idx])
) : (
'None'
);
}
Example #13
Source File: MultiFilter.js From haven with MIT License | 6 votes |
render() {
const {
selected, options, title, style, hasScroll,
} = this.props;
const Wrapper = hasScroll ? ScrollView : View;
return (
<Section title={title}>
<Wrapper style={[styles.wrapper, style]}>
{options.map((val, key) => {
const idx = findIndex(selected, o => o === val.value);
const isLast = key === options.length - 1;
return (
<TouchableWithoutFeedback
key={key}
onPress={() => {
this.onChange(val.value, idx, get(val, 'exclusive', false));
}}
>
<View style={styles.itemWrapper}>
{idx >= 0 ? (
<Ionicons name="ios-checkmark" size={28} style={styles.checkmark} />
) : (
<Ionicons size={28} style={styles.checkmark} />
)}
<View style={[styles.itemTextWrapper, !isLast && styles.bottomBorder]}>
<Text style={styles.itemText}>{val.label}</Text>
</View>
</View>
</TouchableWithoutFeedback>
);
})}
</Wrapper>
</Section>
);
}
Example #14
Source File: index.jsx From mui-phone-input-ssr with MIT License | 5 votes |
constructor(props) {
super(props);
let filteredCountries = countryData.allCountries;
if (props.disableAreaCodes) filteredCountries = this.deleteAreaCodes(filteredCountries);
if (props.regions) filteredCountries = this.filterRegions(props.regions, filteredCountries);
const onlyCountries = this.excludeCountries(
this.getOnlyCountries(props.onlyCountries, filteredCountries), props.excludeCountries,
);
const preferredCountries = filter(filteredCountries, (country) => some(props.preferredCountries, (preferredCountry) => preferredCountry === country.iso2));
const inputNumber = props.value || '';
let countryGuess;
if (inputNumber.length > 1) {
// Country detect by value field
countryGuess = this.guessSelectedCountry(inputNumber.replace(/\D/g, '').substring(0, 6), onlyCountries, props.defaultCountry) || 0;
} else if (props.defaultCountry) {
// Default country
countryGuess = find(onlyCountries, { iso2: props.defaultCountry }) || 0;
} else {
// Empty params
countryGuess = 0;
}
const countryGuessIndex = findIndex(this.allCountries, countryGuess);
const dialCode = (
inputNumber.length < 2
&& countryGuess
&& !startsWith(inputNumber.replace(/\D/g, ''), countryGuess.dialCode)
) ? countryGuess.dialCode : '';
const formattedNumber = (inputNumber === '' && countryGuess === 0) ? ''
: this.formatNumber(
(props.disableCountryCode ? '' : dialCode) + inputNumber.replace(/\D/g, ''),
countryGuess.name ? countryGuess.format : undefined,
);
this.state = {
formattedNumber,
placeholder: props.placeholder,
onlyCountries,
preferredCountries,
defaultCountry: props.defaultCountry,
selectedCountry: countryGuess,
highlightCountryIndex: countryGuessIndex,
queryString: '',
freezeSelection: false,
debouncedQueryStingSearcher: debounce(this.searchCountry, 100),
anchorEl: null,
};
}
Example #15
Source File: SelectorPlaceholder.js From haven with MIT License | 5 votes |
getOptionLabel(val) {
const { options } = this.props;
const idx = findIndex(options, o => o.value === val);
return idx >= 0 ? options[idx].label : 'Select';
}
Example #16
Source File: index.js From hzero-front with Apache License 2.0 | 5 votes |
@Bind()
onCheckboxChange(params) {
const { receiveCode, type, flag } = params;
const { checkedList } = this.state;
const index = findIndex(checkedList, (v) => v.receiveCode === receiveCode);
const checkItem = checkedList[index];
const addOrRemove = (item) => {
// flag为true,代表当前已经被勾选,需要去除勾选
if (flag) {
remove(item && item.receiveTypeList, (v) => v === type);
} else if (
indexOf(item && item.receiveTypeList, type) < 0 &&
indexOf(item.defaultReceiveTypeList, type) > -1
) {
(item.receiveTypeList || []).push(type);
}
};
addOrRemove(checkItem);
/**
* 根据父节点,选择所有的子节点
*
* @param {*} parentId
*/
const iterator = (parentId) => {
const subList = [];
forEach(checkedList, (v) => {
if (v.parentId === parentId) {
addOrRemove(v);
subList.push(v);
}
});
if (subList && subList.length > 0) {
forEach(subList, (v) => iterator(v.receiveCode));
}
};
iterator(checkItem.receiveCode);
/**
* 反向勾选,即根据子节点反向勾选父节点
*
* @param {*} parentId 父节点的receiveCode
*/
const reverseCheck = (parentId) => {
if (!parentId) {
return;
}
const sameParents = checkedList.filter((v) => v.parentId === parentId) || [];
const temp = sameParents.filter((v) => {
if (indexOf(v.defaultReceiveTypeList, type) < 0) {
return true;
}
const idx = indexOf(v && v.receiveTypeList, type);
return flag ? idx < 0 : idx > -1;
});
if (sameParents.length === temp.length || (sameParents.length !== temp.length && flag)) {
const parentIndex = findIndex(checkedList, (v) => v.receiveCode === parentId);
const parent = checkedList[parentIndex];
addOrRemove(parent);
reverseCheck(parent.parentId);
}
};
reverseCheck(checkItem.parentId);
this.setState({ checkedList });
}
Example #17
Source File: profile.js From haven with MIT License | 5 votes |
function* fetchProfile(action) {
const { usecache, async } = yield select(getProfileFetchMode);
const profileQueue = yield select(getProfileQueue);
let { peerID } = action.payload || {};
let getLoaded = get(action.payload, 'getLoaded', false);
if (isEmpty(peerID)) {
peerID = '';
}
if (!isEmpty(peerID)) {
const profiles = yield select(getProfiles);
const profileInCache = profiles.profiles[peerID];
const queueIdx = findIndex(profileQueue, pfID => pfID === peerID);
getLoaded = getLoaded && (!isEmpty(profileInCache) || queueIdx >= 0);
}
if (!getLoaded) {
if (!isEmpty(peerID)) {
// check failed profile queue and if it failed within the last 1 hr, gracefully return
const profileFailedQueue = yield select(getProfileFailedQueue);
const timestamp = profileFailedQueue[peerID];
if (timestamp) {
if ((timeSinceInSeconds(new Date(timestamp)) < PROFILE_RECHECK_HOURS * 3600)) {
return;
} else {
yield put({ type: failedQueueActions.removeFromFailedQueue, payload: peerID });
}
}
yield put({ type: queueActions.addToQueue, payload: peerID });
}
try {
const result = yield call(getProfile, peerID, usecache, async);
if (isEmpty(peerID)) {
yield put({ type: profileActions.setProfile, payload: result });
}
if (result) {
yield put({ type: profilesActions.setProfiles, payload: [result] });
} else if (!isEmpty(peerID)) {
yield put({ type: failedQueueActions.addToFailedQueue, payload: peerID });
}
yield put({ type: profileActions.setProfileLoading, payload: false });
} catch (err) {
// console.log(`Fetch profile error: ${err}`);
} finally {
if (!isEmpty(peerID)) {
yield put({ type: queueActions.removeFromQueue, payload: peerID });
}
}
}
}
Example #18
Source File: ProductState.js From haven with MIT License | 5 votes |
getProductTypeText = (type) => {
const idx = findIndex(prdType, o => o.value === type.toLowerCase());
if (idx >= 0) {
return prdType[idx].label;
}
return 'Unknown';
}
Example #19
Source File: ProductState.js From haven with MIT License | 5 votes |
getProductConditionText = (condition) => {
const idx = findIndex(prdCondition, o => o.value === condition);
if (idx >= 0) {
return prdCondition[idx].label;
}
return 'Unknown';
}
Example #20
Source File: MultiSelector.js From haven with MIT License | 5 votes |
render() {
const { selection, showModal } = this.state;
const { options, title, required } = this.props;
let text = 'None';
if (selection.length === 1) {
if (selection[0] === 'ALL') {
const idx = findIndex(options, option => option.value === 'ALL');
if (idx >= 0) {
text = options[idx].label;
} else {
text = 'All';
}
} else if (hasIn(selection, '[0].label')) {
text = selection[0].label;
} else {
const idx = findIndex(options, option => option.value.toLowerCase() === selection[0].toLowerCase());
text = options[idx].label;
}
} else if (selection.length > 1) {
text = `${selection.length} selected`;
}
return (
<View style={styles.wrapper}>
<TouchableWithoutFeedback onPress={this.onShowSelector}>
<View style={styles.optionTrigger}>
<Text style={styles.title}>
{title}
<Text style={required ? { color: 'red' } : {}}>{required ? '*' : ''}</Text>
</Text>
<Text style={styles.input} numberOfLines={1} ellipsizeMode="tail">{text}</Text>
<Ionicons
name="ios-arrow-forward"
size={18}
color={primaryTextColor}
style={styles.icon}
/>
</View>
</TouchableWithoutFeedback>
<OBLightModal
animationType="slide"
transparent
visible={showModal}
onRequestClose={this.onClose}
>
<Header
modal
title=""
left={<NavBackButton />}
onLeft={this.onClose}
right={<LinkText text="Done" />}
onRight={this.onClose}
/>
<FlatList
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
data={options}
extraData={selection}
/>
{selection.length > 0 && (
<View style={styles.selectionIndicatorWrapper}>
<Text style={styles.selectedIndicator}>
{selection.length} Selected
</Text>
<TouchableOpacity onPress={this.resetSelection}>
<LinkText text="Reset" />
</TouchableOpacity>
</View>
)}
</OBLightModal>
</View>
);
}
Example #21
Source File: profile.js From haven with MIT License | 5 votes |
function* fetchProfiles(action) {
const { usecache, async } = yield select(getProfileFetchMode);
const profileFailedQueue = yield select(getProfileFailedQueue);
const profileQueue = yield select(getProfileQueue);
const profiles = yield select(getProfiles);
const { peerIDs, getLoaded = true } = action.payload;
yield put({ type: queueActions.addBatchToQueue, payload: peerIDs });
let i;
for (i = 0; i < peerIDs.length; i += 1) {
const peerID = peerIDs[i];
const profileInCache = profiles.profiles[peerID];
const queueIdx = findIndex(profileQueue, pfID => pfID === peerID);
const inCahceOrQueue = profileInCache || queueIdx >= 0;
if (!getLoaded || !inCahceOrQueue) {
// check failed profile queue and if it failed within the last 1 hr, gracefully return
const timestamp = profileFailedQueue[peerID];
if (timestamp) {
if ((timeSinceInSeconds(new Date(timestamp)) < PROFILE_RECHECK_HOURS * 3600)) {
yield put({ type: queueActions.removeFromQueue, payload: peerID });
continue;
} else {
yield put({ type: failedQueueActions.removeFromFailedQueue, payload: peerID });
}
}
try {
const result = yield call(getProfile, peerID, usecache, async);
if (result) {
yield put({ type: profilesActions.setProfiles, payload: [result] });
} else {
yield put({ type: failedQueueActions.addToFailedQueue, payload: peerID });
}
} catch (err) {
// console.log(err);
} finally {
yield put({ type: queueActions.removeFromQueue, payload: peerID });
}
}
}
}
Example #22
Source File: addModerators.js From haven with MIT License | 5 votes |
checkSelected(peerID) {
const { selected } = this.state;
const idx = findIndex(selected, o => o === peerID);
return idx >= 0;
}
Example #23
Source File: [key].js From hivemind with Apache License 2.0 | 4 votes |
Page = () => {
const { user } = useUser()
const router = useRouter()
const [timestamp, setTimestamp] = useState(
typeof window === 'undefined'
? null
: parseFloat(new URLSearchParams(location.search).get('timestamp'))
)
const { key } = router.query
const { data, error } = useFetch(
user ? user : null,
`/api/mindmaps/${key}?timestamp=${timestamp || ''}`
)
const { data: edata, error: eerror } = useFetch(
user ? user : null,
`/api/timeline/events?key=${key}`
)
const [title, setTitle] = useState(key)
useEffect(() => {
if (user) {
mutate(
[`/api/mindmaps/${key}?timestamp=${timestamp || ''}`, user.token],
null,
true
)
}
}, [user, timestamp, key])
useEffect(() => {
if (user) {
mutate([`/api/timeline/events?key=${key}`, user.token], null, true)
}
}, [user, key])
useEffect(() => {
if (data && data.ok) {
setTitle(data.data.meta.name)
}
}, [data])
useEffect(() => {
const handleRouteChange = (url) => {
const fullURL = new URL(url, location.origin)
const toTs = fullURL.searchParams.get('timestamp')
const toTsF = parseFloat(toTs) || null
if ((!toTsF && timestamp) || toTsF !== timestamp) {
setTimestamp(toTsF)
}
}
router.events.on('routeChangeComplete', handleRouteChange)
return () => {
router.events.off('routeChangeComplete', handleRouteChange)
}
}, [router.events, timestamp])
if (typeof user === 'undefined') {
return <Spinner />
}
if (error && window.notify) {
const options = {
place: 'tr',
message: 'Failed to fetch mind map!',
type: 'danger',
autoDismiss: 7,
}
window.notify(options)
}
if (eerror && window.notify) {
const options = {
place: 'tr',
message: 'Failed to fetch events!',
type: 'danger',
autoDismiss: 7,
}
window.notify(options)
}
const gotEventData = !eerror && edata && edata.ok
const cEvents = gotEventData && edata.data
const prevDisabled = !gotEventData || timestamp === cEvents[0].lctime
const nextDisabled = !gotEventData || timestamp === last(cEvents).lctime
async function jump(to) {
if (to === 'now') {
await router.push('/mmaps/[key]', `/mmaps/${key}`, { shallow: true })
setTimestamp(null)
} else if (gotEventData) {
let toTS, idx
switch (to) {
case 'first':
toTS = cEvents[0].lctime
break
case 'prev':
idx = timestamp
? findIndex(cEvents, { lctime: timestamp })
: cEvents.length
toTS = cEvents[idx - 1].lctime
break
case 'next':
idx = timestamp
? findIndex(cEvents, { lctime: timestamp })
: cEvents.length - 2
toTS = cEvents[idx + 1].lctime
break
case 'last':
toTS = last(cEvents).lctime
break
default:
toTS = to
}
await router.push(
'/mmaps/[key]',
{
pathname: `/mmaps/${key}`,
query: { timestamp: toTS },
},
{ shallow: true }
)
setTimestamp(toTS)
}
}
if (user) {
const output = [
<Row key="title">
<Col xs="auto" md={7}>
<h3>
{title}
{timestamp ? (
<>
<small className={'text-muted'}>
{' '}
@ {new Date(timestamp * 1000).toLocaleString()}
</small>
</>
) : null}
</h3>
</Col>
<Col xs="auto" md={5} className={'text-right'}>
<ShowAll />
<Fit />
<Search />
|
<ToolTippedButton
className="ml-1"
outline
color="secondary"
id="tag"
disabled={true}
tooltip="Tag (Coming Soon)"
>
<Tag size={16} />
</ToolTippedButton>
<ToolTippedButton
className="ml-1"
outline
color="secondary"
id="first"
disabled={prevDisabled}
tooltip="First"
onClick={() => jump('first')}
>
<SkipBack size={16} />
</ToolTippedButton>
<ToolTippedButton
className="ml-1"
outline
color="secondary"
id="prev"
disabled={prevDisabled}
tooltip="Previous"
onClick={() => jump('prev')}
>
<Rewind size={16} />
</ToolTippedButton>
<ToolTippedButton
className="ml-1"
outline
color="secondary"
id="next"
disabled={nextDisabled}
tooltip="Next"
onClick={() => jump('next')}
>
<FastForward size={16} />
</ToolTippedButton>
<ToolTippedButton
className="ml-1"
outline
color="secondary"
id="last"
disabled={nextDisabled}
tooltip="Last"
onClick={() => jump('last')}
>
<SkipForward size={16} />
</ToolTippedButton>
|
<Rename
nameChangedCallBack={setTitle}
disabled={!!timestamp}
rootNode={get(data, ['data', 'meta'], {})}
/>
<ToolTippedButton
className="ml-1"
outline
color={timestamp ? 'secondary' : 'danger'}
id="now"
tooltip={timestamp ? 'Click to unlock' : 'Click to lock'}
onClick={() => jump(timestamp ? 'now' : 'last')}
>
{timestamp ? <Lock size={16} /> : <Unlock size={16} />}
</ToolTippedButton>
</Col>
</Row>,
]
if (error && data) {
output.push(
<Row key="content">
<Col>
<Error statusCode={data.status} />
</Col>
</Row>
)
} else if (eerror && edata) {
output.push(
<Row key="content">
<Col>
<Error statusCode={edata.status} />
</Col>
</Row>
)
} else {
output.push(
<Row key="content">
<Col>
<MindMap
data={data}
edata={edata}
timestamp={timestamp}
jump={jump}
/>
</Col>
</Row>
)
}
return output
}
return <AuthPrompt />
}
Example #24
Source File: index.js From datapass with GNU Affero General Public License v3.0 | 4 votes |
ÉquipeSection = ({
initialContacts = {},
responsableTechniqueNeedsMobilePhone = false,
}) => {
const {
isUserEnrollmentLoading,
disabled,
onChange,
enrollment: { team_members = [] },
} = useContext(FormContext);
const { user } = useAuth();
const contactConfiguration = useMemo(() => {
const defaultInitialContacts = {
demandeur: {
header: 'Demandeur',
description: getDefaultDemandeurDescription(),
forceDisable: true,
},
responsable_traitement: {
header: 'Responsable de traitement',
description: getDefaultResponsableTraitementDescription(),
},
delegue_protection_donnees: {
header: 'Délégué à la protection des données',
description: getDefaultDelegueProtectionDonneesDescription(),
},
responsable_technique: {
header: 'Responsable technique',
description: getDefaultResponsableTechniqueDescription(
responsableTechniqueNeedsMobilePhone
),
displayMobilePhoneLabel: responsableTechniqueNeedsMobilePhone,
},
};
return chain(defaultInitialContacts)
.assign(initialContacts)
.omitBy((p) => !p)
.value();
}, [initialContacts, responsableTechniqueNeedsMobilePhone]);
const newTeamMembers = useNewTeamMembers({
user,
team_members,
contactConfiguration,
});
useEffect(() => {
if (!isUserEnrollmentLoading && !disabled && !isEmpty(newTeamMembers)) {
onChange({
target: {
name: 'team_members',
value: [...team_members, ...newTeamMembers],
},
});
}
}, [
isUserEnrollmentLoading,
disabled,
onChange,
team_members,
newTeamMembers,
]);
const displayIdForAdministrator = useMemo(
() => user && user.roles.includes('administrator'),
[user]
);
const updateWithUserInformation = useCallback(
(index) => {
if (team_members[index]?.email !== user.email) {
onChange({
target: {
name: `team_members[${index}].email`,
value: user.email,
},
});
}
if (team_members[index]?.given_name !== user.given_name) {
onChange({
target: {
name: `team_members[${index}].given_name`,
value: user.given_name,
},
});
}
if (team_members[index]?.family_name !== user.family_name) {
onChange({
target: {
name: `team_members[${index}].family_name`,
value: user.family_name,
},
});
}
if (team_members[index]?.phone_number !== user.phone_number) {
onChange({
target: {
name: `team_members[${index}].phone_number`,
value: user.phone_number,
},
});
}
if (team_members[index]?.job !== user.job) {
onChange({
target: {
name: `team_members[${index}].job`,
value: user.job,
},
});
}
},
[team_members, user, onChange]
);
useEffect(() => {
if (!isUserEnrollmentLoading && !disabled && !isEmpty(team_members)) {
const currentDemandeurIndex = team_members.findIndex(
({ type, email }) => type === 'demandeur' && email === user.email
);
if (currentDemandeurIndex !== -1) {
updateWithUserInformation(currentDemandeurIndex);
}
}
}, [
isUserEnrollmentLoading,
disabled,
team_members,
user,
updateWithUserInformation,
]);
const addTeamMemberFactory = (type) => {
const tmp_id = uniqueId(`tmp_`);
const newTeamMember = { type, tmp_id };
return () =>
onChange({
target: {
name: 'team_members',
value: [...team_members, newTeamMember],
},
});
};
const removeTeamMember = (index) => {
onChange({
target: {
name: 'team_members',
value: [
...team_members.slice(0, index),
...team_members.slice(index + 1),
],
},
});
};
return (
<ScrollablePanel scrollableId={SECTION_ID}>
<h2>{SECTION_LABEL}</h2>
<ExpandableQuote title="Comment renseigner la liste des contacts ?" large>
{Object.entries(contactConfiguration).map(([type, { description }]) => (
<p key={type}>{description}</p>
))}
</ExpandableQuote>
<CardContainer flex={false}>
{Object.entries(contactConfiguration).map(
([
type,
{
header,
forceDisable,
displayMobilePhoneLabel,
displayIndividualEmailLabel,
displayGroupEmailLabel,
contactByEmailOnly,
multiple,
},
]) => (
<React.Fragment key={type}>
{team_members
.filter(({ type: t }) => t === type)
.map(({ id, tmp_id, ...team_member }) => (
<Contact
heading={header}
key={id || tmp_id}
id={id}
index={findIndex(team_members, ({ id: i, tmp_id: t_i }) => {
if (id) {
// if id is defined match on id field
return i === id;
}
if (tmp_id) {
// if id is not defined and tmp_id is defined
// match on tmp_id
return t_i === tmp_id;
}
return false;
})}
{...team_member}
displayMobilePhoneLabel={displayMobilePhoneLabel}
displayIndividualEmailLabel={displayIndividualEmailLabel}
displayGroupEmailLabel={displayGroupEmailLabel}
contactByEmailOnly={contactByEmailOnly}
displayIdForAdministrator={displayIdForAdministrator}
disabled={forceDisable || disabled}
onChange={onChange}
onDelete={multiple && !id && removeTeamMember}
onUpdateWithUserInformation={updateWithUserInformation}
canUpdatePersonalInformation={
team_member.email === user.email &&
(team_member.given_name !== user.given_name ||
team_member.family_name !== user.family_name ||
team_member.phone_number !== user.phone_number ||
team_member.job !== user.job)
}
/>
))}
{!disabled && multiple && (
<AddCard
label={`ajouter un ${header.toLowerCase()}`}
onClick={addTeamMemberFactory(type)}
/>
)}
</React.Fragment>
)
)}
</CardContainer>
</ScrollablePanel>
);
}
Example #25
Source File: cadastrapp.js From mapstore2-cadastrapp with GNU General Public License v3.0 | 4 votes |
/**
* Holds the state of cadastrapp.
* The shape of the state is the following:
* ```
* {
* loading: true | false // general loading flag
* loadingFlags: {} // object that contain loading flag, for various parts of the application.
* searchType: undefined // one of constant.SEARCH_TOOLS
* selectionType: undefined // one of constant.SELECTION_TYPE
* plots: [{ // an entry for each tab of the plot selection
* data: [{parcelle: "12345", ...}] // data of the tab
* selected: [parcelle1, parcelle2]
* }],
* configuration: { // the configuration from server. e.g.
* cadastreLayerIdParcelle: "geo_parcelle"
* cadastreWFSLayerName: "qgis:cadastrapp_parcelle"
* cadastreWFSURL: "https://domain.org/geoserver/wfs"
* cadastreWMSLayerName: "qgis:cadastrapp_parcelle"
* cadastreWMSURL: "https://domain.org/geoserver/wms"
* cnil1RoleName: "ROLE_EL_APPLIS_CAD_CNIL1"
* cnil2RoleName: "ROLE_EL_APPLIS_CAD_CNIL2"
* dateValiditeEDIGEO: "01/01/2018"
* dateValiditeMajic: "01/01/2018"
* maxRequest: "8"
* minNbCharForSearch: "3"
* minParacelleIdLength: "14"
* organisme: "Un service fourni par "
* pdfbasemapthumbnails: [{,…}, {,…}]
* pdfbasemaptitles: [{value: "Cadastre", key: "pdf.baseMap.0.title"},…]
* uFWFSLayerName: "qgis:cadastrapp_unite_fonciere"
* uFWFSURL: "https://domain.org/geoserver/wfs"
* }
* }
* ```
*
* @param {object} state the application state
* @param {object} action a redux action
*/
export default function cadastrapp(state = DEFAULT_STATE, action) {
const type = action.type;
switch (type) {
case SETUP:
return set('pluginCfg', action.cfg, state);
case SET_CONFIGURATION:
return set('configuration', action.configuration, state);
case LOADING: {
let newValue = action.value;
if (action.mode === 'count') {
const oldValue = get(state, `loadFlags.${action.name}`) ?? 0;
newValue = isNumber(newValue)
? newValue // set with passed value if number
: newValue
? oldValue + 1 // increment if true
: Math.max(oldValue - 1, 0); // decrement if false
}
// anyway sets loading to true
return set(action.name === "loading" ? "loading" : `loadFlags.${action.name}`, newValue, state);
}
case TOGGLE_SELECTION: {
const {selectionType} = action;
// if the current selection button is clicked, it turns off selection
return set("selectionType", selectionType, state);
}
case TOGGLE_SEARCH: {
const { searchType } = action;
// if the current search button is clicked, it closes the search section
return set("searchType", searchType, state);
}
case ADD_PLOTS: {
const { plots, target, activate = true } = action;
const {activePlotSelection = 0 } = state;
let targetPlotSelection = activePlotSelection;
let newState = state;
if (!isNil(target)) {
const targetIndex = isObject(target) ? findIndex(state.plots, {id: target.id}) : target;
// create
if (targetIndex < 0) {
newState = set(`plots`, [...state.plots, { ...EMPTY_PLOT_SELECTION, ...target }], state);
targetPlotSelection = newState.plots.length - 1;
} else {
newState = set(`plots[${targetIndex}]`, {...state.plots[targetIndex], ...target});
targetPlotSelection = targetIndex;
}
}
if (activate) {
newState = set(`activePlotSelection`, targetPlotSelection, newState);
}
// get the current selection or create a new one if it not exists.
let currentSelection = newState?.plots?.[targetPlotSelection] ?? EMPTY_PLOT_SELECTION;
// add every plot received and toggle selection if exist
plots.map(({ parcelle, ...other}) => {
// if exists, toggle selection
currentSelection = toggleSelection(currentSelection, parcelle);
// update/insert the value at the en
currentSelection = arrayUpsert(`data`, { parcelle, ...other }, {parcelle}, currentSelection);
});
// update with new values the state
return set(`plots[${targetPlotSelection}]`, currentSelection, newState);
}
case REMOVE_PLOTS: {
const { parcelles = []} = action;
const {activePlotSelection = 0 } = state;
// get the current selection or create a new one if it not exists.
let currentSelection = state?.plots?.[activePlotSelection] ?? EMPTY_PLOT_SELECTION;
currentSelection = {
...currentSelection,
data: currentSelection.data.filter(({ parcelle }) => !parcelles.includes(parcelle)),
selected: currentSelection.selected.filter(parcelle => !parcelles.includes(parcelle))
};
// update with new values the state
return set(`plots[${activePlotSelection}]`, currentSelection, state);
}
case SELECT_PLOTS:
case DESELECT_PLOTS: {
const { activePlotSelection = 0 } = state;
let currentSelection = state?.plots?.[activePlotSelection] ?? EMPTY_PLOT_SELECTION;
const {plots = []} = action;
const parcelles = plots.map(({ parcelle }) => parcelle);
const selected = action.type === SELECT_PLOTS
? uniq([...(currentSelection.selected || []), ...parcelles])
: (currentSelection.selected || []).filter(id => !parcelles.includes(id));
currentSelection = {
...currentSelection,
selected
};
return set(`plots[${activePlotSelection}]`, currentSelection, state);
}
case ADD_PLOT_SELECTION: {
const {plot = {}} = action;
const currentPlots = state?.plots ?? [];
return compose(
set(`plots`, [...currentPlots, { ...EMPTY_PLOT_SELECTION, ...plot}]),
set(`activePlotSelection`, state?.plots?.length ?? 0) // select the new tab
)(state);
}
case REMOVE_PLOT_SELECTION: {
const active = action.active ?? state.activePlotSelection;
const newPlots = [...state.plots.filter((_, i) => i !== active)];
return compose(
set(`plots`, newPlots),
set(`activePlotSelection`, Math.max(state.activePlotSelection - 1, 0))
)(state);
}
case SET_ACTIVE_PLOT_SELECTION: {
return set('activePlotSelection', action.active, state);
}
case SET_LAYER_STYLE: {
return set(`styles.${action.styleType}`, action.value, state);
}
case UPDATE_LAYER_STYLE: {
return set(`styles.${action.styleType}`, {...(state?.styles?.[action.styleType] ?? {}), ...action.values}, state);
}
case SET_STYLES: {
return set('styles', action.styles, state);
}
case SHOW_OWNERS: {
return compose(
set('owners.data', action.owners),
set('owners.show', true)
)(state);
}
case CLEAR_OWNERS: {
return set('owners', undefined, state);
}
case SHOW_LANDED_PROPERTIES_INFORMATION: {
return set('landedProperty.parcelle', action.parcelle, state);
}
case INFORMATION_UPDATE: {
return set(
`informationData["${action.parcelle}"]${action.path ? '.' + action.path : ''}`, action.data, state
);
}
case INFORMATION_CLEAR: {
return set(
`informationData`, undefined, state
);
}
case SAVE_BUBBLE_INFO: {
return set('infoBulle', action.data, state);
}
case PRINT_RESPONSE: {
return {...state, requestFormData: {...state.requestFormData, allowDocument: action.allowDocument, requestId: action.requestId}};
}
default:
return state;
}
}
Example #26
Source File: index.js From hzero-front with Apache License 2.0 | 4 votes |
/**
* 渲染最终的字段
* @param {Object} field - 字段
*/
renderComposeFormField({ field }) {
const { disableStyle, fieldLabelWidth, col, editable, organizationId, context } = this.props;
const formItemProps = {
labelCol: {
style: { width: fieldLabelWidth, minWidth: fieldLabelWidth, maxWidth: fieldLabelWidth },
},
wrapperCol: { style: { flex: 'auto' } },
};
const colProps = getColLayout(col);
const fieldColProps = getColLayout(col, field.colspan);
const leftEmptyCols = [];
const rightEmptyCols = [];
if (inRange(field.leftOffset, 1, col)) {
for (let i = 0; i < field.leftOffset; i++) {
leftEmptyCols.push(<Col {...colProps} key={`${field.fieldCode}#left-offset-${i}`} />);
}
}
if (inRange(field.rightOffset, 1, col)) {
for (let i = 0; i < field.rightOffset; i++) {
rightEmptyCols.push(<Col {...colProps} key={`${field.fieldCode}#right-offset-${i}`} />);
}
}
const ComponentType = getComponentType(field);
const componentProps = getComponentProps({
field,
componentType: field.componentType,
context,
});
const otherFormItemOptions = {};
let isViewOnly = false; // 附件是否为只读
const getValueFromEvent = getGetValueFromEventFunc(field.componentType);
const getValueProps = getGetValuePropFunc(field);
if (field.componentType === 'Upload') {
otherFormItemOptions.valuePropName = 'attachmentUUID';
if (field.props) {
const propsIndex = findIndex(field.props, ['attributeName', 'viewOnly']);
if (propsIndex >= 0) {
isViewOnly = field.props[propsIndex].attributeValue;
}
}
}
if (getValueFromEvent) {
otherFormItemOptions.getValueFromEvent = getValueFromEvent;
}
if (getValueProps) {
// 不影响存的值, 只影响传递给组件的值
otherFormItemOptions.getValueProps = getValueProps;
}
const composeFormItem = (
<Col {...fieldColProps} key={field.fieldCode}>
<ComposeFormContext.Consumer>
{({ form, dataSource }) => {
const otherComponentProps = {}; // 为 lov 和 valueList 准备的属性
switch (field.componentType) {
case 'Lov':
case 'ValueList':
otherComponentProps.textValue = getDisplayValue(field, dataSource);
break;
default:
break;
}
return editable ? (
<FormItem
label={field.fieldDescription}
{...formItemProps}
required={
field.componentType !== 'Checkbox' &&
toInteger(field.requiredFlag) !== 0 &&
!isViewOnly
} // 当附件只读时,不必输
>
{(field.fieldCode === 'mail'
? form.getFieldDecorator(`mail`, {
...otherFormItemOptions,
initialValue: getInitialValue({ field, dataSource }),
rules: [
{
required: true,
message: intl.get('hzero.common.validation.notNull', {
name: intl.get('hzero.common.email').d('邮箱'),
}),
},
{
pattern: EMAIL,
message: intl.get('hzero.common.validation.email').d('邮箱格式不正确'),
},
{
max: 60,
message: intl.get('hzero.common.validation.max', {
max: 60,
}),
},
],
})
: form.getFieldDecorator(field.fieldCode, {
...otherFormItemOptions,
initialValue: getInitialValue({ field, dataSource }),
rules: [
{
required: toInteger(field.requiredFlag) !== 0 && !isViewOnly,
message: intl.get('hzero.common.validation.notNull', {
name: field.fieldDescription,
}),
},
],
}))(
React.createElement(
ComponentType,
{ ...componentProps, ...otherComponentProps } // otherComponentProps 比 componentProps 优先级高
)
)}
</FormItem>
) : (
<FormItem label={field.fieldDescription} {...formItemProps}>
{renderDisabledField({
field,
dataSource,
formItemProps,
organizationId,
disableStyle,
componentProps: { ...componentProps, ...otherComponentProps },
})}
</FormItem>
);
}}
</ComposeFormContext.Consumer>
</Col>
);
if (isEmpty(leftEmptyCols) && isEmpty(rightEmptyCols)) {
return composeFormItem;
}
return (
<React.Fragment key={field.fieldCode}>
{leftEmptyCols}
{composeFormItem}
{rightEmptyCols}
</React.Fragment>
);
}
Example #27
Source File: Timeline.js From hivemind with Apache License 2.0 | 4 votes |
Timeline = ({ data, timestamp, jump }) => {
const timelineRef = useRef()
const timeline = useRef()
const {
cyWrapper: { cy, viewApi },
} = useContext(GlobalContext)
const [modal, setModal] = useState(false)
const [target, setTarget] = useState('timeline')
const [node, setNode] = useState(<Spinner />)
const [showJump, setShowJump] = useState('d-block')
const [showFind, setShowFind] = useState('d-none')
const [items, setItems] = useState([])
const toggle = () => setModal(!modal)
const jumpTo = async (lctime) => {
if (lctime !== timestamp) {
jump(lctime)
}
setModal(false)
}
const locate = (item) => {
if (item && item.event !== 'deleted') {
const node = cy.$id(item.nid)
viewApi.zoomToSelected(node)
viewApi.removeHighlights(cy.elements())
viewApi.highlight(node)
}
setModal(false)
}
useEffect(() => {
if (get(data, 'ok')) {
setItems(
data.data.map((event, idx) => ({
id: idx,
className: event.lctime === timestamp ? 'pinned' : '',
title: event.event,
content: '',
start: event.lctime * 1000,
style: `background-color: ${bgColors[event.event]};`,
lctime: event.lctime,
nid: event.nids[0] || event.mid,
event: event.event,
}))
)
}
}, [data, timestamp])
useEffect(() => {
if (items.length) {
if (timeline.current) {
timeline.current.setItems(items)
} else {
const container = timelineRef.current
if (container.firstChild) {
container.removeChild(container.firstChild)
}
const margin = (items[items.length - 1].start - items[0].start) * 0.05
const options = {
width: '100%',
height: '120px',
type: 'box',
stack: false,
horizontalScroll: false,
verticalScroll: false,
cluster: {
titleTemplate: '{count}',
maxItems: 1,
showStipes: true,
fitOnDoubleClick: true,
},
max: items[items.length - 1].start + margin,
min: items[0].start - margin,
selectable: false,
dataAttributes: ['id'],
zoomMin: 60000,
}
timeline.current = new VisTimeline(container, items, options)
}
timeline.current.on('click', (properties) => {
const { what, isCluster, item } = properties
if (what === 'item' && !isCluster) {
setNode(<Spinner />)
setTarget(item)
setModal(true)
if (items[item].className === 'pinned') {
setShowJump('d-none')
if (items[item].event !== 'deleted') {
setShowFind('d-block')
}
} else {
setShowJump('d-block')
setShowFind('d-none')
}
} else {
setModal(false)
setTarget('timeline')
}
})
timeline.current.on('doubleClick', (properties) => {
const { what, item, isCluster } = properties
switch (what) {
case 'background':
timeline.current.fit()
break
case 'item':
if (!isCluster) {
timeline.current.focus(item)
}
break
}
})
defer(() => { // To ensure focus/fit on first load.
if (timestamp) {
const idx = findIndex(items, { lctime: timestamp })
timeline.current.focus(idx)
} else {
timeline.current.fit()
}
})
}
}, [items, timestamp])
useEffect(
() => () => {
timeline.current.destroy()
timeline.current = null
},
[]
)
return (
<div className={'border border-secondary rounded'}>
<div id={'timeline'} ref={timelineRef} className={'m-1'} >
<Spinner/>
</div>
<Modal
isOpen={modal}
toggle={toggle}
fade={false}
centered={true}
size={'lg'}
scrollable={true}
>
<ModalHeader toggle={toggle}>
<b>{node}</b> | {get(items, [target, 'event'], 'NA')}{' '}
{new Date(get(items, [target, 'start'], Date.now())).toLocaleString()}
</ModalHeader>
<ModalBody>
{data && data.data[target] ? (
<EventDetail event={data.data[target]} setNode={setNode} />
) : null}
</ModalBody>
<ModalFooter>
<Button
className={`ml-1 ${showJump}`}
outline
color="secondary"
id="jump"
onClick={() => jumpTo(items[target].lctime)}
>
<MapPin size={16} /> Jump
</Button>
<Button
className={`ml-1 ${showFind}`}
outline
color="secondary"
id="find"
onClick={() => locate(items[target])}
>
<Search size={16} /> Find
</Button>
<ToolTippedButton
className="ml-1"
outline
color="secondary"
id="tag"
disabled={true}
tooltip={'Coming Soon'}
>
<Tag size={16} /> Tag
</ToolTippedButton>
</ModalFooter>
</Modal>
</div>
)
}
Example #28
Source File: Canvas.js From hivemind with Apache License 2.0 | 4 votes |
Canvas = ({ data, timestamp, events }) => {
const { cyWrapper, poppers } = useContext(GlobalContext)
const [output, setOutput] = useState(null)
const [els, setEls] = useState([])
const prevEls = usePrevious(els)
useEffect(() => {
if (cyWrapper.cy && prevEls !== els) {
const commonEls = intersectionBy(prevEls, els, 'data.id')
const celMap = zipObject(map(commonEls, 'data.id'), commonEls)
cyWrapper.cy
.elements()
.filter((el) => celMap[el.id()])
.forEach((el) => {
el.removeData('summary content audio lastUpdatedBy')
el.data(celMap[el.id()].data)
})
}
}, [cyWrapper.cy, els, prevEls])
useEffect(() => {
if (get(data, 'ok') && typeof window !== 'undefined') {
setEls(CytoscapeComponent.normalizeElements(data.data.elements))
}
}, [data])
useEffect(() => {
function initCy(cyInternal) {
cyWrapper.cy = cyInternal
cyInternal.nodes().forEach((node) => {
node.scratch('style', node.style())
})
}
const nodes = els.filter((el) => !el.data.id.startsWith('links'))
const fit = shouldFit(nodes)
const options = getOptions(fit)
setOutput(
<CytoscapeComponent
cy={initCy}
style={{ width: '100%', height: '100%' }}
stylesheet={style}
layout={options}
elements={els}
/>
)
}, [cyWrapper, els])
useEffect(() => {
function configurePlugins(access) {
function buildMenu() {
const { viewApi } = cyWrapper
return function (node) {
const menu = []
view(menu, poppers)
if (!node.data('isRoot')) {
hide(menu, viewApi)
}
if (node.scratch('showReveal')) {
reveal(menu, viewApi)
}
if (access && ['admin', 'write'].includes(access.access)) {
add(menu, poppers)
if (!node.data('isRoot')) {
del(menu, poppers)
}
edit(menu, poppers)
}
return menu
}
}
const { cy } = cyWrapper
const minRadius = Math.min(cy.width(), cy.height()) / 8
const viewOpts = {
highlightStyles: [
{
node: { 'border-color': '#0b9bcd', 'border-width': 3 },
edge: {
'line-color': '#0b9bcd',
'source-arrow-color': '#0b9bcd',
'target-arrow-color': '#0b9bcd',
width: 3,
},
},
{
node: { 'border-color': '#04f06a', 'border-width': 3 },
edge: {
'line-color': '#04f06a',
'source-arrow-color': '#04f06a',
'target-arrow-color': '#04f06a',
width: 3,
},
},
],
selectStyles: {
node: {
'border-color': 'white',
'border-width': 3,
'background-color': 'lightgrey',
},
edge: {
'line-color': 'white',
'source-arrow-color': 'white',
'target-arrow-color': 'white',
width: 3,
},
},
setVisibilityOnHide: false, // whether to set visibility on hide/show
setDisplayOnHide: true, // whether to set display on hide/show
zoomAnimationDuration: 500, //default duration for zoom animation speed
neighbor: function (node) {
return node.successors()
},
neighborSelectTime: 500,
}
cyWrapper.viewApi = cy.viewUtilities(viewOpts)
const cxtMenu = {
menuRadius: minRadius + 50, // the radius of the circular menu in pixels
selector: 'node', // elements matching this Cytoscape.js selector will trigger cxtmenus
commands: buildMenu(), // function( ele ){ return [
// /*...*/ ] }, // a function
// that returns
// commands or a promise of commands
fillColor: 'rgba(0, 0, 0, 0.75)', // the background colour of the menu
activeFillColor: 'rgba(100, 100, 100, 0.5)', // the colour used to indicate the selected
// command
activePadding: 10, // additional size in pixels for the active command
indicatorSize: 16, // the size in pixels of the pointer to the active command
separatorWidth: 3, // the empty spacing in pixels between successive commands
spotlightPadding: 4, // extra spacing in pixels between the element and the spotlight
minSpotlightRadius: minRadius - 40, // the minimum radius in pixels of the spotlight
maxSpotlightRadius: minRadius - 20, // the maximum radius in pixels of the spotlight
openMenuEvents: 'tap', // space-separated cytoscape events that will open the menu; only
// `cxttapstart` and/or `taphold` work here
itemColor: 'white', // the colour of text in the command's content
itemTextShadowColor: 'transparent', // the text shadow colour of the command's content
// zIndex: 9999, // the z-index of the ui div
atMouse: false, // draw menu at mouse position
}
cyWrapper.menu = cy.cxtmenu(cxtMenu)
}
function setHandlers() {
const { viewApi, cy } = cyWrapper
cy.on(
'boxend',
throttle(() => defer(() => viewApi.zoomToSelected(cy.$(':selected')))),
1000
)
cy.on('mouseover', 'node', () => {
document.getElementById('cy').style.cursor = 'pointer'
})
cy.on('mouseout', 'node', () => {
document.getElementById('cy').style.cursor = 'default'
})
cy.on('mouseover', 'edge', (e) => {
e.target.style({
width: 4,
'line-color': '#007bff',
'target-arrow-color': '#007bff',
})
})
cy.on('unselect mouseout', 'edge', (e) => {
const edge = e.target
if (!edge.selected()) {
edge.style({
width: 2,
'line-color': '#ccc',
'target-arrow-color': '#ccc',
})
}
})
cy.on('add', 'node', (e) => {
const node = e.target
node.scratch('style', node.style())
})
cy.on(
'add data remove',
'node',
throttle(() => {
if (timestamp) {
const idx = findIndex(events.data, { lctime: timestamp })
const event = events.data[idx]
const { viewApi } = cyWrapper
viewApi.removeHighlights(cy.elements())
if (event && event.event !== 'deleted') {
const nid = event.nids[0]
const node = cy.$id(nid)
viewApi.highlight(node)
}
}
}, 100)
)
cy.on('mouseover', 'node', (e) => {
e.target.style('background-color', '#007bff')
})
cy.on('unselect mouseout', 'node', (e) => {
const node = e.target
viewApi.removeHighlights(node)
if (!node.selected()) {
node.style(
'background-color',
node.scratch('style')['background-color']
)
}
})
}
if (cyWrapper.cy && get(data, 'ok') && get(events, 'ok')) {
configurePlugins(data.data.access)
setHandlers()
}
return () => {
if (cyWrapper.menu) {
cyWrapper.menu.destroy()
}
}
}, [data, events, cyWrapper.menu, cyWrapper, timestamp, poppers, els])
return (
<div
className={`border border-${
timestamp ? 'secondary' : 'danger'
} rounded w-100`}
id="cy-container"
>
<div className="m-1" id="cy">
{output}
</div>
</div>
)
}
Example #29
Source File: index.js From strapi-molecules with MIT License | 4 votes |
function SelectWrapper({
componentUid,
description,
editable,
label,
isCreatingEntry,
isFieldAllowed,
isFieldReadable,
mainField,
name,
relationType,
slug,
targetModel,
placeholder,
valueToSet,
}) {
// Disable the input in case of a polymorphic relation
const isMorph = relationType.toLowerCase().includes("morph");
const {
addRelation,
modifiedData,
moveRelation,
onChange,
onRemoveRelation,
initialData,
} = useDataManager();
const { isDraggingComponent } = useEditView();
const value =
valueToSet && valueToSet !== "current"
? valueToSet
: get(modifiedData, name, null);
const initialValue = get(initialData, name, null);
// This is needed for making requests when used in a component
const fieldName = useMemo(() => {
const fieldNameArray = getFieldName(name);
return fieldNameArray[fieldNameArray.length - 1];
}, [name]);
const { pathname } = useLocation();
const [state, setState] = useState({
_contains: "",
_limit: 20,
_start: 0,
});
const [options, setOptions] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const abortController = new AbortController();
const { signal } = abortController;
const ref = useRef();
const startRef = useRef();
const filteredOptions = useMemo(() => {
return options.filter((option) => {
if (!isEmpty(value)) {
// SelectMany
if (Array.isArray(value)) {
return findIndex(value, (o) => o.id === option.value.id) === -1;
}
// SelectOne
return get(value, "id", "") !== option.value.id;
}
return true;
});
}, [options, value]);
startRef.current = state._start;
ref.current = async () => {
if (isMorph) {
setIsLoading(false);
return;
}
if (!isDraggingComponent) {
try {
const requestUrl = `/${pluginId}/explorer/${slug}/relation-list/${fieldName}`;
const containsKey = `${mainField}_contains`;
const { _contains, ...restState } = cloneDeep(state);
const params = isEmpty(state._contains)
? restState
: { [containsKey]: _contains, ...restState };
if (componentUid) {
set(params, "_component", componentUid);
}
const data = await request(requestUrl, {
method: "GET",
params,
signal,
});
const formattedData = data.map((obj) => {
return { value: obj, label: obj[mainField] };
});
setOptions((prevState) =>
prevState.concat(formattedData).filter((obj, index) => {
const objIndex = prevState.findIndex(
(el) => el.value.id === obj.value.id,
);
if (objIndex === -1) {
return true;
}
return (
prevState.findIndex((el) => el.value.id === obj.value.id) ===
index
);
}),
);
setIsLoading(false);
} catch (err) {
if (err.code !== 20) {
strapi.notification.error("notification.error");
}
}
}
};
useEffect(() => {
if (state._contains !== "") {
let timer = setTimeout(() => {
ref.current();
}, 300);
return () => clearTimeout(timer);
}
if (isFieldAllowed) {
ref.current();
}
return () => {
abortController.abort();
};
}, [state._contains, isFieldAllowed]);
useEffect(() => {
if (state._start !== 0) {
ref.current();
}
return () => {
abortController.abort();
};
}, [state._start]);
const onInputChange = (inputValue, { action }) => {
if (action === "input-change") {
setState((prevState) => {
if (prevState._contains === inputValue) {
return prevState;
}
return { ...prevState, _contains: inputValue, _start: 0 };
});
}
return inputValue;
};
const onMenuScrollToBottom = () => {
setState((prevState) => ({ ...prevState, _start: prevState._start + 20 }));
};
const isSingle = [
"oneWay",
"oneToOne",
"manyToOne",
"oneToManyMorph",
"oneToOneMorph",
].includes(relationType);
const changeRelationValueForCurrentVersion = () => {
if (valueToSet && startRef.current != 0) {
valueToSet !== "current"
? onChange({ target: { name, value: valueToSet } })
: onChange({ target: { name, value: initialValue } });
}
};
useEffect(() => {
changeRelationValueForCurrentVersion();
}, [valueToSet]);
const to = `/plugins/${pluginId}/collectionType/${targetModel}/${
value ? value.id : null
}`;
const link =
value === null ||
value === undefined ||
[
"plugins::users-permissions.role",
"plugins::users-permissions.permission",
].includes(targetModel) ? null : (
<Link to={{ pathname: to, state: { from: pathname } }}>
<FormattedMessage id="content-manager.containers.Edit.seeDetails" />
</Link>
);
const Component = isSingle ? SelectOne : SelectMany;
const associationsLength = isArray(value) ? value.length : 0;
const customStyles = {
option: (provided) => {
return {
...provided,
maxWidth: "100% !important",
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
};
},
};
const isDisabled = useMemo(() => {
if (isMorph) {
return true;
}
if (!isCreatingEntry) {
return !isFieldAllowed && isFieldReadable;
}
return !editable;
});
if (!isFieldAllowed && isCreatingEntry) {
return <NotAllowedInput label={label} />;
}
if (!isCreatingEntry && !isFieldAllowed && !isFieldReadable) {
return <NotAllowedInput label={label} />;
}
return (
<Wrapper className="form-group">
<Nav>
<div>
<label htmlFor={name}>
{label}
{!isSingle && (
<span style={{ fontWeight: 400, fontSize: 12 }}>
({associationsLength})
</span>
)}
</label>
{isSingle && link}
</div>
{!isEmpty(description) && <p className="description">{description}</p>}
</Nav>
<Component
addRelation={(value) => {
addRelation({ target: { name, value } });
}}
id={name}
isDisabled={isDisabled}
isLoading={isLoading}
isClearable
mainField={mainField}
move={moveRelation}
name={name}
options={filteredOptions}
onChange={(value) => {
onChange({ target: { name, value: value ? value.value : value } });
}}
onInputChange={onInputChange}
onMenuClose={() => {
setState((prevState) => ({ ...prevState, _contains: "" }));
}}
onMenuScrollToBottom={onMenuScrollToBottom}
onRemove={onRemoveRelation}
placeholder={
isEmpty(placeholder) ? (
<FormattedMessage id={`${pluginId}.containers.Edit.addAnItem`} />
) : (
placeholder
)
}
styles={customStyles}
targetModel={targetModel}
value={value}
/>
<div style={{ marginBottom: 18 }} />
</Wrapper>
);
}