Skip to content

feat: add support buttons#20339

Merged
mtojek merged 12 commits into
mainfrom
fix-16804-1
Oct 22, 2025
Merged

feat: add support buttons#20339
mtojek merged 12 commits into
mainfrom
fix-16804-1

Conversation

@mtojek
Copy link
Copy Markdown
Member

@mtojek mtojek commented Oct 16, 2025

Fixes: #16804

This PR modifies Navbar to include custom Support buttons. Enterprise users will be able to change their content.

Screenshot 2025-10-16 at 15 48 59 Screenshot 2025-10-16 at 15 48 49

@mtojek mtojek self-assigned this Oct 16, 2025
@mtojek mtojek requested review from bpmct and phorcys420 October 16, 2025 14:22
@mtojek mtojek marked this pull request as ready for review October 16, 2025 14:22
Comment thread site/src/modules/dashboard/Navbar/NavbarView.tsx Outdated
Comment thread site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownContent.tsx Outdated
Comment thread site/src/modules/dashboard/Navbar/SupportButtons.tsx Outdated
Comment thread site/src/modules/dashboard/Navbar/SupportButtons.tsx Outdated
Comment thread site/src/modules/dashboard/Navbar/SupportButtons.tsx Outdated
Comment thread site/src/modules/dashboard/Navbar/SupportButtons.tsx Outdated
Comment thread site/src/modules/dashboard/Navbar/NavbarView.stories.tsx Outdated
Comment thread site/src/modules/dashboard/Navbar/NavbarView.stories.tsx Outdated
Copy link
Copy Markdown
Contributor

@buenos-nachos buenos-nachos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing major, but there are a few things I think could be tightened up

Comment thread site/src/modules/dashboard/Navbar/NavbarView.tsx
Comment thread site/src/modules/dashboard/Navbar/SupportButtons.tsx Outdated
Comment thread site/src/modules/dashboard/Navbar/SupportButtons.tsx Outdated
Copy link
Copy Markdown
Member

@phorcys420 phorcys420 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me but i'll let the more experienced frontend people look into it :-)
thanks for this!

Comment thread codersdk/deployment.go
},
{
Name: "Join the Coder Discord",
Target: "https://coder.com/chat?utm_source=coder&utm_medium=coder&utm_campaign=server-footer",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess we could make a new coder.com/chat link? or at least add a utm_source to the discord.gg url which i think the statistics do give us (unsure, need to check)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for flagging it! We can update the link in a follow up since I don't know who owns these links.

@mtojek
Copy link
Copy Markdown
Member Author

mtojek commented Oct 20, 2025

Hey @aslilac @Parkreiner!

Would you like to re-take a look at this PR or is it ready for approval & merge?

@buenos-nachos
Copy link
Copy Markdown
Contributor

@mtojek I'm starting a review right now

Copy link
Copy Markdown
Contributor

@buenos-nachos buenos-nachos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually a little more awake this time around, so I'm noticing a few more things I think we can tighten up.

Those wouldn't be major enough to block an approval, but I did notice some layout problems in some of the stories. Once those are fixed up, we should basically be ready to go

Comment thread codersdk/deployment.go
Icon string `json:"icon" yaml:"icon" enums:"bug,chat,docs"`
Icon string `json:"icon" yaml:"icon" enums:"bug,chat,docs,star"`

Location string `json:"location,omitempty" yaml:"location,omitempty" enums:"navbar,dropdown"`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just asking because it sounds like I'll be helping out more with coder/coder's backend soon: what uses the enums struct tags?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mainly swagger generator + if we enable go validation, then the field will have restricted values too.

Comment thread site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownContent.tsx Outdated
Comment on lines +28 to +33
const uniqueLinks = appearance.support_links
? appearance.support_links.filter(
(link, index, self) =>
index === self.findIndex((l) => l.name === link.name),
)
: undefined;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it might be better to make the supportLinks prop required for NavbarView, and then change the checks to see whether the array is empty. That way we don't have to deal with both the empty and undefined cases

And if we do that, we can simplify uniqueLinks to:

const uniqueLinks = [...new Set(appearance.support_links)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I don't know if I've ever seen the third self argument used in professional code before

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set is equality by identity. they'll be separate objects with different identities. you'd still have duplicates in your list using that code.

this kind of uniqueness constraint really feels like something that should be enforced by the backend imo, but if we need to do it on the frontend then I would use a Map and use name as the key, then get the list back by doing [...supportLinksMap.values()]

Copy link
Copy Markdown
Member

@aslilac aslilac Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

specifically, here's my suggestion:

Suggested change
const uniqueLinks = appearance.support_links
? appearance.support_links.filter(
(link, index, self) =>
index === self.findIndex((l) => l.name === link.name),
)
: undefined;
const uniqueLinks = new Map<string, LinkConfig>();
for (const link of appearance.support_links) {
if (!uniqueLinks.has(link.name)) {
uniqueLinks.set(link.name, link);
}
}
// and later get the list by doing `[...uniqueLinks.values()]`

tho I still think that data hygiene concerns like this belong more in the backend than that frontend

it's also worth noting that this "call a function if it exists, and give me undefined if not" pattern is common enough that it has it's own operator: ?.

Copy link
Copy Markdown
Contributor

@buenos-nachos buenos-nachos Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, duh. I forgot that these were objects. Another option would be to do this:

const uniqueLinks = [
  ...new Map(
    appearance.supportLinks?.map((l) => [l.name, l])
  ).values()
];

Though the nuances change a little bit. Kayla's suggestion always keeps the first entry that is encountered when you have a conflict, while mine keeps whichever one occurs later in the array

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't touch the backend side now, but we can improve it in a follow-up. I updated the frontend side as you suggested. Please let me know your thoughts.

Comment thread site/src/modules/dashboard/Navbar/NavbarView.tsx Outdated
Comment on lines +260 to +262
return (
<>
{supportLinks.map((link) => (
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part works, but it feels a little clunky to me, because the boundaries aren't super clear. When you look at just this component, you can tell that you're rendering out multiple links, but you don't know how they'll be laid out, because you have to look at the parent component to see what kind of container it's using. It's also hard to reuse the link styling/logic because you can't use one by itself

I feel like a better approach would be to change this component into SupportButton (singular), and then update the navbar to this:

<div className="hidden md:block">
  {supportLinks.filter(isNavbarLink).map((link) => (
    <SupportButton
      name={link.name}
	    target={link.target}
      icon={link.icon}
      location={link.location}
    />
  ))}
</div>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think keeping the container/layout logic closer together also makes another question more obvious: do we want to make this a ul list?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored into SupportButton components, but had to move <div className="hidden md:block"> to iterations, otherwise buttons were unaligned as you spotted on Chromatic. Let me know if there is a better solution, but definitely don't want to refactor the entire file to ul/li :)

@mtojek mtojek requested a review from buenos-nachos October 21, 2025 15:00
Copy link
Copy Markdown
Contributor

@buenos-nachos buenos-nachos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, Marcin! I had to leave early yesterday because I wasn't feeling well, and forgot to approve before I left

I'd still like to see if it makes sense to swap in a ul list, but we can do that later

@mtojek mtojek merged commit f2a4105 into main Oct 22, 2025
30 checks passed
@mtojek mtojek deleted the fix-16804-1 branch October 22, 2025 13:35
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 22, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add navbar property to CODER_SUPPORT_LINKS

4 participants