-
[[typescript]] inception
-
(hidden) 9cnkbc5sc
-
(hidden) M9xrYY-wo
-
(hidden) _KBYPG4gm
-
(hidden) Xdv4jiIGm [[(hidden) H-HInK4E-]]
-
(hidden) eslUj53Tl
-
{{[[TODO]]}} (hidden) 2HHs8KPoA [[(hidden) GzyI03FPg]] [[(hidden) pF-VFeRl_]] [[(hidden) oUmT1dIUU]] [[(hidden) BkxomfDAp]] [[(hidden) DZVAlCLaC]] [[(hidden) IrbpL6uu8]] [[(hidden) xYWARPDlP]] #[[(hidden) -VnoIOF8r]] #bs [[bs]]
-
(hidden) j3iOm0Q7x
-
(hidden) N7d1xkmpV
-
(hidden) 2218q1sAz
-
(hidden) kn6KSowPt #[[(hidden) S-ygYfi0j]] [[(hidden) kxThyjKBd]]
-
(hidden) x19vp4bx3 [[(hidden) PfDdFd_oy]]
-
(hidden) 6eC9hdFGM
-
(hidden) mcHYUaZEk [[(hidden) Ib9bzxQxj]]
-
{{[[TODO]]}} (hidden) 1oN3j_Q4G [[(hidden) UbrBiwJcK]] #[[(hidden) PYUJdtq2R]] [[(hidden) 9HOnq7xIc]]
-
(hidden) tUBrTs-s9
-
{{[[TODO]]}} (hidden) gUtkM06u3 [[(hidden) UbrBiwJcK]]
-
(hidden) gXuFPOOUJ [[react libs]]
-
(hidden) mIKhBQri0
-
#public
-
[[react]] [[state-machine]] [[xstate]] [[redux]]
-
[[refactor]]ing from multiple useState calls to a single [[(hidden) -bbeywaKL]] [[example]]
-
https://stately.ai/blog/redux-is-half-of-a-pattern-12
-
```patch From 0950207cf20e4fb94ba7ebb97ef278d9adbf7b79 Mon Sep 17 00:00:00 2001 From: Kipras Melnikovas <kipras@kipras.org> Date: Fri, 29 Jul 2022 00:42:25 +0300 Subject: [PATCH] refactor FileUpload logic - avoid impossible states (& make code much cleaner) classic. i notice that we have `uploadState` JSX, which has content if `uploadError &&` _and_ `loading &&`, meaning it's possible to achieve an "impossible state", when both `uploadError` and `loading` are `true`. one could say that "we ensure that both of these are never true", but that's irrelevant, both because 1. it's possible code will change in the future thus it's easier to mess this up, 2. we can do better this is where state machines & flow charts (xstate et al) come into play. but for starters, a reducer will do (it's half the pattern, see [1], but will be enough since here we have a simple use case). [1] https://stately.ai/blog/redux-is-half-of-a-pattern-12 Signed-off-by: Kipras Melnikovas <kipras@kipras.org> --- client/api/hooks/use-organization-files.tsx | 58 ++++++++++++------- .../elements/account-files/account-files.tsx | 41 ++++++------- 2 files changed, 56 insertions(+), 43 deletions(-) diff --git a/client/api/hooks/use-organization-files.tsx b/client/api/hooks/use-organization-files.tsx index 5357e21..2a6c34a 100644 --- a/client/api/hooks/use-organization-files.tsx +++ b/client/api/hooks/use-organization-files.tsx @@ -1,4 +1,4 @@ -import React, { createContext, useContext, useEffect, useState } from 'react'; +import React, { createContext, Reducer, useContext, useEffect, useReducer } from 'react'; import { useQuery } from 'react-query'; import { useFilePicker } from 'use-file-picker'; @@ -22,12 +22,21 @@ export const deleteFileMutation = async (fileId: number, orgId: number) => { invalidateFiles(orgId); }; +export type FileUploadStatus = + | { type: 'idle' } + | { type: 'loading'; progress: number } + | { type: 'error'; error: string } + | { type: 'success' }; + +export type FileUploadReducer = Reducer<FileUploadStatus, FileUploadStatus>; +const fileUploadReducer: FileUploadReducer = (_prevState, action) => { + return action; +}; + const FileContext = createContext<{ openFileSelector: () => void; - error: string; - loading: boolean; - uploadProgress: number; - setError: (s: string) => void; + uploadStatus: FileUploadStatus; + clearUploadStatus: () => void; } | null>(null); export const useOpenAndUploadOrganizationFile = () => { @@ -44,44 +53,51 @@ export const FileProvider: React.FC<{ orgId: number }> = ({ orgId, children }) = readAs: 'ArrayBuffer', maxFileSize: 50, }); - const [loading, setLoading] = useState(false); - const [uploadProgress, setUploadProgress] = useState(0); - const [uploadError, setUploadError] = useState(''); + + const [uploadStatus, dispatchUploadStatus] = useReducer<FileUploadReducer>( + fileUploadReducer, // + { + type: 'idle', + }, + ); useEffect(() => { if (errors[0]?.fileSizeToolarge) { - setUploadError('File is too large. Maximum upload file size: 50 MB.'); + dispatchUploadStatus({ + type: 'error', + error: 'File is too large. Maximum upload file size: 50 MB.', + }); } }, [errors]); useEffect(() => { const file = filesContent[0]; if (file) { - setLoading(true); - setUploadError(''); + dispatchUploadStatus({ type: 'loading', progress: 0 }); api.file - .uploadFile({ orgId, file, onUploadProgress: setUploadProgress }) + .uploadFile({ + orgId, + file, + onUploadProgress: (progress) => + dispatchUploadStatus({ type: 'loading', progress }), + }) .then(() => { + dispatchUploadStatus({ type: 'success' }); invalidateFiles(orgId); - setLoading(false); - setUploadProgress(0); }) .catch(() => { - setLoading(false); - setUploadProgress(0); - setUploadError('Something went wrong!'); + dispatchUploadStatus({ type: 'error', error: 'Something went wrong!' }); }); } }, [filesContent, orgId]); + return ( <FileContext.Provider value={{ openFileSelector, - loading, - uploadProgress, - error: uploadError, - setError: setUploadError, + uploadStatus, + clearUploadStatus: () => dispatchUploadStatus({ type: 'idle' }), }} > {children} diff --git a/client/view/elements/account-files/account-files.tsx b/client/view/elements/account-files/account-files.tsx index 8d3e9e5..e124005 100644 --- a/client/view/elements/account-files/account-files.tsx +++ b/client/view/elements/account-files/account-files.tsx @@ -11,6 +11,7 @@ import { } from '../../../api/hooks/use-organization-files'; import { File } from '../../../api/types'; import { fakeTranslator } from '../../../application-state/translator/fake-translator'; +import { assertNever } from '../../../tools/assert-never'; import { Box } from '../../primitives'; import { ErrorFallback } from '../../primitives/error-fallback'; import { ItemWrapperStack } from '../../primitives/item-wrapper'; @@ -28,11 +29,9 @@ interface Props { export const AccountFiles: FC<Props> = ({ files, isError, isLoading, orgId }) => { const lastFileUploaded = fakeTranslator.gettextFake('Last file uploaded'); const { - openFileSelector, - uploadProgress, - loading, - setError, - error: uploadError, + openFileSelector, // + uploadStatus, + clearUploadStatus, } = useOpenAndUploadOrganizationFile(); const fileHandlers = useMemo( @@ -55,22 +54,20 @@ export const AccountFiles: FC<Props> = ({ files, isError, isLoading, orgId }) => return <ErrorFallback refetch={() => invalidateFiles(orgId)} />; } - const uploadState = ( - <> - {uploadError && ( - <Spacing bottom="m"> - <Message variant={'negative'} visible onClose={() => setError('')}> - {uploadError} - </Message> - </Spacing> - )} - {loading && ( - <Spacing bottom="m"> - <Progressbar percent={uploadProgress} variant={'positive'} /> - </Spacing> - )} - </> - ); + const uploadState = + uploadStatus.type === 'error' ? ( + <Spacing bottom="m"> + <Message variant={'negative'} visible onClose={clearUploadStatus}> + {uploadStatus.error} + </Message> + </Spacing> + ) : uploadStatus.type === 'loading' ? ( + <Spacing bottom="m"> + <Progressbar percent={uploadStatus.progress} variant={'positive'} /> + </Spacing> + ) : uploadStatus.type === 'idle' || uploadStatus.type === 'success' ? null : ( + assertNever(uploadStatus) + ); if (files.length === 0) { return ( @@ -84,7 +81,7 @@ export const AccountFiles: FC<Props> = ({ files, isError, isLoading, orgId }) => { <Spacing top="m"> <Button - disabled={loading} + disabled={uploadStatus.type === 'loading'} aria-label="file" offset="left" size="m" -- 2.37.1 ```
-
-
-
-
(hidden) k90PDwScY
-
#public
-
[[fp]] [[classes (programming concept)]] [[round-trips]] [[the notion of grouping things]] [[when grouping goes right]]
-
[[react]] [[js]]
-
fwiw, instead of renaming every prop, might as well not destructure
-
```javascript export const FileSection: React.FC<{ orgId: number }> = ({ orgId }) => { const { openFileSelector } = useOpenAndUploadOrganizationFile(); - const { data: files, isLoading: isLoadingFiles, isError: isErrorFiles } = useFiles(orgId); + const files = useFiles(orgId); return ( <Section> @@ -118,10 +118,10 @@ export const FileSection: React.FC<{ orgId: number }> = ({ orgId }) => { </Flex> </Heading> <AccountFiles - isError={isErrorFiles} - isLoading={isLoadingFiles} + isError={files.isError} + isLoading={files.isLoading} orgId={orgId} - files={files ?? []} + files={files.data ?? []} /> </Section> );```
-
(sometimes grouping is good™️) (sponsored by functional-nerds-who-sometimes-use-classes-anyway®️ 😱)
-
initially stopped hating classes when realized the following about grouping, and that classes are basically grouping.
-
```javascript const styles = { foo: css` `, bar: css` `, } ```
-
instead of
-
```javascript const fooStyle = css` `; const barStyle = css` `; ```
-
because reading
-
```javascript className={styles.foo} ```
-
is way clearer than reading
-
```javascript className={fooStyle} ```
-
because 1st mixes way less w/ other props - it's clear immediately that it's a styling prop, as opposed to the 2nd (esp. if 2nd has a longer name before the ending "Style" suffix)
-
-
-
-
-
-
-
-
(hidden) oyw3lpGA6
-
-
(hidden) RNSYdAUcW
-
-
(hidden) h-VXPmFzT
-
{{[[DONE]]}} (hidden) t1asNILDq
-
(hidden) jA6nx7BDT
-
(hidden) _FWYdtV1L
-
-
(hidden) rYu6PgLwh
-
(hidden) pNn3D-RXQ
-
(hidden) GxCKaEh74
-
(hidden) nKMxLurQk [[(hidden) zJw7j5jxr]]
-
(hidden) fIzgXmkvb
-
(hidden) mJuc-WgdT
-
(hidden) ECaRpuxK6
-
(hidden) N9uz4j3QH
-
(hidden) 47tEvEo_F
-
(hidden) 6b4A2TjB2 [[(hidden) 5cHxKsEl1]]
-
(hidden) 52K3Ogdnx
-
(hidden) 3cY_2mdAd
-
(hidden) FE1kUv9J9 [[(hidden) as_sGflxF]]
-
(hidden) 2F_X8skzg
-
(hidden) CPmIkO94d
-
(hidden) wtFmb3txk
-
-
(hidden) L3wp0_zg1
-
-
(hidden) -ZCYgSwi_
-
(hidden) AkAEIWxHa
-
(hidden) 5tSCjIEZw
-
(hidden) xATR2WCh2
-
(hidden) k8-aQa03i
-
[[roam-traverse-graph]] [[export-html-pages]]
-
{{[[TODO]]}} for runfull.sh, add a new env variable `FIXUP_LAST_DOWNLOAD` to fixup last commit in private-notes repo
-
{{[[TODO]]}} #[[(hidden) jOMmlCP4S]] on the right side in the top of the page, before we have a [[3D graph of outgoing & incoming connections]], we could simply show a list of the outgoing & incoming linked references
-
{{[[TODO]]}} when we'll be implementing block-references, we have to have a way to detect self-referencing blocks, to prevent infinite rendering/expansion :D
-
-
(hidden) hWqjQj_OT
-
(hidden) XkoWtwF5i
-
(hidden) xL5FiOwYX
-
(hidden) ihoLjAsxm [[(hidden) wuMRsjcZv]]
-
(hidden) xckbIOH6z [[(hidden) YY7yFYeGn]]
-
(hidden) K_gcbaFkA
-
(hidden) KrgLNQC78
-
(hidden) UDURtnR8m [[(hidden) Qq7VsATCq]] [[(hidden) 1SRmd2ujC]] [[react]]
-
(hidden) d4_UJPCqg
-
(hidden) LFMh6m2lo [[(hidden) tv1zOVzED]] #[[(hidden) jOMmlCP4S]]
-
(hidden) eRmSTM64X
-
{{[[TODO]]}} (hidden) o2zGieZFY
-
(hidden) jlSn_rrrr
-
(hidden) GBFBPhoF8
-
(hidden) RteXvdsyh #[[(hidden) 7c2C8PgIV]]
-
(hidden) gYF7gb-gv
-
-
(hidden) 1R7OoRiDQ
-
-
(hidden) 5uvU08DI0
-
-
(hidden) 3jUWgJoH2
-
-
(hidden) 7Ld8MEbTK
-
-
(hidden) J-aUbHWcx
-
-
(hidden) 6RLxrbxuA
-
-
(hidden) S_Nc2hpYv
-
(hidden) c0hOJsRbq
-
(hidden) rOxaC8TZm
-
#public
-
[[(hidden) wuMRsjcZv]]
-
[[git-hop]], but not for switching branches that point to the current commit
-
instead -- for hopping thru branch-switching history.
-
first thought of making use of [[(hidden) x7o01uO13]], but idk if it's easier to parse thru it everytime & decode (using e.g. [[(hidden) qbhpV9DHv]]) if a reference is a branch or not
-
-
-
-
-
(hidden) 1mkqcrxiW
-
(hidden) GdQNKtQ4e
-
(hidden) IMeQVY0Zd
-
(hidden) XzoMVG0Rb
-
(hidden) nqpWt9jyd
-
(hidden) pHl6OYDCv
-
(hidden) BZuO_Jcut [[(hidden) 3uMj-Ki8x]]
-
{{[[TODO]]}} (hidden) JmkE3mwEZ #read #[[(hidden) eoMKWyNy0]]
-
(hidden) iAMC0-m4-
-
(hidden) 9ofGcPKCH [[(hidden) iO6XpfUTY]] [[(hidden) f1aG0Mdsv]]
-
(hidden) iStTnilpV
-
(hidden) 3V6P31uhp [[(hidden) rYUMfGhm9]] [[(hidden) gKAk_khk8]] [[(hidden) cbqlEPjly]]
-
(hidden) af0sIoxS5
-
(hidden) LA1fXXTvI [[(hidden) 9lmwkBW7T]]
-
(hidden) NhsjzwAeK
-
(hidden) kfu5eeqnv [[(hidden) wCtSS5mkC]]
-
(hidden) _ieGauCZ6
-
(hidden) mpnEqPE0t [[(hidden) sdn5CP_74]] [[(hidden) m1vh68oDO]]
-
(hidden) yyki2PN6J
-
(hidden) fakIwWXDp
-
(hidden) X3mtHXUfg
-
(hidden) f9N2snAWG [[(hidden) uegxk2aww]]
-
(hidden) EvHVzwDok
-
(hidden) TaK-dvB4p [[wikipedia]] #[[(hidden) 5TkbUFA6W]] [[(hidden) X6WHSweOj]]
-
(hidden) OSxI150Pf
-
(hidden) cFfgZtjCJ [[(hidden) FA5PK5iPi]] #[[(hidden) 5TkbUFA6W]] [[(hidden) G8lb-Xr3u]]
-
(hidden) Ikvfon5E3
-
-
(hidden) 7Fbb5OJ09
-
(hidden) ZrOQN3P62 [[(hidden) EuneK3qOI]] #[[(hidden) DY6wPnICE]]
-
(hidden) _83BfqKMR
-
(hidden) zAw5l72KD
-
-
(hidden) rtfPKZ72X
-
(hidden) OV-4SuDAR
-
(hidden) c4Lw2z6NS
-
(hidden) hER6gBRkQ [[(hidden) 3uMj-Ki8x]]
-
{{[[TODO]]}} (hidden) QIivDPbhI [[(hidden) p1vbExNY9]] [[high signal]] [[(hidden) OwAfUEvHz]] [[(hidden) U5k5oJ6YK]] #read [[(hidden) beXK3WzjI]]
-
(hidden) wj38dLc4I
-
(hidden) 8_afwWKDy [[(hidden) Ff4pGLhRc]] [[(hidden) m1vh68oDO]] [[(hidden) e1uk5UrBJ]]
-
(hidden) G2qozS-Oc
-
(hidden) S_momo8GR
-
(hidden) vfa3hXHGk
-
#public
-
{{[[TODO]]}} #watch "preventing the collapse of civilization" by [[Jonathan Blow (public)]] [[high signal]] [[civilization]] [[technology]]
-
https://youtu.be/ZSRHeXYDLko
-
19ish [[(hidden) 1emn3OovN]]
-
21 [[(hidden) heJsCKvBw]], [[(hidden) 3OrRyssuz]] getting worse, is masked / is riding the benefit wave of [[(hidden) sr-m_VdZk]] improvements
-
to understand the full stack, you have to go very, very deep - down to assembly, to hardware, to physics & electrical engineering
-
& since the best way to learn is by building projects, you'd have to build an actual computer, from scratch, in order to understand it well
-
it's insanely hard
-
some very smart ppl are doing stuff like this & teaching it too, e. g. [[(hidden) DEiTbB4u7]]
-
meanwhile, the [[(hidden) 4npmJjA1a]] / keep growing higher and higher, and one needs to specialise more, thus it gets increasingly difficult to understand the whole stack
-
it grows both higher and lower. lots of improvements in the lower level as well
-
the world of programming is huge
-
https://twitter.com/mitchellh/status/1521648218160832512?t=MrRlacdLdoY5y6yQT6tGAA&s=19
-
so that could be a reason why [[civilization]]s collapse - it becomes too difficult to grasp your technology, thus the decline
-
-
-
-
-
-
-
-
22
-
#observation another reason to learn [[(hidden) dQqknfJ8v]] is that engineers et al in [[(hidden) En_5wCz1g]] are exceptionally good. plus most likely [[(hidden) f1aG0Mdsv]]
-
re: we're getting used to software not working
-
-
-
-
-
-
(hidden) bcj3nN-DF
-
-
(hidden) q1QGsQUp1
-
-
(hidden) c_4Gm6-qi
-
-
(hidden) 1lPp_UbRo
-
(hidden) OqJxeexFx
-
(hidden) BRWv-kcK4
-
[[roam-traverse-graph]] [[export-html-pages]]
-
{{[[TODO]]}} change URLs (thus filenames) of daily notes pages - use their `id` from roam, because already fits what's needed -- YYYY-MM-DD, no spaces
-
-
(hidden) sBNkP-nCE
-
(hidden) SU9n_S5Sl
-
(hidden) W4eXTFkkd
-
(hidden) Y0uNQMWaI [[roam]]
-
(hidden) CXXa0VVZn [[(hidden) Fx7kJSuMZ]] [[(hidden) MEaEHFO-4]] [[(hidden) VZrbM9KJQ]]
-
(hidden) MrxCLWZAh
-
(hidden) zKQpPwu_m
-
(hidden) o5iW2HIwq
-
(hidden) HhzVqeS0u
-
-
(hidden) 5_KGRAHPn
-
(hidden) 68fhQidxJ
-
(hidden) QZOcDSxMq
-
(hidden) KyNBdTIDq
-
(hidden) o_a7vPGJt
-
(hidden) bTsCIWNOB
-
(hidden) qY7_ldavW
-
(hidden) h1y3BHtW4
-
(hidden) dSDyo7lnT
-
(hidden) DYBl1Ml27
-
(hidden) FDh9E8_d0