Browse Source

SONAR-21756 Fix card header heights (#10799)

tags/10.5.0.89998
Andrey Luiz 1 month ago
parent
commit
7d20b99c3c

+ 12
- 0
server/sonar-web/design-system/src/components/Card.tsx View File

import * as React from 'react'; import * as React from 'react';
import tw from 'twin.macro'; import tw from 'twin.macro';
import { themeBorder, themeColor } from '../helpers/theme'; import { themeBorder, themeColor } from '../helpers/theme';
import { BasicSeparator } from './Separator';


interface CardProps extends React.HTMLAttributes<HTMLDivElement> { interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode; children: React.ReactNode;
return <LightGreyCardStyled {...rest}>{children}</LightGreyCardStyled>; return <LightGreyCardStyled {...rest}>{children}</LightGreyCardStyled>;
} }


export function LightGreyCardTitle({ children }: Readonly<React.PropsWithChildren>) {
return (
<>
<div className="sw-flex sw-items-center sw-justify-between sw-w-full sw-mb-4 sw-min-h-6">
{children}
</div>
<BasicSeparator className="sw--mx-6 sw-my-0" />
</>
);
}

export const CardWithPrimaryBackground = styled(Card)` export const CardWithPrimaryBackground = styled(Card)`
background-color: ${themeColor('backgroundPrimary')}; background-color: ${themeColor('backgroundPrimary')};
`; `;

+ 15
- 8
server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx View File

BasicSeparator, BasicSeparator,
LargeCenteredLayout, LargeCenteredLayout,
LightGreyCard, LightGreyCard,
LightGreyCardTitle,
PageContentFontWrapper, PageContentFontWrapper,
} from 'design-system'; } from 'design-system';
import * as React from 'react'; import * as React from 'react';
import { QualityGateStatus } from '../../../types/quality-gates'; import { QualityGateStatus } from '../../../types/quality-gates';
import { Component, MeasureEnhanced, Metric, Period, QualityGate } from '../../../types/types'; import { Component, MeasureEnhanced, Metric, Period, QualityGate } from '../../../types/types';
import { AnalysisStatus } from '../components/AnalysisStatus'; import { AnalysisStatus } from '../components/AnalysisStatus';
import LastAnalysisLabel from '../components/LastAnalysisLabel';
import ActivityPanel from './ActivityPanel'; import ActivityPanel from './ActivityPanel';
import BranchMetaTopBar from './BranchMetaTopBar'; import BranchMetaTopBar from './BranchMetaTopBar';
import FirstAnalysisNextStepsNotif from './FirstAnalysisNextStepsNotif'; import FirstAnalysisNextStepsNotif from './FirstAnalysisNextStepsNotif';
import NoCodeWarning from './NoCodeWarning'; import NoCodeWarning from './NoCodeWarning';
import OverallCodeMeasuresPanel from './OverallCodeMeasuresPanel'; import OverallCodeMeasuresPanel from './OverallCodeMeasuresPanel';
import QualityGatePanel from './QualityGatePanel'; import QualityGatePanel from './QualityGatePanel';
import { QualityGateStatusTitle } from './QualityGateStatusTitle';
import SonarLintPromotion from './SonarLintPromotion'; import SonarLintPromotion from './SonarLintPromotion';
import { TabsPanel } from './TabsPanel'; import { TabsPanel } from './TabsPanel';


</> </>
)} )}
<AnalysisStatus className="sw-mt-6" component={component} /> <AnalysisStatus className="sw-mt-6" component={component} />
<div className="sw-flex sw-mt-6">
<div className="sw-w-1/4 sw-mr-3">
<LightGreyCard className="sw-h-max">
<div className="sw-flex sw-gap-3 sw-mt-6">
<div className="sw-w-1/4">
<LightGreyCard>
<QualityGateStatusTitle />
<QualityGatePanel <QualityGatePanel
component={component} component={component}
loading={loadingStatus} loading={loadingStatus}
/> />
</div> </div>


<LightGreyCard className="sw-flex-1">
<div className="sw-flex sw-flex-col">
<div className="sw-flex-1">
<LightGreyCard className="sw-flex sw-flex-col">
<LightGreyCardTitle>
<div>&nbsp;</div>
<LastAnalysisLabel analysisDate={branch?.analysisDate} />
</LightGreyCardTitle>
<TabsPanel <TabsPanel
analyses={analyses} analyses={analyses}
appLeak={appLeak} appLeak={appLeak}
component={component} component={component}
loading={loadingStatus} loading={loadingStatus}
period={period} period={period}
branch={branch}
qgStatuses={qgStatuses} qgStatuses={qgStatuses}
isNewCode={isNewCodeTab} isNewCode={isNewCodeTab}
onTabSelect={selectTab} onTabSelect={selectTab}
metrics={metrics} metrics={metrics}
onGraphChange={onGraphChange} onGraphChange={onGraphChange}
/> />
</div>
</LightGreyCard>
</LightGreyCard>
</div>
</div> </div>
</div> </div>
)} )}

+ 0
- 2
server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx View File

import QualityGatePanelSection from './QualityGatePanelSection'; import QualityGatePanelSection from './QualityGatePanelSection';
import QualityGateStatusHeader from './QualityGateStatusHeader'; import QualityGateStatusHeader from './QualityGateStatusHeader';
import QualityGateStatusPassedView from './QualityGateStatusPassedView'; import QualityGateStatusPassedView from './QualityGateStatusPassedView';
import { QualityGateStatusTitle } from './QualityGateStatusTitle';


export interface QualityGatePanelProps { export interface QualityGatePanelProps {
component: Pick<Component, 'key' | 'qualifier' | 'qualityGate'>; component: Pick<Component, 'key' | 'qualifier' | 'qualityGate'>;


return ( return (
<div data-testid="overview__quality-gate-panel"> <div data-testid="overview__quality-gate-panel">
<QualityGateStatusTitle />
<div className="sw-pt-5"> <div className="sw-pt-5">
<Spinner loading={loading}> <Spinner loading={loading}>
<QualityGateStatusHeader <QualityGateStatusHeader

+ 11
- 14
server/sonar-web/src/main/js/apps/overview/branches/QualityGateStatusTitle.tsx View File

* along with this program; if not, write to the Free Software Foundation, * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import { BasicSeparator, HelperHintIcon, PageTitle } from 'design-system';
import { HelperHintIcon, LightGreyCardTitle, PageTitle } from 'design-system';
import React from 'react'; import React from 'react';
import HelpTooltip from '../../../components/controls/HelpTooltip'; import HelpTooltip from '../../../components/controls/HelpTooltip';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';


export function QualityGateStatusTitle() { export function QualityGateStatusTitle() {
return ( return (
<>
<div className="sw-flex sw-items-center sw-mb-4 sw--mt-2">
<div className="sw-flex sw-items-center">
<PageTitle as="h2" text={translate('overview.quality_gate.status')} />
<HelpTooltip
className="sw-ml-2"
overlay={<div className="sw-my-4">{translate('overview.quality_gate.help')}</div>}
>
<HelperHintIcon aria-label="help-tooltip" />
</HelpTooltip>
</div>
<LightGreyCardTitle>
<div className="sw-flex sw-items-center">
<PageTitle as="h2" text={translate('overview.quality_gate.status')} />
<HelpTooltip
className="sw-ml-2"
overlay={<div className="sw-my-4">{translate('overview.quality_gate.help')}</div>}
>
<HelperHintIcon aria-label="help-tooltip" />
</HelpTooltip>
</div> </div>
<BasicSeparator className="sw--mx-6" />
</>
</LightGreyCardTitle>
); );
} }

+ 4
- 5
server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureCard.tsx View File

import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { LinkHighlight, LinkStandalone } from '@sonarsource/echoes-react'; import { LinkHighlight, LinkStandalone } from '@sonarsource/echoes-react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Badge, BasicSeparator, LightGreyCard, TextBold, TextSubdued } from 'design-system';
import { Badge, LightGreyCard, LightGreyCardTitle, TextBold, TextSubdued } from 'design-system';
import * as React from 'react'; import * as React from 'react';
import { FormattedMessage, useIntl } from 'react-intl'; import { FormattedMessage, useIntl } from 'react-intl';
import Tooltip from '../../../components/controls/Tooltip'; import Tooltip from '../../../components/controls/Tooltip';
data-testid={`overview__software-impact-card-${softwareQuality}`} data-testid={`overview__software-impact-card-${softwareQuality}`}
className="sw-w-1/3 sw-overflow-hidden sw-rounded-2 sw-p-4 sw-flex-col" className="sw-w-1/3 sw-overflow-hidden sw-rounded-2 sw-p-4 sw-flex-col"
> >
<div className="sw-flex sw-justify-between">
<LightGreyCardTitle>
<TextBold name={intl.formatMessage({ id: `software_quality.${softwareQuality}` })} /> <TextBold name={intl.formatMessage({ id: `software_quality.${softwareQuality}` })} />
{failed && ( {failed && (
<Badge className="sw-h-fit" variant="deleted"> <Badge className="sw-h-fit" variant="deleted">
<FormattedMessage id="overview.measures.failed_badge" /> <FormattedMessage id="overview.measures.failed_badge" />
</Badge> </Badge>
)} )}
</div>
<BasicSeparator className="sw--mx-4" />
</LightGreyCardTitle>
<div className="sw-flex sw-flex-col sw-gap-3"> <div className="sw-flex sw-flex-col sw-gap-3">
<div className="sw-flex sw-mt-2">
<div className="sw-flex sw-mt-4">
<div <div
className={classNames('sw-flex sw-gap-1 sw-items-center', { className={classNames('sw-flex sw-gap-1 sw-items-center', {
'sw-opacity-60': component.needIssueSync, 'sw-opacity-60': component.needIssueSync,

+ 2
- 11
server/sonar-web/src/main/js/apps/overview/branches/TabsPanel.tsx View File

*/ */
import { Spinner } from '@sonarsource/echoes-react'; import { Spinner } from '@sonarsource/echoes-react';
import { isBefore, sub } from 'date-fns'; import { isBefore, sub } from 'date-fns';
import { BasicSeparator, ButtonLink, FlagMessage, LightLabel, Tabs } from 'design-system';
import { ButtonLink, FlagMessage, LightLabel, Tabs } from 'design-system';
import * as React from 'react'; import * as React from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import DocumentationLink from '../../../components/common/DocumentationLink'; import DocumentationLink from '../../../components/common/DocumentationLink';
import { isDiffMetric } from '../../../helpers/measures'; import { isDiffMetric } from '../../../helpers/measures';
import { CodeScope } from '../../../helpers/urls'; import { CodeScope } from '../../../helpers/urls';
import { ApplicationPeriod } from '../../../types/application'; import { ApplicationPeriod } from '../../../types/application';
import { Branch } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component'; import { ComponentQualifier } from '../../../types/component';
import { Analysis, ProjectAnalysisEventCategory } from '../../../types/project-activity'; import { Analysis, ProjectAnalysisEventCategory } from '../../../types/project-activity';
import { QualityGateStatus } from '../../../types/quality-gates'; import { QualityGateStatus } from '../../../types/quality-gates';
import { Component, Period } from '../../../types/types'; import { Component, Period } from '../../../types/types';
import LastAnalysisLabel from '../components/LastAnalysisLabel';
import { MAX_ANALYSES_NB } from './ActivityPanel'; import { MAX_ANALYSES_NB } from './ActivityPanel';
import { LeakPeriodInfo } from './LeakPeriodInfo'; import { LeakPeriodInfo } from './LeakPeriodInfo';


component: Component; component: Component;
loading?: boolean; loading?: boolean;
period?: Period; period?: Period;
branch?: Branch;
qgStatuses?: QualityGateStatus[]; qgStatuses?: QualityGateStatus[];
isNewCode: boolean; isNewCode: boolean;
onTabSelect: (tab: CodeScope) => void; onTabSelect: (tab: CodeScope) => void;
period, period,
qgStatuses = [], qgStatuses = [],
isNewCode, isNewCode,
branch,
children, children,
} = props; } = props;
const isApp = component.qualifier === ComponentQualifier.Application; const isApp = component.qualifier === ComponentQualifier.Application;
]; ];


return ( return (
<div data-testid="overview__measures-panel">
<div className="sw-flex sw-justify-end sw-items-center sw-mb-4">
<LastAnalysisLabel analysisDate={branch?.analysisDate} />
</div>
<BasicSeparator className="sw--mx-6 sw-mb-3" />

<div className="sw-mt-3" data-testid="overview__measures-panel">
{loading ? ( {loading ? (
<div> <div>
<Spinner isLoading={loading} /> <Spinner isLoading={loading} />

Loading…
Cancel
Save