Skip to content

Commit 48bf7e4

Browse files
authored
upcoming: [M3-7697] - Add scrolling for S3 hostnames in the Access Keys modal (linode#10218)
* Upcoming: [M3-7697] - Add scrolling for S3 hostnames in the Access Keys modal * Added changeset: Add scrolling for S3 hostnames in the Access Keys modal. * fix - border color according to the theme. * PR - feedback: @abailly-akamai - Add box shadow for host names list * unit test for HostNamesList
1 parent 20c0869 commit 48bf7e4

File tree

5 files changed

+139
-26
lines changed

5 files changed

+139
-26
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Upcoming Features
3+
---
4+
5+
Add scrolling for S3 hostnames in the Access Keys modal. ([#10218](https://github.com/linode/manager/pull/10218))

packages/manager/src/features/ObjectStorage/AccessKeyLanding/AccessKeyLanding.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ import { AccessKeyDrawer } from './AccessKeyDrawer';
3030
import { AccessKeyTable } from './AccessKeyTable/AccessKeyTable';
3131
import { OMC_AccessKeyDrawer } from './OMC_AccessKeyDrawer';
3232
import { RevokeAccessKeyDialog } from './RevokeAccessKeyDialog';
33-
import { MODE, OpenAccessDrawer } from './types';
3433
import ViewPermissionsDrawer from './ViewPermissionsDrawer';
34+
import { MODE, OpenAccessDrawer } from './types';
3535

3636
interface Props {
3737
accessDrawerOpen: boolean;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { screen } from '@testing-library/react';
2+
import React from 'react';
3+
4+
import { regionFactory } from 'src/factories';
5+
import { makeResourcePage } from 'src/mocks/serverHandlers';
6+
import { rest, server } from 'src/mocks/testServer';
7+
import { renderWithTheme } from 'src/utilities/testHelpers';
8+
9+
import { HostNamesList } from './HostNamesList';
10+
11+
const mockObjectStorageKey = {
12+
access_key: 'test',
13+
bucket_access: null,
14+
id: 0,
15+
label: 'test-label',
16+
limited: false,
17+
regions: [{ id: 'us-central', s3_endpoint: 'http://example.com' }],
18+
secret_key: 'testKey',
19+
};
20+
21+
describe('HostNamesList', () => {
22+
it('renders without crashing', async () => {
23+
server.use(
24+
rest.get('*/regions', (req, res, ctx) => {
25+
const regions = regionFactory.buildList(1, {
26+
id: 'us-central',
27+
label: 'Fake Region, NC',
28+
});
29+
return res(ctx.json(makeResourcePage(regions)));
30+
})
31+
);
32+
33+
renderWithTheme(<HostNamesList objectStorageKey={mockObjectStorageKey} />);
34+
35+
const copyButton = await screen.findByLabelText(
36+
'Copy Fake Region, NC: http://example.com to clipboard'
37+
);
38+
expect(copyButton).toBeInTheDocument();
39+
});
40+
});
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { styled } from '@mui/material/styles';
2+
import React, { useRef } from 'react';
3+
4+
import { Box } from 'src/components/Box';
5+
import { CopyableTextField } from 'src/components/CopyableTextField/CopyableTextField';
6+
import { List } from 'src/components/List';
7+
import { useRegionsQuery } from 'src/queries/regions';
8+
import { omittedProps } from 'src/utilities/omittedProps';
9+
import { getRegionsByRegionId } from 'src/utilities/regions';
10+
11+
import type { ObjectStorageKey } from '@linode/api-v4/lib/object-storage';
12+
13+
const maxHeight = 200;
14+
15+
interface Props {
16+
objectStorageKey: ObjectStorageKey;
17+
}
18+
19+
export const HostNamesList = ({ objectStorageKey }: Props) => {
20+
const { data: regionsData } = useRegionsQuery();
21+
const regionsLookup = regionsData && getRegionsByRegionId(regionsData);
22+
23+
const listRef = useRef<HTMLUListElement>(null);
24+
const currentListHeight = listRef?.current?.clientHeight || 0;
25+
26+
return (
27+
<Box>
28+
<StyledBoxShadowWrapper
29+
sx={(theme) => ({
30+
backgroundColor: theme.bg.main,
31+
border: `1px solid ${theme.name === 'light' ? '#ccc' : '#222'}`,
32+
minHeight: '34px',
33+
})}
34+
displayShadow={currentListHeight > maxHeight}
35+
>
36+
<StyledScrollBox maxHeight={`${maxHeight}px`}>
37+
<StyledHostNamesList ref={listRef}>
38+
{objectStorageKey?.regions.map((region, index) => (
39+
<CopyableTextField
40+
value={`${regionsLookup?.[region.id]?.label}: ${
41+
region.s3_endpoint
42+
}`}
43+
hideLabel
44+
key={index}
45+
label="Create a Filesystem"
46+
sx={{ border: 'none', maxWidth: '100%' }}
47+
/>
48+
))}
49+
</StyledHostNamesList>
50+
</StyledScrollBox>
51+
</StyledBoxShadowWrapper>
52+
</Box>
53+
);
54+
};
55+
56+
export const StyledScrollBox = styled(Box, {
57+
label: 'StyledScrollBox',
58+
})<{ maxHeight: string }>(({ maxHeight }) => ({
59+
maxHeight: `${maxHeight}px`,
60+
overflow: 'auto',
61+
}));
62+
63+
export const StyledBoxShadowWrapper = styled(Box, {
64+
label: 'StyledBoxShadowWrapper',
65+
shouldForwardProp: omittedProps(['displayShadow']),
66+
})<{ displayShadow: boolean }>(({ displayShadow, theme }) => ({
67+
'&:after': {
68+
bottom: 0,
69+
content: '""',
70+
height: '15px',
71+
position: 'absolute',
72+
width: '100%',
73+
...(displayShadow && {
74+
boxShadow: `${theme.color.boxShadow} 0px -15px 10px -10px inset`,
75+
}),
76+
},
77+
position: 'relative',
78+
}));
79+
80+
export const StyledHostNamesList = styled(List, {
81+
label: 'RegionsList',
82+
})(({ theme }) => ({
83+
background: theme.name === 'light' ? theme.bg.main : theme.bg.app,
84+
}));

packages/manager/src/features/Profile/SecretTokenDialog/SecretTokenDialog.tsx

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
55
import { Box } from 'src/components/Box';
66
import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog';
77
import { CopyableAndDownloadableTextField } from 'src/components/CopyableAndDownloadableTextField';
8-
import { CopyableTextField } from 'src/components/CopyableTextField/CopyableTextField';
98
import { Notice } from 'src/components/Notice/Notice';
9+
import { HostNamesList } from 'src/features/ObjectStorage/AccessKeyLanding/HostNamesList';
1010
import { CopyAllHostnames } from 'src/features/ObjectStorage/AccessKeyLanding/CopyAllHostnames';
1111
import { useAccountManagement } from 'src/hooks/useAccountManagement';
1212
import { useFlags } from 'src/hooks/useFlags';
@@ -15,6 +15,7 @@ import { isFeatureEnabled } from 'src/utilities/accountCapabilities';
1515
import { getRegionsByRegionId } from 'src/utilities/regions';
1616

1717
import type { ObjectStorageKey } from '@linode/api-v4/lib/object-storage';
18+
1819
interface Props {
1920
objectStorageKey?: ObjectStorageKey | null;
2021
onClose: () => void;
@@ -59,6 +60,11 @@ export const SecretTokenDialog = (props: Props) => {
5960

6061
return (
6162
<ConfirmationDialog
63+
sx={() => ({
64+
'.MuiPaper-root': {
65+
overflow: 'hidden',
66+
},
67+
})}
6268
actions={actions}
6369
disableEscapeKeyDown
6470
fullWidth
@@ -106,31 +112,9 @@ export const SecretTokenDialog = (props: Props) => {
106112
{isObjMultiClusterEnabled &&
107113
objectStorageKey &&
108114
objectStorageKey?.regions?.length > 0 && (
109-
<Box
110-
sx={(theme) => ({
111-
'.copyIcon': {
112-
marginRight: 0,
113-
paddingRight: 0,
114-
},
115-
backgroundColor: theme.bg.main,
116-
border: `1px solid ${theme.color.grey3}`,
117-
borderColor: theme.name === 'light' ? '#ccc' : '#222',
118-
padding: theme.spacing(1),
119-
})}
120-
>
121-
{objectStorageKey?.regions.map((region, index) => (
122-
<CopyableTextField
123-
value={`${regionsLookup?.[region.id]?.label}: ${
124-
region.s3_endpoint
125-
}`}
126-
hideLabel
127-
key={index}
128-
label="Create a Filesystem"
129-
sx={{ border: 'none', maxWidth: '100%' }}
130-
/>
131-
))}
132-
</Box>
115+
<HostNamesList objectStorageKey={objectStorageKey} />
133116
)}
117+
134118
{objectStorageKey ? (
135119
<>
136120
<Box marginBottom="16px">

0 commit comments

Comments
 (0)