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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
_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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
// 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 vote down vote up
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 vote down vote up
/**
   * 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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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',
      })
    )
  })
})