Skip to content

upcoming: [UIE-10430] - Reserved IP: Implement Landing Screen.#13549

Open
tanushree-akamai wants to merge 2 commits intolinode:developfrom
tanushree-akamai:feature/UIE-10430-ReservedIPs-Landing-screen
Open

upcoming: [UIE-10430] - Reserved IP: Implement Landing Screen.#13549
tanushree-akamai wants to merge 2 commits intolinode:developfrom
tanushree-akamai:feature/UIE-10430-ReservedIPs-Landing-screen

Conversation

@tanushree-akamai
Copy link
Copy Markdown
Contributor

Description 📝

Implement Reserved IP Landing Table alongwith CRUD MSW mock setup.

Changes 🔄

  • Add ReservedIpsLanding component to render Reserved IPs list with pagination, loading/error/empty states using web components.
  • Implement ShowMore to allow overflow of tags based on maxLength
  • Implement ReservedIps factory, seeds and handlers

Scope 🚢

Upon production release, changes in this PR will be visible to:

  • All customers
  • Some customers (e.g. in Beta or Limited Availability)
  • No customers / Not applicable

Target release date 🗓️

Please specify a release date (and environment, if applicable) to guarantee timely review of this PR. If exact date is not known, please approximate and update it as needed.

Preview 📷

Screenshot 2026-03-31 at 5 30 16 PM

How to test 🧪

Prerequisites

  • Open DevTools Panel
  • Enable the Reserved IP feature flag
  • Navigate to "MSW" section, Toggle "Enable MSW" to ON -> Select "CRUD" preset
  • navigate to "Seeds" section -> Set seed counts: Reserve IP: 26

Verification steps

  • Navigate to localhost:3000/reserved-ips/
  • Verify that you are able to see the list
Author Checklists

As an Author, to speed up the review process, I considered 🤔

👀 Doing a self review
❔ Our contribution guidelines
🤏 Splitting feature into small PRs
➕ Adding a changeset
🧪 Providing/improving test coverage
🔐 Removing all sensitive information from the code and PR description
🚩 Using a feature flag to protect the release
👣 Providing comprehensive reproduction steps
📑 Providing or updating our documentation
🕛 Scheduling a pair reviewing session
📱 Providing mobile support
♿ Providing accessibility support


  • I have read and considered all applicable items listed above.

As an Author, before moving this PR from Draft to Open, I confirmed ✅

  • All tests and CI checks are passing
  • TypeScript compilation succeeded without errors
  • Code passes all linting rules

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements the Reserved IPs landing experience (table + row rendering) and adds supporting MSW “CRUD preset” wiring and seed data so the page can be exercised locally behind the feature flag.

Changes:

  • Added Reserved IPs landing UI (table, row rendering, action menu) with pagination and ordering driven by query params/preferences.
  • Extended MSW mock state/types and added Reserved IP list handler + seeder to populate mock data.
  • Wired Reserved IP mocks/seeders into the baseline CRUD preset and DevTools seed list.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/manager/src/mocks/types.ts Adds “Reserved IPs” to CRUD groups/IDs and adds reservedIPs to MockState.
packages/manager/src/mocks/presets/crud/seeds/networking.ts Adds reservedIPSeeder using reservedIPsFactory and IndexedDB seed state.
packages/manager/src/mocks/presets/crud/seeds/index.ts Registers reservedIPSeeder in dbSeeders.
packages/manager/src/mocks/presets/crud/networking.ts Adds reservedIPsCrudPreset to expose Reserved IP handlers in CRUD preset.
packages/manager/src/mocks/presets/crud/handlers/networking.ts Adds MSW GET handler for /v4beta/networking/reserved/ips.
packages/manager/src/mocks/presets/baseline/crud.ts Includes networking and reserved IP handlers in the baseline CRUD preset.
packages/manager/src/mocks/mockState.ts Initializes reservedIPs: [] in the empty mock store.
packages/manager/src/features/ReservedIps/ReservedIpsLanding/ReservedIpsLandingTable.tsx New table component rendering Reserved IPs list with sorting + pagination.
packages/manager/src/features/ReservedIps/ReservedIpsLanding/ReservedIpsLandingRow.tsx New row renderer with assigned-entity link logic and tag overflow handling.
packages/manager/src/features/ReservedIps/ReservedIpsLanding/ReservedIpsLanding.tsx Hooks up queries/pagination/sorting and renders empty/loading/error states.
packages/manager/src/features/ReservedIps/ReservedIpsLanding/ReservedIpsActionMenu.tsx Adds action menu skeleton for Edit/Unreserve actions.
packages/manager/src/factories/networking.ts Adds reservedIPsFactory seed data for Reserved IPs (regions/tags/assigned entities).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

request,
});
}
),
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reserved IP MSW support currently only mocks the GET list endpoint. If the landing screen’s action menu / create button is later wired to reserveIP, updateReservedIP, or unReserveIP, those requests will bypass MSW (or fail) because there are no handlers for POST /networking/reserved/ips, PUT /networking/reserved/ips/:address, or DELETE /networking/reserved/ips/:address. Implement those handlers here (and include them in the preset) to fulfill the intended CRUD mock behavior.

Suggested change
),
),
http.post(
'*/v4beta/networking/reserved/ips',
async ({
request,
}): Promise<StrictResponse<APIErrorResponse | IPAddress>> => {
const payload = await request.clone().json();
const reservedIP = ipAddressFactory.build({
...payload,
});
await mswDB.add('reservedIPs', reservedIP, mockState);
return makeResponse(reservedIP);
}
),
http.put(
'*/v4beta/networking/reserved/ips/:address',
async ({
params,
request,
}): Promise<StrictResponse<APIErrorResponse | IPAddress>> => {
const reservedIPs = await mswDB.getAll('reservedIPs');
const existing = reservedIPs?.find(
({ address }) => address === params.address
);
if (!existing) {
return makeNotFoundResponse();
}
const payload = await request.clone().json();
const updatedReservedIP: IPAddress = {
...existing,
...payload,
};
await mswDB.add('reservedIPs', updatedReservedIP, mockState);
return makeResponse(updatedReservedIP);
}
),
http.delete(
'*/v4beta/networking/reserved/ips/:address',
async ({
params,
}): Promise<StrictResponse<APIErrorResponse | {}>> => {
const reservedIPs = await mswDB.getAll('reservedIPs');
const existing = reservedIPs?.find(
({ address }) => address === params.address
);
if (!existing) {
return makeNotFoundResponse();
}
await mswDB.delete('reservedIPs', existing.address, mockState);
return makeResponse({});
}
),

Copilot uses AI. Check for mistakes.
@tanushree-akamai tanushree-akamai force-pushed the feature/UIE-10430-ReservedIPs-Landing-screen branch from 4aba464 to e90983d Compare March 31, 2026 17:03
@linode-gh-bot
Copy link
Copy Markdown
Collaborator

Cloud Manager UI test results

🔺 1 failing test on test run #3 ↗︎

❌ Failing✅ Passing↪️ Skipped🕐 Duration
1 Failing887 Passing11 Skipped40m 43s

Details

Failing Tests
SpecTest
object-storage-objects-multicluster.spec.tsCloud Manager Cypress Tests→Object Storage Multicluster objects » can upload, access, and delete objects

Troubleshooting

Use this command to re-run the failing tests:

pnpm cy:run -s "cypress/e2e/core/objectStorageMulticluster/object-storage-objects-multicluster.spec.ts"

Copy link
Copy Markdown
Contributor

@grevanak-akamai grevanak-akamai Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let’s get figma screens for mobile view. Currently horizontal scroll is applying in mobile view. I think we will have to hide few columns in mobile view.

)}
</TableCell>
<TableCell>{regionLabel}</TableCell>
<TableCell>{tags?.length > 0 ? <TagsList tags={tags} /> : ''}</TableCell>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In mobile view, with more tags, action menu is overlapped by tags

* Displays up to 3 non-clickable tag chips, with a "+N" ShowMore popover
* for any overflow tags.
*/
const MAX_VISIBLE_TAGS = 3;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we limit this to 2? If the tag is long, then accommodating 3 tags need not be required.


const mockQueryReturn = vi.hoisted(() =>
vi.fn().mockReturnValue({
data: undefined,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null

routeTree,
});

expect(getByText('Reserve an IP Address')).toBeVisible();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This button is shown even when there are IPs to show in the table. So let's look for text within empty state.

});

it('renders the table when reserved IPs are returned', () => {
mockQueryReturn.mockReturnValue({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could use reservedIPsFactory to generate list instead of hardcoding it here.

/>
);

expect(queryByTestId('show-more')).not.toBeInTheDocument();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When there are no tags, looking for "Show more" doesn't makes sense. So let's look for empty string instead.

);
};

const StyledTagChip = styled(Chip, {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See if we can use Badge web component instead of chip here.


return (
<>
<LandingHeader
Copy link
Copy Markdown
Contributor

@grevanak-akamai grevanak-akamai Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to show docs link before the create button. Placeholder URL would be "https://techdocs.akamai.com/cloud-computing/update/docs/reserved-ips"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should be the default sorting for the table? Should it be by IP Address or by region? Also sort icon is shown only on hover for IP address. Is that the expected behavior?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Review

Development

Successfully merging this pull request may close these issues.

4 participants