@@ -2,6 +2,12 @@ import "./App.css";
22import { IDBCache } from "@instructure/idb-cache" ;
33import { useCallback , useEffect , useState } from "react" ;
44import { uuid , deterministicHash , generateTextOfSize } from "./utils" ;
5+ import { Button } from "@instructure/ui-buttons" ;
6+ import { MetricGroup , Metric } from "@instructure/ui-metric" ;
7+ import { View } from "@instructure/ui-view" ;
8+ import { Flex } from "@instructure/ui-flex" ;
9+ import { Heading } from "@instructure/ui-heading" ;
10+ import { NumberInput } from "@instructure/ui-number-input" ;
511
612// For demonstration/testing purposes.
713// Do *not* store cacheKey to localStorage in production.
@@ -25,11 +31,6 @@ const cache = new IDBCache({
2531
2632const DEFAULT_NUM_ITEMS = 1 ;
2733
28- const initialNumItems =
29- Number . parseInt (
30- localStorage . getItem ( "numItems" ) || String ( DEFAULT_NUM_ITEMS ) ,
31- ) || DEFAULT_NUM_ITEMS ;
32-
3334const DEFAULT_ITEM_SIZE = 10240 ;
3435
3536const initialItemSize =
@@ -42,22 +43,21 @@ const App = () => {
4243 const [ hash2 , setHash2 ] = useState < string | null > ( null ) ;
4344 const [ setTime , setSetTime ] = useState < number | null > ( null ) ;
4445 const [ getTime , setGetTime ] = useState < number | null > ( null ) ;
45- const [ numItems , setNumItems ] = useState < number > ( initialNumItems ) ;
4646 const [ itemSize , setItemSize ] = useState < number > ( initialItemSize ) ;
4747 const [ isEncrypting , setIsEncrypting ] = useState < boolean > ( false ) ;
4848 const [ isDecrypting , setIsDecrypting ] = useState < boolean > ( false ) ;
4949
5050 const encryptAndStore = useCallback ( async ( ) => {
5151 console . time ( "generating content" ) ;
5252 setIsEncrypting ( true ) ;
53- const paragraphs = Array . from ( { length : numItems } , ( _ , index ) =>
53+ const paragraphs = Array . from ( { length : DEFAULT_NUM_ITEMS } , ( _ , index ) =>
5454 generateTextOfSize ( itemSize , `${ cacheBuster } -${ index } ` ) ,
5555 ) ;
5656 console . timeEnd ( "generating content" ) ;
5757
5858 const start = performance . now ( ) ;
5959
60- for ( let i = 0 ; i < numItems ; i ++ ) {
60+ for ( let i = 0 ; i < DEFAULT_NUM_ITEMS ; i ++ ) {
6161 await cache . setItem ( `item-${ i } ` , paragraphs [ i ] ) ;
6262 }
6363
@@ -66,14 +66,14 @@ const App = () => {
6666
6767 setHash1 ( deterministicHash ( paragraphs . join ( "" ) ) ) ;
6868 setIsEncrypting ( false ) ;
69- } , [ numItems , itemSize ] ) ;
69+ } , [ itemSize ] ) ;
7070
7171 const retrieveAndDecrypt = useCallback ( async ( ) => {
7272 setIsDecrypting ( true ) ;
7373 const results : Array < string | null > = [ ] ;
7474 const start = performance . now ( ) ;
7575
76- for ( let i = 0 ; i < numItems ; i ++ ) {
76+ for ( let i = 0 ; i < DEFAULT_NUM_ITEMS ; i ++ ) {
7777 const result = await cache . getItem ( `item-${ i } ` ) ;
7878 results . push ( result ) ;
7979 }
@@ -82,7 +82,7 @@ const App = () => {
8282 setGetTime ( end - start ) ;
8383 setHash2 ( results . length > 0 ? deterministicHash ( results . join ( "" ) ) : null ) ;
8484 setIsDecrypting ( false ) ;
85- } , [ numItems ] ) ;
85+ } , [ ] ) ;
8686
8787 // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
8888 useEffect ( ( ) => {
@@ -135,9 +135,9 @@ const App = () => {
135135
136136 < div className = "min-h-screen bg-gray-50 p-8" >
137137 < div className = "max-w-4xl mx-auto p-6 bg-white shadow-md rounded-lg" >
138- < h1 className = "text-4xl font-bold text-center text-primary mb-6 ">
138+ < Heading level = "h1" margin = "0 0 small 0 ">
139139 @instructure/idb-cache
140- </ h1 >
140+ </ Heading >
141141
142142 < form >
143143 < fieldset className = "border border-gray-300 rounded-lg p-4 mb-6" >
@@ -149,32 +149,27 @@ const App = () => {
149149 < span >
150150 Cache key: < code className = "text-sm" > { cacheKey } </ code >
151151 </ span >
152- < button
153- type = "button"
154- className = "btn btn-sm"
152+ < Button
155153 onClick = { ( ) => {
156154 localStorage . removeItem ( "cacheKey" ) ;
157155 window . location . reload ( ) ;
158156 } }
159157 >
160158 Reset
161- </ button >
159+ </ Button >
162160 </ div >
163161 < div className = "flex items-center justify-between" >
164162 < span >
165- Cache buster (salt):{ " " }
166- < code className = "text-sm" > { cacheBuster } </ code >
163+ Cache buster: < code className = "text-sm" > { cacheBuster } </ code >
167164 </ span >
168- < button
169- type = "button"
170- className = "btn btn-sm"
165+ < Button
171166 onClick = { ( ) => {
172167 localStorage . removeItem ( "cacheBuster" ) ;
173168 window . location . reload ( ) ;
174169 } }
175170 >
176171 Reset
177- </ button >
172+ </ Button >
178173 </ div >
179174 </ div >
180175 </ fieldset >
@@ -184,139 +179,109 @@ const App = () => {
184179 Performance Test
185180 </ legend >
186181 < div className = "flex flex-col gap-4" >
187- < div className = "form-control" >
188- < label className = "label" >
189- < span className = "label-text font-medium" >
190- Size of each item (kb):
191- </ span >
192- < input
193- // biome-ignore lint/a11y/noAutofocus: <explanation>
194- autoFocus = { true }
195- className = "input input-bordered w-full max-w-xs"
196- type = "number"
197- value = { Math . round ( itemSize / 1024 ) }
182+ < Flex gap = "medium" >
183+ < Flex . Item shouldGrow >
184+ < NumberInput
185+ renderLabel = "Size of data (kb):"
198186 onChange = { ( e ) => {
199- setItemSize ( Number ( e . target . value ) * 1024 ) ;
200- localStorage . setItem (
201- "itemSize" ,
202- String ( Number . parseInt ( e . target . value ) * 1024 ) ,
187+ const newValue = Math . max (
188+ Number . parseInt ( e . target . value ) * 1024 ,
189+ 1024 ,
203190 ) ;
191+ setItemSize ( newValue ) ;
192+ localStorage . setItem ( "itemSize" , String ( newValue ) ) ;
204193 } }
205- />
206- </ label >
207- </ div >
208-
209- < div className = "form-control" >
210- < label className = "label" >
211- < span className = "label-text font-medium" >
212- Number of items:
213- </ span >
214- < input
215- className = "input input-bordered w-full max-w-xs"
216- type = "number"
217- value = { numItems }
218- onChange = { ( e ) => {
219- setNumItems ( Number ( e . target . value ) ) ;
220- localStorage . setItem ( "numItems" , e . target . value ) ;
194+ onIncrement = { ( ) => {
195+ const newValue = Math . max (
196+ Math . round ( itemSize ) + 1 * 1024 ,
197+ 1024 ,
198+ ) ;
199+ setItemSize ( newValue ) ;
200+ localStorage . setItem ( "itemSize" , String ( newValue ) ) ;
221201 } }
222- />
223- </ label >
224- </ div >
225-
226- < div className = "flex flex-col gap-4" >
227- < button
228- className = "btn btn-primary"
229- type = "button"
230- onClick = { encryptAndStore }
231- >
232- Encrypt and store
233- < span
234- className = "loading loading-spinner"
235- style = { {
236- visibility : ! isEncrypting ? "hidden" : "visible" ,
202+ onDecrement = { ( ) => {
203+ const newValue = Math . max (
204+ Math . round ( itemSize ) - 1 * 1024 ,
205+ 1024 ,
206+ ) ;
207+ setItemSize ( newValue ) ;
208+ localStorage . setItem ( "itemSize" , String ( newValue ) ) ;
237209 } }
210+ isRequired
211+ value = { Math . round ( itemSize / 1024 ) }
238212 />
239- </ button >
240- < div className = "stats shadow" >
241- < div
242- className = "stat place-items-center"
243- style = { {
244- visibility : hash1 ? "visible" : "hidden" ,
245- } }
246- >
247- < >
248- < div className = "stat-title" > Took</ div >
249- < div className = "stat-value" >
250- { setTime !== null
251- ? `${ Math . round ( setTime ) } ms`
252- : "N/A" }
253- </ div >
254- < div className = "stat-desc" > to encrypt and store</ div >
255- </ >
256- </ div >
257-
258- < div
259- className = "stat place-items-center"
260- style = { {
261- visibility : hash1 ? "visible" : "hidden" ,
262- } }
263- >
264- < >
265- < div className = "stat-title" > Hash</ div >
266- < div className = "stat-value" > { hash1 } </ div >
267- < div className = "stat-desc" > of data</ div >
268- </ >
269- </ div >
270- </ div >
271- </ div >
272-
273- < div className = "flex flex-col gap-4" >
274- < button
275- className = "btn btn-secondary"
276- type = "button"
277- onClick = { retrieveAndDecrypt }
278- >
279- Retrieve and decrypt
280- < span
281- className = "loading loading-spinner"
282- style = { {
283- visibility : ! isDecrypting ? "hidden" : "visible" ,
284- } }
213+ </ Flex . Item >
214+ < Flex . Item shouldGrow >
215+ < NumberInput
216+ renderLabel = "Number of chunks:"
217+ interaction = "disabled"
218+ value = { Math . ceil ( itemSize / 25000 ) }
285219 />
286- </ button >
220+ </ Flex . Item >
221+ </ Flex >
287222
288- < div className = "stats shadow" >
289- < div
290- className = "stat place-items-center"
291- style = { {
292- visibility : hash2 ? "visible" : "hidden" ,
293- } }
294- >
295- < >
296- < div className = "stat-title" > Took</ div >
297- < div className = "stat-value" >
298- { getTime !== null
299- ? `${ Math . round ( getTime ) } ms`
300- : "error" }
301- </ div >
302- < div className = "stat-desc" > to retrieve and decrypt</ div >
303- </ >
304- </ div >
223+ < View
224+ as = "span"
225+ display = "inline-block"
226+ margin = "none"
227+ padding = "medium"
228+ background = "primary"
229+ shadow = "resting"
230+ >
231+ < Flex direction = "column" >
232+ < Button color = "primary" onClick = { encryptAndStore } >
233+ Encrypt and store
234+ </ Button >
235+ < View padding = "medium 0 0 0" >
236+ < MetricGroup >
237+ < Metric
238+ renderLabel = "to encrypt and store"
239+ renderValue = {
240+ setTime !== null
241+ ? `${ Math . round ( setTime ) } ms`
242+ : "N/A"
243+ }
244+ />
245+ < Metric
246+ renderLabel = "hash of data"
247+ renderValue = { hash1 }
248+ />
249+ </ MetricGroup >
250+ </ View >
251+ </ Flex >
252+ </ View >
305253
306- < div
307- className = "stat place-items-center"
308- style = { {
309- visibility : hash2 ? "visible" : "hidden" ,
310- } }
311- >
312- < >
313- < div className = "stat-title" > Hash</ div >
314- < div className = "stat-value" > { hash2 } </ div >
315- < div className = "stat-desc" > of data</ div >
316- </ >
317- </ div >
318- </ div >
319- </ div >
254+ < View
255+ as = "span"
256+ display = "inline-block"
257+ margin = "none"
258+ padding = "medium"
259+ background = "primary"
260+ shadow = "resting"
261+ >
262+ < Flex direction = "column" >
263+ < Button color = "primary" onClick = { retrieveAndDecrypt } >
264+ Retrieve and decrypt
265+ </ Button >
266+
267+ < View padding = "medium 0 0 0" >
268+ < MetricGroup >
269+ < Metric
270+ renderLabel = "to retrieve and decrypt"
271+ renderValue = {
272+ getTime !== null
273+ ? `${ Math . round ( getTime ) } ms`
274+ : "error"
275+ }
276+ />
277+ < Metric
278+ renderLabel = "hash of data"
279+ renderValue = { hash2 }
280+ />
281+ </ MetricGroup >
282+ </ View >
283+ </ Flex >
284+ </ View >
320285 </ div >
321286 </ fieldset >
322287 </ form >
0 commit comments