Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion apps/explorer/src/components/search/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,28 @@ import { useDebouncedValue } from '~/hooks/useDebouncedValue';
import { useSearch } from '~/hooks/useSearch';
import { ampli } from '~/lib/utils';

/**
* Extract an ID without a dash, if it is present as a suffix.
*
* CONTEXT: Search result `id` is used as React element key and must be unique,
* because of this, search result now comes with a suffix like `-notarization` or
* `-identity`, which must be ripped off as this is invalid network ID.
*
* @example
* extractOnlyTheId('0x123-audit-trail')
* // output: '0x123'
* @example
* extractOnlyTheId('0x123-identity')
* // output: '0x123'
* @example
* extractOnlyTheId('0x123')
* // output: '0x123'
*/
function extractOnlyTheId(possibleDashedId: string): string {
const dashAt = possibleDashedId.indexOf('-') || -1;
return dashAt > -1 ? possibleDashedId.slice(0, dashAt) : possibleDashedId;
}
Comment on lines +30 to +33

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in testnet, searching for did:iota:testnet:0xdc704ab63984d5763576c12ce5f62fe735766bc1fc9892a5e2a7be777a9af897 gets me to /identity/did?network=testnet so it breaks.

do this instead:

Suggested change
function extractOnlyTheId(possibleDashedId: string): string {
const dashAt = possibleDashedId.indexOf('-') || -1;
return dashAt > -1 ? possibleDashedId.slice(0, dashAt) : possibleDashedId;
}
function extractOnlyTheId(possibleDashedId: string): string {
return possibleDashedId.replace(/-(audittrail|notarization)$/, '');
}


export function Search(): JSX.Element {
const [query, setQuery] = useState('');
const debouncedQuery = useDebouncedValue(query);
Expand All @@ -22,7 +44,7 @@ export function Search(): JSX.Element {
searchQuery: result.id,
searchCategory: result.type,
});
navigate(`/${result?.type}/${encodeURIComponent(result?.id)}`, {});
navigate(`/${result.type}/${encodeURIComponent(extractOnlyTheId(result.id))}`, {});
setQuery('');
}
},
Expand Down
28 changes: 26 additions & 2 deletions apps/explorer/src/hooks/useSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,33 @@ import { type IdentityClientReadOnly } from '@iota/identity-wasm/web';
import { useFeatureIsOn } from '@iota/apps-backend-client';
import { type NotarizationClientReadOnly } from '@iota/notarization/web';
import { tryDIDParse, tryEncodeDidToUrl } from '~/lib/utils/trust-framework/client';
import { useIdentityClient, useNotarizationClient } from '~/contexts';
import { useAuditTrailClient, useIdentityClient, useNotarizationClient } from '~/contexts';
import { type AuditTrailClientReadOnly } from '@iota/audit-trails/web';

const isGenesisLibAddress = (value: string): boolean => /^(0x|0X)0{0,39}[12]$/.test(value);

type Results = { id: string; label: string; type: string }[];

const getResultsForAuditTrail = async (
auditTrailClient: AuditTrailClientReadOnly | null,
isAuditTrailEnabled: boolean,
query: string,
): Promise<Results | null> => {
if (auditTrailClient == null) return null; // client not available
if (!isAuditTrailEnabled) return null; // feature flag disabled

const auditTrailChain = await auditTrailClient.trail(query).get();
if (!auditTrailChain) return null;

return [
{
id: `${auditTrailChain.id}-audittrail`,
label: auditTrailChain.id,
type: 'audit-trail',
},
];
};

const getResultsForNotarization = async (
notarizationClient: NotarizationClientReadOnly | null,
isNotarizationEnabled: boolean,
Expand All @@ -41,7 +62,7 @@ const getResultsForNotarization = async (

return [
{
id: notarizationChain.id,
id: `${notarizationChain.id}-notarization`,
label: notarizationChain.id,
type: 'notarization',
},
Expand Down Expand Up @@ -278,10 +299,12 @@ export function useSearch(query: string): UseQueryResult<Results, Error> {
const client = useIotaClient();
const identityClient = useIdentityClient();
const notarizationClient = useNotarizationClient();
const auditTrailClient = useAuditTrailClient();
const { data: systemStateSummary } = useIotaClientQuery('getLatestIotaSystemState');

const isTFIdentityEnabled = useFeatureIsOn(Feature.ExplorerTFIdentity as string);
const isTFNotarizationEnabled = useFeatureIsOn(Feature.ExplorerTFNotarization as string);
const isTFAuditTrailEnabled = useFeatureIsOn(Feature.ExplorerTFAuditTrail as string);
const { iotaNamesClient } = useIotaNamesClient();

return useQuery<Results, Error>({
Expand All @@ -296,6 +319,7 @@ export function useSearch(query: string): UseQueryResult<Results, Error> {
getResultsForAddress(client, query, iotaNamesClient),
getResultsForDid(identityClient, isTFIdentityEnabled, query),
getResultsForNotarization(notarizationClient, isTFNotarizationEnabled, query),
getResultsForAuditTrail(auditTrailClient, isTFAuditTrailEnabled, query),
getResultsForObject(client, query),
getResultsForValidatorByPoolIdOrIotaAddress(systemStateSummary || null, query),
])
Expand Down
Loading