lodash#difference TypeScript Examples
The following examples show how to use
lodash#difference.
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: utils.ts From admin with MIT License | 7 votes |
mapIdsToItems = <T extends Idable>(
items: T[] = [],
ids: string[] = [],
source: T[] = []
) => {
const itemIds = items.map((item) => item?.id)
/* we need to add an entity to the selectedItems list */
if (items.length < ids.length) {
const added = difference(ids, itemIds)
const newItems = added.map((id) => source.find((s) => s.id === id)) as T[]
return items.concat(newItems)
} else if (items.length > ids.length) {
/* we need to remove an entity from the selectedItems */
const removed = difference(itemIds, ids)
const newItems = items.slice()
removed.forEach((id) => {
const index = newItems.findIndex((item) => item?.id === id)
newItems.splice(index, 1)
})
return newItems
}
return items
}
Example #2
Source File: util.ts From gio-design with Apache License 2.0 | 7 votes |
getResultValue = (value?: (string | number)[], val?: string | number) => {
if (indexOf(value, val) !== -1) {
return difference(value, [val]);
}
if (typeof val === 'string') {
return concat(value, val);
}
return value;
// ? :
}
Example #3
Source File: checkPermissions.ts From next-core with GNU General Public License v3.0 | 6 votes |
export async function validatePermissions(
usedActions: string[]
): Promise<void> {
// Do not request known actions.
const actions = difference(usedActions, Array.from(permissionMap.keys()));
if (actions.length === 0) {
return;
}
try {
const result = await PermissionApi_validatePermissions({ actions });
for (const item of result.actions) {
permissionMap.set(item.action, item.authorizationStatus);
if (item.authorizationStatus === "undefined") {
// eslint-disable-next-line no-console
console.error(`Undefined permission action: "${item.action}"`);
}
}
} catch (error) {
// Allow pre-check to fail, and
// make it not crash when the backend service is not updated.
// eslint-disable-next-line no-console
console.error("Pre-check permissions failed", error);
}
}
Example #4
Source File: platform.ts From homebridge-zigbee-nt with Apache License 2.0 | 6 votes |
async handleZigBeeReady(): Promise<void> {
const info: Device = this.zigBeeClient.getCoordinator();
this.log.info(`ZigBee platform initialized @ ${info.ieeeAddr}`);
// Init permit join accessory
await this.initPermitJoinAccessory();
// Init switch to reset devices through Touchlink feature
this.initTouchLinkAccessory();
// Init devices
const paired = (
await Promise.all(
this.zigBeeClient.getAllPairedDevices().map(device => this.initDevice(device))
)
).filter(uuid => uuid !== null);
paired.push(this.permitJoinAccessory.accessory.UUID);
paired.push(this.touchLinkAccessory.accessory.UUID);
const missing = difference([...this.accessories.keys()], paired);
missing.forEach(uuid => {
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [
this.accessories.get(uuid),
]);
this.accessories.delete(uuid);
this.homekitAccessories.delete(uuid);
});
if (this.config.disableHttpServer !== true) {
try {
this.httpServer = new HttpServer(this.config.httpPort);
this.httpServer.start(this);
} catch (e) {
this.log.error('WEB UI failed to start.', e);
}
} else {
this.log.info('WEB UI disabled.');
}
}
Example #5
Source File: helpers.ts From leda with MIT License | 6 votes |
getSortedSuggestions = ({
shouldSelectedGoFirst,
selectedSuggestions,
filteredData,
sortSuggestions,
}: GetSortedSuggestionsProps) => {
const suggestions = filteredData ? filteredData.slice() : [];
if (shouldSelectedGoFirst && selectedSuggestions) {
const notSelectedSuggestions = selectedSuggestions ? difference(suggestions, selectedSuggestions) : suggestions;
if (sortSuggestions) {
notSelectedSuggestions.sort(sortSuggestions);
}
const sortedSelectedSuggestions = sortSuggestions ? [...selectedSuggestions].sort(sortSuggestions) : selectedSuggestions;
return [...sortedSelectedSuggestions, ...notSelectedSuggestions];
}
return sortSuggestions
? suggestions.sort(sortSuggestions)
: suggestions;
}
Example #6
Source File: fixLocales.ts From nextclade with MIT License | 6 votes |
export function parseLocale(json: Record<string, string>) {
return Object.entries(json).map(([reference, localized], index) => {
const refSubsts = getSubstitutions(reference)
const locSubsts = getSubstitutions(localized)
const missing = difference(refSubsts, locSubsts)
const extra = difference(locSubsts, refSubsts)
return { index, missing, extra, reference, localized }
})
}
Example #7
Source File: schema.ts From analytics-next with MIT License | 6 votes |
expect.extend({
toContainSchema(got: object, expected: object) {
const gotSchema = objectSchema(got)
const expectedSchema = objectSchema(expected)
const missing = difference(expectedSchema, gotSchema)
const message = () =>
'Incompatible schema. Missing the following properties: \n ' +
missing.join('\n')
return {
pass: missing.length === 0,
message,
}
},
})
Example #8
Source File: updateBillReferences.ts From advocacy-maps with MIT License | 6 votes |
getCommitteeUpdates(): BillUpdates {
const billsInCommittee = flatten(
this.committees.map(c => c.content.DocumentsBeforeCommittee)
)
const billsOutOfCommittee = difference(this.billIds, billsInCommittee)
const updates: BillUpdates = new Map()
// Set the committee on bills listed in a committee
this.committees.forEach(c =>
c.content.DocumentsBeforeCommittee.forEach(billId => {
updates.set(billId, {
currentCommittee: {
id: c.id,
name: c.content.FullName,
houseChair: this.formatChair(c.content.HouseChairperson),
senateChair: this.formatChair(c.content.SenateChairperson)
}
})
})
)
// Clear the committee on bills not in committee
billsOutOfCommittee.forEach(id => {
updates.set(id, {
currentCommittee: FieldValue.delete()
})
})
return updates
}
Example #9
Source File: updateBillReferences.ts From advocacy-maps with MIT License | 6 votes |
getCityUpdates(): BillUpdates {
const billsWithoutCity = difference(
this.billIds,
flatten(this.cities.map(c => c.bills))
)
const updates: BillUpdates = new Map()
// Update the city for each bill listed in a city
this.cities.forEach(city => {
city.bills.forEach(id => {
updates.set(id, { city: city.id })
})
})
// Remove the city for bills without a matching city
billsWithoutCity.forEach(id => {
updates.set(id, { city: FieldValue.delete() })
})
return updates
}
Example #10
Source File: boxFetcher.ts From nautilus-wallet with MIT License | 6 votes |
export async function fetchBoxes(
walletId: number,
options: { tokenId?: string; useAllAddressesAsFallback: boolean; includeUnconfirmed: boolean } = {
tokenId: ERG_TOKEN_ID,
useAllAddressesAsFallback: true,
includeUnconfirmed: true
}
): Promise<ErgoBox[]> {
const addresses = await assestsDbService.getAddressesByTokenId(
walletId,
options.tokenId ?? ERG_TOKEN_ID
);
const pendingBoxes = options.includeUnconfirmed
? await utxosDbService.getByWalletId(walletId)
: [];
let boxes = await fetchBoxesFromExplorer(addresses);
if (
options.useAllAddressesAsFallback &&
isEmpty(boxes) &&
!find(pendingBoxes, (b) => !b.locked && b.content)
) {
boxes = await fetchBoxesFromExplorer(difference(await getAllAddresses(walletId), addresses));
}
if (!isEmpty(pendingBoxes)) {
const lockedIds = pendingBoxes.filter((x) => x.locked).map((x) => x.id);
const unconfirmed = pendingBoxes.filter((b) => !b.locked && b.content).map((b) => b.content!);
if (!isEmpty(lockedIds)) {
boxes = boxes.filter((b) => !lockedIds.includes(b.boxId));
}
if (!isEmpty(unconfirmed)) {
boxes = unionBy(boxes, unconfirmed, (b) => b.boxId);
}
}
return sortBy(boxes, (x) => x.creationHeight).reverse();
}
Example #11
Source File: reports.ts From yearn-watch-legacy with GNU Affero General Public License v3.0 | 6 votes |
_getReportsForStrategies = async (
strategies: string[],
network: Network,
strategyReportContext: StrategyReportContextValue
): Promise<void> => {
if (strategies.length === 0) {
throw new Error(
'Error: getReportsForStrategies expected valid strategy address'
);
}
const { strategyReports, updateStrategyReports } = strategyReportContext;
const cachedStrategies = strategies.filter(
(s) => s.toLowerCase() in strategyReports
);
// Only query for uncached strategies
const strategiesToQuery = difference(strategies, cachedStrategies);
if (strategiesToQuery.length > 0) {
const reportResults: StratReportGraphResult = await querySubgraphData(
buildReportsQuery(strategiesToQuery.map((s) => s.toLowerCase())),
network
);
const strategyResults: Strategy[] = get(
reportResults,
'data.strategies',
[]
);
strategyResults.forEach((results) => {
strategyReports[results.id.toLowerCase()] = _parseReportValues(
results.reports
);
});
updateStrategyReports(strategyReports);
}
}
Example #12
Source File: utils.ts From prism-frontend with MIT License | 6 votes |
convertToTableData = (result: ExposedPopulationResult) => {
const {
key,
groupBy,
statistic,
featureCollection: { features },
} = result;
const fields = uniq(features.map(f => f.properties && f.properties[key]));
const featureProperties = features.map(feature => {
return {
[groupBy]: feature.properties?.[groupBy],
[key]: feature.properties?.[key],
[statistic]: feature.properties?.[statistic],
};
});
const rowData = mapValues(_groupBy(featureProperties, groupBy), k => {
return mapValues(_groupBy(k, key), v =>
parseInt(
v.map(x => x[statistic]).reduce((acc, value) => acc + value),
10,
),
);
});
const groupedRowData = Object.keys(rowData).map(k => {
return {
[groupBy]: k,
...rowData[k],
};
});
const groupedRowDataWithAllLabels = groupedRowData.map(row => {
const labelsWithoutValue = difference(fields, keysIn(row));
const extras = labelsWithoutValue.map(k => ({ [k]: 0 }));
return extras.length !== 0 ? assign(row, ...extras) : row;
});
const headlessRows = groupedRowDataWithAllLabels.map(row => {
// TODO - Switch between MAX and SUM depending on the polygon source.
// Then re-add "Total" to the list of columns
// const total = fields.map(f => row[f]).reduce((a, b) => a + b);
// return assign(row, { Total: total });
return row;
});
const columns = [groupBy, ...fields]; // 'Total'
const headRow = zipObject(columns, columns);
const rows = [headRow, ...headlessRows];
return { columns, rows };
}
Example #13
Source File: multisig.ts From subscan-multisig-react with Apache License 2.0 | 6 votes |
export function useUnapprovedAccounts() {
const { accounts } = useApi();
const { multisigAccount } = useMultisig();
const getUnapprovedInjectedList = useCallback(
(data: Entry | null) => {
if (!data) {
return [];
}
const extensionAddresses = accounts?.map((item) => item.address) || [];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const multisigPairAddresses = (multisigAccount?.meta.addressPair as any[])?.map((item) => item.address);
const extensionInPairs = intersection(extensionAddresses, multisigPairAddresses);
const approvedExtensionAddresses = intersection(extensionInPairs, data.approvals);
return difference(extensionInPairs, approvedExtensionAddresses);
},
[accounts, multisigAccount?.meta.addressPair]
);
return [getUnapprovedInjectedList];
}
Example #14
Source File: row-column-click.ts From S2 with MIT License | 6 votes |
private handleExpandIconClick(node: Node) {
const lastHiddenColumnsDetail = this.spreadsheet.store.get(
'hiddenColumnsDetail',
[],
);
const { hideColumnNodes = [] } =
lastHiddenColumnsDetail.find(({ displaySiblingNode }) =>
isEqualDisplaySiblingNodeId(displaySiblingNode, node.id),
) || {};
const { hiddenColumnFields: lastHideColumnFields } =
this.spreadsheet.options.interaction;
const willDisplayColumnFields = hideColumnNodes.map(
this.getHideColumnField,
);
const hiddenColumnFields = difference(
lastHideColumnFields,
willDisplayColumnFields,
);
const hiddenColumnsDetail = lastHiddenColumnsDetail.filter(
({ displaySiblingNode }) =>
!isEqualDisplaySiblingNodeId(displaySiblingNode, node.id),
);
this.spreadsheet.setOptions({
interaction: {
hiddenColumnFields,
},
});
this.spreadsheet.store.set('hiddenColumnsDetail', hiddenColumnsDetail);
this.spreadsheet.interaction.reset();
this.spreadsheet.render(false);
}
Example #15
Source File: turn.ts From fishbowl with MIT License | 6 votes |
export function drawableCards(
turns: CurrentGameSubscription["games"][0]["turns"],
cards: CurrentGameSubscription["games"][0]["cards"]
) {
const allCompletedCardIds = flatMap(turns, (turn) => turn.completed_card_ids)
const maxCount = max(values(countBy(allCompletedCardIds)))
let completedCardIdsForRound = filter(
groupBy(allCompletedCardIds),
(arr) => arr.length === maxCount
).map((arr) => arr[0])
const remainingIdsForRound = difference(
cards.map((card) => card.id),
completedCardIdsForRound
)
if (remainingIdsForRound.length === 0) {
return cards
} else {
return filter(cards, (card) => remainingIdsForRound.includes(card.id))
}
}
Example #16
Source File: assetInfoDbService.ts From nautilus-wallet with MIT License | 6 votes |
public async addIfNotExists(assets: IAssetInfo[]) {
if (isEmpty(assets)) {
return;
}
assets = uniqBy(assets, (a) => a.id);
const paramIds = assets.map((a) => a.id);
const dbIds = await dbContext.assetInfo.where("id").anyOf(paramIds).primaryKeys();
const uncommited = difference(paramIds, dbIds);
if (!isEmpty(uncommited)) {
await dbContext.assetInfo.bulkAdd(assets.filter((a) => uncommited.includes(a.id)));
}
}
Example #17
Source File: txInterpreter.ts From nautilus-wallet with MIT License | 6 votes |
constructor(tx: UnsignedTx, ownAddresses: string[], assetInfo: StateAssetInfo) {
this._tx = tx;
this._addresses = ownAddresses;
this._assetInfo = assetInfo;
this._feeBox = find(tx.outputs, (b) => b.ergoTree === MINER_FEE_TREE);
this._changeBox = findLast(tx.outputs, (b) =>
ownAddresses.includes(addressFromErgoTree(b.ergoTree))
);
this._sendingBoxes = difference(tx.outputs, [this._feeBox, this._changeBox]).filter(
(b) => b !== undefined
) as ErgoBoxCandidate[];
if (isEmpty(this._sendingBoxes) && this._changeBox) {
this._sendingBoxes.push(this._changeBox);
this._changeBox = undefined;
}
}
Example #18
Source File: smoke.test.ts From analytics-next with MIT License | 5 votes |
describe('Smoke Tests', () => {
// needs to be written as a string so it's not transpiled
const code = `(async () => {
await window.analytics.identify('Test', {
email: '[email protected]',
})
await window.analytics.track('Track!', {
leProp: 'propé',
})
await window.analytics.page()
})()`
test.concurrent.each(samples)(`smoke test`, async (writekey) => {
const [url, chrome] = await Promise.all([server(), browser()])
const results = await run({
browser: chrome,
script: code,
serverURL: url,
writeKey: writekey,
})
const classicReqs = results.classic.networkRequests
.map((n) => new URL(n.url).host)
.sort()
const nextReqs = results.next.networkRequests
.map((n) => new URL(n.url).host)
.sort()
expect(nextReqs).not.toEqual([])
const missing = difference(classicReqs, nextReqs)
expect(missing).toEqual([])
expect(nextReqs).toEqual(expect.arrayContaining(classicReqs))
const nextCookies = results.next.cookies.reduce((all, cookie) => {
return {
...all,
[cookie.name]: cookie.value,
}
}, {} as Record<string, string>)
const classicCookies = results.classic.cookies.reduce((all, cookie) => {
return {
...all,
[cookie.name]: cookie.value,
}
}, {} as Record<string, string>)
expect(nextCookies['ajs_user_id']).toContain('Test')
expect(classicCookies['ajs_user_id']).toContain('Test')
compareSchema(results)
})
test.concurrent.each(samples)(`obfuscated smoke test`, async (writekey) => {
const [url, chrome] = await Promise.all([server(true), browser()])
const obfuscatedresults = await run({
browser: chrome,
script: code,
serverURL: url,
writeKey: writekey,
})
obfuscatedresults.next.bundleRequestFailures.forEach((result) => {
expect(result).toBe(null)
})
compareSchema(obfuscatedresults)
})
})
Example #19
Source File: profile-repository.spec.ts From linkedin-private-api with MIT License | 5 votes |
describe('getProfile', () => {
it('should return the correct profile from the response', async () => {
const { response, resultProfile } = createGetProfileResponse();
const reqParams = {
q: 'memberIdentity',
memberIdentity: resultProfile.publicIdentifier,
decorationId: 'com.linkedin.voyager.dash.deco.identity.profile.FullProfileWithEntities-35',
};
when(axios.get(getProfileRequestUrl, { params: reqParams })).thenResolve({ data: response });
const client = new Client();
await client.login.userPass({ username, password });
const profile = await client.profile.getProfile({ publicIdentifier: resultProfile.publicIdentifier });
expect(profile.publicIdentifier).toEqual(resultProfile.publicIdentifier);
expect(difference(Object.keys(resultProfile), Object.keys(profile)).length).toEqual(0);
});
it('should populate company on the result profile', async () => {
const { response, resultProfile, resultCompany } = createGetProfileResponse();
const reqParams = {
q: 'memberIdentity',
memberIdentity: resultProfile.publicIdentifier,
decorationId: 'com.linkedin.voyager.dash.deco.identity.profile.FullProfileWithEntities-35',
};
when(axios.get(getProfileRequestUrl, { params: reqParams })).thenResolve({ data: response });
const client = new Client();
await client.login.userPass({ username, password });
const profile = await client.profile.getProfile({ publicIdentifier: resultProfile.publicIdentifier });
expect(profile.company).toEqual(resultCompany);
});
it('should populate profile picture urls on the result profile', async () => {
const { response, resultProfile } = createGetProfileResponse();
const reqParams = {
q: 'memberIdentity',
memberIdentity: resultProfile.publicIdentifier,
decorationId: 'com.linkedin.voyager.dash.deco.identity.profile.FullProfileWithEntities-35',
};
when(axios.get(getProfileRequestUrl, { params: reqParams })).thenResolve({ data: response });
const client = new Client();
await client.login.userPass({ username, password });
const profile = await client.profile.getProfile({ publicIdentifier: resultProfile.publicIdentifier });
expect(profile.pictureUrls).toHaveLength(4);
profile.pictureUrls.forEach((url: string) => expect(typeof url).toEqual('string'));
});
});
Example #20
Source File: profile-repository.spec.ts From linkedin-private-api with MIT License | 5 votes |
describe('getOwnProfile', () => {
const requestUrl = new URL('me', linkedinApiUrl).toString();
it('should return the correct profile from the response', async () => {
const { response: miniProfileResponse, resultProfile: resultMiniProfile } = createGetOwnProfileResponse();
const { response: profileResponse, resultProfile } = createGetProfileResponse();
const reqParams = {
q: 'memberIdentity',
memberIdentity: resultMiniProfile.publicIdentifier,
decorationId: 'com.linkedin.voyager.dash.deco.identity.profile.FullProfileWithEntities-35',
};
resultProfile.publicIdentifier = resultMiniProfile.publicIdentifier;
when(axios.get(requestUrl, undefined)).thenResolve({ data: miniProfileResponse });
when(axios.get(getProfileRequestUrl, { params: reqParams })).thenResolve({ data: profileResponse });
const client = new Client();
await client.login.userPass({ username, password });
const profile = await client.profile.getOwnProfile();
expect(profile.publicIdentifier).toEqual(resultProfile.publicIdentifier);
expect(difference(Object.keys(resultProfile), Object.keys(profile)).length).toEqual(0);
});
it('should populate company on the result profile', async () => {
const { response: miniProfileResponse, resultProfile: resultMiniProfile } = createGetOwnProfileResponse();
const { response: profileResponse, resultProfile, resultCompany } = createGetProfileResponse();
const reqParams = {
q: 'memberIdentity',
memberIdentity: resultMiniProfile.publicIdentifier,
decorationId: 'com.linkedin.voyager.dash.deco.identity.profile.FullProfileWithEntities-35',
};
resultProfile.publicIdentifier = resultMiniProfile.publicIdentifier;
when(axios.get(requestUrl, undefined)).thenResolve({ data: miniProfileResponse });
when(axios.get(getProfileRequestUrl, { params: reqParams })).thenResolve({ data: profileResponse });
const client = new Client();
await client.login.userPass({ username, password });
const profile = await client.profile.getOwnProfile();
expect(profile.company).toEqual(resultCompany);
});
it('should populate profile picture urls on the result profile', async () => {
const { response: miniProfileResponse, resultProfile: resultMiniProfile } = createGetOwnProfileResponse();
const { response: profileResponse, resultProfile } = createGetProfileResponse();
const reqParams = {
q: 'memberIdentity',
memberIdentity: resultMiniProfile.publicIdentifier,
decorationId: 'com.linkedin.voyager.dash.deco.identity.profile.FullProfileWithEntities-35',
};
resultProfile.publicIdentifier = resultMiniProfile.publicIdentifier;
when(axios.get(requestUrl, undefined)).thenResolve({ data: miniProfileResponse });
when(axios.get(getProfileRequestUrl, { params: reqParams })).thenResolve({ data: profileResponse });
const client = new Client();
await client.login.userPass({ username, password });
const profile = await client.profile.getOwnProfile();
expect(profile.pictureUrls).toHaveLength(4);
profile.pictureUrls.forEach((url: string) => expect(typeof url).toEqual('string'));
});
it('should return null and not request full profile if undefined response was returned', async () => {
when(axios.get(requestUrl, undefined)).thenResolve({ data: undefined });
const client = new Client();
await client.login.userPass({ username, password });
const profile = await client.profile.getOwnProfile();
expect(profile).toBe(null);
verify(axios.get(getProfileRequestUrl), { ignoreExtraArgs: true, times: 0 });
});
});
Example #21
Source File: index.tsx From erda-ui with GNU Affero General Public License v3.0 | 5 votes |
UserSelector = (props: any) => {
const { value } = props;
const [searchKey, setSearchKey] = React.useState('');
const [searchResult, setSearchResult] = React.useState([] as any[]);
const [searchLackUser, setSearchLackUser] = React.useState(false);
React.useEffect(() => {
if (!isEmpty(value)) {
// 兼容选项有值无list情况
const curValue = isString(value) ? [value] : value;
const existUserId = map(searchResult || [], 'id'); // 当前存在的user
const lackUser = difference(curValue, existUserId);
if (lackUser.length && !searchLackUser) {
setSearchLackUser(true); // 请求过一次后就不再请求
getUsers({ userID: lackUser }).then((res: any) => {
setSearchResult(get(res, 'data.users'));
});
}
}
}, [value, searchResult, searchLackUser]);
const handleSearch = (q: string) => {
const query = {
q,
pageNo: 1,
pageSize: 15,
};
setSearchKey(q);
if (q.trim() !== '') {
getUsersNew(query).then((res: any) => {
setSearchResult(get(res, 'data.users'));
});
}
};
const userOptionRender = (member: IMember) => {
const { avatar, nick, name } = member;
const id = member.id || member.userId;
return (
<Option key={id} value={id}>
<Avatar src={avatar} size="small">
{nick ? getAvatarChars(nick) : i18n.t('None')}
</Avatar>
<span className="ml-2" title={name}>
{nick || i18n.t('common:None')}
</span>
</Option>
);
};
return (
<Select
className="w-full"
showSearch
notFoundContent={searchKey ? i18n.t('common:please confirm that the user is registered') : ''}
showArrow={false}
filterOption={false}
defaultActiveFirstOption={false}
placeholder={i18n.t('Please enter the member name to search')}
onSearch={debounce(handleSearch, 800)}
{...props}
>
{(searchResult || []).map(userOptionRender)}
</Select>
);
}
Example #22
Source File: OrganizationEmployee.ts From condo with MIT License | 5 votes |
function convertToGQLInput (state: IOrganizationEmployeeFormState, obj: IOrganizationEmployeeUIState): OrganizationEmployeeUpdateInput {
const sender = getClientSideSenderInfo()
const result = { dv: 1, sender }
for (const attr of Object.keys(state)) {
if (RELATIONS.includes(attr)) {
if (Array.isArray(state[attr])) {
const newIds = map(state[attr], item => get(item, 'id') || item)
if (obj) { // update operation
const oldIds = map(obj[attr], item => get(item, 'id') || item)
const changes: RelateToManyInput = {}
const idsToConnect = difference(newIds, oldIds)
if (idsToConnect.length > 0) {
changes.connect = map(idsToConnect, id => ({ id }))
}
const idsToDisconnect = difference(oldIds, newIds)
if (idsToDisconnect.length > 0) {
changes.disconnect = map(idsToDisconnect, id => ({ id }))
}
if (Object.keys(changes).length > 0) {
result[attr] = changes
}
} else { // create operation
if (newIds.length > 0) {
result[attr] = {
connect: map(newIds, id => ({ id })),
}
}
}
} else {
const newAttrId = get(state[attr], 'id') || state[attr]
if (obj) { // update operation
const oldAttrId = get(obj[attr], 'id') || obj[attr]
if (newAttrId && oldAttrId && newAttrId !== oldAttrId) {
result[attr] = { connect: { id: newAttrId } }
} else if (!newAttrId) {
result[attr] = { disconnectAll: true }
}
} else { // create operation
if (newAttrId) {
result[attr] = { connect: { id: newAttrId } }
}
}
}
} else {
result[attr] = state[attr]
}
}
return result
}
Example #23
Source File: Division.ts From condo with MIT License | 5 votes |
// TODO(antonal): move this function into `generate.hooks` and use it everywhere, since no extra logic is introduced in each duplicate of this function
/**
* Converts form values of form into GraphQL `…UpdateInput` shape
* @param state - form values
* @param obj - existing object from `useObjects`, that will be passed in case of update operation by `useUpdate` and `useSoftDelete` hooks
*/
export function convertToGQLInput (state: IDivisionFormState, obj?: IDivisionUIState): DivisionUpdateInput {
const sender = getClientSideSenderInfo()
const result = { dv: 1, sender }
for (const attr of Object.keys(state)) {
if (RELATIONS.includes(attr)) {
if (Array.isArray(state[attr])) {
const newIds = map(state[attr], item => get(item, 'id') || item)
if (obj) { // update operation
const oldIds = map(obj[attr], item => get(item, 'id') || item)
const changes: RelateToManyInput = {}
const idsToConnect = difference(newIds, oldIds)
if (idsToConnect.length > 0) {
changes.connect = map(idsToConnect, id => ({ id }))
}
const idsToDisconnect = difference(oldIds, newIds)
if (idsToDisconnect.length > 0) {
changes.disconnect = map(idsToDisconnect, id => ({ id }))
}
if (Object.keys(changes).length > 0) {
result[attr] = changes
}
} else { // create operation
if (newIds.length > 0) {
result[attr] = {
connect: map(newIds, id => ({ id })),
}
}
}
} else {
const newAttrId = get(state[attr], 'id') || state[attr]
if (obj) { // update operation
const oldAttrId = get(obj[attr], 'id') || obj[attr]
if (newAttrId && oldAttrId && newAttrId !== oldAttrId) {
result[attr] = { connect: { id: newAttrId } }
} else if (!newAttrId) {
result[attr] = { disconnectAll: true }
}
} else { // create operation
if (newAttrId) {
result[attr] = { connect: { id: newAttrId } }
}
}
}
} else {
result[attr] = state[attr]
}
}
return result
}
Example #24
Source File: meta-fields.tsx From erda-ui with GNU Affero General Public License v3.0 | 5 votes |
LabelFiedExtra = (props: LabelExtraProps) => {
const { labelUpdate, optionList, onCancel, onOk } = props;
const { prev, current } = labelUpdate;
const [expand, setExpand] = React.useState(true);
const data = getIssueRelation.useData();
if (!data?.include?.length) {
return null;
}
if (prev.join(',') === current.join(',')) {
return null;
} else {
const del = difference(prev, current);
const add = difference(current, prev);
return (
<div className="bg-default-04 rounded border border-solid border-default-1 p-3 issue-labels-extra max-w-[600px] issue-extra-field relative">
<div className="flex-h-center justify-between">
<div className="font-medium mr-3 flex-h-center">
<ErdaIcon
type="caret-down"
className={`mr-1 cursor-pointer expand-icon ${expand ? '' : 'un-expand'}`}
size={'18'}
onClick={() => setExpand((_expand) => !_expand)}
/>
{i18n.t('dop:issue-labels-update-tip')}
</div>
<div className="flex-h-center">
<Button type="primary" ghost size="small" onClick={onCancel}>
{i18n.t('Cancel')}
</Button>
<Button size="small" className="ml-2" type="primary" onClick={onOk}>
{i18n.t('dop:synchronize')}
</Button>
</div>
</div>
{expand ? (
<div className="mx-6 issue-label-diff">
{add.length ? (
<div className="flex py-2">
<span className="mr-2 text-success">{`${i18n.t('dop:Add')}: `}</span>
<div className="flex-1">
{add.map((item) => {
const curLabel = optionList.find((opt) => opt.name === item);
return curLabel ? (
<TagItem
style={{ marginBottom: 2 }}
key={item}
label={{ label: item, color: curLabel.color }}
readOnly
/>
) : null;
})}
</div>
</div>
) : null}
{del.length ? (
<div className="flex py-2">
<span className="mr-2 text-danger">{`${i18n.t('Delete')}: `}</span>
<div className="flex-1">
{del.map((item) => {
const curLabel = optionList.find((opt) => opt.name === item);
return curLabel ? (
<TagItem
style={{ marginBottom: 2 }}
key={item}
label={{ label: item, color: curLabel.color }}
readOnly
/>
) : null;
})}
</div>
</div>
) : null}
</div>
) : null}
</div>
);
}
}
Example #25
Source File: pivot-data-set.ts From S2 with MIT License | 5 votes |
/**
* Provide a way to append some drill-down data in indexesData
* @param extraRowField
* @param drillDownData
* @param rowNode
*/
public transformDrillDownData(
extraRowField: string,
drillDownData: DataType[],
rowNode: Node,
) {
const { columns, values: dataValues } = this.fields;
const currentRowFields = Node.getFieldPath(rowNode, true);
const nextRowFields = [...currentRowFields, extraRowField];
const store = this.spreadsheet.store;
// 1、通过values在data中注入额外的维度信息,并分离`明细数据`&`汇总数据`
const transformedData = this.standardTransform(drillDownData, dataValues);
const totalData = splitTotal(transformedData, {
columns: this.fields.columns,
rows: nextRowFields,
});
const originData = difference(transformedData, totalData);
// 2. 检查该节点是否已经存在下钻维度
const rowNodeId = rowNode?.id;
const idPathMap = store.get('drillDownIdPathMap') ?? new Map();
if (idPathMap.has(rowNodeId)) {
// the current node has a drill-down field, clean it
forEach(idPathMap.get(rowNodeId), (path: number[]) => {
unset(this.indexesData, path);
});
deleteMetaById(this.rowPivotMeta, rowNodeId);
}
// 3、转换数据
const {
paths: drillDownDataPaths,
indexesData,
rowPivotMeta,
colPivotMeta,
sortedDimensionValues,
} = transformIndexesData({
rows: nextRowFields,
columns,
originData,
totalData,
indexesData: this.indexesData,
sortedDimensionValues: this.sortedDimensionValues,
rowPivotMeta: this.rowPivotMeta,
colPivotMeta: this.colPivotMeta,
});
this.indexesData = indexesData;
this.rowPivotMeta = rowPivotMeta;
this.colPivotMeta = colPivotMeta;
this.sortedDimensionValues = sortedDimensionValues;
// 4、record data paths by nodeId
// set new drill-down data path
idPathMap.set(rowNodeId, drillDownDataPaths);
store.set('drillDownIdPathMap', idPathMap);
}
Example #26
Source File: updateBillReferences.ts From advocacy-maps with MIT License | 5 votes |
async getEventUpdates(): Promise<BillUpdates> {
const hearings = await db
.collection(`/events`)
.where("startsAt", ">=", new Date())
.where("type", "==", "hearing")
.get()
.then(this.load(Hearing))
const updates: BillUpdates = new Map()
// Set the next hearing on every bill referenced by upcoming hearings.
const billEvents = flattenDeep<{
startsAt: Timestamp
billId: string
hearingId: string
court: number
}>(
hearings.map(hearing =>
hearing.content.HearingAgendas.map(agenda =>
agenda.DocumentsInAgenda.map(doc => ({
startsAt: parseApiDateTime(agenda.StartTime),
billId: doc.BillNumber,
court: doc.GeneralCourtNumber,
hearingId: hearing.id
}))
)
)
)
billEvents.forEach(event => {
const existing = updates.get(event.billId)
if (!existing || event.startsAt < (existing.nextHearingAt as Timestamp)) {
updates.set(event.billId, {
nextHearingAt: event.startsAt,
nextHearingId: event.hearingId
})
}
})
// Remove the next hearing on any bills that reference upcoming hearings but
// aren't on the agenda.
const hearingIds = new Set(billEvents.map(e => e.hearingId)),
billsWithEvents = billEvents.map(e => e.billId),
existingBillsWithEvents = this.bills
.filter(b => hearingIds.has(b.nextHearingId))
.map(b => b.id as string),
billsWithRemovedEvents = difference(
existingBillsWithEvents,
billsWithEvents
)
billsWithRemovedEvents.forEach(id => {
updates.set(id, {
nextHearingAt: FieldValue.delete(),
nextHearingId: FieldValue.delete()
})
})
return updates
}
Example #27
Source File: base-list.tsx From erda-ui with GNU Affero General Public License v3.0 | 4 votes |
BatchOperation = <T extends unknown>(props: IBatchProps<T>) => { const { rowKey, dataSource, onSelectChange, execOperation, selectedRowKeys = emptyKeys, batchRowsHandle } = props; const selectableData = React.useMemo(() => dataSource.filter((item) => item.selectable !== false), [dataSource]); const [{ checkAll, indeterminate }, updater, update] = useUpdate({ checkAll: false, indeterminate: false, }); React.useEffect(() => { const allKeys = map(selectableData, rowKey); const curChosenKeys = intersection(allKeys, selectedRowKeys); update({ checkAll: !!(curChosenKeys.length && curChosenKeys.length === allKeys.length), indeterminate: !!(curChosenKeys.length && curChosenKeys.length < allKeys.length), }); }, [update, selectableData, rowKey, selectedRowKeys]); const optMenus = React.useMemo(() => { const { options } = batchRowsHandle?.serverData; return options.map((mItem) => { const { allowedRowIDs, forbiddenRowIDs } = mItem; const validChosenOpt = intersection(selectedRowKeys, allowedRowIDs || selectedRowKeys).length === selectedRowKeys.length && intersection(selectedRowKeys, forbiddenRowIDs).length === 0; const disabledProps = selectedRowKeys?.length ? { disabled: has(mItem, 'disabled') ? mItem.disabled : !validChosenOpt, disabledTip: i18n.t('exist item which not match operation'), } : { disabled: true, disabledTip: i18n.t('no items selected') }; const reMenu = { ...mItem, ...disabledProps, }; return reMenu; }); }, [batchRowsHandle, selectedRowKeys]); const dropdownMenu = ( <Menu theme="dark"> {map(optMenus, (mItem) => { return ( <Menu.Item key={mItem.id} disabled={!!mItem.disabled}> <OperationAction operation={{ ...mItem, ...batchRowsHandle }} onClick={() => execOperation({ key: 'batchRowsHandle', ...batchRowsHandle, clientData: { dataRef: mItem, selectedOptionsID: mItem.id, selectedRowIDs: selectedRowKeys }, }) } tipProps={{ placement: 'right' }} > <div className="flex-h-center"> {mItem.icon ? ( <ErdaIcon type={typeof mItem.icon === 'string' ? mItem.icon : mItem.icon.type} className="mr-1" /> ) : null} <span>{mItem.text}</span> </div> </OperationAction> </Menu.Item> ); })} </Menu> ); const onCheckAllChange = () => { const allKeys = map(selectableData, rowKey); if (checkAll) { onSelectChange(difference(selectedRowKeys, allKeys)); } else { onSelectChange(compact(selectedRowKeys.concat(allKeys))); } }; return ( <div className="flex items-center"> <Checkbox className="mr-2" indeterminate={indeterminate} onChange={onCheckAllChange} checked={checkAll} /> <span className="mr-2">{`${i18n.t('{name} items selected', { name: selectedRowKeys?.length || 0, })}`}</span> <Dropdown overlay={dropdownMenu} zIndex={1000}> <Button className="flex items-center"> {i18n.t('Batch Operations')} <ErdaIcon size="18" type="caret-down" className="ml-1 text-default-4" /> </Button> </Dropdown> </div> ); }
Example #28
Source File: destinations.test.ts From analytics-next with MIT License | 4 votes |
describe('Destination Tests', () => {
// needs to be written as a string so it's not transpiled
// We use a 150ms fake interval between each to ensure that we don't any destination buffering
// e.g. Clicky, Google Analytics, and others will treat our events as bots (or will buffer them)
// if we deliver events too quickly.
const code = `(async () => {
await new Promise(res => window.analytics.page({}, res))
// second page so that assumePageView destinations stop complaining
await new Promise(res => setTimeout(res, Math.random() * 150 + 100))
await new Promise(res => window.analytics.page({}, res))
await new Promise(res => setTimeout(res, Math.random() * 150 + 100))
await new Promise(res => window.analytics.identify('Test', {
email: '[email protected]',
}, res))
await new Promise(res => setTimeout(res, Math.random() * 150 + 100))
await new Promise(res => window.analytics.track('Track!', {
leProp: 'propé',
}, res))
})()`
test.concurrent.each(destinations)(`%p`, async (destination) => {
const key = destination as keyof typeof samples
const writeKey = samples[key][0]
const [url, chrome] = await Promise.all([server(), browser()])
const results = await run({
browser: chrome,
script: code,
serverURL: url,
writeKey,
key,
})
const classicReqs = results.classic.networkRequests
.map((n) => {
const url = new URL(n.url)
return JSON.stringify({
host: url.host + url.pathname,
queryParams: Array.from(url.searchParams.entries())
.map((entry) => entry[0])
.filter((p) => !p.match(/^\d+$/))
.sort(),
})
})
.sort()
const nextReqs = results.next.networkRequests
.map((n) => {
const url = new URL(n.url)
return JSON.stringify({
host: url.host + url.pathname,
queryParams: Array.from(url.searchParams.entries())
.map((entry) => entry[0])
.filter((p) => !p.match(/^\d+$/))
.sort(),
})
})
.sort()
const nextMetrics = results.next.metrics
const classicMetrics = results.classic.metrics
if (process.env.STATS_WRITEKEY) {
await reportMetrics(nextMetrics, classicMetrics)
}
expect(nextReqs).not.toEqual([])
expect(classicReqs).not.toEqual([])
const missing = difference(classicReqs, nextReqs)
expect(missing).toEqual([])
expect(nextReqs).toEqual(expect.arrayContaining(classicReqs))
})
})
Example #29
Source File: backwards-compatibility.test.ts From analytics-next with MIT License | 4 votes |
describe('Backwards compatibility', () => {
test('provides all same properties', async () => {
const code = `(() => {
return [
...new Set([
...Object.getOwnPropertyNames(Object.getPrototypeOf(window.analytics)),
...Object.getOwnPropertyNames(window.analytics)
])
].sort()
})()`
const results = await run({
browser: await browser(),
script: code,
serverURL: await server(),
writeKey: TEST_WRITEKEY,
})
const next = results.next.codeEvaluation as string[]
const classic = results.classic.codeEvaluation as string[]
const missing = difference(classic, next).filter(
(fn) =>
!fn.startsWith('_') &&
// These are inherited through Emitter
!['emit', 'off', 'on', 'once', 'require'].includes(fn)
)
expect(missing).toEqual([])
})
test('accesses user_id the same way', async () => {
const code = `(async () => {
await analytics.identify('Test User')
return analytics.user().id()
})()`
const results = await run({
browser: await browser(),
script: code,
serverURL: await server(),
writeKey: TEST_WRITEKEY,
})
const nextId = results.next.codeEvaluation
const classicId = results.classic.codeEvaluation
expect(nextId).toEqual(classicId)
expect(nextId).not.toBeFalsy()
})
test('accesses traits the same way', async () => {
const code = `(async () => {
await analytics.identify('Test User', { email: '[email protected]' })
return analytics.user().traits()
})()`
const results = await run({
browser: await browser(),
script: code,
serverURL: await server(),
writeKey: TEST_WRITEKEY,
})
const nextId = results.next.codeEvaluation as { email: string }
const classicId = results.classic.codeEvaluation as { email: string }
expect(nextId).toEqual(classicId)
expect(nextId.email).toEqual('[email protected]')
})
test('loads bundles from custom domain CDN', async () => {
const code = `(async () => {})()`
const result = await run({
browser: await browser(),
script: code,
serverURL: await server(),
writeKey: TEST_WRITEKEY,
})
const resultString = result.next.bundleRequests.join()
expect(resultString).toContain(
'http://localhost:4000/dist/umd/standalone.js'
)
expect(resultString).toContain(
'http://localhost:4000/dist/umd/vendors-node_modules_segment_tsub_dist_index_js.bundle'
)
expect(resultString).toContain(
'http://localhost:4000/dist/umd/ajs-destination.bundle'
)
expect(resultString).toContain(
'http://localhost:4000/dist/umd/legacyVideos.bundle'
)
expect(resultString).toContain(
'http://localhost:4000/dist/umd/vendors-node_modules_segment_analytics_js-video-plugins_dist_index_umd_js.bundle'
)
})
test('event emitters emit the same properties', async () => {
const code = `(async () => {
let allEvents = {}
const analytics = window.analytics
analytics.on('page', (...args) => {
allEvents['page'] = [...args].filter(a => a !== undefined && Object.keys(a ?? {}).length > 0)
})
analytics.on('track', (...args) => {
allEvents['track'] = [...args].filter(a => a !== undefined && Object.keys(a ?? {}).length > 0)
})
analytics.on('identify', (...args) => {
allEvents['identify'] = [...args].filter(a => a !== undefined && Object.keys(a ?? {}).length > 0)
})
await analytics.page()
await analytics.identify('Hasbulla', { goat: true })
await analytics.track('hello world')
return allEvents
})()`
const result = await run({
browser: await browser(),
script: code,
serverURL: await server(),
writeKey: TEST_WRITEKEY,
})
const classic = result.classic.codeEvaluation
const next = result.next.codeEvaluation
expect(next['track']).toEqual(classic['track'])
expect(next['identify']).toEqual(classic['identify'])
expect(classic['page']).toMatchInlineSnapshot(`
Array [
Object {
"path": "/",
"referrer": "",
"search": "?type=classic&wk=D8frB7upBChqDN9PMWksNvZYDaKJIYo6",
"title": "",
"url": "http://localhost:4000/?type=classic&wk=D8frB7upBChqDN9PMWksNvZYDaKJIYo6",
},
Object {
"context": Object {
"page": Object {
"path": "/",
"referrer": "",
"search": "?type=classic&wk=D8frB7upBChqDN9PMWksNvZYDaKJIYo6",
"title": "",
"url": "http://localhost:4000/?type=classic&wk=D8frB7upBChqDN9PMWksNvZYDaKJIYo6",
},
},
},
]
`)
const pagecallback = next['page']
expect(pagecallback[0]).toEqual(
expect.objectContaining({
...classic['page'][0],
search: '?type=next&wk=D8frB7upBChqDN9PMWksNvZYDaKJIYo6',
url:
'http://localhost:4000/?type=next&wk=D8frB7upBChqDN9PMWksNvZYDaKJIYo6',
})
)
})
})