Skip to content

CONSOLE-5300: Parallelize context detection to reduce initial load time#16477

Merged
openshift-merge-bot[bot] merged 2 commits into
openshift:mainfrom
logonoff:CONSOLE-5300-skeleton
May 22, 2026
Merged

CONSOLE-5300: Parallelize context detection to reduce initial load time#16477
openshift-merge-bot[bot] merged 2 commits into
openshift:mainfrom
logonoff:CONSOLE-5300-skeleton

Conversation

@logonoff
Copy link
Copy Markdown
Member

@logonoff logonoff commented May 20, 2026

Analysis / Root cause:

The console's initial load path runs context detection sequentially: AppWithExtensions blocks until plugin extensions resolve, then DetectPerspective blocks until perspective user preferences load, then DetectNamespace blocks until namespace resolution completes (including K8s API calls). Each stage must fully complete before the next can begin, making the total startup time the sum of all operations rather than the maximum.

Solution description:

Consolidate DetectPerspective, DetectNamespace, DetectLanguage, and AppWithExtensions into a single DetectContext component that calls all initialization hooks at the same React component level. This means all async work (user preference loads, K8s API calls, extension resolution) fires in parallel on mount, reducing startup time from T_extensions + T_perspective + T_namespace to max(T_all).

Key changes:

  • New detect-context/ directory: Merges detect-perspective/, detect-namespace/, and detect-language/ into one location
  • DetectContext component: Runs all detection and extension resolution hooks at the same level, provides PerspectiveContext, NamespaceContext, and resolved plugin context provider extensions
  • PageSkeleton component: Replaces bare LoadingBox spinners with an empty PatternFly Page layout (masthead + sidebar + content area) during initialization, preventing layout shift
  • Dynamic blame tracking: The skeleton's blame label dynamically lists which subsystems are still loading (e.g., "Perspective, Namespace, Reducers")
  • ContextProviderExtensionWrapper: Reads resolved plugin context providers from an internal context and wraps children, preserving the original nesting order (inside ModalProvider / OverlayProvider) to avoid breaking dynamic plugins
  • AppWithExtensions removed: Extension resolution moved into DetectContext, App renders directly from AppRouter
  • app.tsx simplified: Removed EnhancedProvider, extension-related imports, and the contextProviderExtensions prop from App

Screenshots / screen recording:
After is first

Screen.Recording.2026-05-20.at.5.13.16.PM.mov

Test setup:
No special setup required. The ?crp-blame query parameter can be used to see which subsystems are loading in the skeleton.

Test cases:

  • Verify the console loads correctly with the PageSkeleton visible briefly during initialization
  • Verify perspective switching works (URL ?perspective=dev parameter)
  • Verify namespace detection and switching works
  • Verify language preferences are applied
  • Verify dynamic plugin context providers still function correctly
  • Verify the skeleton shows proper page layout (masthead, sidebar, content area)
  • Verify the skeleton is not shown to unauthenticated users

Browser conformance:

  • Chrome
  • Firefox
  • Safari (or Epiphany on Linux)

Additional info:

The plugin context provider nesting order is preserved — plugin-provided contexts remain inside ModalProvider > OverlayProvider, matching the original hierarchy. This ensures no breaking changes for dynamic plugins that depend on modal or overlay APIs from within their context providers.

Reviewers and assignees:

Summary by CodeRabbit

Release Notes

  • New Features

    • Added skeleton loading indicator during app initialization and perspective switching.
  • Refactor

    • Streamlined app startup by consolidating perspective, namespace, and language detection logic into a unified initialization process.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label May 20, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented May 20, 2026

@logonoff: This pull request references CONSOLE-5300 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Analysis / Root cause:

The console's initial load path runs context detection sequentially: AppWithExtensions blocks until plugin extensions resolve, then DetectPerspective blocks until perspective user preferences load, then DetectNamespace blocks until namespace resolution completes (including K8s API calls). Each stage must fully complete before the next can begin, making the total startup time the sum of all operations rather than the maximum.

Solution description:

Consolidate DetectPerspective, DetectNamespace, DetectLanguage, and AppWithExtensions into a single DetectContext component that calls all initialization hooks at the same React component level. This means all async work (user preference loads, K8s API calls, extension resolution) fires in parallel on mount, reducing startup time from T_extensions + T_perspective + T_namespace to max(T_all).

Key changes:

  • New detect-context/ directory: Merges detect-perspective/, detect-namespace/, and detect-language/ into one location
  • DetectContext component: Runs all detection and extension resolution hooks at the same level, provides PerspectiveContext, NamespaceContext, and resolved plugin context provider extensions
  • PageSkeleton component: Replaces bare LoadingBox spinners with an empty PatternFly Page layout (masthead + sidebar + content area) during initialization, preventing layout shift
  • Dynamic blame tracking: The skeleton's blame label dynamically lists which subsystems are still loading (e.g., "Perspective, Namespace, Reducers")
  • ContextProviderExtensionWrapper: Reads resolved plugin context providers from an internal context and wraps children, preserving the original nesting order (inside ModalProvider / OverlayProvider) to avoid breaking dynamic plugins
  • AppWithExtensions removed: Extension resolution moved into DetectContext, App renders directly from AppRouter
  • app.tsx simplified: Removed EnhancedProvider, extension-related imports, and the contextProviderExtensions prop from App

Screenshots / screen recording:

Test setup:
No special setup required. The ?crp-blame query parameter can be used to see which subsystems are loading in the skeleton.

Test cases:

  • Verify the console loads correctly with the PageSkeleton visible briefly during initialization
  • Verify perspective switching works (URL ?perspective=dev parameter)
  • Verify namespace detection and switching works
  • Verify language preferences are applied
  • Verify dynamic plugin context providers still function correctly
  • Verify the skeleton shows proper page layout (masthead, sidebar, content area)
  • Run existing test suite: cd frontend && yarn test packages/console-app/src/components/detect-context/

Browser conformance:

  • Chrome
  • Firefox
  • Safari (or Epiphany on Linux)

Additional info:

The plugin context provider nesting order is preserved — plugin-provided contexts remain inside ModalProvider > OverlayProvider, matching the original hierarchy. This ensures no breaking changes for dynamic plugins that depend on modal or overlay APIs from within their context providers.

Reviewers and assignees:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci Bot requested review from cajieh and rhamilto May 20, 2026 21:06
@openshift-ci openshift-ci Bot added component/core Related to console core functionality component/sdk Related to console-plugin-sdk approved Indicates a PR has been approved by an approver from all required OWNERS files. component/shared Related to console-shared plugin-api-changed Categorizes a PR as containing plugin API changes labels May 20, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

📝 Walkthrough

Walkthrough

This PR consolidates three separate asynchronous detection components—perspective, namespace, and language—into a single DetectContext orchestration that coordinates their resolution, applies Redux extensions, and manages a unified loading state. The app composition is refactored to wrap the page content in DetectContext and ContextProviderExtensionWrapper instead of the previous AppWithExtensions pattern. Module paths are updated to reflect the relocated detect-context directory, and supporting styles are added for the new PageSkeleton loading indicator.

🚥 Pre-merge checks | ✅ 12
✅ Passed checks (12 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly and concisely describes the main architectural refactoring—parallelizing context detection to improve initial load time—with proper Jira prefix (CONSOLE-5300).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed No Go files or Ginkgo tests in PR; only frontend TypeScript/React/SCSS changes with Jest tests. Check is not applicable.
Test Structure And Quality ✅ Passed This PR contains only Jest/React test code, no Ginkgo tests. The custom check applies only to Ginkgo test code, making it not applicable to this frontend React/TypeScript pull request.
Microshift Test Compatibility ✅ Passed This PR adds no Ginkgo e2e tests. The custom check applies only to new Ginkgo e2e tests; this PR modifies frontend React/TypeScript code and adds a Jest unit test, not e2e tests.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No Ginkgo e2e tests added in this PR. All changes are frontend refactoring (React/TypeScript) with Jest unit tests only. SNO compatibility check does not apply.
Topology-Aware Scheduling Compatibility ✅ Passed PR modifies only frontend React/TypeScript code and stylesheets—no Kubernetes manifests, operator code, controllers, or scheduling constraints present. Topology-aware check not applicable.
Ote Binary Stdout Contract ✅ Passed PR contains only frontend React/TypeScript, SCSS, and JSON changes—no Go test code or process-level code that could violate OTE binary stdout contract. Check is not applicable.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed This PR contains only frontend TypeScript/SCSS changes (React components, Jest tests, styling). No Ginkgo Go e2e tests are added. The custom check does not apply.
Description check ✅ Passed PR description comprehensively covers analysis, solution, test cases, and design rationale with appropriate technical depth for architectural consolidation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@frontend/packages/console-app/src/components/detect-context/DetectContext.tsx`:
- Around line 108-109: The readiness gate currently ignores the
preferred-language loading state so the app can render before the locale is
applied; update the readiness logic to include preferredLanguageLoaded and defer
calling useLanguage until that flag is true. Specifically, incorporate
preferredLanguageLoaded into the ready/pending evaluation used in DetectContext
(where usePreferredLanguage() is called) and wrap the
useLanguage(preferredLanguage, preferredLanguageLoaded) invocation so it only
runs when preferredLanguageLoaded is true (and ensure any effects depending on
ready/pending also account for preferredLanguageLoaded). Apply the same change
to the other occurrence in this file that mirrors lines 133–146 so both language
hooks participate in the startup readiness gate.
- Around line 128-130: The call to applyReduxExtensions (which calls
store.replaceReducer) must not run during render; move the conditional block
that currently runs when reducersResolved into a React effect by creating a
useEffect hook that watches [reducersResolved, reduxReducerExtensions] and
invokes applyReduxExtensions(reduxReducerExtensions) only when reducersResolved
is true; ensure you reference the existing symbols (reducersResolved,
reduxReducerExtensions, applyReduxExtensions) and remove the direct call from
render so reducer replacement only happens inside the effect.
- Around line 82-89: The provider nesting is reversed because
contextProviderExtensions is reduced left-to-right; change the call to use
reduceRight so the original extension order is preserved (first extension
becomes the outermost). Specifically, replace the use of
contextProviderExtensions.reduce(...) that wraps children with <EnhancedProvider
key={e.uid} {...e.properties}> with contextProviderExtensions.reduceRight(...),
keeping the same accumulator structure and children variable, so
EnhancedProvider and keys remain unchanged.

In `@frontend/public/style/_layout.scss`:
- Line 1: After switching to "`@use` './vars';" the Sass variables $screen-md-min
and $screen-sm-max are no longer global, so update all references in
_layout.scss to use the module namespace (vars.$screen-md-min and
vars.$screen-sm-max) wherever those unprefixed breakpoint variables are used
(eg. in media queries or mixin calls) so compilation succeeds with the vars
module.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 414a7fe7-b6fe-42ca-b20d-075857b60acd

📥 Commits

Reviewing files that changed from the base of the PR and between 93da815 and 15d25b5.

📒 Files selected for processing (23)
  • frontend/packages/console-app/package.json
  • frontend/packages/console-app/src/components/detect-context/DetectContext.tsx
  • frontend/packages/console-app/src/components/detect-context/PerspectiveConfiguration.tsx
  • frontend/packages/console-app/src/components/detect-context/PerspectiveDetector.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/PerspectiveDetector.spec.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/checkNamespaceExists.spec.ts
  • frontend/packages/console-app/src/components/detect-context/__tests__/getValueForNamespace.spec.ts
  • frontend/packages/console-app/src/components/detect-context/__tests__/namespace.spec.ts
  • frontend/packages/console-app/src/components/detect-context/__tests__/useValuesForPerspectiveContext.spec.ts
  • frontend/packages/console-app/src/components/detect-context/checkNamespaceExists.ts
  • frontend/packages/console-app/src/components/detect-context/getValueForNamespace.ts
  • frontend/packages/console-app/src/components/detect-context/namespace.ts
  • frontend/packages/console-app/src/components/detect-context/useLastNamespace.ts
  • frontend/packages/console-app/src/components/detect-context/useLastPerspective.ts
  • frontend/packages/console-app/src/components/detect-context/useValuesForPerspectiveContext.ts
  • frontend/packages/console-app/src/components/detect-language/DetectLanguage.tsx
  • frontend/packages/console-app/src/components/detect-namespace/DetectNamespace.tsx
  • frontend/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx
  • frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts
  • frontend/packages/console-shared/src/hooks/useActiveNamespace.ts
  • frontend/public/components/app.tsx
  • frontend/public/style/_layout.scss
💤 Files with no reviewable changes (3)
  • frontend/packages/console-app/src/components/detect-namespace/DetectNamespace.tsx
  • frontend/packages/console-app/src/components/detect-language/DetectLanguage.tsx
  • frontend/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (15)
frontend/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/**/*.{ts,tsx,js,jsx}: Never import from package index files (e.g., @console/shared) in new code, as they can create circular dependencies and slow builds. Import from specific file paths instead.
Do not use backticks in t() calls for i18n strings, as the i18n parser cannot extract keys from template literals. Use single or double quotes instead.

Files:

  • frontend/packages/console-shared/src/hooks/useActiveNamespace.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts
  • frontend/packages/console-app/src/components/detect-context/DetectContext.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
  • frontend/public/components/app.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import from deprecated packages or use code with the @deprecated TSdoc tag in new code.

**/*.{ts,tsx}: Use React functional components with hooks instead of class components
State Management: Use React hooks and Context API (migrating away from legacy Redux/Immutable.js)
Hooks: Use existing hooks from console-shared when possible (useK8sWatchResource, useUserSettings, etc.)
API calls: Use k8s resource hooks for data fetching, consoleFetchJSON for HTTP requests
Extensions: Use console extension points for plugin integration
Types: Check existing types in console-shared before creating new ones
Dynamic Plugins: Use console extension points for plugin integration
Styling: Use SCSS modules co-located with components, PatternFly design system components, avoid any SCSS/CSS if possible
Accessibility: Follow WCAG 2.1 AA standards, use semantic HTML, ARIA labels where needed, ensure keyboard navigation, test with screen readers
i18n: Use useTranslation('namespace') hook with key format for translation keys
Error Handling: Use ErrorBoundary components and graceful degradation patterns
Optimize re-renders: Use useCallback for memoized callbacks to avoid function recreation every render
Optimize re-renders: Use useMemo for expensive computations to avoid recalculating on every render
Lazy loading: Use React.lazy() to lazy load heavy components
TypeScript type safety: Avoid using any type; suggest proper type definitions and verify null/undefined are handled properly
Type component props properly: Reuse existing component prop types instead of duplicating type definitions
Use proper hooks: Use specialized hooks like usePluginInfo for plugin data instead of generic data fetching patterns
Avoid deprecated components: Check for JSDoc @deprecated tags, import paths containing /deprecated, and DEPRECATED_ file name prefix before using components
Importing from barrel files and circular dependencies: Import directly from specific files instead...

Files:

  • frontend/packages/console-shared/src/hooks/useActiveNamespace.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts
  • frontend/packages/console-app/src/components/detect-context/DetectContext.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
  • frontend/public/components/app.tsx
frontend/**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Never use absolute URLs or paths in the console code. The console runs behind a proxy under an arbitrary path.

Files:

  • frontend/packages/console-shared/src/hooks/useActiveNamespace.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts
  • frontend/packages/console-app/package.json
  • frontend/packages/console-app/src/components/detect-context/DetectContext.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
  • frontend/public/components/app.tsx
frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

When writing code for static plugins, ensure that all $codeRef reference the corresponding extension type from the @console/dynamic-plugin-sdk package.

Files:

  • frontend/packages/console-shared/src/hooks/useActiveNamespace.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts
  • frontend/packages/console-app/src/components/detect-context/DetectContext.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
  • frontend/public/components/app.tsx
**/*.{tsx,ts}

📄 CodeRabbit inference engine (TESTING.md)

**/*.{tsx,ts}: Always use page.getByTestId('x') for Playwright selectors which queries [data-test="x"]. If a React element only has a legacy test attribute, add data-test to the element. Never remove legacy attributes
Prefer data-test attributes in Cypress selectors (e.g., cy.get('[data-test="create-deployment"]')) over brittle CSS/ARIA selectors

File Naming: PascalCase for components, kebab-case for utilities, *.spec.ts(x) for tests

Files:

  • frontend/packages/console-shared/src/hooks/useActiveNamespace.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts
  • frontend/packages/console-app/src/components/detect-context/DetectContext.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
  • frontend/public/components/app.tsx
**/*.{go,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (STYLEGUIDE.md)

Use lowercase dash-separated names for all files to avoid git issues with case-insensitive file systems

Files:

  • frontend/packages/console-shared/src/hooks/useActiveNamespace.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts
  • frontend/packages/console-app/src/components/detect-context/DetectContext.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
  • frontend/public/components/app.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (STYLEGUIDE.md)

**/*.{ts,tsx,js,jsx}: New code MUST be written in TypeScript, not JavaScript
Prefer functional programming patterns and immutable data structures
Run the linter and follow all rules defined in .eslintrc
Never use absolute paths in code - the app should be able to run behind a proxy under an arbitrary path

Files:

  • frontend/packages/console-shared/src/hooks/useActiveNamespace.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts
  • frontend/packages/console-app/src/components/detect-context/DetectContext.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
  • frontend/public/components/app.tsx
**/*.ts

📄 CodeRabbit inference engine (STYLEGUIDE.md)

Plugin SDK Changes: Any updates to console-dynamic-plugin-sdk should aim to maintain backward compatibility as it's a public API - use the plugin-api-review skill to vet changes for public API impact and ensure proper documentation updates

Files:

  • frontend/packages/console-shared/src/hooks/useActiveNamespace.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts
frontend/**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (README.md)

frontend/**/*.{js,ts,tsx}: Support only the latest versions of Edge, Chrome, Safari, and Firefox browsers; IE 11 and earlier are not supported
CSP violations should be automatically reported to telemetry by parsing dynamic plugin names from securitypolicyviolation events, with throttling to prevent duplicate reports within a day

Files:

  • frontend/packages/console-shared/src/hooks/useActiveNamespace.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts
  • frontend/packages/console-app/src/components/detect-context/DetectContext.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
  • frontend/public/components/app.tsx
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (INTERNATIONALIZATION.md)

For dynamic translation keys that cannot be parsed by i18next-parser (t(key), t('key' + id), t(key${id})), specify possible static values in comments for the parser to extract

Files:

  • frontend/packages/console-shared/src/hooks/useActiveNamespace.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/api/internal-api.ts
  • frontend/packages/console-app/src/components/detect-context/DetectContext.tsx
  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
  • frontend/public/components/app.tsx
**/__tests__/**/*.spec.tsx

📄 CodeRabbit inference engine (TESTING.md)

**/__tests__/**/*.spec.tsx: Unit tests must use Jest framework with @testing-library/react and @testing-library/jest-dom libraries for testing React components, hooks, and utilities
Test what users see and interact with - DO NOT test internal component state, private methods, props passed to child components, CSS class names/styles, or component structure
Use accessibility-first queries that match how screen readers and users interact with the UI
Always prefer role-based queries (e.g., getByRole) over generic selectors for semantic testing
Use reusable helper functions such as renderWithProviders and renderHookWithProviders from frontend/packages/console-shared/src/test-utils. Extract repetitive setup not covered by these helpers into custom functions if needed
Handle asynchronous updates with findBy* and waitFor in tests
Use proper TypeScript types for props, state, and mock data in unit tests
Structure tests following the Arrange-Act-Assert (AAA) pattern: Arrange (render component with mocks), Act (perform user actions), Assert (verify expected state)
Test files must be located in __tests__/ directory within the component directory, use the same name as the implementation file, and use .spec.tsx extension
When mocking, ALWAYS use ESM import statements at the top of the file - NEVER use require('react') or React.createElement() in mocks
Prefer jest.mock() for module mocks and jest.fn() for component mocks instead of jest.spyOn()
Keep mocks simple - return null, strings, or children directly. Use jest.fn(() => null) for simple component mocks, jest.fn(() => 'ComponentName') for mocks that display text, and jest.fn((props) => props.children) for wrapper components
Mock custom hooks with jest.fn() returning mock data
Clean up mocks with afterEach(() => { jest.restoreAllMocks(); })

Files:

  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (STYLEGUIDE.md)

Tests should follow a similar 'test tables' convention as used in Go where applicable

Files:

  • frontend/packages/console-app/src/components/detect-context/__tests__/DetectContext.spec.tsx
frontend/**/*.{scss,css}

📄 CodeRabbit inference engine (AGENTS.md)

Exhaust PatternFly component options before writing custom SCSS. When custom SCSS is necessary, use BEM naming convention with co- prefix.

Files:

  • frontend/public/style/_layout.scss
**/*.scss

📄 CodeRabbit inference engine (STYLEGUIDE.md)

**/*.scss: Use lowercase dash-separated names for all files to avoid git issues with case-insensitive file systems
When possible, avoid writing any custom SCSS/CSS and use PatternFly for all styling
Avoid element selectors when possible; class selectors are preferred
Scope all classes with a recognizable prefix to avoid collisions with imported CSS (this project uses co- by convention)
Class names should be all lowercase and dash-separated
All SCSS variables should be scoped within their component
Use BEM (Block Element Modifier) naming conventions

Files:

  • frontend/public/style/_layout.scss
**/_*.scss

📄 CodeRabbit inference engine (STYLEGUIDE.md)

All SCSS files should be prefixed with an underscore (eg _my-custom-file.scss)

Files:

  • frontend/public/style/_layout.scss

Comment thread frontend/packages/console-app/src/components/detect-context/DetectContext.tsx Outdated
Comment thread frontend/public/style/_layout.scss
@logonoff logonoff force-pushed the CONSOLE-5300-skeleton branch from 15d25b5 to 28d4ec6 Compare May 20, 2026 21:17
@logonoff
Copy link
Copy Markdown
Member Author

/label px-approved
/label docs-approved

no api changes
/label plugin-api-approved

@openshift-ci openshift-ci Bot added px-approved Signifies that Product Support has signed off on this PR docs-approved Signifies that Docs has signed off on this PR plugin-api-approved Indicates a PR with plugin API changes has been approved by an API reviewer labels May 20, 2026
@logonoff
Copy link
Copy Markdown
Member Author

/test all

* Runs perspective, namespace, language, and extension resolution hooks at the
* same level so their async work executes in parallel, then provides the
* resolved values via PerspectiveContext, NamespaceContext, and
* ContextProviderExtensionsContext.
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.

I think it would be helpful to provide an explicit bullet list of all kinds of detections performed by this component.

  • detect active perspective
  • detect active namespace
  • detect preferred language
  • resolve all ReduxReducer and ContextProvider extensions

@logonoff logonoff force-pushed the CONSOLE-5300-skeleton branch from 28d4ec6 to aad0384 Compare May 21, 2026 16:06
Consolidate DetectPerspective, DetectNamespace, DetectLanguage, and
AppWithExtensions into a single DetectContext component. Previously
these ran sequentially — namespace detection could not start until
perspective detection completed, and neither could start until
extension resolution finished. Now all hooks fire at the same React
component level, reducing load time from the sum of all operations
to the duration of the longest one.

- Merge detect-perspective/, detect-namespace/, and detect-language/
  into a single detect-context/ directory
- Replace bare LoadingBox spinners with a PageSkeleton that renders
  an empty PatternFly Page layout during initialization
- Dynamically track pending subsystems in the skeleton blame label
- Preserve plugin context provider nesting order to avoid breaking
  dynamic plugins

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@logonoff logonoff force-pushed the CONSOLE-5300-skeleton branch from aad0384 to f7aa632 Compare May 21, 2026 16:07
@vojtechszocs
Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label May 21, 2026
@logonoff
Copy link
Copy Markdown
Member Author

logonoff commented May 21, 2026

QA Verification Evidence

Details
Branch CONSOLE-5300-skeleton
Baseline main @ a163b3a25c
Candidate CONSOLE-5300-skeleton @ f7aa632be2
Verified 2026-05-21
Browser Playwright 1.60.0 / Chrome for Testing 148.0.7778.96 (playwright chromium v1223)
OS Darwin 25.5.0
Jira CONSOLE-5300

Verification Steps

# Route Action Status
1 / Navigate, wait for load pass
2 /?crp-blame Navigate, observe skeleton pass
3 /?perspective=dev Navigate, wait for load pass
4 /k8s/ns/default/pods Navigate, wait for load pass
5 /k8s/ns/openshift-console/deployments Navigate, wait for load pass
6 /k8s/cluster/projects Navigate, wait for load pass
7 /search?kind=ConfigMap Navigate, wait for load pass
8 / Load time measurement (10 runs) pass
Animated overview (click to expand)
Baseline Candidate
Step 1: Dashboard overview (pass)
Baseline (main) Candidate (CONSOLE-5300-skeleton)
Step 2: Skeleton with blame labels (pass)
Baseline (main) Candidate (CONSOLE-5300-skeleton)
Step 3: Developer perspective (pass)
Baseline (main) Candidate (CONSOLE-5300-skeleton)
Step 4: Pods list (default namespace) (pass)
Baseline (main) Candidate (CONSOLE-5300-skeleton)
Step 5: Deployments list (openshift-console) (pass)
Baseline (main) Candidate (CONSOLE-5300-skeleton)
Step 6: Projects page (pass)
Baseline (main) Candidate (CONSOLE-5300-skeleton)
Step 7: Search ConfigMaps (pass)
Baseline (main) Candidate (CONSOLE-5300-skeleton)

Step 8: Time-to-Content Benchmark

Measures time from navigation start (performance.now()) to first meaningful content render (document title changes from generic "Red Hat OpenShift" to route-specific title). Each run navigates from about:blank to /?perspective=admin. 10 runs per lane.

Raw measurements (click to expand)
Run Baseline (main) Candidate (CONSOLE-5300-skeleton)
1 4250 ms 2974 ms
2 2366 ms 2434 ms
3 3180 ms 3278 ms
4 3486 ms 2472 ms
5 2731 ms 2903 ms
6 3279 ms 2942 ms
7 3821 ms 2257 ms
8 3167 ms 3467 ms
9 2457 ms 3796 ms
10 3476 ms 2303 ms
Metric Baseline (main) Candidate (CONSOLE-5300-skeleton) Delta
Average 3221 ms 2883 ms -339 ms (-10.5%)
Median 3230 ms 2922 ms -307 ms (-9.5%)
Std Dev 588 ms 521 ms -67 ms
Min 2366 ms 2257 ms -109 ms
Max 4250 ms 3796 ms -454 ms

Note

The candidate shows a ~10% improvement in time-to-content across 10 runs (average and median). Both branches show high variance (~500-600ms stdev) typical of a local dev environment, but the improvement is consistent across all summary metrics. The PR's parallelization benefit would be more pronounced on production clusters where API latencies are higher and the sequential-to-parallel conversion eliminates compounding network round-trips.

Console Errors

Error Count Errors
Baseline 1 404 metal3.io/v1alpha1/provisionings (expected in dev)
Candidate 1 404 metal3.io/v1alpha1/provisionings (identical)

No new console errors introduced.


Warning

This verification was performed by an AI agent. Results may contain false positives or miss
regressions that require human judgment. Always review the screenshots manually before approving.

Automated QA verification by Claude Code

@openshift-ci openshift-ci Bot removed the lgtm Indicates that a PR is ready to be merged. label May 21, 2026
Fire a lightweight coFetch to /api/kubernetes/api at module load time,
before graphQLReady or DetectContext mount. If the user is not
authenticated, coFetch's 401 interceptor triggers authSvc.handle401()
and redirects to the login page immediately, preventing a flash of the
PageSkeleton for unauthenticated users.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@logonoff logonoff force-pushed the CONSOLE-5300-skeleton branch from 2deb594 to 66779e7 Compare May 21, 2026 19:14
@logonoff
Copy link
Copy Markdown
Member Author

/verified by claude

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label May 21, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@logonoff: This PR has been marked as verified by claude.

Details

In response to this:

/verified by claude

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@vojtechszocs
Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label May 21, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 21, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: logonoff, vojtechszocs

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 21, 2026

@logonoff: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-merge-bot openshift-merge-bot Bot merged commit bc1c232 into openshift:main May 22, 2026
9 checks passed
@logonoff logonoff deleted the CONSOLE-5300-skeleton branch May 22, 2026 02:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. component/core Related to console core functionality component/sdk Related to console-plugin-sdk component/shared Related to console-shared docs-approved Signifies that Docs has signed off on this PR jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. plugin-api-approved Indicates a PR with plugin API changes has been approved by an API reviewer plugin-api-changed Categorizes a PR as containing plugin API changes px-approved Signifies that Product Support has signed off on this PR verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants