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
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const GENERAL_SECTIONS: {
},
{
id: "/settings/team",
label: "Team",
label: "Organization",
icon: <HiOutlineUserGroup className="h-4 w-4" />,
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export function MemberActions({
<DialogContent>
<DialogHeader>
<DialogTitle>
{isCurrentUser ? "Leave organization?" : "Remove team member?"}
{isCurrentUser ? "Leave organization?" : "Remove member?"}
</DialogTitle>
<DialogDescription>
{isCurrentUser ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ function TeamSettingsPage() {
<div className="flex-1 flex flex-col min-h-0">
<div className="p-8 border-b">
<div className="max-w-5xl">
<h2 className="text-2xl font-semibold">Team</h2>
<h2 className="text-2xl font-semibold">Organization</h2>
<p className="text-sm text-muted-foreground mt-1">
Manage members in your organization
</p>
Expand Down Expand Up @@ -95,7 +95,7 @@ function TeamSettingsPage() {
</div>
) : members.length === 0 ? (
<div className="text-center py-12 text-muted-foreground border rounded-lg">
No team members yet
No members yet
</div>
) : (
<div className="border rounded-lg">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,42 @@
import { COMPANY } from "@superset/shared/constants";
import { Avatar } from "@superset/ui/atoms/Avatar";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@superset/ui/dropdown-menu";
import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip";
import { useLiveQuery } from "@tanstack/react-db";
import { useNavigate } from "@tanstack/react-router";
import { FaDiscord, FaXTwitter } from "react-icons/fa6";
import {
HiCheck,
HiChevronUpDown,
HiOutlineArrowRightOnRectangle,
HiOutlineBugAnt,
HiOutlineCog6Tooth,
HiOutlineEnvelope,
HiOutlineUserGroup,
} from "react-icons/hi2";
import { LuKeyboard, LuLifeBuoy } from "react-icons/lu";
import { authClient } from "renderer/lib/auth-client";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { useCollections } from "renderer/routes/_authenticated/providers/CollectionsProvider";
import { useHotkeyText } from "renderer/stores/hotkeys";

interface OrganizationDropdownProps {
isCollapsed?: boolean;
}

export function OrganizationDropdown({
isCollapsed = false,
}: OrganizationDropdownProps) {
export function OrganizationDropdown() {
const { data: session } = authClient.useSession();
const collections = useCollections();
const signOutMutation = electronTrpc.auth.signOut.useMutation();
const navigate = useNavigate();
const shortcutsHotkey = useHotkeyText("SHOW_HOTKEYS");
const showShortcut = shortcutsHotkey !== "Unassigned";

const activeOrganizationId = session?.session?.activeOrganizationId;

Expand All @@ -45,8 +49,7 @@ export function OrganizationDropdown({
(o) => o.id === activeOrganizationId,
);

// Always render dropdown to prevent trapping users without orgs
const orgName = activeOrganization?.name ?? "No Organization";
const userEmail = session?.user?.email;

const switchOrganization = async (newOrgId: string) => {
await authClient.organization.setActive({
Expand All @@ -59,65 +62,64 @@ export function OrganizationDropdown({
signOutMutation.mutate();
};

const trigger = isCollapsed ? (
<Tooltip delayDuration={300}>
<TooltipTrigger asChild>
const handleKeyboardShortcuts = () => {
navigate({ to: "/settings/keyboard" });
};

const handleContactUs = () => {
window.open(COMPANY.MAIL_TO, "_blank");
};

const handleReportIssue = () => {
window.open(COMPANY.REPORT_ISSUE_URL, "_blank");
};

const handleJoinDiscord = () => {
window.open(COMPANY.DISCORD_URL, "_blank");
};

const handleTwitter = () => {
window.open(COMPANY.X_URL, "_blank");
};

const userName = session?.user?.name;
const displayName = activeOrganization?.name ?? userName ?? "Organization";

return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button
type="button"
className="flex items-center justify-center size-8 rounded-md hover:bg-accent/50 transition-colors"
className="no-drag flex items-center gap-1.5 h-6 px-1.5 rounded border border-border/60 bg-secondary/50 hover:bg-secondary hover:border-border transition-all duration-150 ease-out focus:outline-none focus:ring-1 focus:ring-ring"
aria-label="Organization menu"
>
<Avatar
size="sm"
size="xs"
fullName={activeOrganization?.name}
image={activeOrganization?.logo}
className="rounded-md"
className="rounded size-4"
/>
<span className="text-xs font-medium truncate max-w-32">
{displayName}
</span>
<HiChevronUpDown className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
</button>
</TooltipTrigger>
<TooltipContent side="right">{orgName}</TooltipContent>
</Tooltip>
) : (
<button
type="button"
className="flex items-center gap-2 w-full px-2 py-1.5 rounded-md hover:bg-accent/50 transition-colors text-left"
>
<Avatar
size="sm"
fullName={activeOrganization?.name}
image={activeOrganization?.logo}
className="rounded-md"
/>
<span className="flex-1 text-sm font-medium truncate">{orgName}</span>
<HiChevronUpDown className="h-4 w-4 text-muted-foreground shrink-0" />
</button>
);

const userEmail = session?.user?.email;
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56">
{/* Settings and team management - always shown for logged in users */}
<DropdownMenuItem
onSelect={() => navigate({ to: "/settings/account" })}
>
<HiOutlineCog6Tooth className="h-4 w-4" />
<span>Settings</span>
</DropdownMenuItem>

return (
<DropdownMenu>
<DropdownMenuTrigger asChild>{trigger}</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-56">
{/* Only show org-specific items if user has an active organization */}
{activeOrganization && (
<>
{/* Settings */}
<DropdownMenuItem
onSelect={() => navigate({ to: "/settings/account" })}
>
<span>Settings</span>
</DropdownMenuItem>
<DropdownMenuItem onSelect={() => navigate({ to: "/settings/team" })}>
<HiOutlineUserGroup className="h-4 w-4" />
<span>Organization</span>
</DropdownMenuItem>

{/* Team management */}
<DropdownMenuItem
onSelect={() => navigate({ to: "/settings/team" })}
>
<span>Invite and manage members</span>
</DropdownMenuItem>

<DropdownMenuSeparator />
</>
)}
<DropdownMenuSeparator />

{/* Org switcher - only show if user has multiple orgs */}
{organizations && organizations.length > 1 && (
Expand All @@ -127,7 +129,6 @@ export function OrganizationDropdown({
<span>Switch organization</span>
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
{/* User email header in submenu */}
{userEmail && (
<DropdownMenuLabel className="font-normal text-muted-foreground text-xs">
{userEmail}
Expand Down Expand Up @@ -157,6 +158,40 @@ export function OrganizationDropdown({
</>
)}

{/* Support section */}
<DropdownMenuItem onClick={handleReportIssue}>
<HiOutlineBugAnt className="h-4 w-4" />
Report Issue
</DropdownMenuItem>
<DropdownMenuItem onClick={handleKeyboardShortcuts}>
<LuKeyboard className="h-4 w-4" />
Keyboard Shortcuts
{showShortcut && (
<DropdownMenuShortcut>{shortcutsHotkey}</DropdownMenuShortcut>
)}
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<LuLifeBuoy className="h-4 w-4" />
Contact Us
</DropdownMenuSubTrigger>
<DropdownMenuSubContent sideOffset={8} className="w-56">
<DropdownMenuItem onClick={handleJoinDiscord}>
<FaDiscord className="h-4 w-4" />
Discord
</DropdownMenuItem>
<DropdownMenuItem onClick={handleTwitter}>
<FaXTwitter className="h-4 w-4" />X
</DropdownMenuItem>
<DropdownMenuItem onClick={handleContactUs}>
<HiOutlineEnvelope className="h-4 w-4" />
Email Founders
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>

<DropdownMenuSeparator />

{/* Sign out - ALWAYS show so users can never get trapped */}
<DropdownMenuItem onSelect={handleSignOut} className="gap-2">
<HiOutlineArrowRightOnRectangle className="h-4 w-4" />
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useParams } from "@tanstack/react-router";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { OpenInMenuButton } from "./OpenInMenuButton";
import { SupportMenu } from "./SupportMenu";
import { OrganizationDropdown } from "./OrganizationDropdown";
import { WindowControls } from "./WindowControls";

export function TopBar() {
Expand Down Expand Up @@ -32,7 +32,7 @@ export function TopBar() {
branch={workspace.worktree?.branch}
/>
)}
<SupportMenu />
<OrganizationDropdown />
{!isMac && <WindowControls />}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
import { useWorkspaceSidebarStore } from "renderer/stores";
import { STROKE_WIDTH, STROKE_WIDTH_THIN } from "../constants";
import { NewWorkspaceButton } from "./NewWorkspaceButton";
import { OrganizationDropdown } from "./OrganizationDropdown";

interface WorkspaceSidebarHeaderProps {
isCollapsed?: boolean;
Expand Down Expand Up @@ -85,8 +84,6 @@ export function WorkspaceSidebarHeader({
<TooltipContent side="right">Toggle sidebar</TooltipContent>
</Tooltip>

<OrganizationDropdown isCollapsed />

<Tooltip delayDuration={300}>
<TooltipTrigger asChild>
<button
Expand Down Expand Up @@ -157,8 +154,6 @@ export function WorkspaceSidebarHeader({
<TooltipContent side="right">Toggle sidebar</TooltipContent>
</Tooltip>

<OrganizationDropdown />

<button
type="button"
onClick={handleWorkspacesClick}
Expand Down
Loading