diff --git a/assets/images/search/copilot-action.png b/assets/images/search/copilot-action.png deleted file mode 100644 index 83d42b5f2255..000000000000 Binary files a/assets/images/search/copilot-action.png and /dev/null differ diff --git a/data/reusables/copilot/repository-cust-instr-code-review.md b/data/reusables/copilot/repository-cust-instr-code-review.md deleted file mode 100644 index 763a7e68e216..000000000000 --- a/data/reusables/copilot/repository-cust-instr-code-review.md +++ /dev/null @@ -1 +0,0 @@ -For examples of repository custom instructions used to configure {% data variables.copilot.copilot_code-review_short %}, see [AUTOTITLE](/copilot/how-tos/agents/copilot-code-review/using-copilot-code-review?tool=webui#customizing-copilots-reviews-with-custom-instructions). diff --git a/data/reusables/organizations/ent-ownership-recommendation.md b/data/reusables/organizations/ent-ownership-recommendation.md deleted file mode 100644 index 436a04770aed..000000000000 --- a/data/reusables/organizations/ent-ownership-recommendation.md +++ /dev/null @@ -1 +0,0 @@ -If an enterprise only has one owner, the enterprise's resources can become inaccessible if the owner is unreachable. To protect access to your resources, we recommend that at least two people within the enterprise have the owner role. diff --git a/src/fixtures/tests/playwright-rendering.spec.ts b/src/fixtures/tests/playwright-rendering.spec.ts index 99bd97eb2684..10e82e2b3a67 100644 --- a/src/fixtures/tests/playwright-rendering.spec.ts +++ b/src/fixtures/tests/playwright-rendering.spec.ts @@ -115,7 +115,8 @@ test('open search, and select a general search article', async ({ page }) => { await page.getByTestId('overlay-search-input').fill('serve playwright') // Let new suggestions load - await page.waitForTimeout(1000) + const searchOverlay = page.getByTestId('general-autocomplete-suggestions') + await expect(searchOverlay.getByText('For Playwright')).toBeVisible() // Navigate to general search item, "For Playwright" await page.keyboard.press('ArrowDown') // Select the general search item, "For Playwright" diff --git a/src/frame/lib/frontmatter.ts b/src/frame/lib/frontmatter.ts index 6d26a951ef39..bd8267a44d38 100644 --- a/src/frame/lib/frontmatter.ts +++ b/src/frame/lib/frontmatter.ts @@ -405,6 +405,14 @@ export const schema: Schema = { maxItems: 9, description: 'Array of articles to feature in the carousel section', }, + // Included categories for article grid filtering + includedCategories: { + type: 'array', + items: { + type: 'string', + }, + description: 'Array of category names to include in the article grid dropdown filter', + }, }, } diff --git a/src/landings/components/bespoke/BespokeLanding.tsx b/src/landings/components/bespoke/BespokeLanding.tsx index 5dc38b35890a..a7d46ff8871a 100644 --- a/src/landings/components/bespoke/BespokeLanding.tsx +++ b/src/landings/components/bespoke/BespokeLanding.tsx @@ -6,7 +6,16 @@ import { UtmPreserver } from '@/frame/components/UtmPreserver' import { LandingCarousel } from '@/landings/components/shared/LandingCarousel' export const BespokeLanding = () => { - const { title, intro, heroImage, introLinks, tocItems, recommended } = useLandingContext() + const { + title, + intro, + heroImage, + introLinks, + tocItems, + recommended, + includedCategories, + landingType, + } = useLandingContext() return ( @@ -16,7 +25,11 @@ export const BespokeLanding = () => {
- +
diff --git a/src/landings/components/discovery/DiscoveryLanding.tsx b/src/landings/components/discovery/DiscoveryLanding.tsx index c8fe5a2d5974..6e090e5492e9 100644 --- a/src/landings/components/discovery/DiscoveryLanding.tsx +++ b/src/landings/components/discovery/DiscoveryLanding.tsx @@ -6,7 +6,16 @@ import { LandingCarousel } from '@/landings/components/shared/LandingCarousel' import { UtmPreserver } from '@/frame/components/UtmPreserver' export const DiscoveryLanding = () => { - const { title, intro, heroImage, introLinks, tocItems, recommended } = useLandingContext() + const { + title, + intro, + heroImage, + introLinks, + tocItems, + recommended, + includedCategories, + landingType, + } = useLandingContext() return ( @@ -15,7 +24,11 @@ export const DiscoveryLanding = () => {
- +
diff --git a/src/landings/components/shared/LandingArticleGridWithFilter.tsx b/src/landings/components/shared/LandingArticleGridWithFilter.tsx index 841f86bd81c7..e23ae00c90f3 100644 --- a/src/landings/components/shared/LandingArticleGridWithFilter.tsx +++ b/src/landings/components/shared/LandingArticleGridWithFilter.tsx @@ -6,11 +6,14 @@ import cx from 'classnames' import { Link } from '@/frame/components/Link' import { useTranslation } from '@/languages/components/useTranslation' import { ArticleCardItems, ChildTocItem, TocItem } from '@/landings/types' +import { LandingType } from '@/landings/context/LandingContext' import styles from './LandingArticleGridWithFilter.module.scss' type ArticleGridProps = { tocItems: TocItem[] + includedCategories?: string[] + landingType: LandingType } const ALL_CATEGORIES = 'all_categories' @@ -66,7 +69,7 @@ const useResponsiveArticlesPerPage = () => { return articlesPerPage } -export const ArticleGrid = ({ tocItems }: ArticleGridProps) => { +export const ArticleGrid = ({ tocItems, includedCategories, landingType }: ArticleGridProps) => { const { t } = useTranslation('product_landing') const [searchQuery, setSearchQuery] = useState('') const [selectedCategory, setSelectedCategory] = useState(ALL_CATEGORIES) @@ -83,21 +86,42 @@ export const ArticleGrid = ({ tocItems }: ArticleGridProps) => { [tocItems], ) + // Filter articles based on includedCategories for discovery landing pages + // For bespoke landing pages, show all articles regardless of includedCategories + const filteredArticlesByLandingType = useMemo(() => { + if (landingType === 'discovery' && includedCategories && includedCategories.length > 0) { + // For discovery pages, only include articles that have at least one matching category + return allArticles.filter((article) => { + if (!article.category || article.category.length === 0) return false + return article.category.some((cat) => + includedCategories.some((included) => included.toLowerCase() === cat.toLowerCase()), + ) + }) + } + // For bespoke pages or when includedCategories is empty/undefined, return all articles + return allArticles + }, [allArticles, includedCategories, landingType]) + // Reset to first page when articlesPerPage changes (screen size changes) useEffect(() => { setCurrentPage(1) }, [articlesPerPage]) - // Extract unique categories from the articles + // Extract unique categories from the filtered articles, filtering dropdown by includedCategories if provided const categories: string[] = [ ALL_CATEGORIES, - ...Array.from(new Set(allArticles.flatMap((item) => item.category || []))).sort((a, b) => - a.localeCompare(b), - ), + ...Array.from(new Set(filteredArticlesByLandingType.flatMap((item) => item.category || []))) + .filter((category) => { + if (!includedCategories || includedCategories.length === 0) return true + // Case-insensitive comparison for dropdown filtering + const lowerCategory = category.toLowerCase() + return includedCategories.some((included) => included.toLowerCase() === lowerCategory) + }) + .sort((a, b) => a.localeCompare(b)), ] const applyFilters = () => { - let results = allArticles + let results = filteredArticlesByLandingType if (searchQuery) { results = results.filter((token) => { diff --git a/src/landings/context/LandingContext.tsx b/src/landings/context/LandingContext.tsx index 1fa89ab55e72..e6dc490b38cb 100644 --- a/src/landings/context/LandingContext.tsx +++ b/src/landings/context/LandingContext.tsx @@ -26,6 +26,8 @@ export type LandingContextT = { introLinks?: Record // For journey landing pages journeyTracks?: JourneyTrack[] + // For article grid category filtering + includedCategories?: string[] } export const LandingContext = createContext(null) @@ -83,5 +85,6 @@ export const getLandingContextFromRequest = async ( introLinks: page.introLinks || null, recommended, journeyTracks, + includedCategories: page.includedCategories || [], } }