Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions packages/bruno-app/src/components/RequestTabPanel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import EnvironmentSettings from 'components/Environments/EnvironmentSettings';
import GlobalEnvironmentSettings from 'components/Environments/GlobalEnvironmentSettings';
import OpenAPISyncTab from 'components/OpenAPISyncTab';
import OpenAPISpecTab from 'components/OpenAPISpecTab';
import Spinner from 'components/Spinner';

const MIN_LEFT_PANE_WIDTH = 300;
const MIN_RIGHT_PANE_WIDTH = 490;
Expand Down Expand Up @@ -176,6 +177,14 @@ const RequestTabPanel = () => {
return <div></div>;
}

if (!activeWorkspace?.scratchCollectionUid) {
return (
<div className="w-full h-full flex items-center justify-center">
<Spinner size="lg" />
</div>
);
}
Comment on lines +180 to +186
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't use scratchCollectionUid absence as the loading signal.

mountScratchCollection() can return null in packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js:986-1049, and switchWorkspace() still continues in packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js:347-398. In that path, Line 180 becomes a permanent spinner, and it also blocks tabs like preferences, global-environment-settings, and workspace tabs that do not depend on the scratch collection at all. Please key this off an explicit workspace-loading flag, or move the guard below the branches that can render without scratchCollectionUid.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-app/src/components/RequestTabPanel/index.js` around lines 180
- 186, RequestTabPanel is using the absence of
activeWorkspace?.scratchCollectionUid to show a loading spinner which can
permanently block rendering when mountScratchCollection() returns null (and
switchWorkspace() continues); change the guard so that rendering is keyed off an
explicit workspace-loading flag (e.g., workspaceLoading from the workspace slice
or the action that calls mountScratchCollection/switchWorkspace) or move the
scratchCollectionUid check below the branches that render tabs which do not
depend on the scratch collection (for example the "preferences",
"global-environment-settings", and workspace tabs). Specifically, in
RequestTabPanel replace the current top-level check on
activeWorkspace?.scratchCollectionUid with either (a) a check for a dedicated
loading boolean provided by the workspaces reducer/actions (consume
workspaceLoading) before showing the spinner, or (b) relocate the
scratchCollectionUid-dependent guard to only wrap components that need it,
leaving tab branches that don't depend on scratchCollectionUid to render
normally; reference mountScratchCollection, switchWorkspace, activeWorkspace,
scratchCollectionUid and the RequestTabPanel component to locate the code to
change.


if (!activeTabUid || !focusedTab) {
return <div className="pb-4 px-4">An error occurred!</div>;
}
Expand Down
67 changes: 58 additions & 9 deletions packages/bruno-app/src/components/Spinner/StyledWrapper.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,64 @@
import styled from 'styled-components';
import styled, { keyframes } from 'styled-components';

const spin = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;

const sizeStyles = {
xs: `
.spinner {
width: 0.75rem;
height: 0.75rem;
}
`,
sm: `
.spinner {
width: 1rem;
height: 1rem;
}
`,
md: `
.spinner {
width: 1.25rem;
height: 1.25rem;
}
`,
lg: `
.spinner {
width: 1.5rem;
height: 1.5rem;
}
`,
xl: `
.spinner {
width: 2rem;
height: 2rem;
}
`
};

const StyledWrapper = styled.div`
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
color: ${(props) => props.theme.brand};

${(props) => sizeStyles[props.$size] || sizeStyles.md}

.spinner {
display: inline-block;
width: 2rem;
height: 2rem;
vertical-align: text-bottom;
border: 0.25em solid currentColor;
border-right-color: transparent;
border-radius: 50%;
animation: spinner-border 0.75s linear infinite;
display: inline-flex;
animation: ${spin} 0.75s linear infinite;
}

.spinner-text {
font-size: 0.875rem;
color: inherit;
}
`;

Expand Down
36 changes: 31 additions & 5 deletions packages/bruno-app/src/components/Spinner/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
import React from 'react';
import StyledWrapper from './StyledWrapper';

// Todo: Size, Color config support
const Spinner = ({ size, color, children }) => {
const Spinner = ({ size = 'md', children }) => {
const sizeMap = {
xs: 12,
sm: 16,
md: 20,
lg: 24,
xl: 32
};

const spinnerSize = sizeMap[size] || 20;

return (
<StyledWrapper>
<div className="animate-spin"></div>
{children && <div>{children}</div>}
<StyledWrapper $size={size}>
<span className="spinner">
<svg
width={spinnerSize}
height={spinnerSize}
viewBox="0 0 24 24"
fill="none"
>
<circle
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="3"
strokeLinecap="round"
strokeDasharray="31.4 31.4"
/>
</svg>
</span>
{children && <div className="spinner-text">{children}</div>}
Comment on lines +4 to +35
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Expose status semantics for standalone spinners.

The new initial-load path in packages/bruno-app/src/components/RequestTabPanel/index.js:180-184 renders this with no text. Right now it's just an unlabeled SVG, so assistive tech gets no loading announcement. Please give the wrapper a status role/label and mark the SVG decorative.

Possible fix
-const Spinner = ({ size = 'md', children }) => {
+const Spinner = ({ size = 'md', children, label = 'Loading' }) => {
   const sizeMap = {
     xs: 12,
     sm: 16,
     md: 20,
     lg: 24,
     xl: 32
   };

   const spinnerSize = sizeMap[size] || 20;

   return (
-    <StyledWrapper $size={size}>
-      <span className="spinner">
+    <StyledWrapper
+      $size={size}
+      role="status"
+      aria-label={children ? undefined : label}
+    >
+      <span className="spinner" aria-hidden="true">
         <svg
           width={spinnerSize}
           height={spinnerSize}
           viewBox="0 0 24 24"
           fill="none"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const Spinner = ({ size = 'md', children }) => {
const sizeMap = {
xs: 12,
sm: 16,
md: 20,
lg: 24,
xl: 32
};
const spinnerSize = sizeMap[size] || 20;
return (
<StyledWrapper>
<div className="animate-spin"></div>
{children && <div>{children}</div>}
<StyledWrapper $size={size}>
<span className="spinner">
<svg
width={spinnerSize}
height={spinnerSize}
viewBox="0 0 24 24"
fill="none"
>
<circle
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="3"
strokeLinecap="round"
strokeDasharray="31.4 31.4"
/>
</svg>
</span>
{children && <div className="spinner-text">{children}</div>}
const Spinner = ({ size = 'md', children, label = 'Loading' }) => {
const sizeMap = {
xs: 12,
sm: 16,
md: 20,
lg: 24,
xl: 32
};
const spinnerSize = sizeMap[size] || 20;
return (
<StyledWrapper
$size={size}
role="status"
aria-label={children ? undefined : label}
>
<span className="spinner" aria-hidden="true">
<svg
width={spinnerSize}
height={spinnerSize}
viewBox="0 0 24 24"
fill="none"
>
<circle
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="3"
strokeLinecap="round"
strokeDasharray="31.4 31.4"
/>
</svg>
</span>
{children && <div className="spinner-text">{children}</div>}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-app/src/components/Spinner/index.js` around lines 4 - 35, The
Spinner component currently renders an unlabeled SVG; update the component
(Spinner, StyledWrapper and the span.spinner wrapper) to include role="status"
on the wrapper and provide an accessible label when no children are passed
(e.g., set aria-label="Loading" or aria-live if you prefer) so assistive tech
announces the loading state, and mark the SVG as purely decorative by adding
aria-hidden="true" (and focusable="false") on the svg element; ensure existing
visible children still render as the announcement instead of the default label.

</StyledWrapper>
);
};
Expand Down
Loading