Skip to content
Merged
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
458 changes: 244 additions & 214 deletions websites/app/src/components/Dashboard/RecentActivity.tsx

Large diffs are not rendered by default.

19 changes: 12 additions & 7 deletions websites/app/src/consts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
export const EMAIL_REGEX =
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
export const TELEGRAM_REGEX = /^@\w{5,32}$/;
export const ETH_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;
export const ETH_SIGNATURE_REGEX = /^0x[a-fA-F0-9]{130}$/;
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
export const TELEGRAM_REGEX = /^@\w{5,32}$/
export const ETH_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/
export const ETH_SIGNATURE_REGEX = /^0x[a-fA-F0-9]{130}$/

export const DAPPLOOKER_API_KEY = import.meta.env.REACT_APP_DAPPLOOKER_API_KEY || "";
export const SUBGRAPH_GNOSIS_ENDPOINT = import.meta.env.REACT_APP_SUBGRAPH_GNOSIS_ENDPOINT || "https://api.studio.thegraph.com/query/108432/gtcr-subgraph-gnosis/version/latest";
export const SUBGRAPH_KLEROS_DISPLAY_GNOSIS_ENDPOINT = import.meta.env.REACT_APP_SUBGRAPH_KLEROS_DISPLAY_GNOSIS_ENDPOINT || "https://api.studio.thegraph.com/query/61738/kleros-display-gnosis/version/latest";
export const DAPPLOOKER_API_KEY =
import.meta.env.REACT_APP_DAPPLOOKER_API_KEY || ''
export const SUBGRAPH_GNOSIS_ENDPOINT =
import.meta.env.REACT_APP_SUBGRAPH_GNOSIS_ENDPOINT ||
'https://indexer.hyperindex.xyz/1a2f51c/v1/graphql'
export const SUBGRAPH_KLEROS_DISPLAY_GNOSIS_ENDPOINT =
import.meta.env.REACT_APP_SUBGRAPH_KLEROS_DISPLAY_GNOSIS_ENDPOINT ||
'https://api.studio.thegraph.com/query/61738/kleros-display-gnosis/version/latest'
241 changes: 131 additions & 110 deletions websites/app/src/hooks/queries/useExportItems.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import { gql, request } from 'graphql-request';
import { GraphItem } from 'utils/items';
import { useQuery } from '@tanstack/react-query';
import { SUBGRAPH_GNOSIS_ENDPOINT } from 'consts/index';
import { chains, getNamespaceForChainId } from 'utils/chains';
import { gql, request } from 'graphql-request'
import { GraphItem } from 'utils/items'
import { useQuery } from '@tanstack/react-query'
import { SUBGRAPH_GNOSIS_ENDPOINT } from 'consts/index'
import { chains, getNamespaceForChainId } from 'utils/chains'

export interface ExportFilters {
registryId?: string;
status?: string[];
disputed?: boolean[];
fromDate?: string;
toDate?: string;
network?: string[];
text?: string;
registryId?: string
status?: string[]
disputed?: boolean[]
fromDate?: string
toDate?: string
network?: string[]
text?: string
}

export const useExportItems = (filters: ExportFilters) => {
return useQuery<GraphItem[]>({
queryKey: ['exportItems', filters],
enabled: false, // Only fetch when export button is clicked
queryFn: async () => {
let allData: GraphItem[] = [];
const first = 1000;
let skip = 0;
let keepFetching = true;
let allData: GraphItem[] = []
const first = 1000
let skip = 0
let keepFetching = true

const {
registryId,
Expand All @@ -31,102 +31,113 @@ export const useExportItems = (filters: ExportFilters) => {
fromDate,
toDate,
network = [],
text = ''
} = filters;
text = '',
} = filters

if (!registryId) {
throw new Error('Registry ID is required for export');
throw new Error('Registry ID is required for export')
}

const isTagsQueriesRegistry = registryId === '0xae6aaed5434244be3699c56e7ebc828194f26dc3';
const isTagsQueriesRegistry =
registryId === '0xae6aaed5434244be3699c56e7ebc828194f26dc3'

// Build network filter
const selectedChainIds = network.filter((id) => id !== 'unknown');
const includeUnknown = network.includes('unknown');
const definedChainIds = chains.map((c) => c.id);
const knownPrefixes = [...new Set(chains.map((chain) => {
if (chain.namespace === 'solana') {
return 'solana:';
}
return `${chain.namespace}:${chain.id}:`;
}))];
const selectedChainIds = network.filter((id) => id !== 'unknown')
const includeUnknown = network.includes('unknown')
const definedChainIds = chains.map((c) => c.id)
const knownPrefixes = [
...new Set(
chains.map((chain) => {
if (chain.namespace === 'solana') {
return 'solana:'
}
return `${chain.namespace}:${chain.id}:`
}),
),
]

let networkQueryObject = '';
let networkQueryObject = ''
if (isTagsQueriesRegistry && network.length > 0) {
const conditions = selectedChainIds.map(
(chainId) =>
`{or: [{metadata_: {key2: "${chainId}"}}, {metadata_: {key1: "${chainId}"}}]}`
);
`{ _or: [{ key2: { _eq: "${chainId}"}}, { key1: { _eq: "${chainId}"}}]}`,
)
if (includeUnknown) {
conditions.push(
`{and: [{metadata_: {key1_not_in: $definedChainIds}}, {metadata_: {key2_not_in: $definedChainIds}}]}`
);
`{ _and: [{ key1: { _nin: $definedChainIds}}, { key2: { _nin: $definedChainIds}}]}`,
)
}
networkQueryObject = conditions.length > 0 ? `{or: [${conditions.join(',')}]}` : '{}';
networkQueryObject =
conditions.length > 0 ? `{_or: [${conditions.join(',')}]}` : '{}'
} else if (network.length > 0) {
const conditions = selectedChainIds.map((chainId) => {
const namespace = getNamespaceForChainId(chainId);
const namespace = getNamespaceForChainId(chainId)
if (namespace === 'solana') {
return `{metadata_: {key0_starts_with_nocase: "solana:"}}`;
return `{key0: { _ilike: "solana:%"}}`
}
return `{metadata_: {key0_starts_with_nocase: "${namespace}:${chainId}:"}}`;
});
networkQueryObject = conditions.length > 0 ? `{or: [${conditions.join(',')}]}` : '{}';
return `{key0: {_ilike: "${namespace}:${chainId}:%"}}`
})
networkQueryObject =
conditions.length > 0 ? `{_or: [${conditions.join(',')}]}` : '{}'
}

// Build text filter
const textFilterObject = text
? `{or: [
{metadata_: {key0_contains_nocase: $text}},
{metadata_: {key1_contains_nocase: $text}},
{metadata_: {key2_contains_nocase: $text}},
{metadata_: {key3_contains_nocase: $text}},
{metadata_: {key4_contains_nocase: $text}}
]}`
: '';
? `{_or: [
{key0: {_ilike: $text}},
{key1: {_ilike: $text}},
{key2: {_ilike: $text}},
{key3: {_ilike: $text}},
{key4: {_ilike: $text}}
]}`
: ''

// Build date filter
let dateFilterObject = '';
let dateFilterObject = ''
if (fromDate || toDate) {
const conditions = [];
const conditions: string[] = []
if (fromDate) {
const fromTimestamp = Math.floor(new Date(fromDate).getTime() / 1000);
conditions.push(`{latestRequestSubmissionTime_gte: "${fromTimestamp}"}`);
const fromTimestamp = Math.floor(new Date(fromDate).getTime() / 1000)
conditions.push(
`{latestRequestSubmissionTime: { _gte: "${fromTimestamp}"}}`,
)
}
if (toDate) {
const toTimestamp = Math.floor(new Date(toDate).getTime() / 1000);
conditions.push(`{latestRequestSubmissionTime_lte: "${toTimestamp}"}`);
const toTimestamp = Math.floor(new Date(toDate).getTime() / 1000)
conditions.push(
`{latestRequestSubmissionTime: {_lte: "${toTimestamp}"}}`,
)
}
dateFilterObject = conditions.length > 0 ? `{and: [${conditions.join(',')}]}` : '';
dateFilterObject =
conditions.length > 0 ? `{_and: [${conditions.join(',')}]}` : ''
}

// Build the complete where clause
const whereConditions = [
`{registry: "${registryId}"}`,
`{status_in: $status}`,
`{disputed_in: $disputed}`,
`{registry_id: {_eq: "${registryId}"}}`,
`{status: {_in: $status}}`,
`{disputed: {_in: $disputed}}`,
networkQueryObject && `${networkQueryObject}`,
textFilterObject && `${textFilterObject}`,
dateFilterObject && `${dateFilterObject}`
].filter(Boolean) as string[];
dateFilterObject && `${dateFilterObject}`,
].filter(Boolean) as string[]

const query = gql`
query (
$status: [String!]!
$status: [status!]!
$disputed: [Boolean!]!
$text: String!
$text: String
$skip: Int!
$first: Int!
${includeUnknown && isTagsQueriesRegistry ? '$definedChainIds: [String!]!' : ''}
) {
litems(
litems: LItem(
where: {
and: [${whereConditions.join(',')}]
_and: [${whereConditions.join(',')}]
}
skip: $skip
first: $first
orderBy: "latestRequestSubmissionTime"
orderDirection: desc
offset: $skip
limit: $first
order_by: {latestRequestSubmissionTime: desc}
) {
id
latestRequestSubmissionTime
Expand All @@ -135,21 +146,19 @@ export const useExportItems = (filters: ExportFilters) => {
status
disputed
data
metadata {
key0
key1
key2
key3
key4
props {
value
type
label
description
isIdentifier
}
key0
key1
key2
key3
key4
props {
value
type: itemType
label
description
isIdentifier
}
requests(first: 1, orderBy: submissionTime, orderDirection: desc) {
requests(limit: 1, order_by: {submissionTime: desc}) {
disputed
disputeID
submissionTime
Expand All @@ -158,7 +167,7 @@ export const useExportItems = (filters: ExportFilters) => {
challenger
resolutionTime
deposit
rounds(first: 1, orderBy: creationTime, orderDirection: desc) {
rounds(limit: 1, order_by: {creationTime : desc}) {
appealPeriodStart
appealPeriodEnd
ruling
Expand All @@ -170,65 +179,77 @@ export const useExportItems = (filters: ExportFilters) => {
}
}
}
`;
`

try {
while (keepFetching) {
const variables: any = {
status,
disputed,
text,
skip,
first,
};
}

if (text) {
variables.text = `%${text}%`
}

if (includeUnknown && isTagsQueriesRegistry) {
variables.definedChainIds = definedChainIds;
variables.definedChainIds = definedChainIds
}

const result = (await request({
url: SUBGRAPH_GNOSIS_ENDPOINT,
document: query,
variables,
})) as any;
})) as any

let items = result.litems;
let items = result.litems

// Client-side filtering for non-Tags_Queries registries
if (!isTagsQueriesRegistry && network.length > 0) {
const selectedPrefixes = selectedChainIds.map((chainId) => {
const namespace = getNamespaceForChainId(chainId);
const namespace = getNamespaceForChainId(chainId)
if (namespace === 'solana') {
return 'solana:';
return 'solana:'
}
return `${namespace}:${chainId}:`;
});
return `${namespace}:${chainId}:`
})

items = items.filter((item: GraphItem) => {
const key0 = item.metadata?.key0?.toLowerCase() || '';
const matchesSelectedChain = selectedPrefixes.length > 0
? selectedPrefixes.some((prefix) => key0.startsWith(prefix.toLowerCase()))
: false;

const isUnknownChain = !knownPrefixes.some((prefix) => key0.startsWith(prefix.toLowerCase()));

return (selectedPrefixes.length > 0 && matchesSelectedChain) || (includeUnknown && isUnknownChain);
});
const key0 = item?.key0?.toLowerCase() || ''
const matchesSelectedChain =
selectedPrefixes.length > 0
? selectedPrefixes.some((prefix) =>
key0.startsWith(prefix.toLowerCase()),
)
: false

const isUnknownChain = !knownPrefixes.some((prefix) =>
key0.startsWith(prefix.toLowerCase()),
)

return (
(selectedPrefixes.length > 0 && matchesSelectedChain) ||
(includeUnknown && isUnknownChain)
)
})
}

allData = allData.concat(items);
allData = allData.concat(items)

if (items.length < first) {
keepFetching = false;
keepFetching = false
}

skip += first;
skip += first
}
} catch (error) {
console.error('Error fetching export data:', error);
throw error;
console.error('Error fetching export data:', error)
throw error
}

return allData;
return allData
},
});
};
})
}
Loading