Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
19 changes: 19 additions & 0 deletions hub/app/javascript/components/feedback-icon/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function FeedbackIcon({ size = 16 }: { size?: number }) {
return (
<svg
aria-hidden="true"
focusable="false"
width={size}
height={size}
viewBox="0 0 16 16"
fill="none"
stroke="currentColor"
strokeWidth="1.4"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M8 1.5a6.5 6.5 0 0 0-5.44 10.06L2 14.5l3.08-.8A6.5 6.5 0 1 0 8 1.5Z" />
<path d="M8 11S5 9.25 5 7.5a1.5 1.5 0 0 1 3-.3 1.5 1.5 0 0 1 3 .3C11 9.25 8 11 8 11Z" />
</svg>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,25 @@ type RepositoryNavigationItemProps = {
| {
href: string
selected?: boolean
external?: boolean
onClick?: MouseEventHandler<HTMLAnchorElement>
expanded?: never
}
| { href?: never; selected?: never; onClick: () => void; expanded: boolean }
| {
href?: never
selected?: never
external?: never
onClick: () => void
expanded: boolean
}
)

/** Renders a sidebar destination or a control with the same row treatment. */
export function RepositoryNavigationItem({
ariaLabel,
count,
expanded,
external = false,
href,
icon: Icon,
label,
Expand All @@ -45,12 +53,14 @@ export function RepositoryNavigationItem({
return href !== undefined ? (
<a
href={href}
data-sg-visit="true"
data-sg-visit={external ? undefined : "true"}
className="repository-navigation-item"
data-has-count={count !== undefined && count > 0 ? "true" : undefined}
data-active={selected ? "true" : undefined}
aria-current={selected ? "page" : undefined}
aria-label={ariaLabel}
target={external ? "_blank" : undefined}
rel={external ? "noopener noreferrer" : undefined}
onClick={onClick}
>
{content}
Expand Down
16 changes: 16 additions & 0 deletions hub/app/javascript/components/workspace-navigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { ReactNode } from "react"
import { SidebarCollapseIcon, SidebarExpandIcon } from "@primer/octicons-react"
import { Tooltip } from "@primer/react-brand"

import { FeedbackIcon } from "@components/feedback-icon"
import { RepositoryNavigationItem } from "@components/repository-navigation-item"
import { RepositoryUserMenu } from "@components/repository-user-menu"

Expand Down Expand Up @@ -36,6 +37,14 @@ export function WorkspaceNavigation({
onClick={() => onCollapsedChange(!collapsed)}
/>
)
const feedbackLink = (
<RepositoryNavigationItem
href="https://gh.io/replica-feedback"
icon={FeedbackIcon}
label={data.feedbackLabel}
external
/>
)

return (
<aside className={`repository-navigation ${className ?? ""}`} data-collapsed={collapsed}>
Expand All @@ -47,6 +56,13 @@ export function WorkspaceNavigation({
) : null}
</div>
<div className="repository-navigation__account">
{collapsed ? (
<Tooltip text={data.feedbackLabel} type="label" direction="e">
{feedbackLink}
</Tooltip>
) : (
feedbackLink
)}
{collapsed ? (
<Tooltip text={toggleLabel} type="label" direction="e">
{collapseButton}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export interface WorkspaceAccountData {
authenticityToken: string
collapseNavigationLabel: string
expandNavigationLabel: string
feedbackLabel: string
currentUser: {
avatarUrl: string | null
login: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,16 @@ describe("RepositoryNavigation()", () => {
"Public sharing",
"End all Hub sessions",
"Security audit",
"Feedback",
])
const feedback = screen.getByRole("link", { name: "Feedback" })
expect(feedback).toHaveAttribute("href", "https://gh.io/replica-feedback")
expect(feedback).toHaveAttribute("target", "_blank")
expect(feedback).toHaveAttribute("rel", "noopener noreferrer")
expect(feedback).not.toHaveAttribute("data-sg-visit")
Comment thread
lukasoppermann marked this conversation as resolved.
for (const link of container.querySelectorAll("aside a")) {
if (link === feedback) continue

expect(link).toHaveAttribute("data-sg-visit", "true")
}
expect(screen.getByRole("link", { name: "Prototypes" })).toHaveAttribute(
Expand All @@ -109,7 +117,7 @@ describe("RepositoryNavigation()", () => {
repositorySelector,
)
const account = container.querySelector(".repository-navigation__account")!
expect(account.querySelector("a")).toBeNull()
expect(account.querySelector("a")).toBe(feedback)
expect([...account.querySelectorAll("button")]).toEqual([
screen.getByRole("button", { name: collapsed ? "Expand sidebar" : "Collapse sidebar" }),
screen.getByRole("button", { name: prototypeWorkspaceData.accountMenuLabel }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { templatesData } from "@/storybook/fixtures/templates"
const PAGE_DATA: NewPrototypePageData = {
accountMenuLabel: "Account menu",
darkThemeLabel: "Dark",
feedbackLabel: "Feedback",
lightThemeLabel: "Light",
systemThemeLabel: "System",
authenticityToken: "token",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ let currentReviewComments = REVIEW_COMMENTS
const PROTOTYPES_SHOW_PAGE_DATA: PrototypesShowPageData = {
accountMenuLabel: "Account menu for @octocat",
darkThemeLabel: "Dark",
feedbackLabel: "Feedback",
lightThemeLabel: "Light",
systemThemeLabel: "System",
author: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { RepositoriesShowPageData } from "./types"
const PAGE_DATA: RepositoriesShowPageData = {
accountMenuLabel: "Account menu for @octocat",
darkThemeLabel: "Dark",
feedbackLabel: "Feedback",
lightThemeLabel: "Light",
systemThemeLabel: "System",
alert: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const authenticatedHeaderData = {
authenticityToken: "storybook-token",
currentUser: octocat,
darkThemeLabel: "Dark",
feedbackLabel: "Feedback",
lightThemeLabel: "Light",
productName: "Replica Hub",
rootPath: "/repositories",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ hub_admin = Current.user &&
User.where(id: Current.user.id, hub_admin: true).where.not(github_id: nil).exists? &&
local_assigns.fetch(:administration_allowed, true)
json.settingsNavigationLabel t("hub_administration_workspace.settings_navigation")
json.feedbackLabel t("repository_workspace.feedback")
context_repository = local_assigns.fetch(:context_repository, @repository)
context = { repository_github_id: context_repository&.route_id }
json.administrationLinks(hub_admin ? [
Expand Down
1 change: 1 addition & 0 deletions hub/config/locales/gallery.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ en:
navigation: Repository navigation
collapse_navigation: Collapse sidebar
expand_navigation: Expand sidebar
feedback: Feedback
new_prototype: Create
prototypes: Prototypes
theme_system: System
Expand Down
4 changes: 3 additions & 1 deletion hub/test/views/hub_administration_navigation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ class HubAdministrationNavigationTest < ActionView::TestCase

test "a repository administrator does not get Hub administration" do
@repository_permission = "admin"
assert_no_administration(users.create)
data = navigation_for(users.create)
assert_empty data.fetch("administrationLinks")
assert_equal "Feedback", data.fetch("feedbackLabel")
end

test "a local identity does not get Hub administration even with a saved role" do
Expand Down
Loading