Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
B
Block Explorer UI
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
hive
Block Explorer UI
Commits
29de93cb
Commit
29de93cb
authored
1 month ago
by
Lukas
Committed by
mcfarhat
1 month ago
Browse files
Options
Downloads
Patches
Plain Diff
Update SearchRanges component
parent
caea956b
No related branches found
No related tags found
1 merge request
!596
Update SearchRanges component
Pipeline
#118748
canceled
1 month ago
Stage: build
Stage: test
Stage: test-report-aggregate
Stage: cleanup
Changes
1
Pipelines
3
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
components/searchRanges/SearchRanges.tsx
+136
-122
136 additions, 122 deletions
components/searchRanges/SearchRanges.tsx
with
136 additions
and
122 deletions
components/searchRanges/SearchRanges.tsx
+
136
−
122
View file @
29de93cb
import
React
,
{
use
Effect
,
useState
}
from
"
react
"
;
import
React
,
{
use
State
,
useEffect
}
from
"
react
"
;
import
moment
from
"
moment
"
;
import
{
SearchRangesResult
}
from
"
../../hooks/common/useSearchRanges
"
;
import
{
Select
,
SelectContent
,
SelectTrigger
,
SelectItem
}
from
"
../ui/select
"
;
import
{
Input
}
from
"
../ui/input
"
;
import
DateTimePicker
from
"
../DateTimePicker
"
;
import
ErrorMessage
from
"
../ErrorMessage
"
;
// Import the ErrorMessage component
import
ErrorMessage
from
"
../ErrorMessage
"
;
interface
SearchRangesProps
{
rangesProps
:
SearchRangesResult
;
safeTimeRangeDisplay
?:
boolean
;
}
const
SearchRanges
:
React
.
FC
<
SearchRangesProps
>
=
({
rangesProps
,
safeTimeRangeDisplay
,
})
=>
{
const
SearchRanges
:
React
.
FC
<
SearchRangesProps
>
=
({
rangesProps
})
=>
{
const
{
rangeSelectOptions
,
timeSelectOptions
,
...
...
@@ -38,79 +35,100 @@ const SearchRanges: React.FC<SearchRangesProps> = ({
const
[
rangeError
,
setRangeError
]
=
useState
<
string
|
null
>
(
null
);
const
handleOnBlur
=
(
e
:
React
.
FocusEvent
<
HTMLInputElement
>
,
fieldSetter
:
Function
,
validateField
:
Function
|
null
)
=>
{
const
value
=
e
.
target
.
value
;
const
numericValue
=
value
?
Number
(
value
)
:
undefined
;
const
[
localLastBlocks
,
setLocalLastBlocks
]
=
useState
(
lastBlocksValue
!==
undefined
?
String
(
lastBlocksValue
)
:
""
);
const
[
localLastTimeUnit
,
setLocalLastTimeUnit
]
=
useState
(
lastTimeUnitValue
!==
undefined
?
String
(
lastTimeUnitValue
)
:
""
);
const
[
localFromBlock
,
setLocalFromBlock
]
=
useState
(
fromBlock
!==
undefined
?
String
(
fromBlock
)
:
""
);
const
[
localToBlock
,
setLocalToBlock
]
=
useState
(
toBlock
!==
undefined
?
String
(
toBlock
)
:
""
);
// Fetch the latest block number dynamically
let
validated
=
true
;
if
(
validateField
)
{
validated
=
validateField
(
e
,
numericValue
);
useEffect
(()
=>
{
setLocalLastBlocks
(
lastBlocksValue
!==
undefined
?
String
(
lastBlocksValue
)
:
""
);
setLocalLastTimeUnit
(
lastTimeUnitValue
!==
undefined
?
String
(
lastTimeUnitValue
)
:
""
);
setLocalFromBlock
(
fromBlock
!==
undefined
?
String
(
fromBlock
)
:
""
);
setLocalToBlock
(
toBlock
!==
undefined
?
String
(
toBlock
)
:
""
);
},
[
lastBlocksValue
,
lastTimeUnitValue
,
fromBlock
,
toBlock
]);
const
sanitizeNumericInput
=
(
value
:
string
,
allowDecimal
=
false
)
=>
{
let
cleaned
=
allowDecimal
?
value
.
replace
(
/
[^
0-9.
]
/g
,
""
)
:
value
.
replace
(
/
[^
0-9
]
/g
,
""
);
if
(
allowDecimal
&&
cleaned
.
split
(
"
.
"
).
length
>
2
)
{
const
parts
=
cleaned
.
split
(
"
.
"
);
cleaned
=
parts
.
shift
()
+
"
.
"
+
parts
.
join
(
""
);
}
validated
?
fieldSetter
(
numericValue
)
:
fieldSetter
(
null
);
if
(
cleaned
.
length
>
15
)
{
cleaned
=
cleaned
.
slice
(
0
,
15
);
}
return
cleaned
;
};
const
validateToBlock
=
(
e
:
React
.
FocusEvent
<
HTMLInputElement
>
,
value
:
number
|
undefined
)
=>
{
if
(
value
!==
undefined
&&
value
<=
0
)
{
const
validateFromBlock
=
(
numVal
:
number
|
undefined
)
=>
{
if
(
numVal
!==
undefined
&&
numVal
<=
0
)
{
setRangeError
(
"
Block Number must be a positive number
"
);
e
.
target
.
value
=
""
;
return
false
;
}
if
(
value
&&
fromBlock
&&
!
isNaN
(
value
)
&&
value
<
fromBlock
)
{
setRangeError
(
"
To block must be greater than From block
"
);
e
.
target
.
value
=
""
;
if
(
numVal
&&
toBlock
&&
!
isNaN
(
numVal
)
&&
numVal
>
toBlock
)
{
setRangeError
(
"
From block must be less than To block
"
);
return
false
;
}
return
true
;
};
const
validateFromBlock
=
(
e
:
React
.
FocusEvent
<
HTMLInputElement
>
,
value
:
number
|
undefined
)
=>
{
if
(
value
!==
undefined
&&
value
<=
0
)
{
const
validateToBlock
=
(
numVal
:
number
|
undefined
)
=>
{
if
(
numVal
!==
undefined
&&
numVal
<=
0
)
{
setRangeError
(
"
Block Number must be a positive number
"
);
e
.
target
.
value
=
""
;
return
false
;
}
if
(
value
&&
toBlock
&&
!
isNaN
(
value
)
&&
value
>
toBlock
)
{
setRangeError
(
"
From block must be less than To block
"
);
e
.
target
.
value
=
""
;
if
(
numVal
&&
fromBlock
&&
!
isNaN
(
numVal
)
&&
numVal
<
fromBlock
)
{
setRangeError
(
"
To block must be greater than From block
"
);
return
false
;
}
return
true
;
};
const
handle
NumericInput
=
(
e
:
React
.
ChangeEvent
<
HTMLInputElement
>
,
allowDecimal
:
boolean
=
false
)
=>
{
let
cleanedValue
=
e
.
target
.
value
;
const
handle
LastBlocksBlur
=
()
=>
{
const
val
=
localLastBlocks
?
Number
(
localLastBlocks
)
:
undefined
;
setLastBlocksValue
(
val
);
setRangeError
(
null
);
}
;
// Clean the value based on the logic
cleanedValue
=
allowDecimal
?
cleanedValue
.
replace
(
/
[^
0-9.
]
/g
,
""
)
// Allow numbers and decimal point
:
cleanedValue
.
replace
(
/
[^
0-9
]
/g
,
""
);
// Only allow numbers
const
handleLastTimeUnitBlur
=
()
=>
{
const
val
=
localLastTimeUnit
?
Number
(
localLastTimeUnit
)
:
undefined
;
setLastTimeUnitValue
(
val
);
setRangeError
(
null
);
};
if
(
allowDecimal
&&
cleanedValue
.
split
(
"
.
"
).
length
>
2
)
{
cleanedValue
=
cleanedValue
.
slice
(
0
,
cleanedValue
.
indexOf
(
"
.
"
)
+
1
)
+
cleanedValue
.
split
(
"
.
"
).
slice
(
1
).
join
(
""
);
// Remove extra decimals
const
handleFromBlockBlur
=
()
=>
{
const
val
=
localFromBlock
?
Number
(
localFromBlock
)
:
undefined
;
if
(
!
validateFromBlock
(
val
))
{
setFromBlock
(
undefined
);
return
;
}
setFromBlock
(
val
);
setRangeError
(
null
);
};
if
(
cleanedValue
.
length
>
15
)
{
cleanedValue
=
cleanedValue
.
slice
(
0
,
15
);
// Limit to 15 digits
const
handleToBlockBlur
=
()
=>
{
const
val
=
localToBlock
?
Number
(
localToBlock
)
:
undefined
;
if
(
!
validateToBlock
(
val
))
{
setToBlock
(
undefined
);
return
;
}
e
.
target
.
value
=
cleanedValue
;
setToBlock
(
val
);
setRangeError
(
null
)
;
};
useEffect
(()
=>
{
...
...
@@ -130,22 +148,17 @@ const SearchRanges: React.FC<SearchRangesProps> = ({
value
=
{
rangeSelectKey
}
>
<
SelectTrigger
className
=
"w-1/2 border-0 border-b-2 bg-theme text-text"
>
{
rangeSelectOptions
.
find
(
(
selectOption
)
=>
selectOption
.
key
===
rangeSelectKey
)?.
name
}
{
rangeSelectOptions
.
find
((
opt
)
=>
opt
.
key
===
rangeSelectKey
)?.
name
}
</
SelectTrigger
>
<
SelectContent
className
=
"bg-theme text-text rounded-sm max-h-[31rem]"
>
{
rangeSelectOptions
.
map
((
selectO
ption
,
i
nde
x
)
=>
(
{
rangeSelectOptions
.
map
((
o
ption
,
i
d
x
)
=>
(
<
SelectItem
className
=
"text-center"
key
=
{
index
}
value
=
{
selectOption
.
key
}
defaultChecked
=
{
false
}
key
=
{
idx
}
value
=
{
option
.
key
}
data-testid
=
"search-select-option"
>
{
selectO
ption
.
name
}
{
o
ption
.
name
}
</
SelectItem
>
))
}
</
SelectContent
>
...
...
@@ -153,90 +166,91 @@ const SearchRanges: React.FC<SearchRangesProps> = ({
{
rangeSelectKey
===
"
lastBlocks
"
&&
(
<
div
className
=
"flex items-center"
>
<
div
className
=
"flex flex-col w-full"
>
<
Input
className
=
"w-1/2 border-0 border-b-2 bg-theme
"
type
=
"text"
// Use type="text" to allow custom validation
defaultValue
=
{
lastBlocksValue
||
""
}
onChange
=
{
(
e
)
=>
handleNumericInput
(
e
)
}
onBlur
=
{
(
e
)
=>
handleOnBlur
(
e
,
setLastBlocksValue
,
null
)
}
placeholder
=
{
"
Last
"
}
/>
</
div
>
<
Input
className
=
"w-1/2 border-0 border-b-2 bg-theme"
type
=
"text
"
value
=
{
localLastBlocks
}
onChange
=
{
(
e
)
=>
setLocalLastBlocks
(
sanitizeNumericInput
(
e
.
target
.
value
))
}
onBlur
=
{
handleLastBlocksBlur
}
placeholder
=
"Last"
/
>
</
div
>
)
}
{
rangeSelectKey
===
"
lastTime
"
&&
(
<>
<
div
className
=
"flex items-center justify-center"
>
<
div
className
=
"flex flex-col w-full mr-2"
>
<
Input
type
=
"text"
className
=
"bg-theme border-0 border-b-2 text-text"
defaultValue
=
{
lastTimeUnitValue
||
""
}
onChange
=
{
(
e
)
=>
handleNumericInput
(
e
,
true
)
}
onBlur
=
{
(
e
)
=>
handleOnBlur
(
e
,
setLastTimeUnitValue
,
null
)
}
placeholder
=
{
"
Last
"
}
/>
</
div
>
<
Select
onValueChange
=
{
setTimeUnitSelectKey
}
>
<
SelectTrigger
className
=
"pl-2 bg-theme border-0 border-b-2 text-text"
>
{
timeSelectOptions
.
find
(
(
selectOption
)
=>
selectOption
.
key
===
timeUnitSelectKey
)?.
name
}
</
SelectTrigger
>
<
SelectContent
className
=
"bg-theme text-text rounded-sm max-h-[31rem]"
data-testid
=
"select-time-option-units"
>
{
timeSelectOptions
.
map
((
selectOption
,
index
)
=>
(
<
SelectItem
className
=
"text-center"
key
=
{
index
}
value
=
{
selectOption
.
key
}
defaultChecked
=
{
false
}
>
{
selectOption
.
name
}
</
SelectItem
>
))
}
</
SelectContent
>
</
Select
>
</
div
>
</>
<
div
className
=
"flex items-center justify-center"
>
<
Input
type
=
"text"
className
=
"bg-theme border-0 border-b-2 text-text mr-2"
value
=
{
localLastTimeUnit
}
onChange
=
{
(
e
)
=>
setLocalLastTimeUnit
(
sanitizeNumericInput
(
e
.
target
.
value
,
true
))
}
onBlur
=
{
handleLastTimeUnitBlur
}
placeholder
=
"Last"
/>
<
Select
onValueChange
=
{
setTimeUnitSelectKey
}
value
=
{
timeUnitSelectKey
}
>
<
SelectTrigger
className
=
"pl-2 bg-theme border-0 border-b-2 text-text"
>
{
timeSelectOptions
.
find
((
opt
)
=>
opt
.
key
===
timeUnitSelectKey
)
?.
name
}
</
SelectTrigger
>
<
SelectContent
className
=
"bg-theme text-text rounded-sm max-h-[31rem]"
>
{
timeSelectOptions
.
map
((
option
,
index
)
=>
(
<
SelectItem
className
=
"text-center"
key
=
{
index
}
value
=
{
option
.
key
}
>
{
option
.
name
}
</
SelectItem
>
))
}
</
SelectContent
>
</
Select
>
</
div
>
)
}
{
rangeSelectKey
===
"
blockRange
"
&&
(
<
div
className
=
"flex items-center"
>
<
div
className
=
"
flex flex-col
w-full
mr-2
"
>
<
div
className
=
"
mr-2
w-full"
>
<
Input
type
=
"text"
className
=
"bg-theme border-0 border-b-2"
data-testid
=
"from-block-input"
defaultValue
=
{
fromBlock
||
""
}
onChange
=
{
(
e
)
=>
handleNumericInput
(
e
)
}
onBlur
=
{
(
e
)
=>
handleOnBlur
(
e
,
setFromBlock
,
validateFromBlock
)
}
value
=
{
localFromBlock
}
onChange
=
{
(
e
)
=>
setLocalFromBlock
(
sanitizeNumericInput
(
e
.
target
.
value
))
}
onBlur
=
{
handleFromBlockBlur
}
placeholder
=
"From"
/>
</
div
>
<
div
className
=
"
flex flex-col
w-full"
>
<
div
className
=
"w-full"
>
<
Input
className
=
"bg-theme border-0 border-b-2"
data-testid
=
"headblock-number"
type
=
"text"
defaultValue
=
{
toBlock
||
""
}
onChange
=
{
(
e
)
=>
handleNumericInput
(
e
)
}
placeholder
=
{
"
To
"
}
onBlur
=
{
(
e
)
=>
handleOnBlur
(
e
,
setToBlock
,
validateToBlock
)
}
value
=
{
localToBlock
}
onChange
=
{
(
e
)
=>
setLocalToBlock
(
sanitizeNumericInput
(
e
.
target
.
value
))
}
onBlur
=
{
handleToBlockBlur
}
placeholder
=
"To"
/>
</
div
>
</
div
>
)
}
{
rangeError
&&
(
<
ErrorMessage
message
=
{
rangeError
}
onClose
=
{
()
=>
setRangeError
(
null
)
}
// Close the error message
onClose
=
{
()
=>
setRangeError
(
null
)
}
timeout
=
{
3000
}
/>
)
}
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment