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

[Research] OUI usage audit in the expressions plugin #4122

Open
BSFishy opened this issue May 23, 2023 · 2 comments
Open

[Research] OUI usage audit in the expressions plugin #4122

BSFishy opened this issue May 23, 2023 · 2 comments
Labels
OUI compliance Issues and PRs to maximize OUI usage and remove style and component hacks OUI Issues that require migration to OUI

Comments

@BSFishy
Copy link
Contributor

BSFishy commented May 23, 2023

Audit

The expressions plugin has 2 Sass files: index.scss and _expression_renderer.scss. Index just includes the other one, which defines a few classes:

.expExpressionRenderer {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.expExpressionRenderer__expression {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: auto;
position: relative;
flex: 1 1 100%;
}
.expExpressionRenderer-isEmpty,
.expExpressionRenderer-hasError {
.expExpressionRenderer__expression {
display: none;
}
}

Related React code:

const classes = classNames('expExpressionRenderer', className, {
'expExpressionRenderer-isEmpty': state.isEmpty,
'expExpressionRenderer-hasError': !!state.error,
});
const expressionStyles: React.CSSProperties = {};
if (padding) {
expressionStyles.padding = theme.paddingSizes[padding];
}
return (
<div {...dataAttrs} className={classes}>
{state.isEmpty && <EuiLoadingChart mono size="l" />}
{state.isLoading && <EuiProgress size="xs" color="accent" position="absolute" />}
{!state.isLoading &&
state.error &&
renderError &&
renderError(state.error.message, state.error)}
<div
className="expExpressionRenderer__expression"
style={expressionStyles}
ref={mountpoint}
/>
</div>
);

For the most part, these can be replaced with EuiPanel, EuiFlexGroup, and EuiFlexItem. However, there are a few misses from OUI:

  1. OUI doesn't provide any way to do display: none. It is important we apply this value because we need to get a ref to the element this is applied to while data is loading.
  2. OUI doesn't provide anything for overflow: auto. Not sure how necessary this is, but it might be nice to have parity with the older version. I think this might be useful when the parent is size constricting, so it adds a scrollbar.
  3. OUI doesn't allow editing flex-shrink or flex-basis on EuiFlexItem. Again, not sure how important this is, but it would be nice to have parity.

Conclusion

We should follow these action items:

  1. Create OUI utility class oui-displayNone to apply display: none
  2. Create OUI utility class oui-overflowAuto to apply overflow: auto
  3. Allow EuiFlexItem to modify flex-shrink and flex-basis

Once those changes are made to OUI, the React code can be modified to use OUI:

  const classes = classNames('oui-overflowAuto', {
    'oui-displayNone': !state.isEmpty && !state.error,
  });

  return (
    <EuiFlexGroup {...dataAttrs} alignItems="center" justifyContent="center" gutterSize="none" className={className}>
      {state.isEmpty && <EuiLoadingChart mono size="l" />}
      {state.isLoading && <EuiProgress size="xs" color="accent" position="absolute" />}
      {!state.isLoading &&
        state.error &&
        renderError &&
        renderError(state.error.message, state.error)}
      <EuiFlexItem grow={1}>
        <EuiPanel
          paddingSize={padding}
          hasShadow={false}
          hasBorder={false}
          color="transparent"
          className={classes}
          panelRef={mountpoint}
        />
      </EuiFlexItem>
    </EuiFlexGroup>
  );
@joshuarrrr
Copy link
Member

It is important we apply this value because we need to get a ref to the element this is applied to while data is loading.

Can you explain more about why this is necessary? In your proposed solution, there's still a lot of rendering logic going on for what is a very common pattern. The panel has some initial empty state, followed by a loading state, and then a success or error state. I'm not sure I understand why we'd need the success state component (EuiPanel) to be rendered but hidden in any of the other states. Is it just to fill up the space?

OUI doesn't provide anything for overflow: auto. Not sure how necessary this is, but it might be nice to have parity with the older version. I think this might be useful when the parent is size constricting, so it adds a scrollbar.

I think a fixed-size container with scrollable contents is definitely a use-case we need to solve for in OUI, and my gut would lean toward making OuiPanel more customizable. In your proposed solution, I'm not convinced we need OuiFlexGroup or OuiFlexItem at all. Why can't LoadingChart, Progress, and Error states be children/contents of the panel?

For the benefit of UX, can you provide screenshots that break down the states and phases of this expression component, so we can have a better perspective on what's happening with the DOM at each point.

@joshuarrrr joshuarrrr moved this to In Progress in Look & Feel Jun 8, 2023
@joshuarrrr
Copy link
Member

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OUI compliance Issues and PRs to maximize OUI usage and remove style and component hacks OUI Issues that require migration to OUI
Projects
Status: In Progress
Development

No branches or pull requests

2 participants