123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- /*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
- import { BasicSeparator, FlagMessage, Link } from 'design-system';
- import * as React from 'react';
- import { FormattedMessage } from 'react-intl';
- import withAppStateContext from '../../../app/components/app-state/withAppStateContext';
- import { isBranch, isPullRequest } from '../../../helpers/branch-like';
- import { translate } from '../../../helpers/l10n';
- import { AppState } from '../../../types/appstate';
- import { BranchLike } from '../../../types/branch-like';
- import {
- ComponentQualifier,
- isApplication,
- isPortfolioLike,
- isProject,
- isView,
- } from '../../../types/component';
- import {
- Facet,
- ReferencedComponent,
- ReferencedLanguage,
- ReferencedRule,
- } from '../../../types/issues';
- import { GlobalSettingKeys } from '../../../types/settings';
- import { Component, Dict } from '../../../types/types';
- import { UserBase } from '../../../types/users';
- import { Query } from '../utils';
- import { AssigneeFacet } from './AssigneeFacet';
- import { AttributeCategoryFacet } from './AttributeCategoryFacet';
- import { AuthorFacet } from './AuthorFacet';
- import { CreationDateFacet } from './CreationDateFacet';
- import { DirectoryFacet } from './DirectoryFacet';
- import { FileFacet } from './FileFacet';
- import { LanguageFacet } from './LanguageFacet';
- import { PeriodFilter } from './PeriodFilter';
- import { ProjectFacet } from './ProjectFacet';
- import { ResolutionFacet } from './ResolutionFacet';
- import { RuleFacet } from './RuleFacet';
- import { ScopeFacet } from './ScopeFacet';
- import { SeverityFacet } from './SeverityFacet';
- import { SoftwareQualityFacet } from './SoftwareQualityFacet';
- import { StandardFacet } from './StandardFacet';
- import { StatusFacet } from './StatusFacet';
- import { TagFacet } from './TagFacet';
- import { TypeFacet } from './TypeFacet';
- import { VariantFacet } from './VariantFacet';
-
- export interface Props {
- appState: AppState;
- branchLike?: BranchLike;
- component: Component | undefined;
- createdAfterIncludesTime: boolean;
- facets: Dict<Facet | undefined>;
- loadSearchResultCount: (property: string, changes: Partial<Query>) => Promise<Facet>;
- loadingFacets: Dict<boolean>;
- myIssues: boolean;
- onFacetToggle: (property: string) => void;
- onFilterChange: (changes: Partial<Query>) => void;
- openFacets: Dict<boolean>;
- showVariantsFilter: boolean;
- query: Query;
- referencedComponentsById: Dict<ReferencedComponent>;
- referencedComponentsByKey: Dict<ReferencedComponent>;
- referencedLanguages: Dict<ReferencedLanguage>;
- referencedRules: Dict<ReferencedRule>;
- referencedUsers: Dict<UserBase>;
- }
-
- export class SidebarClass extends React.PureComponent<Props> {
- renderComponentFacets() {
- const { component, facets, loadingFacets, openFacets, query, branchLike, showVariantsFilter } =
- this.props;
-
- const hasFileOrDirectory =
- !isApplication(component?.qualifier) && !isPortfolioLike(component?.qualifier);
-
- if (!component || !hasFileOrDirectory) {
- return null;
- }
-
- const commonProps = {
- componentKey: component.key,
- loadSearchResultCount: this.props.loadSearchResultCount,
- onChange: this.props.onFilterChange,
- onToggle: this.props.onFacetToggle,
- query,
- };
-
- return (
- <>
- {showVariantsFilter && isProject(component?.qualifier) && (
- <>
- <BasicSeparator className="sw-my-4" />
-
- <VariantFacet
- fetching={loadingFacets.codeVariants === true}
- open={!!openFacets.codeVariants}
- stats={facets.codeVariants}
- values={query.codeVariants}
- {...commonProps}
- />
- </>
- )}
-
- {component.qualifier !== ComponentQualifier.Directory && (
- <>
- <BasicSeparator className="sw-my-4" />
-
- <DirectoryFacet
- branchLike={branchLike}
- directories={query.directories}
- fetching={loadingFacets.directories === true}
- open={!!openFacets.directories}
- stats={facets.directories}
- {...commonProps}
- />
- </>
- )}
-
- <BasicSeparator className="sw-my-4" />
-
- <FileFacet
- branchLike={branchLike}
- fetching={loadingFacets.files === true}
- files={query.files}
- open={!!openFacets.files}
- stats={facets.files}
- {...commonProps}
- />
- </>
- );
- }
-
- render() {
- const {
- appState: { settings },
- component,
- createdAfterIncludesTime,
- facets,
- openFacets,
- query,
- branchLike,
- } = this.props;
-
- const disableDeveloperAggregatedInfo =
- settings[GlobalSettingKeys.DeveloperAggregatedInfoDisabled] === 'true';
-
- const branch =
- (isBranch(branchLike) && branchLike.name) ||
- (isPullRequest(branchLike) && branchLike.branch) ||
- undefined;
-
- const displayPeriodFilter = component !== undefined && !isPortfolioLike(component.qualifier);
- const displayProjectsFacet = !component || isView(component.qualifier);
-
- const needIssueSync = component?.needIssueSync;
-
- return (
- <>
- {displayPeriodFilter && (
- <PeriodFilter
- onChange={this.props.onFilterChange}
- newCodeSelected={query.inNewCodePeriod}
- />
- )}
-
- {!needIssueSync && (
- <>
- <AttributeCategoryFacet
- fetching={this.props.loadingFacets.cleanCodeAttributeCategories === true}
- needIssueSync={needIssueSync}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.cleanCodeAttributeCategories}
- stats={facets.cleanCodeAttributeCategories}
- categories={query.cleanCodeAttributeCategories}
- />
-
- <BasicSeparator className="sw-my-4" />
-
- <SoftwareQualityFacet
- fetching={this.props.loadingFacets.impactSoftwareQualities === true}
- needIssueSync={needIssueSync}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.impactSoftwareQualities}
- stats={facets.impactSoftwareQualities}
- qualities={query.impactSoftwareQualities}
- />
-
- <BasicSeparator className="sw-my-4" />
-
- <SeverityFacet
- fetching={this.props.loadingFacets.impactSeverities === true}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.impactSeverities}
- severities={query.impactSeverities}
- stats={facets.impactSeverities}
- />
-
- <BasicSeparator className="sw-my-4" />
- </>
- )}
-
- <TypeFacet
- fetching={this.props.loadingFacets.types === true}
- needIssueSync={needIssueSync}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.types}
- stats={facets.types}
- types={query.types}
- />
-
- {!needIssueSync && (
- <>
- <BasicSeparator className="sw-my-4" />
-
- <ScopeFacet
- fetching={this.props.loadingFacets.scopes === true}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.scopes}
- stats={facets.scopes}
- scopes={query.scopes}
- />
-
- <BasicSeparator className="sw-my-4" />
-
- <ResolutionFacet
- fetching={this.props.loadingFacets.resolutions === true}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.resolutions}
- resolutions={query.resolutions}
- resolved={query.resolved}
- stats={facets.resolutions}
- />
-
- <BasicSeparator className="sw-my-4" />
-
- <StatusFacet
- fetching={this.props.loadingFacets.statuses === true}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.statuses}
- stats={facets.statuses}
- statuses={query.statuses}
- />
-
- <BasicSeparator className="sw-my-4" />
-
- <StandardFacet
- cwe={query.cwe}
- cweOpen={!!openFacets.cwe}
- cweStats={facets.cwe}
- fetchingCwe={this.props.loadingFacets.cwe === true}
- fetchingOwaspTop10={this.props.loadingFacets.owaspTop10 === true}
- fetchingOwaspTop10-2021={this.props.loadingFacets['owaspTop10-2021'] === true}
- fetchingSonarSourceSecurity={this.props.loadingFacets.sonarsourceSecurity === true}
- loadSearchResultCount={this.props.loadSearchResultCount}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.standards}
- owaspTop10={query.owaspTop10}
- owaspTop10Open={!!openFacets.owaspTop10}
- owaspTop10Stats={facets.owaspTop10}
- owaspTop10-2021={query['owaspTop10-2021']}
- owaspTop10-2021Open={!!openFacets['owaspTop10-2021']}
- owaspTop10-2021Stats={facets['owaspTop10-2021']}
- query={query}
- sonarsourceSecurity={query.sonarsourceSecurity}
- sonarsourceSecurityOpen={!!openFacets.sonarsourceSecurity}
- sonarsourceSecurityStats={facets.sonarsourceSecurity}
- />
-
- <BasicSeparator className="sw-my-4" />
-
- <CreationDateFacet
- component={component}
- createdAfter={query.createdAfter}
- createdAfterIncludesTime={createdAfterIncludesTime}
- createdAt={query.createdAt}
- createdBefore={query.createdBefore}
- createdInLast={query.createdInLast}
- fetching={this.props.loadingFacets.createdAt === true}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.createdAt}
- inNewCodePeriod={query.inNewCodePeriod}
- stats={facets.createdAt}
- />
-
- <BasicSeparator className="sw-my-4" />
-
- <LanguageFacet
- fetching={this.props.loadingFacets.languages === true}
- loadSearchResultCount={this.props.loadSearchResultCount}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.languages}
- query={query}
- referencedLanguages={this.props.referencedLanguages}
- selectedLanguages={query.languages}
- stats={facets.languages}
- />
-
- <BasicSeparator className="sw-my-4" />
-
- <RuleFacet
- fetching={this.props.loadingFacets.rules === true}
- loadSearchResultCount={this.props.loadSearchResultCount}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.rules}
- query={query}
- referencedRules={this.props.referencedRules}
- stats={facets.rules}
- />
-
- {!disableDeveloperAggregatedInfo && (
- <>
- <BasicSeparator className="sw-my-4" />
-
- <TagFacet
- component={component}
- branch={branch}
- fetching={this.props.loadingFacets.tags === true}
- loadSearchResultCount={this.props.loadSearchResultCount}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.tags}
- query={query}
- stats={facets.tags}
- tags={query.tags}
- />
-
- {displayProjectsFacet && (
- <>
- <BasicSeparator className="sw-my-4" />
-
- <ProjectFacet
- component={component}
- fetching={this.props.loadingFacets.projects === true}
- loadSearchResultCount={this.props.loadSearchResultCount}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.projects}
- projects={query.projects}
- query={query}
- referencedComponents={this.props.referencedComponentsByKey}
- stats={facets.projects}
- />
- </>
- )}
-
- {this.renderComponentFacets()}
-
- {!this.props.myIssues && (
- <>
- <BasicSeparator className="sw-my-4" />
-
- <AssigneeFacet
- assigned={query.assigned}
- assignees={query.assignees}
- fetching={this.props.loadingFacets.assignees === true}
- loadSearchResultCount={this.props.loadSearchResultCount}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.assignees}
- query={query}
- referencedUsers={this.props.referencedUsers}
- stats={facets.assignees}
- />
- </>
- )}
-
- <BasicSeparator className="sw-my-4" />
-
- <AuthorFacet
- author={query.author}
- component={component}
- fetching={this.props.loadingFacets.author === true}
- loadSearchResultCount={this.props.loadSearchResultCount}
- onChange={this.props.onFilterChange}
- onToggle={this.props.onFacetToggle}
- open={!!openFacets.author}
- query={query}
- stats={facets.author}
- />
- </>
- )}
- </>
- )}
-
- {needIssueSync && (
- <>
- <BasicSeparator className="sw-my-4" />
-
- <FlagMessage className="sw-my-6" variant="info">
- <div>
- {translate('indexation.page_unavailable.description')}
- <span className="sw-ml-1">
- <FormattedMessage
- defaultMessage={translate('indexation.filters_unavailable')}
- id="indexation.filters_unavailable"
- values={{
- link: (
- <Link to="https://docs.sonarsource.com/sonarqube/latest/instance-administration/reindexing/">
- {translate('learn_more')}
- </Link>
- ),
- }}
- />
- </span>
- </div>
- </FlagMessage>
- </>
- )}
- </>
- );
- }
- }
-
- export const Sidebar = withAppStateContext(SidebarClass);
|