Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add support buttons#20339

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

Merged
mtojek merged 12 commits intomainfromfix-16804-1
Oct 22, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletioncoderd/apidoc/docs.go
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

6 changes: 5 additions & 1 deletioncoderd/apidoc/swagger.json
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

11 changes: 7 additions & 4 deletionscodersdk/deployment.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -983,9 +983,10 @@ func DefaultSupportLinks(docsURL string) []LinkConfig {
Icon: "bug",
},
{
Name: "Join the Coder Discord",
Target: "https://coder.com/chat?utm_source=coder&utm_medium=coder&utm_campaign=server-footer",
Copy link
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
MemberAuthor

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.

Icon: "chat",
Name: "Join the Coder Discord",
Target: "https://discord.gg/coder",
Icon: "chat",
Location: "navbar",
},
{
Name: "Star the Repo",
Expand DownExpand Up@@ -3325,7 +3326,9 @@ type SupportConfig struct {
type LinkConfig struct {
Name string `json:"name" yaml:"name"`
Target string `json:"target" yaml:"target"`
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
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 withcoder/coder's backend soon: what uses theenums struct tags?

Copy link
MemberAuthor

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.

}

// Validate checks cross-field constraints for deployment values.
Expand Down
1 change: 1 addition & 0 deletionsdocs/reference/api/enterprise.md
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

1 change: 1 addition & 0 deletionsdocs/reference/api/general.md
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

30 changes: 20 additions & 10 deletionsdocs/reference/api/schemas.md
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

11 changes: 11 additions & 0 deletionsenterprise/coderd/appearance_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -201,6 +201,17 @@ func TestCustomSupportLinks(t *testing.T) {
Target:"http://second-link-2",
Icon:"bug",
},
{
Name:"First button",
Target:"http://first-button-1",
Icon:"bug",
Location:"navbar",
},
{
Name:"Third link",
Target:"http://third-link-3",
Icon:"star",
},
}
cfg:=coderdtest.DeploymentValues(t)
cfg.Support.Links= serpent.Struct[[]codersdk.LinkConfig]{
Expand Down
1 change: 1 addition & 0 deletionssite/src/api/typesGenerated.ts
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

9 changes: 8 additions & 1 deletionsite/src/modules/dashboard/Navbar/Navbar.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
import { buildInfo } from "api/queries/buildInfo";
import type { LinkConfig } from "api/typesGenerated";
import { useProxy } from "contexts/ProxyContext";
import { useAuthenticated } from "hooks";
import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata";
Expand All@@ -25,12 +26,18 @@ export const Navbar: FC = () => {
const canViewConnectionLog =
featureVisibility.connection_log && permissions.viewAnyConnectionLog;

const uniqueLinks = new Map<string, LinkConfig>();
for (const link of appearance.support_links ?? []) {
if (!uniqueLinks.has(link.name)) {
uniqueLinks.set(link.name, link);
}
}
return (
<NavbarView
user={me}
logo_url={appearance.logo_url}
buildInfo={buildInfoQuery.data}
supportLinks={appearance.support_links}
supportLinks={Array.from(uniqueLinks.values())}
onSignOut={signOut}
canViewDeployment={canViewDeployment}
canViewOrganizations={canViewOrganizations}
Expand Down
62 changes: 62 additions & 0 deletionssite/src/modules/dashboard/Navbar/NavbarView.stories.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,6 +33,7 @@ const meta: Meta<typeof NavbarView> = {
canViewDeployment: true,
canViewHealth: true,
canViewOrganizations: true,
supportLinks: [],
},
decorators: [withDashboardProvider],
};
Expand DownExpand Up@@ -129,3 +130,64 @@ export const IdleTasks: Story = {
],
},
};

export const SupportLinks: Story = {
args: {
user: MockUserMember,
canViewAuditLog: false,
canViewDeployment: false,
canViewHealth: false,
canViewOrganizations: false,
supportLinks: [
{
name: "This is a bug",
icon: "bug",
target: "#",
},
{
name: "This is a star",
icon: "star",
target: "#",
location: "navbar",
},
{
name: "This is a chat",
icon: "chat",
target: "#",
location: "navbar",
},
{
name: "No icon here",
icon: "",
target: "#",
location: "navbar",
},
{
name: "No icon here too",
icon: "",
target: "#",
},
],
},
};

export const DefaultSupportLinks: Story = {
args: {
user: MockUserMember,
canViewAuditLog: false,
canViewDeployment: false,
canViewHealth: false,
canViewOrganizations: false,
supportLinks: [
{ icon: "docs", name: "Documentation", target: "" },
{ icon: "bug", name: "Report a bug", target: "" },
{
icon: "chat",
name: "Join the Coder Discord",
target: "",
location: "navbar",
},
{ icon: "star", name: "Star the Repo", target: "" },
],
},
};
4 changes: 4 additions & 0 deletionssite/src/modules/dashboard/Navbar/NavbarView.test.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,6 +34,7 @@ describe("NavbarView", () => {
canViewHealth
canViewAuditLog
canViewConnectionLog
supportLinks={[]}
/>,
);
const workspacesLink =
Expand All@@ -52,6 +53,7 @@ describe("NavbarView", () => {
canViewHealth
canViewAuditLog
canViewConnectionLog
supportLinks={[]}
/>,
);
const templatesLink =
Expand All@@ -70,6 +72,7 @@ describe("NavbarView", () => {
canViewHealth
canViewAuditLog
canViewConnectionLog
supportLinks={[]}
/>,
);
const deploymentMenu = await screen.findByText("Admin settings");
Expand All@@ -89,6 +92,7 @@ describe("NavbarView", () => {
canViewHealth
canViewAuditLog
canViewConnectionLog
supportLinks={[]}
/>,
);
const deploymentMenu = await screen.findByText("Admin settings");
Expand Down
48 changes: 46 additions & 2 deletionssite/src/modules/dashboard/Navbar/NavbarView.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,13 +21,14 @@ import { cn } from "utils/cn";
import { DeploymentDropdown } from "./DeploymentDropdown";
import { MobileMenu } from "./MobileMenu";
import { ProxyMenu } from "./ProxyMenu";
import { SupportIcon } from "./SupportIcon";
import { UserDropdown } from "./UserDropdown/UserDropdown";

interface NavbarViewProps {
logo_url?: string;
user: TypesGen.User;
buildInfo?: TypesGen.BuildInfoResponse;
supportLinks?: readonly TypesGen.LinkConfig[];
supportLinks: readonly TypesGen.LinkConfig[];
onSignOut: () => void;
canViewDeployment: boolean;
canViewOrganizations: boolean;
Expand DownExpand Up@@ -71,6 +72,16 @@ export const NavbarView: FC<NavbarViewProps> = ({
<NavItems className="ml-4" user={user} />

<div className="flex items-center gap-3 ml-auto">
{supportLinks.filter(isNavbarLink).map((link) => (
<div key={link.name} className="hidden md:block">
<SupportButton
name={link.name}
target={link.target}
icon={link.icon}
/>
</div>
))}

{proxyContextValue && (
<div className="hidden md:block">
<ProxyMenu proxyContextValue={proxyContextValue} />
Expand DownExpand Up@@ -121,7 +132,7 @@ export const NavbarView: FC<NavbarViewProps> = ({
<UserDropdown
user={user}
buildInfo={buildInfo}
supportLinks={supportLinks}
supportLinks={supportLinks?.filter((link) => !isNavbarLink(link))}
onSignOut={onSignOut}
/>
</div>
Expand DownExpand Up@@ -240,3 +251,36 @@ const TasksNavItem: FC<TasksNavItemProps> = ({ user }) => {
function idleTasksLabel(count: number) {
return `You have ${count} ${count === 1 ? "task" : "tasks"} waiting for input`;
}

function isNavbarLink(link: TypesGen.LinkConfig): boolean {
return link.location === "navbar";
}

interface SupportButtonProps {
name: string;
target: string;
icon: string;
location?: string;
}

const SupportButton: FC<SupportButtonProps> = ({ name, target, icon }) => {
return (
<Button asChild variant="outline">
<a
href={target}
target="_blank"
rel="noreferrer"
className="inline-block"
>
{icon && (
<SupportIcon
icon={icon}
className={"size-5 text-content-secondary"}
/>
)}
{name}
<span className="sr-only"> (link opens in new tab)</span>
</a>
</Button>
);
};
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp