Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
336fcf55
Commit
336fcf55
authored
Jan 22, 2024
by
isstuev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
search
parent
09e4f139
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
229 additions
and
15 deletions
+229
-15
index.ts
mocks/search/index.ts
+16
-1
search.ts
types/api/search.ts
+9
-2
SearchResults.pw.tsx
ui/pages/SearchResults.pw.tsx
+31
-0
SearchResults.tsx
ui/pages/SearchResults.tsx
+17
-5
SearchResults.pw.tsx_default_search-by-user-op-hash-mobile-1.png
...esults.pw.tsx_default_search-by-user-op-hash-mobile-1.png
+0
-0
SearchResults.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
...Results.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
+0
-0
SearchResultListItem.tsx
ui/searchResults/SearchResultListItem.tsx
+29
-3
SearchResultTableItem.tsx
ui/searchResults/SearchResultTableItem.tsx
+28
-0
utils.ts
ui/shared/search/utils.ts
+11
-1
SearchBar.pw.tsx
ui/snippets/searchBar/SearchBar.pw.tsx
+30
-0
SearchBarSuggest.tsx
ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggest.tsx
+3
-3
SearchBarSuggestItem.tsx
...ppets/searchBar/SearchBarSuggest/SearchBarSuggestItem.tsx
+7
-0
SearchBarSuggestUserOp.tsx
...ets/searchBar/SearchBarSuggest/SearchBarSuggestUserOp.tsx
+48
-0
SearchBar.pw.tsx_default_search-by-user-op-hash-mobile-1.png
...rchBar.pw.tsx_default_search-by-user-op-hash-mobile-1.png
+0
-0
SearchBar.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
...archBar.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
+0
-0
No files found.
mocks/search/index.ts
View file @
336fcf55
import
type
{
SearchResultToken
,
SearchResultBlock
,
SearchResultAddressOrContract
,
SearchResultTx
,
SearchResultLabel
,
SearchResult
}
from
'
types/api/search
'
;
import
type
{
SearchResultToken
,
SearchResultBlock
,
SearchResultAddressOrContract
,
SearchResultTx
,
SearchResultLabel
,
SearchResult
,
SearchResultUserOp
,
}
from
'
types/api/search
'
;
export
const
token1
:
SearchResultToken
=
{
export
const
token1
:
SearchResultToken
=
{
address
:
'
0x377c5F2B300B25a534d4639177873b7fEAA56d4B
'
,
address
:
'
0x377c5F2B300B25a534d4639177873b7fEAA56d4B
'
,
...
@@ -101,6 +109,13 @@ export const tx1: SearchResultTx = {
...
@@ -101,6 +109,13 @@ export const tx1: SearchResultTx = {
url
:
'
/tx/0x349d4025d03c6faec117ee10ac0bce7c7a805dd2cbff7a9f101304d9a8a525dd
'
,
url
:
'
/tx/0x349d4025d03c6faec117ee10ac0bce7c7a805dd2cbff7a9f101304d9a8a525dd
'
,
};
};
export
const
userOp1
:
SearchResultUserOp
=
{
timestamp
:
'
2024-01-11T14:15:48.000000Z
'
,
type
:
'
user_operation
'
,
user_operation_hash
:
'
0xcb560d77b0f3af074fa05c1e5c691bcdfe457e630062b5907e9e71fc74b2ec61
'
,
url
:
'
/op/0xcb560d77b0f3af074fa05c1e5c691bcdfe457e630062b5907e9e71fc74b2ec61
'
,
};
export
const
baseResponse
:
SearchResult
=
{
export
const
baseResponse
:
SearchResult
=
{
items
:
[
items
:
[
token1
,
token1
,
...
...
types/api/search.ts
View file @
336fcf55
...
@@ -55,7 +55,14 @@ export interface SearchResultTx {
...
@@ -55,7 +55,14 @@ export interface SearchResultTx {
url
?:
string
;
// not used by the frontend, we build the url ourselves
url
?:
string
;
// not used by the frontend, we build the url ourselves
}
}
export
type
SearchResultItem
=
SearchResultToken
|
SearchResultAddressOrContract
|
SearchResultBlock
|
SearchResultTx
|
SearchResultLabel
;
export
interface
SearchResultUserOp
{
type
:
'
user_operation
'
;
user_operation_hash
:
string
;
timestamp
:
string
;
url
?:
string
;
// not used by the frontend, we build the url ourselves
}
export
type
SearchResultItem
=
SearchResultToken
|
SearchResultAddressOrContract
|
SearchResultBlock
|
SearchResultTx
|
SearchResultLabel
|
SearchResultUserOp
;
export
interface
SearchResult
{
export
interface
SearchResult
{
items
:
Array
<
SearchResultItem
>
;
items
:
Array
<
SearchResultItem
>
;
...
@@ -79,5 +86,5 @@ export interface SearchResultFilters {
...
@@ -79,5 +86,5 @@ export interface SearchResultFilters {
export
interface
SearchRedirectResult
{
export
interface
SearchRedirectResult
{
parameter
:
string
|
null
;
parameter
:
string
|
null
;
redirect
:
boolean
;
redirect
:
boolean
;
type
:
'
address
'
|
'
block
'
|
'
transaction
'
|
null
;
type
:
'
address
'
|
'
block
'
|
'
transaction
'
|
'
user_operation
'
|
null
;
}
}
ui/pages/SearchResults.pw.tsx
View file @
336fcf55
...
@@ -8,6 +8,7 @@ import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
...
@@ -8,6 +8,7 @@ import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
import
TestApp
from
'
playwright/TestApp
'
;
import
TestApp
from
'
playwright/TestApp
'
;
import
*
as
app
from
'
playwright/utils/app
'
;
import
*
as
app
from
'
playwright/utils/app
'
;
import
buildApiUrl
from
'
playwright/utils/buildApiUrl
'
;
import
buildApiUrl
from
'
playwright/utils/buildApiUrl
'
;
import
*
as
configs
from
'
playwright/utils/configs
'
;
import
SearchResults
from
'
./SearchResults
'
;
import
SearchResults
from
'
./SearchResults
'
;
...
@@ -157,6 +158,36 @@ test('search by tx hash +@mobile', async({ mount, page }) => {
...
@@ -157,6 +158,36 @@ test('search by tx hash +@mobile', async({ mount, page }) => {
await
expect
(
component
.
locator
(
'
main
'
)).
toHaveScreenshot
();
await
expect
(
component
.
locator
(
'
main
'
)).
toHaveScreenshot
();
});
});
const
testWithUserOps
=
test
.
extend
({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context
:
contextWithEnvs
(
configs
.
featureEnvs
.
userOps
)
as
any
,
});
testWithUserOps
(
'
search by user op hash +@mobile
'
,
async
({
mount
,
page
})
=>
{
const
hooksConfig
=
{
router
:
{
query
:
{
q
:
searchMock
.
userOp1
.
user_operation_hash
},
},
};
await
page
.
route
(
buildApiUrl
(
'
search
'
)
+
`?q=
${
searchMock
.
userOp1
.
user_operation_hash
}
`
,
(
route
)
=>
route
.
fulfill
({
status
:
200
,
body
:
JSON
.
stringify
({
items
:
[
searchMock
.
userOp1
,
],
}),
}));
const
component
=
await
mount
(
<
TestApp
>
<
SearchResults
/>
</
TestApp
>,
{
hooksConfig
},
);
await
expect
(
component
.
locator
(
'
main
'
)).
toHaveScreenshot
();
});
test
.
describe
(
'
with apps
'
,
()
=>
{
test
.
describe
(
'
with apps
'
,
()
=>
{
const
MARKETPLACE_CONFIG_URL
=
app
.
url
+
buildExternalAssetFilePath
(
'
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL
'
,
'
https://marketplace-config.json
'
)
||
''
;
const
MARKETPLACE_CONFIG_URL
=
app
.
url
+
buildExternalAssetFilePath
(
'
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL
'
,
'
https://marketplace-config.json
'
)
||
''
;
const
extendedTest
=
test
.
extend
({
const
extendedTest
=
test
.
extend
({
...
...
ui/pages/SearchResults.tsx
View file @
336fcf55
...
@@ -3,6 +3,7 @@ import { useRouter } from 'next/router';
...
@@ -3,6 +3,7 @@ import { useRouter } from 'next/router';
import
type
{
FormEvent
}
from
'
react
'
;
import
type
{
FormEvent
}
from
'
react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
config
from
'
configs/app
'
;
import
useMarketplaceApps
from
'
ui/marketplace/useMarketplaceApps
'
;
import
useMarketplaceApps
from
'
ui/marketplace/useMarketplaceApps
'
;
import
SearchResultListItem
from
'
ui/searchResults/SearchResultListItem
'
;
import
SearchResultListItem
from
'
ui/searchResults/SearchResultListItem
'
;
import
SearchResultsInput
from
'
ui/searchResults/SearchResultsInput
'
;
import
SearchResultsInput
from
'
ui/searchResults/SearchResultsInput
'
;
...
@@ -52,6 +53,10 @@ const SearchResultsPageContent = () => {
...
@@ -52,6 +53,10 @@ const SearchResultsPageContent = () => {
router
.
replace
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
redirectCheckQuery
.
data
.
parameter
}
});
router
.
replace
({
pathname
:
'
/tx/[hash]
'
,
query
:
{
hash
:
redirectCheckQuery
.
data
.
parameter
}
});
return
;
return
;
}
}
case
'
user_operation
'
:
{
router
.
replace
({
pathname
:
'
/op/[hash]
'
,
query
:
{
hash
:
redirectCheckQuery
.
data
.
parameter
}
});
return
;
}
}
}
}
}
...
@@ -62,12 +67,19 @@ const SearchResultsPageContent = () => {
...
@@ -62,12 +67,19 @@ const SearchResultsPageContent = () => {
event
.
preventDefault
();
event
.
preventDefault
();
},
[
]);
},
[
]);
const
dataToDisplay
=
(
data
?.
items
||
[]).
filter
((
item
)
=>
{
if
(
!
config
.
features
.
userOps
.
isEnabled
&&
item
.
type
===
'
user_operation
'
)
{
return
false
;
}
return
true
;
});
const
content
=
(()
=>
{
const
content
=
(()
=>
{
if
(
isError
)
{
if
(
isError
)
{
return
<
DataFetchAlert
/>;
return
<
DataFetchAlert
/>;
}
}
const
hasData
=
data
?.
items
.
length
||
(
pagination
.
page
===
1
&&
marketplaceApps
.
displayedApps
.
length
);
const
hasData
=
data
ToDisplay
.
length
||
(
pagination
.
page
===
1
&&
marketplaceApps
.
displayedApps
.
length
);
if
(
!
hasData
)
{
if
(
!
hasData
)
{
return
null
;
return
null
;
...
@@ -83,7 +95,7 @@ const SearchResultsPageContent = () => {
...
@@ -83,7 +95,7 @@ const SearchResultsPageContent = () => {
searchTerm=
{
debouncedSearchTerm
}
searchTerm=
{
debouncedSearchTerm
}
/>
/>
))
}
))
}
{
data
&&
data
.
items
.
map
((
item
,
index
)
=>
(
{
data
ToDisplay
.
map
((
item
,
index
)
=>
(
<
SearchResultListItem
<
SearchResultListItem
key=
{
(
isPlaceholderData
?
'
placeholder_
'
:
'
actual_
'
)
+
index
}
key=
{
(
isPlaceholderData
?
'
placeholder_
'
:
'
actual_
'
)
+
index
}
data=
{
item
}
data=
{
item
}
...
@@ -110,7 +122,7 @@ const SearchResultsPageContent = () => {
...
@@ -110,7 +122,7 @@ const SearchResultsPageContent = () => {
searchTerm=
{
debouncedSearchTerm
}
searchTerm=
{
debouncedSearchTerm
}
/>
/>
))
}
))
}
{
data
&&
data
.
items
.
map
((
item
,
index
)
=>
(
{
data
ToDisplay
.
map
((
item
,
index
)
=>
(
<
SearchResultTableItem
<
SearchResultTableItem
key=
{
(
isPlaceholderData
?
'
placeholder_
'
:
'
actual_
'
)
+
index
}
key=
{
(
isPlaceholderData
?
'
placeholder_
'
:
'
actual_
'
)
+
index
}
data=
{
item
}
data=
{
item
}
...
@@ -130,7 +142,7 @@ const SearchResultsPageContent = () => {
...
@@ -130,7 +142,7 @@ const SearchResultsPageContent = () => {
return
null
;
return
null
;
}
}
const
resultsCount
=
pagination
.
page
===
1
&&
!
data
?.
next_page_params
?
(
data
?.
items
.
length
||
0
)
+
marketplaceApps
.
displayedApps
.
length
:
'
50+
'
;
const
resultsCount
=
pagination
.
page
===
1
&&
!
data
?.
next_page_params
?
(
data
ToDisplay
.
length
||
0
)
+
marketplaceApps
.
displayedApps
.
length
:
'
50+
'
;
const
text
=
isPlaceholderData
&&
pagination
.
page
===
1
?
(
const
text
=
isPlaceholderData
&&
pagination
.
page
===
1
?
(
<
Skeleton
h=
{
6
}
w=
"280px"
borderRadius=
"full"
mb=
{
pagination
.
isVisible
?
0
:
6
}
/>
<
Skeleton
h=
{
6
}
w=
"280px"
borderRadius=
"full"
mb=
{
pagination
.
isVisible
?
0
:
6
}
/>
...
@@ -141,7 +153,7 @@ const SearchResultsPageContent = () => {
...
@@ -141,7 +153,7 @@ const SearchResultsPageContent = () => {
<
chakra
.
span
fontWeight=
{
700
}
>
<
chakra
.
span
fontWeight=
{
700
}
>
{
resultsCount
}
{
resultsCount
}
</
chakra
.
span
>
</
chakra
.
span
>
<
span
>
matching result
{
(((
data
?.
items
.
length
||
0
)
+
marketplaceApps
.
displayedApps
.
length
)
>
1
)
||
pagination
.
page
>
1
?
'
s
'
:
''
}
for
</
span
>
<
span
>
matching result
{
(((
data
ToDisplay
.
length
||
0
)
+
marketplaceApps
.
displayedApps
.
length
)
>
1
)
||
pagination
.
page
>
1
?
'
s
'
:
''
}
for
</
span
>
“
<
chakra
.
span
fontWeight=
{
700
}
>
{
debouncedSearchTerm
}
</
chakra
.
span
>
”
“
<
chakra
.
span
fontWeight=
{
700
}
>
{
debouncedSearchTerm
}
</
chakra
.
span
>
”
</
Box
>
</
Box
>
)
)
...
...
ui/pages/__screenshots__/SearchResults.pw.tsx_default_search-by-user-op-hash-mobile-1.png
0 → 100644
View file @
336fcf55
25.6 KB
ui/pages/__screenshots__/SearchResults.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
0 → 100644
View file @
336fcf55
21.3 KB
ui/searchResults/SearchResultListItem.tsx
View file @
336fcf55
...
@@ -15,6 +15,7 @@ import * as AddressEntity from 'ui/shared/entities/address/AddressEntity';
...
@@ -15,6 +15,7 @@ import * as AddressEntity from 'ui/shared/entities/address/AddressEntity';
import
*
as
BlockEntity
from
'
ui/shared/entities/block/BlockEntity
'
;
import
*
as
BlockEntity
from
'
ui/shared/entities/block/BlockEntity
'
;
import
*
as
TokenEntity
from
'
ui/shared/entities/token/TokenEntity
'
;
import
*
as
TokenEntity
from
'
ui/shared/entities/token/TokenEntity
'
;
import
*
as
TxEntity
from
'
ui/shared/entities/tx/TxEntity
'
;
import
*
as
TxEntity
from
'
ui/shared/entities/tx/TxEntity
'
;
import
*
as
UserOpEtity
from
'
ui/shared/entities/userOp/UserOpEntity
'
;
import
HashStringShortenDynamic
from
'
ui/shared/HashStringShortenDynamic
'
;
import
HashStringShortenDynamic
from
'
ui/shared/HashStringShortenDynamic
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
...
@@ -56,7 +57,6 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
...
@@ -56,7 +57,6 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
wordBreak=
"break-all"
wordBreak=
"break-all"
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
onClick=
{
handleLinkClick
}
onClick=
{
handleLinkClick
}
flexGrow=
{
1
}
overflow=
"hidden"
overflow=
"hidden"
>
>
<
Skeleton
<
Skeleton
...
@@ -200,6 +200,26 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
...
@@ -200,6 +200,26 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
</
TxEntity
.
Container
>
</
TxEntity
.
Container
>
);
);
}
}
case
'
user_operation
'
:
{
return
(
<
UserOpEtity
.
Container
>
<
UserOpEtity
.
Icon
/>
<
UserOpEtity
.
Link
isLoading=
{
isLoading
}
hash=
{
data
.
user_operation_hash
}
onClick=
{
handleLinkClick
}
>
<
UserOpEtity
.
Content
asProp=
"mark"
hash=
{
data
.
user_operation_hash
}
fontSize=
"sm"
lineHeight=
{
5
}
fontWeight=
{
700
}
/>
</
UserOpEtity
.
Link
>
</
UserOpEtity
.
Container
>
);
}
}
}
})();
})();
...
@@ -240,6 +260,12 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
...
@@ -240,6 +260,12 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
<
Text
variant=
"secondary"
>
{
dayjs
(
data
.
timestamp
).
format
(
'
llll
'
)
}
</
Text
>
<
Text
variant=
"secondary"
>
{
dayjs
(
data
.
timestamp
).
format
(
'
llll
'
)
}
</
Text
>
);
);
}
}
case
'
user_operation
'
:
{
return
(
<
Text
variant=
"secondary"
>
{
dayjs
(
data
.
timestamp
).
format
(
'
llll
'
)
}
</
Text
>
);
}
case
'
label
'
:
{
case
'
label
'
:
{
return
(
return
(
<
Flex
alignItems=
"center"
>
<
Flex
alignItems=
"center"
>
...
@@ -295,12 +321,12 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
...
@@ -295,12 +321,12 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
return
(
return
(
<
ListItemMobile
py=
{
3
}
fontSize=
"sm"
rowGap=
{
2
}
>
<
ListItemMobile
py=
{
3
}
fontSize=
"sm"
rowGap=
{
2
}
>
<
Flex
justifyContent=
"space-between
"
w=
"100%"
overflow=
"hidden"
lineHeight=
{
6
}
>
<
Grid
templateColumns=
"1fr auto
"
w=
"100%"
overflow=
"hidden"
lineHeight=
{
6
}
>
{
firstRow
}
{
firstRow
}
<
Skeleton
isLoaded=
{
!
isLoading
}
color=
"text_secondary"
ml=
{
8
}
textTransform=
"capitalize"
>
<
Skeleton
isLoaded=
{
!
isLoading
}
color=
"text_secondary"
ml=
{
8
}
textTransform=
"capitalize"
>
<
span
>
{
category
?
searchItemTitles
[
category
].
itemTitleShort
:
''
}
</
span
>
<
span
>
{
category
?
searchItemTitles
[
category
].
itemTitleShort
:
''
}
</
span
>
</
Skeleton
>
</
Skeleton
>
</
Flex
>
</
Grid
>
{
Boolean
(
secondRow
)
&&
(
{
Boolean
(
secondRow
)
&&
(
<
Box
w=
"100%"
overflow=
"hidden"
whiteSpace=
{
data
.
type
!==
'
app
'
?
'
nowrap
'
:
undefined
}
>
<
Box
w=
"100%"
overflow=
"hidden"
whiteSpace=
{
data
.
type
!==
'
app
'
?
'
nowrap
'
:
undefined
}
>
{
secondRow
}
{
secondRow
}
...
...
ui/searchResults/SearchResultTableItem.tsx
View file @
336fcf55
...
@@ -15,6 +15,7 @@ import * as AddressEntity from 'ui/shared/entities/address/AddressEntity';
...
@@ -15,6 +15,7 @@ import * as AddressEntity from 'ui/shared/entities/address/AddressEntity';
import
*
as
BlockEntity
from
'
ui/shared/entities/block/BlockEntity
'
;
import
*
as
BlockEntity
from
'
ui/shared/entities/block/BlockEntity
'
;
import
*
as
TokenEntity
from
'
ui/shared/entities/token/TokenEntity
'
;
import
*
as
TokenEntity
from
'
ui/shared/entities/token/TokenEntity
'
;
import
*
as
TxEntity
from
'
ui/shared/entities/tx/TxEntity
'
;
import
*
as
TxEntity
from
'
ui/shared/entities/tx/TxEntity
'
;
import
*
as
UserOpEtity
from
'
ui/shared/entities/userOp/UserOpEntity
'
;
import
HashStringShortenDynamic
from
'
ui/shared/HashStringShortenDynamic
'
;
import
HashStringShortenDynamic
from
'
ui/shared/HashStringShortenDynamic
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
import
LinkExternal
from
'
ui/shared/LinkExternal
'
;
...
@@ -284,6 +285,33 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => {
...
@@ -284,6 +285,33 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => {
</>
</>
);
);
}
}
case
'
user_operation
'
:
{
return
(
<>
<
Td
colSpan=
{
2
}
fontSize=
"sm"
>
<
UserOpEtity
.
Container
>
<
UserOpEtity
.
Icon
/>
<
UserOpEtity
.
Link
isLoading=
{
isLoading
}
hash=
{
data
.
user_operation_hash
}
onClick=
{
handleLinkClick
}
>
<
UserOpEtity
.
Content
asProp=
"mark"
hash=
{
data
.
user_operation_hash
}
fontSize=
"sm"
lineHeight=
{
5
}
fontWeight=
{
700
}
/>
</
UserOpEtity
.
Link
>
</
UserOpEtity
.
Container
>
</
Td
>
<
Td
fontSize=
"sm"
verticalAlign=
"middle"
isNumeric
>
<
Text
variant=
"secondary"
>
{
dayjs
(
data
.
timestamp
).
format
(
'
llll
'
)
}
</
Text
>
</
Td
>
</>
);
}
}
}
})();
})();
...
...
ui/shared/search/utils.ts
View file @
336fcf55
import
type
{
SearchResultItem
}
from
'
types/api/search
'
;
import
type
{
SearchResultItem
}
from
'
types/api/search
'
;
import
type
{
MarketplaceAppOverview
}
from
'
types/client/marketplace
'
;
import
type
{
MarketplaceAppOverview
}
from
'
types/client/marketplace
'
;
export
type
ApiCategory
=
'
token
'
|
'
nft
'
|
'
address
'
|
'
public_tag
'
|
'
transaction
'
|
'
block
'
;
import
config
from
'
configs/app
'
;
export
type
ApiCategory
=
'
token
'
|
'
nft
'
|
'
address
'
|
'
public_tag
'
|
'
transaction
'
|
'
block
'
|
'
user_operation
'
;
export
type
Category
=
ApiCategory
|
'
app
'
;
export
type
Category
=
ApiCategory
|
'
app
'
;
export
type
ItemsCategoriesMap
=
export
type
ItemsCategoriesMap
=
...
@@ -23,6 +25,10 @@ export const searchCategories: Array<{id: Category; title: string }> = [
...
@@ -23,6 +25,10 @@ export const searchCategories: Array<{id: Category; title: string }> = [
{
id
:
'
block
'
,
title
:
'
Blocks
'
},
{
id
:
'
block
'
,
title
:
'
Blocks
'
},
];
];
if
(
config
.
features
.
userOps
.
isEnabled
)
{
searchCategories
.
push
({
id
:
'
user_operation
'
,
title
:
'
User operations
'
});
}
export
const
searchItemTitles
:
Record
<
Category
,
{
itemTitle
:
string
;
itemTitleShort
:
string
}
>
=
{
export
const
searchItemTitles
:
Record
<
Category
,
{
itemTitle
:
string
;
itemTitleShort
:
string
}
>
=
{
app
:
{
itemTitle
:
'
App
'
,
itemTitleShort
:
'
App
'
},
app
:
{
itemTitle
:
'
App
'
,
itemTitleShort
:
'
App
'
},
token
:
{
itemTitle
:
'
Token
'
,
itemTitleShort
:
'
Token
'
},
token
:
{
itemTitle
:
'
Token
'
,
itemTitleShort
:
'
Token
'
},
...
@@ -31,6 +37,7 @@ export const searchItemTitles: Record<Category, { itemTitle: string; itemTitleSh
...
@@ -31,6 +37,7 @@ export const searchItemTitles: Record<Category, { itemTitle: string; itemTitleSh
public_tag
:
{
itemTitle
:
'
Public tag
'
,
itemTitleShort
:
'
Tag
'
},
public_tag
:
{
itemTitle
:
'
Public tag
'
,
itemTitleShort
:
'
Tag
'
},
transaction
:
{
itemTitle
:
'
Transaction
'
,
itemTitleShort
:
'
Txn
'
},
transaction
:
{
itemTitle
:
'
Transaction
'
,
itemTitleShort
:
'
Txn
'
},
block
:
{
itemTitle
:
'
Block
'
,
itemTitleShort
:
'
Block
'
},
block
:
{
itemTitle
:
'
Block
'
,
itemTitleShort
:
'
Block
'
},
user_operation
:
{
itemTitle
:
'
User operation
'
,
itemTitleShort
:
'
User op
'
},
};
};
export
function
getItemCategory
(
item
:
SearchResultItem
|
SearchResultAppItem
):
Category
|
undefined
{
export
function
getItemCategory
(
item
:
SearchResultItem
|
SearchResultAppItem
):
Category
|
undefined
{
...
@@ -57,5 +64,8 @@ export function getItemCategory(item: SearchResultItem | SearchResultAppItem): C
...
@@ -57,5 +64,8 @@ export function getItemCategory(item: SearchResultItem | SearchResultAppItem): C
case
'
app
'
:
{
case
'
app
'
:
{
return
'
app
'
;
return
'
app
'
;
}
}
case
'
user_operation
'
:
{
return
'
user_operation
'
;
}
}
}
}
}
ui/snippets/searchBar/SearchBar.pw.tsx
View file @
336fcf55
...
@@ -9,6 +9,7 @@ import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
...
@@ -9,6 +9,7 @@ import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
import
TestApp
from
'
playwright/TestApp
'
;
import
TestApp
from
'
playwright/TestApp
'
;
import
*
as
app
from
'
playwright/utils/app
'
;
import
*
as
app
from
'
playwright/utils/app
'
;
import
buildApiUrl
from
'
playwright/utils/buildApiUrl
'
;
import
buildApiUrl
from
'
playwright/utils/buildApiUrl
'
;
import
*
as
configs
from
'
playwright/utils/configs
'
;
import
SearchBar
from
'
./SearchBar
'
;
import
SearchBar
from
'
./SearchBar
'
;
...
@@ -204,6 +205,35 @@ test('search by tx hash +@mobile', async({ mount, page }) => {
...
@@ -204,6 +205,35 @@ test('search by tx hash +@mobile', async({ mount, page }) => {
await
expect
(
page
).
toHaveScreenshot
({
clip
:
{
x
:
0
,
y
:
0
,
width
:
1200
,
height
:
300
}
});
await
expect
(
page
).
toHaveScreenshot
({
clip
:
{
x
:
0
,
y
:
0
,
width
:
1200
,
height
:
300
}
});
});
});
const
testWithUserOps
=
base
.
extend
({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context
:
contextWithEnvs
(
configs
.
featureEnvs
.
userOps
)
as
any
,
});
testWithUserOps
(
'
search by user op hash +@mobile
'
,
async
({
mount
,
page
})
=>
{
await
page
.
route
(
'
https://request-global.czilladx.com/serve/native.php?z=19260bf627546ab7242
'
,
(
route
)
=>
route
.
fulfill
({
status
:
200
,
body
:
JSON
.
stringify
(
textAdMock
.
duck
),
}));
const
API_URL
=
buildApiUrl
(
'
quick_search
'
)
+
`?q=
${
searchMock
.
tx1
.
tx_hash
}
`
;
await
page
.
route
(
API_URL
,
(
route
)
=>
route
.
fulfill
({
status
:
200
,
body
:
JSON
.
stringify
([
searchMock
.
userOp1
,
]),
}));
await
mount
(
<
TestApp
>
<
SearchBar
/>
</
TestApp
>,
);
await
page
.
getByPlaceholder
(
/search/i
).
type
(
searchMock
.
tx1
.
tx_hash
);
await
page
.
waitForResponse
(
API_URL
);
await
expect
(
page
).
toHaveScreenshot
({
clip
:
{
x
:
0
,
y
:
0
,
width
:
1200
,
height
:
300
}
});
});
test
(
'
search with view all link
'
,
async
({
mount
,
page
})
=>
{
test
(
'
search with view all link
'
,
async
({
mount
,
page
})
=>
{
const
API_URL
=
buildApiUrl
(
'
quick_search
'
)
+
'
?q=o
'
;
const
API_URL
=
buildApiUrl
(
'
quick_search
'
)
+
'
?q=o
'
;
await
page
.
route
(
API_URL
,
(
route
)
=>
route
.
fulfill
({
await
page
.
route
(
API_URL
,
(
route
)
=>
route
.
fulfill
({
...
...
ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggest.tsx
View file @
336fcf55
...
@@ -111,12 +111,12 @@ const SearchBarSuggest = ({ query, searchTerm, onItemClick, containerId }: Props
...
@@ -111,12 +111,12 @@ const SearchBarSuggest = ({ query, searchTerm, onItemClick, containerId }: Props
return
<
Text
>
Something went wrong. Try refreshing the page or come back later.
</
Text
>;
return
<
Text
>
Something went wrong. Try refreshing the page or come back later.
</
Text
>;
}
}
if
(
!
query
.
data
||
query
.
data
.
length
===
0
)
{
const
resultCategories
=
searchCategories
.
filter
(
cat
=>
itemsGroups
[
cat
.
id
]);
if
(
resultCategories
.
length
===
0
)
{
return
<
Text
>
No results found.
</
Text
>;
return
<
Text
>
No results found.
</
Text
>;
}
}
const
resultCategories
=
searchCategories
.
filter
(
cat
=>
itemsGroups
[
cat
.
id
]);
return
(
return
(
<>
<>
{
resultCategories
.
length
>
1
&&
(
{
resultCategories
.
length
>
1
&&
(
...
...
ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggestItem.tsx
View file @
336fcf55
...
@@ -12,6 +12,7 @@ import SearchBarSuggestItemLink from './SearchBarSuggestItemLink';
...
@@ -12,6 +12,7 @@ import SearchBarSuggestItemLink from './SearchBarSuggestItemLink';
import
SearchBarSuggestLabel
from
'
./SearchBarSuggestLabel
'
;
import
SearchBarSuggestLabel
from
'
./SearchBarSuggestLabel
'
;
import
SearchBarSuggestToken
from
'
./SearchBarSuggestToken
'
;
import
SearchBarSuggestToken
from
'
./SearchBarSuggestToken
'
;
import
SearchBarSuggestTx
from
'
./SearchBarSuggestTx
'
;
import
SearchBarSuggestTx
from
'
./SearchBarSuggestTx
'
;
import
SearchBarSuggestUserOp
from
'
./SearchBarSuggestUserOp
'
;
interface
Props
{
interface
Props
{
data
:
SearchResultItem
;
data
:
SearchResultItem
;
...
@@ -38,6 +39,9 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
...
@@ -38,6 +39,9 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
case
'
block
'
:
{
case
'
block
'
:
{
return
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
String
(
data
.
block_hash
)
}
});
return
route
({
pathname
:
'
/block/[height_or_hash]
'
,
query
:
{
height_or_hash
:
String
(
data
.
block_hash
)
}
});
}
}
case
'
user_operation
'
:
{
return
route
({
pathname
:
'
/op/[hash]
'
,
query
:
{
hash
:
data
.
user_operation_hash
}
});
}
}
}
})();
})();
...
@@ -60,6 +64,9 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
...
@@ -60,6 +64,9 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
case
'
transaction
'
:
{
case
'
transaction
'
:
{
return
<
SearchBarSuggestTx
data=
{
data
}
searchTerm=
{
searchTerm
}
isMobile=
{
isMobile
}
/>;
return
<
SearchBarSuggestTx
data=
{
data
}
searchTerm=
{
searchTerm
}
isMobile=
{
isMobile
}
/>;
}
}
case
'
user_operation
'
:
{
return
<
SearchBarSuggestUserOp
data=
{
data
}
searchTerm=
{
searchTerm
}
isMobile=
{
isMobile
}
/>;
}
}
}
})();
})();
...
...
ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggestUserOp.tsx
0 → 100644
View file @
336fcf55
import
{
chakra
,
Text
,
Flex
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
type
{
SearchResultUserOp
}
from
'
types/api/search
'
;
import
dayjs
from
'
lib/date/dayjs
'
;
import
*
as
UserOpEntity
from
'
ui/shared/entities/userOp/UserOpEntity
'
;
import
HashStringShortenDynamic
from
'
ui/shared/HashStringShortenDynamic
'
;
interface
Props
{
data
:
SearchResultUserOp
;
isMobile
:
boolean
|
undefined
;
searchTerm
:
string
;
}
const
SearchBarSuggestTx
=
({
data
,
isMobile
}:
Props
)
=>
{
const
icon
=
<
UserOpEntity
.
Icon
/>;
const
hash
=
(
<
chakra
.
mark
overflow=
"hidden"
whiteSpace=
"nowrap"
fontWeight=
{
700
}
>
<
HashStringShortenDynamic
hash=
{
data
.
user_operation_hash
}
isTooltipDisabled
/>
</
chakra
.
mark
>
);
const
date
=
dayjs
(
data
.
timestamp
).
format
(
'
llll
'
);
if
(
isMobile
)
{
return
(
<>
<
Flex
alignItems=
"center"
>
{
icon
}
{
hash
}
</
Flex
>
<
Text
variant=
"secondary"
>
{
date
}
</
Text
>
</>
);
}
return
(
<
Flex
columnGap=
{
2
}
>
<
Flex
alignItems=
"center"
minW=
{
0
}
>
{
icon
}
{
hash
}
</
Flex
>
<
Text
variant=
"secondary"
textAlign=
"end"
flexShrink=
{
0
}
ml=
"auto"
>
{
date
}
</
Text
>
</
Flex
>
);
};
export
default
React
.
memo
(
SearchBarSuggestTx
);
ui/snippets/searchBar/__screenshots__/SearchBar.pw.tsx_default_search-by-user-op-hash-mobile-1.png
0 → 100644
View file @
336fcf55
27.4 KB
ui/snippets/searchBar/__screenshots__/SearchBar.pw.tsx_mobile_search-by-user-op-hash-mobile-1.png
0 → 100644
View file @
336fcf55
16.6 KB
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment