- Notifications
You must be signed in to change notification settings - Fork1k
feat: add sidebar to the task page#19628
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Conversation
A few questions:
|
|
BrunoQuaresma commentedAug 29, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
|
brettkolodny left a comment• edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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.
Without doing a deep dive I see a bunch of stuff that need some more attention:
"use client";
Isn't this for fullstack frameworks? I don't think it does anything here- Do we need a
useMobile
hook? I feel like this could be accomplished all within CSS - The folder
LayotuSidebar
is misspelled - The
useQuery
inUsersCombobox
has no error handling - Cookies seem like a strange choice for controlling the sidebar state. Is there a reason we couldn't do this with React state?
- I could be wrong but a lot of these
useMemo
s anduseCallback
s don't seem to be necessary, but I need to look more into them first
This isn't my final review but I wanted to flag these issues, and also get some feedback from someone with more frontend experience like@Parkreiner to take a look at as well
BrunoQuaresma commentedAug 29, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@brettkolodny most of these points are related to shadcn component implementation provided by them. To make it easier in the future to upgrade/update them, I would leave them as they are. About the other topics:
|
brettkolodny commentedAug 29, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
It seems like a common action within the code base would be to show an error
Gotcha! I'd want to hear someone else's thoughts on this. I generally enjoy shad's smaller components but for something this large the implementation seems odd... I'm curious what their rationale is for doing it this way, and whether or not we should just wholesale add it to the code base or if something similar is possible. Especially if this is the only place we're using this sidebar.
Honestly I still want to see some more thought put into this UI. I'm immediately seeing some things that could be improved in terms of spacing, and placement. I'll follow up in a few minutes with an example improvement. While I understand that it's better than what we have I worry about adding "design debt". There are a lot of places in the app currently that need some love and I'd rather have things in a baseline state that we're happy to shit to customers |
This is really only touching the sidebar but to me this already feels cleaner CleanShot.2025-08-29.at.14.17.37.mp4Some other notes though
|
brettkolodny commentedAug 29, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
|
brettkolodny commentedAug 29, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Yeah agreed, if it's going to be full screen we need the story about entering and leaving the state needs to be better.
IMO the spacing is awkward, but maybe making that and making the user picker full width would fix some of my initial pullback. But also what I have above is still collapsible I just forgot to take a video of that. But either way if y'all feel strongly that this is the way to go then that's fine
I get that, but I think in this sense maybe it's a bit overkill? I've made similar components from scratch before with a lot of success, and they were more flexible/simpler than this. This sidebar component is very opinionated and seems better suited for entire application navigation. If we just want something that can collapse that should be pretty easy to do, I do similar things in the Dynamic Parameters playground |
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 really concerned about some of these code changes, and I wasn't able to get Git authenticated properly when using the Dogfood backend with the dev frontend, so I wasn't able to test this yet
I'm just throwing out comments for what sticks out to me from glancing at the code, but I'm happy to pair with you on Tuesday so that we can get you unstuck. At the very least, I think we should be swapping inuseEffectEvent
to avoid some subscription behavior
}; | ||
getTasks=async(filter:TasksFilter):Promise<Task[]>=>{ | ||
getTasks=async(filter:TasksFilter={}):Promise<Task[]>=>{ |
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.
Is there a reason why this has a default parameter? There's nothing in the type information to indicate that the filter could ever be undefined
@@ -0,0 +1,21 @@ | |||
import*asReactfrom"react"; |
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'd prefer if we could importuseState
anduseEffect
explicitly. There's no need to import React like this in a Vite project
constMOBILE_BREAKPOINT=768; | ||
exportfunctionuseIsMobile(){ |
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 feel like there are issues with the entire conceit behind this hook. I'm not convinced if we actually need to care whether a user is on a mobile device specifically – we should be making sure the layout is responsive to as content widths as possible
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.
Can we also add an explicit return value?
@@ -0,0 +1,21 @@ | |||
import*asReactfrom"react"; | |||
constMOBILE_BREAKPOINT=768; |
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 feels like a really arbitrary value. I know thatsome mobile devices have this width, and that this corresponds to Tailwind's defaultmd
breakpoint, but how did we decide that we wanted this one specifically?
const[isMobile,setIsMobile]=React.useState<boolean|undefined>( | ||
undefined, | ||
); |
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 we're always returning out a boolean, we can initialize this state with justfalse
<SheetHeaderclassName="sr-only"> | ||
<SheetTitle>Sidebar</SheetTitle> | ||
<SheetDescription>Displays the mobile sidebar.</SheetDescription> | ||
</SheetHeader> |
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 don't get the point of having specialized, stylized components, if we're just going to shove them into ansr-only
container
// Random width between 50 to 90%. | ||
constwidth=useMemo(()=>{ | ||
return`${Math.floor(Math.random()*40)+50}%`; | ||
},[]); |
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 shouldn't be usinguseMemo
to stabilize nondeterministic values, especially when,per the React docs, React reserves the right to throw memo results away as part of its internal scheduling
In the future, this code could cause the elements to randomly change widths on re-renders
className={cn( | ||
"relative w-[var(--sidebar-width)] bg-transparent transition-[width] duration-200 ease-linear", | ||
"group-data-[collapsible=offcanvas]:w-0", | ||
"group-data-[side=right]:rotate-180", | ||
variant==="floating"||variant==="inset" | ||
?"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem)]" | ||
:"group-data-[collapsible=icon]:w-[var(--sidebar-width-icon)]", | ||
)} |
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.
Honestly, my eyes are kind of glazing over with all this Tailwind. I'm just trusting that this does what it's supposed to
<SidebarMenuButtonasChild> | ||
<RouterLinkto="/tasks"> | ||
<SquarePenIcon/> | ||
<span>New task</span> |
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.
Do we need the span here?
conststate=open ?"expanded" :"collapsed"; | ||
// biome-ignore lint/correctness/useExhaustiveDependencies: set by library author | ||
constcontextValue=useMemo<SidebarContextProps>( |
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 whole setup feels super, super fragile. I feel like memoizing this doesn't actually get us much:
- Because so many values are potentially coming from props, this value is likely going to get invalidated a ton
- Even if it does get invalidated, because this is part of a bunch of components that would be localized to a specific part of the page, I don't know if extra re-render from context would actually cause any meaningful problems
I had some time today and did someexploration of what it would look like if we were to implement the core behavior we need of the collapsible navbar ourselves. For the sake of a 1:1 comparison I kept the overall layout the same and just switched out components. Personally I think it works pretty well, and if we decide to go down this route please feel free grab any of the code! I get using shadcn to speed up development, and I think generally their more basic components are really solid. But in the case of the collapsible sidebar I think since it's meant to be used for site-wide navigation it's both overkill and too opinionated for this page, especially since we're only using it in this one place. |
Hey@Parkreiner and@brettkolodny 👋 @Parkreiner I noticed most of your comments and requests are related to the shadcn implementation of the sidebar component. I’m curious about what benefits you see in adapting it to match our internal preferences. From my perspective, I’m not sure the tradeoff is worth it since we’d likely only be touching these components during upgrades. In those cases, we’d need to re-apply all our preferences or carefully cherry-pick changes, which could add a lot of overhead. @brettkolodny If the component library we’re already using provides a sidebar abstraction, my inclination would be to lean on that rather than building something in-house. It feels like a faster and more reliable path, especially since we’d be standing on top of tools that are widely adopted and battle-tested by the community. On the Tasks feature, since it’s still evolving and may change direction based on customer feedback, I think it makes sense to keep our focus on speed and iteration over perfect code quality right now—at least while it remains isolated. As long as the code is easy to remove later and doesn’t introduce major UX issues, I’d consider that “good enough” for this stage. We can always come back and refine it once the feature proves its value and stabilizes. That said, these are just my thoughts and preferences. Since both of you are reviewing, I’m happy to support whichever direction you feel is best to move this forward. I won’t be able to finish it myself since I’ll be on PTO until September 14th, so I’d love your help wrapping this up in the meantime. Wdyt? |
I get what you're saying, but like I said above I still think that in this case the shadcn component is overkill/not really intended for this use case, and building something in house is actually easy enough for the functionality you're looking for. And like I tried to demonstrate in my above comment/exploration in this case I think we can get something that matches the functionality pretty easily.
I'm going to push back on this idea a bit. I totally understand that we're moving fast and things are changing quickly but adding code just because we think it's easy to remove seems dangerous. In my experience that doesn't typically pan out, and it will live in the code base for much longer than we'd expect. I've traditionally tried to approach this balance by making sure all the code that is being added is code that I'm happy with, and the time saved comes from code I'm not adding. All of that being said, I'm going to remove myself as a reviewer on this PR and let@Parkreiner give their input. I don't there to be too many cooks in the kitchen |
Parkreiner commentedSep 4, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@BrunoQuaresma Really, really sorry for just now following up. But I guess my understanding (as someone who hasn't actually brought in a Shad component yet) was that we were going to take advantage of the vendoring Shad gives us, instead of treating it as a library with extra steps The way I think about it is:
I'm curious to know what@aslilac thinks, though. And while he's not involved with the frontend, I'd also love to hear if@spikecurtis has any thoughts on how Coder should approach code vendoring in general |
my understanding when we decided to start using shadcn was that every component would be a starting point, that we would adapt it to our code style, it would be owned by us from that point forward (without concerns for "upgrading"), and that we would add and remove functionality from the base implementations freely as needed. shadcn is mostly just styles. any functional/important/bug fixing updates should be delivered by a new version of a radix package. I don't think we get much value by trying to "preserve" shadcn code. I think of it this way: because shadcn is vendored, when we decide to use more of their code, it has to be accepted as part of our codebase through the usual avenues. a pull request, review from peers, and addressing the feedback given. imagine if we changed the situation just slightly and the code was from stack overflow. if anyone asked in slack "can I use some code I found on slack overflow?" I think the response would be similar to the response on this pr: it's fine to use it if it fits the problem and solves it well, but we should adapt it to our code standards, we should remove bits we don't need, we should test it, and we should understand it. no one would suggest that you not alter the code you found on stack overflow just because someone might edit the answer later. my vision of a successful transition was that in the end we would not be using shadcn, but we would be using our own component library, that we would maintain ourselves and have direct control over. shadcn would be the stepping stone, not the destination. |
Closes#19573
Demo:
Screen.Recording.2025-08-28.at.17.11.08.mov
Goals: