Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: [M3-8843] - StackScript Landing page #11215

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d23c1ec
initial refactoring
bnussman Nov 4, 2024
b281621
more progress
bnussman Nov 4, 2024
1958a60
a little but of clean up
bnussman Nov 4, 2024
0613c73
a little bit more progress
bnussman Nov 4, 2024
92dc6be
a few fixes
bnussman Nov 5, 2024
f7833e2
react queryify more
bnussman Nov 5, 2024
29ec2b1
more progress
bnussman Nov 5, 2024
f845a1e
parity with old ui
bnussman Nov 5, 2024
a826534
properly handle error state
bnussman Nov 5, 2024
5250dea
more progress
bnussman Nov 5, 2024
86dc0b9
fix typecheck
bnussman Nov 5, 2024
f67b727
get tests passing
bnussman Nov 6, 2024
7759dfb
add some testing
bnussman Nov 6, 2024
99a00cf
small fixes
bnussman Nov 6, 2024
0fad37e
unrelated bug fix
bnussman Nov 6, 2024
014b61c
unrelated bug fix
bnussman Nov 6, 2024
ef10652
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Nov 6, 2024
f024b20
get closer to parity with old code
bnussman Nov 6, 2024
d92c1a2
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Nov 6, 2024
74806f7
re-add span to fix cypress tests
bnussman Nov 6, 2024
17429bd
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Nov 8, 2024
24bfdca
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Nov 20, 2024
e48b61a
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Nov 21, 2024
340c627
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Nov 21, 2024
23a19bb
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Nov 25, 2024
ce90363
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Nov 25, 2024
9fceb98
use correct `Typography` import
bnussman Nov 25, 2024
a3a1d7f
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Nov 26, 2024
8946be2
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Nov 27, 2024
807cc5b
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Dec 2, 2024
6069548
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Jan 31, 2025
1d409bc
fix up e2e tests
bnussman Jan 31, 2025
07961ca
fix type errors
bnussman Jan 31, 2025
62298e7
Merge branch 'develop' into refactor/begin-react-queryifying-stackscrโ€ฆ
bnussman Feb 3, 2025
55a39a4
Added changeset: Refactor StackScripts landing page
bnussman Feb 3, 2025
ca91002
Apply suggestions from code review
bnussman-akamai Feb 4, 2025
ae07990
improve restricted user support
bnussman Feb 4, 2025
80c51ac
sort imports
bnussman Feb 4, 2025
f760f3a
update cypress test after removing crazy copy
bnussman Feb 4, 2025
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
@@ -0,0 +1,5 @@
---
"@linode/manager": Changed
---

Refactor StackScripts landing page ([#11215](https://github.com/linode/manager/pull/11215))
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { StackScript } from '@linode/api-v4';
import { Profile, getImages, getProfile } from '@linode/api-v4';
import { Profile, getProfile } from '@linode/api-v4';

import { stackScriptFactory } from 'src/factories';
import { isLinodeKubeImageId } from 'src/store/image/image.helpers';
import { formatDate } from 'src/utilities/formatDate';

import { authenticate } from 'support/api/authentication';
Expand All @@ -15,12 +14,9 @@ import {
} from 'support/intercepts/stackscripts';
import { ui } from 'support/ui';
import { cleanUp } from 'support/util/cleanup';
import { depaginate } from 'support/util/paginate';
import { randomLabel, randomString } from 'support/util/random';
import { chooseRegion } from 'support/util/regions';

import type { Image } from '@linode/api-v4';

const mockStackScripts: StackScript[] = [
stackScriptFactory.build({
id: 443929,
Expand Down Expand Up @@ -106,7 +102,10 @@ describe('Community Stackscripts integration tests', () => {
cy.visitWithLogin('/stackscripts/community');
cy.wait('@getStackScripts');

cy.get('[data-qa-stackscript-empty-msg="true"]').should('not.exist');
// Confirm that empty state is not shown.
cy.get('[data-qa-placeholder-container="resources-section"]').should(
'not.exist'
);
cy.findByText('Automate deployment scripts').should('not.exist');

cy.defer(getProfile, 'getting profile').then((profile: Profile) => {
Expand Down Expand Up @@ -138,7 +137,7 @@ describe('Community Stackscripts integration tests', () => {

// Search the corresponding community stack script
mockGetStackScripts([stackScript]).as('getFilteredStackScripts');
cy.get('[id="search-by-label,-username,-or-description"]')
cy.findByPlaceholderText('Search by Label, Username, or Description')
.click()
.type(`${stackScript.label}{enter}`);
cy.wait('@getFilteredStackScripts');
Expand Down Expand Up @@ -194,69 +193,39 @@ describe('Community Stackscripts integration tests', () => {
interceptGetStackScripts().as('getStackScripts');

// Fetch all public Images to later use while filtering StackScripts.
cy.defer(() =>
depaginate((page) => getImages({ page }, { is_public: true }))
).then((publicImages: Image[]) => {
cy.visitWithLogin('/stackscripts/community');
cy.wait('@getStackScripts');

// Confirm that empty state is not shown.
cy.get('[data-qa-stackscript-empty-msg="true"]').should('not.exist');
cy.findByText('Automate deployment scripts').should('not.exist');

// Confirm that scrolling to the bottom of the StackScripts list causes
// pagination to occur automatically. Perform this check 3 times.
for (let i = 0; i < 3; i += 1) {
cy.findByLabelText('List of StackScripts')
.should('be.visible')
.within(() => {
// Scroll to the bottom of the StackScripts list, confirm Cloud fetches StackScripts,
// then confirm that list updates with the new StackScripts shown.
cy.get('tr').last().scrollIntoView();
cy.wait('@getStackScripts').then((xhr) => {
const stackScripts = xhr.response?.body['data'] as
| StackScript[]
| undefined;

if (!stackScripts) {
throw new Error(
'Unexpected response received when fetching StackScripts'
);
}

// Cloud Manager hides certain StackScripts from the landing page (although they can
// still be found via search). It does this if either condition is met:
//
// - The StackScript is only compatible with deprecated Images
// - The StackScript is only compatible with LKE Images
//
// As a consequence, we can't use the API response directly to assert
// that content is shown in the list. We need to apply identical filters
// to the response first, then assert the content using that data.
const filteredStackScripts = stackScripts.filter(
(stackScript: StackScript) => {
const hasNonDeprecatedImages = stackScript.images.some(
(stackScriptImage) => {
return !!publicImages.find(
(publicImage) => publicImage.id === stackScriptImage
);
}
);

const usesKubeImage = stackScript.images.some(
(stackScriptImage) => isLinodeKubeImageId(stackScriptImage)
);
return hasNonDeprecatedImages && !usesKubeImage;
}
);
cy.visitWithLogin('/stackscripts/community');
cy.wait('@getStackScripts');

cy.contains(
`${filteredStackScripts[0].username} / ${filteredStackScripts[0].label}`
).should('be.visible');
});
});
}
});
// Confirm that empty state is not shown.
cy.get('[data-qa-placeholder-container="resources-section"]').should(
'not.exist'
);
cy.findByText('Automate deployment scripts').should('not.exist');

// Confirm that scrolling to the bottom of the StackScripts list causes
// pagination to occur automatically. Perform this check 3 times.
for (let i = 0; i < 3; i += 1) {
cy.findByLabelText('List of StackScripts')
.should('be.visible')
.within(() => {
// Scroll to the bottom of the StackScripts list, confirm Cloud fetches StackScripts,
// then confirm that list updates with the new StackScripts shown.
cy.get('tr').last().scrollIntoView();
cy.wait('@getStackScripts').then((xhr) => {
const stackScripts = xhr.response?.body['data'] as
| StackScript[]
| undefined;

if (!stackScripts) {
throw new Error(
'Unexpected response received when fetching StackScripts'
);
}

cy.contains(`${stackScripts[0].username} / ${stackScripts[0].label}`).should('be.visible');
});
});
}
});

/*
Expand All @@ -271,13 +240,16 @@ describe('Community Stackscripts integration tests', () => {
cy.visitWithLogin('/stackscripts/community');
cy.wait('@getStackScripts');

cy.get('[data-qa-stackscript-empty-msg="true"]').should('not.exist');
// Confirm that empty state is not shown.
cy.get('[data-qa-placeholder-container="resources-section"]').should(
'not.exist'
);
cy.findByText('Automate deployment scripts').should('not.exist');

cy.get('tr').then((value) => {
const rowCount = Cypress.$(value).length - 1; // Remove the table title row

cy.get('[id="search-by-label,-username,-or-description"]')
cy.findByPlaceholderText('Search by Label, Username, or Description')
.click()
.type(`${stackScript.label}{enter}`);
cy.get(`[data-qa-table-row="${stackScript.label}"]`).should('be.visible');
Expand Down Expand Up @@ -311,7 +283,7 @@ describe('Community Stackscripts integration tests', () => {
cy.visitWithLogin('/stackscripts/community');
cy.wait(['@getStackScripts', '@getPreferences']);

cy.get('[id="search-by-label,-username,-or-description"]')
cy.findByPlaceholderText('Search by Label, Username, or Description')
.click()
.type(`${stackScriptName}{enter}`);
cy.get(`[data-qa-table-row="${stackScriptName}"]`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ describe('Display stackscripts', () => {
cy.wait('@getStackScripts');

cy.findByText('Automate deployment scripts').should('be.visible');
cy.get('[data-qa-stackscript-empty-msg="true"]')

cy.get('[data-qa-placeholder-container="resources-section"]')
.should('be.visible')
.within(() => {
ui.button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ describe('Update stackscripts', () => {
.should('be.visible')
.click();
ui.dialog
.findByTitle('Woah, just a word of caution...')
.findByTitle(`Make StackScript ${stackScripts[0].label} Public?`)
.should('be.visible')
.within(() => {
ui.button.findByTitle('Cancel').should('be.visible').click();
Expand Down Expand Up @@ -262,11 +262,11 @@ describe('Update stackscripts', () => {
'mockGetStackScripts'
);
ui.dialog
.findByTitle('Woah, just a word of caution...')
.findByTitle(`Make StackScript ${stackScripts[0].label} Public?`)
.should('be.visible')
.within(() => {
ui.button
.findByTitle('Yes, make me a star!')
.findByTitle('Confirm')
.should('be.visible')
.click();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getAPIFilterFromQuery } from '@linode/search';
import { Typography } from '@linode/ui';
import {
Box,
Button,
Expand All @@ -17,7 +16,6 @@ import { useController, useFormContext } from 'react-hook-form';
import { Waypoint } from 'react-waypoint';
import { debounce } from 'throttle-debounce';

import { Code } from 'src/components/Code/Code';
import { Table } from 'src/components/Table';
import { TableBody } from 'src/components/TableBody';
import { TableCell } from 'src/components/TableCell/TableCell';
Expand All @@ -27,6 +25,7 @@ import { TableRowEmpty } from 'src/components/TableRowEmpty/TableRowEmpty';
import { TableRowError } from 'src/components/TableRowError/TableRowError';
import { TableRowLoading } from 'src/components/TableRowLoading/TableRowLoading';
import { TableSortCell } from 'src/components/TableSortCell';
import { StackScriptSearchHelperText } from 'src/features/StackScripts/Partials/StackScriptSearchHelperText';
import { useOrder } from 'src/hooks/useOrder';
import {
useStackScriptQuery,
Expand Down Expand Up @@ -176,36 +175,12 @@ export const StackScriptSelectionList = ({ type }: Props) => {
</InputAdornment>
),
}}
tooltipText={
<Stack spacing={1}>
<Typography>
You can search for a specific item by prepending your search term
with "username:", "label:", or "description:".
</Typography>
<Box>
<Typography fontFamily={(theme) => theme.font.bold}>
Examples
</Typography>
<Typography fontSize="0.8rem">
<Code>username: linode</Code>
</Typography>
<Typography fontSize="0.8rem">
<Code>label: sql</Code>
</Typography>
<Typography fontSize="0.8rem">
<Code>description: "ubuntu server"</Code>
</Typography>
<Typography fontSize="0.8rem">
<Code>label: sql or label: php</Code>
</Typography>
</Box>
</Stack>
}
hideLabel
label="Search"
onChange={debounce(400, (e) => setQuery(e.target.value))}
placeholder="Search StackScripts"
spellCheck={false}
tooltipText={<StackScriptSearchHelperText />}
tooltipWidth={300}
value={query}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React from 'react';
import { InlineMenuAction } from 'src/components/InlineMenuAction/InlineMenuAction';
import { TableCell } from 'src/components/TableCell';
import { TableRow } from 'src/components/TableRow';
import { isLKEStackScript } from 'src/features/StackScripts/stackScriptUtils';
import { truncate } from 'src/utilities/truncate';

import type { StackScript } from '@linode/api-v4';
Expand All @@ -20,9 +21,9 @@ interface Props {
export const StackScriptSelectionRow = (props: Props) => {
const { disabled, isSelected, onOpenDetails, onSelect, stackscript } = props;

// Never show LKE StackScripts. We try to hide these from the user, even though they
// Never show LKE StackScripts. We try to hide these from the user even though they
// are returned by the API.
if (stackscript.username.startsWith('lke-service-account-')) {
if (isLKEStackScript(stackscript)) {
return null;
}

Expand Down
Loading