-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement UI for certificate #232
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the loading progress is not the correct UX here.
A certificate request will probably take at the very minimum 1-2 minutes, users will not wait that long for that animation (it looks cool for sure, but still)
Also, it feels like it tries to keep the user glued to the screen, but the process is unfortunately not that fast for this to be feasible.
This is why we talked about showing some kind of pending state in the same structure we are showing the certificate details in the second screen in your video
On the other hand, the cert details screen looks very nice :) |
Yeah... I'm struggling a bit with understanding what a good UX is for the loading page. From what I can understand, you want to head directly to the 2nd page, but provide some sort of a "loading" buffer before displaying the details? Like a spinning wheel of some kind? |
Yes, with some kind of description, that we are creating the certificate, but this is an asyncrhronous process, requiring multiple 3rd party providers (route53 and let's encrypt), so for this reason it will take a few minutes |
also a note that the user can leave the page and come back later, the process will continue in the background |
The loading page is meant to stay regardless on whether the user refresh the page or not. The state will only change after the certificate becomes valid (at least that's how I thought it would work...). Right now it's handled by a timeout |
I really love this @Ririio, great job. A few comments:
|
We're allowed to use this website for illustration? I
I recall there was a discussion for the ui to be left-aligned-- I had to change the layout on the figma template |
Yes, it is open licensed
What I heard in that meeting was "left-aligned in a container that is centred," but if I'm wrong, do what you have. cc @Myrfion, @Eakam1007 |
Yeah, I believe it was discussed that the form should not touch the left edge but should be a bit more towards the center (so basically a margin on the left) I think this suggestion should make it work |
Just to be clear, I just have to move the container more to the center, and have its content left align? |
I would say it is up to you how you decide to do it. But yeah, I think that should work |
What I'm more looking for is that this be responsive. When we're on a really wide screen, it's nicer to put it in the middle. On a narrower screen, it's going to be more on the left, etc. We can also do that stuff in a follow up. But putting the "main" part of this in a container that is in the center, and the contents are left-aligned within it, seems good to me. If it doesn't work, don't do it. Just a thought. |
@humphd @dadolhay I changed the loading screen, and aligned the containers in the middle as per your suggestion. If you don't mind taking a look here's a demo... 2023-02-16.19-00-15.mp4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like where this is going.
Reading the code, I wonder if we should be splitting this up into a few larger components vs. having such deep nesting on state. That could happen in a follow-up, so we don't block this for 0.3, but I think this file is getting pretty big, and we could separate the three states into smaller pieces of code that would be easier to maintain.
I'm tagging some other reviewers who can help with thinking about the front-end stuff.
If we're splitting them up, can I create a directory called |
I believe there already is a components directory under app. I think you could use that? |
sure |
@Eakam1007 is this what you meant? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
certificate-display.tsx
does the exact same UI twice. You could break that up into re-usable pieces too, which will halve this code, and pass the things that are different (e.g., the title, the value in the accordion view) as props.
Because you have a bunch of "certificate" components (e.g., loading
is pretty vague, I'd put them all under
app/components/certificate/*` so they are logically grouped together. Then you can break out smaller bits without it getting overwhelming.
In your certificate/index.tsx
, don't be afraid to use an if
:
if(loading) {
return <Loading />
}
if(certificate) {
return <CertificateDetails certificate={certificate} />
}
return <RequestCertificate />
let key = props.cert.certificate; | ||
let val = 'Public Key'; | ||
|
||
if (props.priv) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of doing this, pass down the title
to show (e.g., 'Private Key'
) and also the value
to use (i.e., the specific PEM string to show). This component shouldn't have to know anything about what it's showing, do that above it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit confused as to what you mean, do you mind explaining it one more time?
<Heading as="h4" size="sm"> | ||
{props.priv ? 'Private Key' : 'Public Key'} | ||
</Heading> | ||
<Tooltip label="Copy Public Key"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This public
vs. private
logic should get figured out via props vs hard-coding like this and below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to create a switch
and 3 new variables that will be used for the key
, currentState
and Description
. This should remove any need for hard coding, because the output is dependent on the current state of the isPrivate
props
onClick={() => onCopy()} | ||
/> | ||
</Tooltip> | ||
<Tooltip label="Download Public Key"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I create a variable that changes depending on the state of isPrivate
?
<HStack gap="6" marginTop="2"> | ||
<VStack> | ||
<Text fontWeight="bold">Created On</Text> | ||
<Text>{props.cert.validFrom.toDateString()}</Text> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use chakra.time
for a <time>
element, and use the datatime
attribute to set a machine readable value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry I can't seem to find the document relating to chakra.time
do you happen to have the link for it?
@@ -0,0 +1,18 @@ | |||
import { Center, Flex, Box, Image, Heading } from '@chakra-ui/react'; | |||
|
|||
import image from 'img/undraw_Processing_re_tbdu.png'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm unclear how Remix handles assets. Are these supposed to go in public/
or in the tree like this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll also need to include the license for this image, or we are breaking the license.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also not sure... Alex might know a bit more about it, because she has also have files on the img
directory
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was looking for someone to go read the docs, which are here https://remix.run/docs/en/v1/guides/migrating-react-router-app#asset-imports.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another question: does undraw not supply these as SVGs? They will scale much better if so.
import type { Certificate } from '@prisma/client'; | ||
|
||
interface Props { | ||
cert: Certificate; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass the specific thing down you want to show: domainName
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not quite sure what you mean by this?
</Heading> | ||
</div> | ||
); | ||
const [request, setRequest] = useState(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does request
represent? Would this not be certificate
(i.e., you'd show the certificate display only if you have a certificate)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the 'request' is a state when the certificate has already been requested (true) or not (false). This helps when rendering pages depending on whether we have a new certificate. If you have a different idea I can change the current iteration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is whether or not the certificate has been requested, use that: certificateRequested
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, PR looks good! I added some minor change requests that would improve code quality in my opinion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add e2e tests for this or create a issue for them?
@@ -0,0 +1,18 @@ | |||
import { Center, Flex, Box, Image, Heading } from '@chakra-ui/react'; | |||
|
|||
import image from 'img/undraw_Processing_re_tbdu.png'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was looking for someone to go read the docs, which are here https://remix.run/docs/en/v1/guides/migrating-react-router-app#asset-imports.
</Heading> | ||
</div> | ||
); | ||
const [request, setRequest] = useState(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is whether or not the certificate has been requested, use that: certificateRequested
@@ -0,0 +1,18 @@ | |||
import { Center, Flex, Box, Image, Heading } from '@chakra-ui/react'; | |||
|
|||
import image from 'img/undraw_Processing_re_tbdu.png'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another question: does undraw not supply these as SVGs? They will scale much better if so.
} | ||
|
||
export default function CertificateDisplay(props: CertificateDisplayProps) { | ||
const { title, description, value } = props; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
export default function CertificateDisplay({ title, description, value }: CertificateDisplayProps) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh that makes it much better than calling it again inside
function onCopy() { | ||
navigator.clipboard.writeText(value); | ||
toast({ | ||
title: `${title} was copied to clipboard`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"the clipboard"
/> | ||
</> | ||
)} | ||
{!certificateRequested && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pattern feels off to me. We have a state that will result in one of two component sub-trees being rendered in this view. I think you should make two components and do:
{ certificateRequested ? <View1 /> : <View2 /> }
Maybe name them:
- CertificateRequested
- CertificateAvailable
There might be something better, not sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually thought about doing this on my previous commits, but I can't seem to figure out how I'll handle the button for request certificate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh it's actually fairly simple to do...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking better and better. A few more things
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One small change, and this is r+ from me
replacing privkey with privateKey center components | adding unDraw illustration creating 'loading' and 'certificate-display' components creating new components for certificate Implementing advice from reviews Changing function name to be more descriptive passing props instead of using logic in child component Trimming the index to only contain two components as to a tree all logic should occur in the parent component following react event handler prefix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pr is based on issue #213
Here's a live demo of the UI:
2023-02-15.19-37-31.mp4
textArea
, I find it a lot more cleaneruseState
to display different components once the user has pressed theRequest a Certificate
buttonseed
certificate, so I'm using a temporary object to produce the necessary output