Skip to content

Commit 0c2551c

Browse files
authored
Fixed number pool popover position issue on initial render (#7310)
1 parent 70c3b5e commit 0c2551c

File tree

9 files changed

+91
-110
lines changed

9 files changed

+91
-110
lines changed

changelog/+ui-number-pool.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed issue with number pool popover stuck in the top-left corner and not expandable during the initial render in some cases.

frontend/app/src/entities/resource-manager/api/get-number-pools-from-api.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@ export const GET_NUMBER_POOLS = gql`
99
edges {
1010
node {
1111
id
12+
hfid
1213
display_label
13-
name {
14-
id
15-
value
16-
}
1714
node {
1815
id
1916
value

frontend/app/src/entities/resource-manager/domain/get-number-pools.query.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { queryOptions, useQuery } from "@tanstack/react-query";
2+
import { useAtomValue } from "jotai";
23

34
import { ContextParams } from "@/shared/api/types";
4-
import { store } from "@/shared/stores";
55
import { datetimeAtom } from "@/shared/stores/time.atom";
66

7-
import { getCurrentBranchName } from "@/entities/branches/domain/get-current-branch";
7+
import { useCurrentBranch } from "@/entities/branches/ui/branches-provider";
88
import { NUMBER_POOL_KIND } from "@/entities/resource-manager/constants";
99

1010
import { GetNumberPoolsParams, getNumberPools } from "./get-number-pools";
@@ -19,12 +19,12 @@ export function getNumberPoolsQueryOptions(params: GetNumberPoolsParams) {
1919
export function useGetNumberPools({
2020
objectKinds,
2121
}: Omit<GetNumberPoolsParams, keyof ContextParams>) {
22-
const currentBranchName = getCurrentBranchName();
23-
const timeMachineDate = store.get(datetimeAtom);
22+
const { currentBranch } = useCurrentBranch();
23+
const timeMachineDate = useAtomValue(datetimeAtom);
2424

2525
return useQuery(
2626
getNumberPoolsQueryOptions({
27-
branchName: currentBranchName,
27+
branchName: currentBranch.name,
2828
atDate: timeMachineDate,
2929
objectKinds,
3030
})

frontend/app/src/entities/resource-manager/domain/get-number-pools.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ export const getNumberPools: GetNumberPools = async (params) => {
1616
throw new Error(errors[0].message);
1717
}
1818

19-
return data[NUMBER_POOL_KIND].edges.map(({ node }: any) => ({
20-
id: node.id,
21-
label: node.display_label,
22-
kind: node.__typename,
23-
nodeAttribute: {
24-
id: node.node_attribute.id,
25-
name: node.node_attribute.value,
26-
},
27-
}));
19+
return data[NUMBER_POOL_KIND].edges.map(
20+
({ node }: any): NumberPool => ({
21+
id: node.id,
22+
hfid: node.hfid,
23+
display_label: node.display_label,
24+
__typename: node.__typename,
25+
schemaKind: node.node.value,
26+
attributeName: node.node_attribute.value,
27+
})
28+
);
2829
};
Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
export type NumberPool = {
2-
id: string;
3-
label: string;
4-
kind: string;
5-
nodeAttribute: {
6-
id: string;
7-
name: string;
8-
};
9-
};
1+
import { NodeCore } from "@/entities/nodes/types";
2+
3+
export interface NumberPool extends NodeCore {
4+
schemaKind: string;
5+
attributeName: string;
6+
}

frontend/app/src/shared/components/form/fields/input.field.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const InputField = ({
5353
fieldData={fieldData}
5454
/>
5555

56-
<Row>
56+
<Row className="gap-1">
5757
<FormInput>
5858
{!selectedPoolId || override ? (
5959
<Input
Lines changed: 64 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
import { Icon } from "@iconify-icon/react";
2+
import { PopoverTriggerProps } from "@radix-ui/react-popover";
23
import { Slot } from "@radix-ui/react-slot";
3-
import React, { forwardRef } from "react";
4+
import React from "react";
5+
import { Button as AriaButton } from "react-aria-components";
46

5-
import { Button } from "@/shared/components/buttons/button-primitive";
7+
import { Row } from "@/shared/components/container";
68
import { FormFieldValue } from "@/shared/components/form/type";
79
import { ComboboxContent, ComboboxItem, ComboboxList } from "@/shared/components/ui/combobox";
8-
import { Popover, PopoverAnchor, PopoverTrigger } from "@/shared/components/ui/popover";
10+
import { Popover, PopoverTrigger } from "@/shared/components/ui/popover";
11+
import { inputStyle } from "@/shared/components/ui/style";
912
import { Tooltip } from "@/shared/components/ui/tooltip";
13+
import { classNames } from "@/shared/utils/common";
1014

15+
import { getNodeLabel } from "@/entities/nodes/object/utils/get-node-label";
1116
import { NumberPool } from "@/entities/resource-manager/domain/type";
1217

1318
export type PoolValue = {
@@ -25,73 +30,67 @@ type PoolSelectorProps = {
2530
value: FormFieldValue;
2631
};
2732

28-
export const PoolSelector = forwardRef<HTMLElement, PoolSelectorProps>(
29-
({ children, onChange, value, pools }, ref) => {
30-
const [override, setOverride] = React.useState(false);
33+
export function PoolSelector({ children, onChange, value, pools }: PoolSelectorProps) {
34+
const [override, setOverride] = React.useState(false);
3135

32-
const items = pools.map((pool) => ({
33-
label: pool.label,
34-
value: {
35-
from_pool: {
36-
id: pool.id,
37-
name: pool.label,
38-
kind: pool.kind,
39-
},
40-
},
41-
}));
36+
const displayFromPool =
37+
typeof value.value === "object" && value.value && "from_pool" in value.value;
4238

43-
const displayFromPool =
44-
typeof value.value === "object" && value.value && "from_pool" in value.value;
39+
return (
40+
<Popover>
41+
<Row className="gap-1">
42+
{value.source?.type !== "pool" || override || !displayFromPool ? (
43+
<Slot autoFocus={override} onBlur={() => setOverride(false)}>
44+
{children}
45+
</Slot>
46+
) : (
47+
<AriaButton onClick={() => setOverride(true)} className={inputStyle}>
48+
Allocated by pool
49+
</AriaButton>
50+
)}
4551

46-
return (
47-
<Popover>
48-
<div className="flex w-full gap-1">
49-
<PopoverAnchor asChild>
50-
{value.source?.type !== "pool" || override || !displayFromPool ? (
51-
<Slot autoFocus={override} onBlur={() => setOverride(false)} ref={ref}>
52-
{children}
53-
</Slot>
54-
) : (
55-
<Button
56-
variant="outline"
57-
onClick={() => setOverride(true)}
58-
className="flex h-10 w-full justify-start gap-2 border-gray-300 px-2 font-normal shadow-none"
59-
>
60-
<Icon icon="mdi:view-grid-outline" />
61-
<span>{value.source.label}</span>
62-
</Button>
63-
)}
64-
</PopoverAnchor>
65-
66-
<Tooltip content="select a pool" enabled>
67-
<PopoverTrigger asChild>
68-
<Button
69-
variant="outline"
70-
className="h-10 w-10 border-gray-300"
71-
data-testid="number-pool-button"
72-
>
73-
<Icon icon="mdi:view-grid-outline" className="text-gray-500" />
74-
</Button>
75-
</PopoverTrigger>
76-
</Tooltip>
77-
</div>
52+
<PoolPopoverTrigger data-testid="number-pool-button" />
53+
</Row>
7854

79-
<ComboboxContent portal={true}>
80-
<ComboboxList>
81-
{items.map((item) => (
55+
<ComboboxContent align="end" fitTriggerWidth={false} portal>
56+
<ComboboxList>
57+
{pools.map((pool) => {
58+
const poolLabel = getNodeLabel(pool);
59+
return (
8260
<ComboboxItem
83-
key={item.value.from_pool.id}
84-
value={item.value.from_pool.id}
85-
keywords={[item.label]}
86-
onSelect={() => onChange(item.value)}
61+
key={pool.id}
62+
value={pool.id}
63+
keywords={[poolLabel, pool.id]}
64+
onSelect={() =>
65+
onChange({
66+
from_pool: {
67+
id: pool.id,
68+
name: poolLabel,
69+
kind: pool.__typename,
70+
},
71+
})
72+
}
8773
selectedValue={value?.source?.id}
8874
>
89-
{item.label}
75+
{poolLabel}
9076
</ComboboxItem>
91-
))}
92-
</ComboboxList>
93-
</ComboboxContent>
94-
</Popover>
95-
);
96-
}
97-
);
77+
);
78+
})}
79+
</ComboboxList>
80+
</ComboboxContent>
81+
</Popover>
82+
);
83+
}
84+
85+
export function PoolPopoverTrigger({ className, ...props }: PopoverTriggerProps) {
86+
return (
87+
<Tooltip content="select a pool" enabled>
88+
<PopoverTrigger
89+
className={classNames(inputStyle, "size-10 shrink-0 justify-center", className)}
90+
{...props}
91+
>
92+
<Icon icon="mdi:view-grid-outline" className="text-gray-500" />
93+
</PopoverTrigger>
94+
</Tooltip>
95+
);
96+
}

frontend/app/src/shared/components/form/utils/getFormFieldFromAttribute.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export const getFormFieldFromAttribute = ({
150150
}
151151

152152
if (attributeSchema.kind === ATTRIBUTE_KIND.NUMBER) {
153-
const numberPools = pools?.filter((pool) => pool.nodeAttribute.name === attributeSchema.name);
153+
const numberPools = pools?.filter((pool) => pool.attributeName === attributeSchema.name);
154154

155155
const dropdownField: DynamicNumberFieldProps = {
156156
...basicFormFieldProps,

frontend/app/src/shared/components/inputs/pool-select.tsx

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import { Icon } from "@iconify-icon/react";
21
import React from "react";
32

4-
import { Button } from "@/shared/components/buttons/button-primitive";
5-
import { PoolValue } from "@/shared/components/form/pool-selector";
3+
import { PoolPopoverTrigger, PoolValue } from "@/shared/components/form/pool-selector";
64
import { Combobox, ComboboxContent } from "@/shared/components/ui/combobox";
7-
import { PopoverTrigger } from "@/shared/components/ui/popover";
8-
import { Tooltip } from "@/shared/components/ui/tooltip";
95

106
import { RelationshipComboboxList } from "@/entities/nodes/relationships/ui/relationship-combobox-list";
117
import { IP_ADDRESS_POOL, IP_PREFIX_POOL } from "@/entities/resource-manager/constants";
@@ -47,17 +43,7 @@ export function PoolSelect({
4743

4844
return (
4945
<Combobox open={isOpen} onOpenChange={setIsOpen}>
50-
<Tooltip content="select a pool" enabled>
51-
<PopoverTrigger asChild>
52-
<Button
53-
variant="outline"
54-
className="h-10 w-10 border-gray-300"
55-
data-testid="select-open-pool-option-button"
56-
>
57-
<Icon icon="mdi:view-grid-outline" className="text-gray-500" />
58-
</Button>
59-
</PopoverTrigger>
60-
</Tooltip>
46+
<PoolPopoverTrigger data-testid="select-open-pool-option-button" />
6147

6248
<ComboboxContent align="end" fitTriggerWidth={false}>
6349
<RelationshipComboboxList

0 commit comments

Comments
 (0)