From cd742e077636f94daa85d29ffc4c9d60e3d86bd8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 23 Dec 2025 01:53:19 +0000 Subject: [PATCH 1/3] Refactor: Improve dropdown alignment logic Add logic to determine dropdown alignment based on viewport width. Co-authored-by: eric.okuma --- .../table/dropdownAlignment.ts | 24 +++++++++ .../table/users/UserActionsCell.svelte | 2 +- .../table/users/UserGroupsCell.svelte | 51 +++++++++++++++++- .../table/users/UserProjectsCell.svelte | 51 +++++++++++++++++- .../table/users/UserRoleCell.svelte | 54 ++++++++++++++++++- 5 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 web-admin/src/features/organizations/user-management/table/dropdownAlignment.ts diff --git a/web-admin/src/features/organizations/user-management/table/dropdownAlignment.ts b/web-admin/src/features/organizations/user-management/table/dropdownAlignment.ts new file mode 100644 index 00000000000..08c94c976b1 --- /dev/null +++ b/web-admin/src/features/organizations/user-management/table/dropdownAlignment.ts @@ -0,0 +1,24 @@ +const DEFAULT_VIEWPORT_MARGIN_PX = 16; +const DEFAULT_MENU_WIDTH_PX = 240; + +export function determineDropdownAlign({ + triggerRect, + menuWidth, + viewportWidth, + margin = DEFAULT_VIEWPORT_MARGIN_PX, +}: { + triggerRect: DOMRect | null; + menuWidth?: number; + viewportWidth: number; + margin?: number; +}): "start" | "end" { + if (!triggerRect) return "start"; + + const width = typeof menuWidth === "number" ? menuWidth : DEFAULT_MENU_WIDTH_PX; + const projectedRightEdge = triggerRect.left + width; + const safeViewportRight = viewportWidth - margin; + + return projectedRightEdge > safeViewportRight ? "end" : "start"; +} + +export const DROPDOWN_DEFAULT_MARGIN = DEFAULT_VIEWPORT_MARGIN_PX; diff --git a/web-admin/src/features/organizations/user-management/table/users/UserActionsCell.svelte b/web-admin/src/features/organizations/user-management/table/users/UserActionsCell.svelte index 42d1979893b..c81461cb8db 100644 --- a/web-admin/src/features/organizations/user-management/table/users/UserActionsCell.svelte +++ b/web-admin/src/features/organizations/user-management/table/users/UserActionsCell.svelte @@ -81,7 +81,7 @@ - + {#if role === OrgUserRoles.Guest} import { getUserGroupsForUsersInOrg } from "@rilldata/web-admin/features/organizations/user-management/selectors.ts"; + import { determineDropdownAlign } from "@rilldata/web-admin/features/organizations/user-management/table/dropdownAlignment.ts"; import * as Dropdown from "@rilldata/web-common/components/dropdown-menu"; import CaretDownIcon from "@rilldata/web-common/components/icons/CaretDownIcon.svelte"; import CaretUpIcon from "@rilldata/web-common/components/icons/CaretUpIcon.svelte"; import { writable } from "svelte/store"; + import { browser } from "$app/environment"; + import { onDestroy, onMount, tick } from "svelte"; export let organization: string; export let userId: string; @@ -13,6 +16,9 @@ let isDropdownOpen = false; const userGroupsEnabledStore = writable(false); $: userGroupsEnabledStore.set(isDropdownOpen); + let dropdownAlign: "start" | "end" = "start"; + let dropdownTriggerEl: HTMLElement | null = null; + let dropdownContentEl: HTMLElement | null = null; const userGroupsQuery = getUserGroupsForUsersInOrg( organization, @@ -21,11 +27,54 @@ ); $: ({ data: userGroups, isPending, error } = $userGroupsQuery); $: hasGroups = groupCount > 0; + + async function updateDropdownAlignment() { + if (!browser || !isDropdownOpen || !dropdownTriggerEl) return; + await tick(); + + const menuWidth = + dropdownContentEl?.offsetWidth ?? + dropdownTriggerEl?.offsetWidth ?? + 200; + + dropdownAlign = determineDropdownAlign({ + triggerRect: dropdownTriggerEl.getBoundingClientRect(), + menuWidth, + viewportWidth: window.innerWidth, + }); + } + + function handleWindowResize() { + void updateDropdownAlignment(); + } + + onMount(() => { + if (!browser) return; + window.addEventListener("resize", handleWindowResize); + }); + + onDestroy(() => { + if (!browser) return; + window.removeEventListener("resize", handleWindowResize); + }); + + $: if (isDropdownOpen) { + void updateDropdownAlignment(); + } + + $: if (isDropdownOpen && dropdownContentEl) { + void updateDropdownAlignment(); + } + + $: if (isDropdownOpen && userGroups?.length !== undefined) { + void updateDropdownAlignment(); + } {#if hasGroups} {/if} - + {#if isPending} Loading... {:else if error} diff --git a/web-admin/src/features/organizations/user-management/table/users/UserProjectsCell.svelte b/web-admin/src/features/organizations/user-management/table/users/UserProjectsCell.svelte index dabcfd5f150..93c923932a7 100644 --- a/web-admin/src/features/organizations/user-management/table/users/UserProjectsCell.svelte +++ b/web-admin/src/features/organizations/user-management/table/users/UserProjectsCell.svelte @@ -1,11 +1,14 @@