diff --git a/clomonitor-apiserver/src/filters.rs b/clomonitor-apiserver/src/filters.rs index b5946d62..dd026244 100644 --- a/clomonitor-apiserver/src/filters.rs +++ b/clomonitor-apiserver/src/filters.rs @@ -1,19 +1,12 @@ /// Template filter that returns the section score x-axis translate value for /// the score bar. -pub fn rs_section_score_arrow_t_x(score: &usize) -> ::askama::Result { - let v = score + 19; - if v < 23 { - return Ok(23); - } - Ok(v) +pub fn rs_section_score_arrow_t_x(score: &usize) -> ::askama::Result { + Ok((158.0 + *score as f64 * 1.21).round()) } /// Template filter that returns the width of the section score bar. -pub fn rs_section_score_width(score: &usize) -> ::askama::Result { - if *score < 100 { - return Ok(score.saturating_sub(4)); - } - Ok(*score) +pub fn rs_section_score_width(score: &usize) -> ::askama::Result { + Ok((*score as f64 * 1.21).round()) } /// Template filter that returns the rating letter corresponding to the score diff --git a/clomonitor-apiserver/templates/report-summary.svg b/clomonitor-apiserver/templates/report-summary.svg index da0656b0..447fb6bd 100644 --- a/clomonitor-apiserver/templates/report-summary.svg +++ b/clomonitor-apiserver/templates/report-summary.svg @@ -1,8 +1,8 @@ @@ -225,13 +225,13 @@ x="1" y="50" class="bg" - height="145" + height="160" width="448" /> - + @@ -242,27 +242,27 @@ - - - - - - Documentation - - + + + + + + Documentation + + - {{ score.documentation }} + {{ score.documentation }} - - {% if score.documentation < 100 %} - {% endif %} - - - - - - - License - - + + + + + + + License + + - {{ score.license }} + {{ score.license }} - {% if score.license < 100 %} - {% endif %} - - - - - - - Best Practices - - + + + + + + + + + + Best Practices + + - {{ score.best_practices }} + {{ score.best_practices }} - {% if score.best_practices < 100 %} - {% endif %} - - - - - - - Security - - + + + + + + + Security + + - {{ score.security }} + {{ score.security }} - {% if score.security < 100 %} + + + + + + + + + + + + + + + + Legal + + + + + + {{ score.legal }} + + + + + + - {% endif %} diff --git a/clomonitor-core/src/linter/primary.rs b/clomonitor-core/src/linter/primary.rs index 83772adf..195949b1 100644 --- a/clomonitor-core/src/linter/primary.rs +++ b/clomonitor-core/src/linter/primary.rs @@ -12,6 +12,7 @@ pub struct Report { pub license: License, pub best_practices: BestPractices, pub security: Security, + pub legal: Legal, } /// Documentation section of the report. @@ -46,7 +47,6 @@ pub struct BestPractices { pub community_meeting: bool, pub openssf_badge: bool, pub recent_release: bool, - pub trademark_footer: bool, } /// Security section of the report. @@ -56,6 +56,13 @@ pub struct Security { pub security_policy: bool, } +/// Legal section of the report. +#[derive(Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub struct Legal { + pub trademark_footer: bool, +} + /// Lint the path provided and return a report. pub async fn lint(options: LintOptions<'_>) -> Result { // Get CLOMonitor metadata @@ -65,9 +72,10 @@ pub async fn lint(options: LintOptions<'_>) -> Result { let gh_md = github::get_metadata(options.url).await?; // Async checks: documentation, best_practices - let (documentation, best_practices) = tokio::try_join!( + let (documentation, best_practices, legal) = tokio::try_join!( lint_documentation(options.root, options.url, &gh_md), - lint_best_practices(options.root, options.url, &gh_md), + lint_best_practices(options.root, options.url), + lint_legal(&gh_md), )?; Ok(Report { @@ -75,6 +83,7 @@ pub async fn lint(options: LintOptions<'_>) -> Result { license: lint_license(options.root, &md)?, best_practices, security: lint_security(options.root)?, + legal, }) } @@ -238,11 +247,7 @@ fn lint_license(root: &Path, md: &Option) -> Result { } /// Run best practices checks and prepare the report's best practices section. -async fn lint_best_practices( - root: &Path, - repo_url: &str, - gh_md: &Repository, -) -> Result { +async fn lint_best_practices(root: &Path, repo_url: &str) -> Result { // Artifact Hub badge let artifacthub_badge = check::content::matches( Globs { @@ -276,20 +281,11 @@ async fn lint_best_practices( // Recent release let recent_release = check::github::has_recent_release(repo_url).await?; - // Trademark footer - let mut trademark_footer: bool = false; - if let Some(url) = &gh_md.homepage { - if !url.is_empty() { - trademark_footer = check::content::remote_matches(url, TRADEMARK_FOOTER).await?; - } - } - Ok(BestPractices { artifacthub_badge, community_meeting, openssf_badge, recent_release, - trademark_footer, }) } @@ -311,3 +307,16 @@ fn lint_security(root: &Path) -> Result { Ok(Security { security_policy }) } + +/// Run legal checks and prepare the report's legal section. +async fn lint_legal(gh_md: &Repository) -> Result { + // Trademark footer + let mut trademark_footer: bool = false; + if let Some(url) = &gh_md.homepage { + if !url.is_empty() { + trademark_footer = check::content::remote_matches(url, TRADEMARK_FOOTER).await?; + } + } + + Ok(Legal { trademark_footer }) +} diff --git a/clomonitor-core/src/score/mod.rs b/clomonitor-core/src/score/mod.rs index 5b77c2df..9ece4c07 100644 --- a/clomonitor-core/src/score/mod.rs +++ b/clomonitor-core/src/score/mod.rs @@ -78,6 +78,7 @@ fn merge_primaries(scores: Vec, k: f64) -> primary::Score { score.license += (entry.license as f64 * k).round() as usize; score.best_practices += (entry.best_practices as f64 * k).round() as usize; score.security += (entry.security as f64 * k).round() as usize; + score.legal += (entry.legal as f64 * k).round() as usize; } } score @@ -111,6 +112,7 @@ fn merge_mixed(scores: Vec, k_pri_only: f64, k_pri: f64, k_sec: f64) -> p score.license += (entry.license as f64 * k_pri).round() as usize; score.best_practices += (entry.best_practices as f64 * k_pri_only).round() as usize; score.security += (entry.security as f64 * k_pri_only).round() as usize; + score.legal += (entry.legal as f64 * k_pri_only).round() as usize; } Score::Secondary(entry) => { score.global += (entry.global as f64 * k_sec).round() as usize; @@ -146,6 +148,7 @@ mod tests { license: 30, best_practices: 40, security: 50, + legal: 60, }) .global(), 10 @@ -174,6 +177,7 @@ mod tests { license: 0, best_practices: 0, security: 0, + legal: 0, }) .rating(), 'a' @@ -203,6 +207,7 @@ mod tests { license: 80, best_practices: 80, security: 80, + legal: 80, }), Score::Primary(primary::Score { global: 60, @@ -210,6 +215,7 @@ mod tests { license: 60, best_practices: 60, security: 60, + legal: 60, }), ]), Score::Primary(primary::Score { @@ -218,6 +224,7 @@ mod tests { license: 70, best_practices: 70, security: 70, + legal: 70, }) ) } @@ -255,6 +262,7 @@ mod tests { license: 80, best_practices: 80, security: 80, + legal: 80, }), Score::Secondary(secondary::Score { global: 100, @@ -268,6 +276,7 @@ mod tests { license: 84, best_practices: 80, security: 80, + legal: 80, }) ) } diff --git a/clomonitor-core/src/score/primary.rs b/clomonitor-core/src/score/primary.rs index 563d4a25..df2d70c0 100644 --- a/clomonitor-core/src/score/primary.rs +++ b/clomonitor-core/src/score/primary.rs @@ -10,6 +10,7 @@ pub struct Score { pub license: usize, pub best_practices: usize, pub security: usize, + pub legal: usize, } impl Score { @@ -22,6 +23,7 @@ impl Score { license: 0, best_practices: 0, security: 0, + legal: 0, } } } @@ -81,26 +83,28 @@ pub(crate) fn calculate_score(report: &Report) -> Score { score.best_practices += 25; } if report.best_practices.openssf_badge { - score.best_practices += 50; + score.best_practices += 60; } if report.best_practices.recent_release { score.best_practices += 10; } - if report.best_practices.trademark_footer { - score.best_practices += 10; - } // Security if report.security.security_policy { score.security = 100; } + // Legal + if report.legal.trademark_footer { + score.legal = 100; + } + // Global - let global = (score.documentation as f64 - + score.license as f64 - + score.best_practices as f64 - + score.security as f64) - / 4.0; + let global = (score.documentation as f64 * 0.3) + + (score.license as f64 * 0.2) + + (score.best_practices as f64 * 0.2) + + (score.security as f64 * 0.2) + + (score.legal as f64 * 0.1); score.global = global.round() as usize; score @@ -120,6 +124,7 @@ mod tests { license: 0, best_practices: 0, security: 0, + legal: 0, } ); } @@ -149,11 +154,13 @@ mod tests { community_meeting: true, openssf_badge: true, recent_release: true, - trademark_footer: true, }, security: Security { security_policy: true, }, + legal: Legal { + trademark_footer: true, + }, }), Score { global: 100, @@ -161,6 +168,7 @@ mod tests { license: 100, best_practices: 100, security: 100, + legal: 100, } ); } @@ -190,11 +198,13 @@ mod tests { community_meeting: false, openssf_badge: false, recent_release: false, - trademark_footer: false, }, security: Security { security_policy: false, }, + legal: Legal { + trademark_footer: false, + }, }), Score::new() ); diff --git a/clomonitor-linter/src/display.rs b/clomonitor-linter/src/display.rs index a612e5d6..a11ed429 100644 --- a/clomonitor-linter/src/display.rs +++ b/clomonitor-linter/src/display.rs @@ -44,7 +44,8 @@ pub(crate) fn display_primary(report: &linter::primary::Report, score: &score::p cell_entry("Best practices"), cell_score(score.best_practices), ]) - .add_row(vec![cell_entry("Security"), cell_score(score.security)]); + .add_row(vec![cell_entry("Security"), cell_score(score.security)]) + .add_row(vec![cell_entry("Legal"), cell_score(score.legal)]); println!("{summary}\n"); // Checks table @@ -124,13 +125,13 @@ pub(crate) fn display_primary(report: &linter::primary::Report, score: &score::p cell_entry("Best practices / Recent release"), cell_check(report.best_practices.recent_release), ]) - .add_row(vec![ - cell_entry("Best practices / Trademark footer"), - cell_check(report.best_practices.trademark_footer), - ]) .add_row(vec![ cell_entry("Security / Security policy"), cell_check(report.security.security_policy), + ]) + .add_row(vec![ + cell_entry("Legal / Trademark footer"), + cell_check(report.legal.trademark_footer), ]); println!("{checks}\n"); } diff --git a/docs/screenshots/project-dark.png b/docs/screenshots/project-dark.png index 1a149fa8..6634ef75 100644 Binary files a/docs/screenshots/project-dark.png and b/docs/screenshots/project-dark.png differ diff --git a/docs/screenshots/project-light.png b/docs/screenshots/project-light.png index 031dda3e..b35043d0 100644 Binary files a/docs/screenshots/project-light.png and b/docs/screenshots/project-light.png differ diff --git a/docs/screenshots/search-dark.png b/docs/screenshots/search-dark.png index ff6cc1c7..a3282451 100644 Binary files a/docs/screenshots/search-dark.png and b/docs/screenshots/search-dark.png differ diff --git a/docs/screenshots/search-light.png b/docs/screenshots/search-light.png index dfdd89a9..d1eb7723 100644 Binary files a/docs/screenshots/search-light.png and b/docs/screenshots/search-light.png differ diff --git a/web/src/data.tsx b/web/src/data.tsx index 0b59563f..927b1f95 100644 --- a/web/src/data.tsx +++ b/web/src/data.tsx @@ -8,7 +8,7 @@ import { GoLaw } from 'react-icons/go'; import { HiOutlinePencilAlt, HiTerminal } from 'react-icons/hi'; import { ImOffice } from 'react-icons/im'; import { IoIosPeople, IoMdRibbon } from 'react-icons/io'; -import { RiRoadMapLine } from 'react-icons/ri'; +import { RiRoadMapLine, RiShieldStarLine } from 'react-icons/ri'; import ExternalLink from './layout/common/ExternalLink'; import QualityDot from './layout/common/QualityDot'; @@ -84,10 +84,11 @@ export const FILTERS: FiltersSection[] = [ ]; export const CATEGORY_ICONS = { - [ScoreType.Global]: , + [ScoreType.BestPractices]: , [ScoreType.Documentation]: , - [ScoreType.License]: , - [ScoreType.BestPractices]: , + [ScoreType.Global]: , + [ScoreType.Legal]: , + [ScoreType.License]: , [ScoreType.Security]: , }; diff --git a/web/src/layout/common/ScoreSummary.module.css b/web/src/layout/common/CategoriesSummary.module.css similarity index 71% rename from web/src/layout/common/ScoreSummary.module.css rename to web/src/layout/common/CategoriesSummary.module.css index 286e45be..2795ebb5 100644 --- a/web/src/layout/common/ScoreSummary.module.css +++ b/web/src/layout/common/CategoriesSummary.module.css @@ -4,8 +4,9 @@ padding: 1rem; } -.categories { - top: -3px; +.badge { + width: 3.5rem; + border: 2px solid transparent; } @media only screen and (min-width: 768px) { @@ -16,4 +17,8 @@ .summary:not(.bigSize) { padding: 1.5rem; } + + .badge { + width: 5.5rem; + } } diff --git a/web/src/layout/common/ScoreSummary.test.tsx b/web/src/layout/common/CategoriesSummary.test.tsx similarity index 77% rename from web/src/layout/common/ScoreSummary.test.tsx rename to web/src/layout/common/CategoriesSummary.test.tsx index 272ecbcc..e5dc7dd4 100644 --- a/web/src/layout/common/ScoreSummary.test.tsx +++ b/web/src/layout/common/CategoriesSummary.test.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react'; import { BrowserRouter as Router } from 'react-router-dom'; import { ScoreKind, ScoreType } from '../../types'; -import ScoreSummary from './ScoreSummary'; +import CategoriesSummary from './CategoriesSummary'; const defaultProps = { score: { @@ -12,11 +12,12 @@ const defaultProps = { [ScoreType.License]: 80, score_kind: ScoreKind.Primary, [ScoreType.Security]: 0, + [ScoreType.Legal]: 75, }, bigSize: false, }; -describe('ScoreSummary', () => { +describe('CategoriesSummary', () => { afterEach(() => { jest.resetAllMocks(); }); @@ -24,7 +25,7 @@ describe('ScoreSummary', () => { it('creates snapshot', () => { const { asFragment } = render( - + ); @@ -35,7 +36,7 @@ describe('ScoreSummary', () => { it('renders component', () => { render( - + ); @@ -43,16 +44,17 @@ describe('ScoreSummary', () => { expect(screen.getByText('License')).toBeInTheDocument(); expect(screen.getByText('Best Practices')).toBeInTheDocument(); expect(screen.getByText('Security')).toBeInTheDocument(); + expect(screen.getByText('Legal')).toBeInTheDocument(); expect(screen.getByTestId('global-score')).toBeInTheDocument(); - expect(screen.getAllByTestId('line')).toHaveLength(4); - expect(screen.getAllByTestId('peak')).toHaveLength(4); + expect(screen.getAllByTestId('line')).toHaveLength(5); + expect(screen.getAllByTestId('peak')).toHaveLength(5); }); it('renders correct classes when bigSize is true', () => { const { container } = render( - + ); @@ -60,7 +62,6 @@ describe('ScoreSummary', () => { expect(container.children[0].children[1]).toHaveClass('px-0 px-sm-3'); expect(container.children[0].children[1].children[0]).toHaveClass('gx-4 gx-md-5'); expect(screen.getByText('85')).toHaveClass('bigSize'); - expect(screen.getByTestId('global-score').parentNode).toHaveClass('mx-3'); }); }); }); diff --git a/web/src/layout/common/ScoreSummary.tsx b/web/src/layout/common/CategoriesSummary.tsx similarity index 72% rename from web/src/layout/common/ScoreSummary.tsx rename to web/src/layout/common/CategoriesSummary.tsx index 97fceef6..5372fe7c 100644 --- a/web/src/layout/common/ScoreSummary.tsx +++ b/web/src/layout/common/CategoriesSummary.tsx @@ -2,16 +2,16 @@ import classNames from 'classnames'; import { CATEGORY_ICONS } from '../../data'; import { Score, ScoreType } from '../../types'; -import Category from './Category'; +import styles from './CategoriesSummary.module.css'; +import CategoryProgressbar from './CategoryProgressbar'; import RoundScore from './RoundScore'; -import styles from './ScoreSummary.module.css'; interface Props { score: Score; bigSize: boolean; } -const ScoreSummaryCard = (props: Props) => { +const CategoriesSummary = (props: Props) => { return (
{ { 'mx-3': props.bigSize } )} > - +
+ +
- - -
-
- - +
); }; -export default ScoreSummaryCard; +export default CategoriesSummary; diff --git a/web/src/layout/common/Category.tsx b/web/src/layout/common/Category.tsx deleted file mode 100644 index 3e36178f..00000000 --- a/web/src/layout/common/Category.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import classNames from 'classnames'; -import { isUndefined } from 'lodash'; - -import getCategoryColor from '../../utils/getCategoryColor'; -import styles from './Category.module.css'; - -interface Props { - icon?: JSX.Element; - value: number; - name: string; - shortName?: string; - bigSize?: boolean; -} - -const Category = (props: Props) => { - const color = getCategoryColor(props.value); - return ( -
-
- {props.icon && {props.icon}} - - {props.name} - - {!isUndefined(props.shortName) && ( - {props.shortName} - )} -
-
-
- {props.value} -
-
-
- {props.value !== 100 && ( -
- )} -
-
-
-
- ); -}; - -export default Category; diff --git a/web/src/layout/common/Category.module.css b/web/src/layout/common/CategoryProgressbar.module.css similarity index 63% rename from web/src/layout/common/Category.module.css rename to web/src/layout/common/CategoryProgressbar.module.css index 06823dc8..756635eb 100644 --- a/web/src/layout/common/Category.module.css +++ b/web/src/layout/common/CategoryProgressbar.module.css @@ -1,13 +1,20 @@ +.wrapper { + margin: 0.1rem 0; +} + .title { font-size: 75%; + min-width: 120px; + width: 45%; + max-width: 230px; } .icon { - top: -2px; + top: -1px; } .value { - width: 35px; + min-width: 35px; font-size: 0.75rem; background-color: var(--color-black-10); } @@ -23,15 +30,15 @@ @media only screen and (min-width: 768px) { .bigSize { - height: 30px; - line-height: 30px; - font-size: 1rem; + height: 24px; + line-height: 24px; + font-size: 0.8rem; width: 50px; } .bigArrow { - border-top: 15px solid transparent; - border-bottom: 15px solid transparent; + border-top: 12px solid transparent; + border-bottom: 12px solid transparent; } } diff --git a/web/src/layout/common/Category.test.tsx b/web/src/layout/common/CategoryProgressbar.test.tsx similarity index 51% rename from web/src/layout/common/Category.test.tsx rename to web/src/layout/common/CategoryProgressbar.test.tsx index 7c334037..47cee1bb 100644 --- a/web/src/layout/common/Category.test.tsx +++ b/web/src/layout/common/CategoryProgressbar.test.tsx @@ -1,29 +1,25 @@ import { render, screen } from '@testing-library/react'; -import Category from './Category'; +import CategoryProgressbar from './CategoryProgressbar'; const defaultProps = { value: 80, name: 'Documentation', - shortName: 'Docs', }; -describe('Category', () => { +describe('CategoryProgressbar', () => { afterEach(() => { jest.resetAllMocks(); }); it('creates snapshot', () => { - const { asFragment } = render(); + const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); }); it('renders proper content', () => { - render(); + render(); expect(screen.getByText('Documentation')).toBeInTheDocument(); - expect(screen.getByText('Documentation')).toHaveClass('d-none d-md-inline-block'); - expect(screen.getByText('Docs')).toBeInTheDocument(); - expect(screen.getByText('Docs')).toHaveClass('d-inline-block d-md-none'); expect(screen.getByText('80')).toBeInTheDocument(); const line = screen.getByTestId('line'); @@ -32,9 +28,4 @@ describe('Category', () => { expect(screen.getByTestId('peak')).toBeInTheDocument(); }); - - it('does not render peak when value is 100', () => { - render(); - expect(screen.queryByTestId('peak')).toBeNull(); - }); }); diff --git a/web/src/layout/common/CategoryProgressbar.tsx b/web/src/layout/common/CategoryProgressbar.tsx new file mode 100644 index 00000000..12361344 --- /dev/null +++ b/web/src/layout/common/CategoryProgressbar.tsx @@ -0,0 +1,46 @@ +import getCategoryColor from '../../utils/getCategoryColor'; +import styles from './CategoryProgressbar.module.css'; + +interface Props { + icon?: JSX.Element; + value: number; + name: string; + bigSize?: boolean; +} + +const CategoryProgressbar = (props: Props) => { + const color = getCategoryColor(props.value); + return ( +
+
+
+ {props.icon && {props.icon}} + {props.name} +
+
+ {props.value} +
+
+
+
+
+
+
+
+ ); +}; + +export default CategoryProgressbar; diff --git a/web/src/layout/common/__snapshots__/CategoriesSummary.test.tsx.snap b/web/src/layout/common/__snapshots__/CategoriesSummary.test.tsx.snap new file mode 100644 index 00000000..f751ed24 --- /dev/null +++ b/web/src/layout/common/__snapshots__/CategoriesSummary.test.tsx.snap @@ -0,0 +1,307 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CategoriesSummary creates snapshot 1`] = ` + +
+
+
+
+ 65 +
+
+
+
+
+
+
+
+ + + + + + + Documentation + +
+
+ 85 +
+
+
+
+
+
+
+
+
+
+
+ + + + + + + License + +
+
+ 80 +
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + Best Practices + +
+
+ 95 +
+
+
+
+
+
+
+
+
+
+
+ + + + + + + Security + +
+
+ 0 +
+
+
+
+
+
+
+
+
+
+
+ + + + + + + Legal + +
+
+ 75 +
+
+
+
+
+
+
+
+
+
+
+ +`; diff --git a/web/src/layout/common/__snapshots__/Category.test.tsx.snap b/web/src/layout/common/__snapshots__/CategoryProgressbar.test.tsx.snap similarity index 58% rename from web/src/layout/common/__snapshots__/Category.test.tsx.snap rename to web/src/layout/common/__snapshots__/CategoryProgressbar.test.tsx.snap index 54bb318b..8ec2ad9a 100644 --- a/web/src/layout/common/__snapshots__/Category.test.tsx.snap +++ b/web/src/layout/common/__snapshots__/CategoryProgressbar.test.tsx.snap @@ -1,34 +1,29 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Category creates snapshot 1`] = ` +exports[`CategoryProgressbar creates snapshot 1`] = `
-
- - Documentation - - - Docs - -
+
+ + Documentation + +
80
-
-
-
- 65 -
-
-
-
-
-
- - - - - - - Documentation - - - Docs - -
-
-
- 85 -
-
-
-
-
-
-
-
-
-
- - - - - - - License - -
-
-
- 80 -
-
-
-
-
-
-
-
-
-
-
-
- - - - - - - Best Practices - -
-
-
- 95 -
-
-
-
-
-
-
-
-
-
- - - - - - - Security - -
-
-
- 0 -
-
-
-
-
-
-
-
-
-
-
- -`; diff --git a/web/src/layout/detail/index.tsx b/web/src/layout/detail/index.tsx index 9d6466be..1ca45fea 100644 --- a/web/src/layout/detail/index.tsx +++ b/web/src/layout/detail/index.tsx @@ -10,13 +10,13 @@ import useScrollRestorationFix from '../../hooks/useScrollRestorationFix'; import { ProjectDetail } from '../../types'; import CartegoryBadge from '../common/badges/CategoryBadge'; import MaturityBadge from '../common/badges/MaturityBadge'; +import CategoriesSummary from '../common/CategoriesSummary'; import ExternalLink from '../common/ExternalLink'; import Image from '../common/Image'; import Loading from '../common/Loading'; import NoData from '../common/NoData'; import ProjectDropdown from '../common/ProjectDropdown'; import RoundScore from '../common/RoundScore'; -import ScoreSummary from '../common/ScoreSummary'; import SubNavbar from '../navigation/SubNavbar'; import RepositorySection from '../search/RepositorySection'; import styles from './Detail.module.css'; @@ -160,7 +160,7 @@ const Detail = () => {

- +
diff --git a/web/src/layout/detail/repositories/Summary.module.css b/web/src/layout/detail/repositories/Summary.module.css index 1fcd64d0..9b713760 100644 --- a/web/src/layout/detail/repositories/Summary.module.css +++ b/web/src/layout/detail/repositories/Summary.module.css @@ -39,8 +39,18 @@ } } +@media only screen and (min-width: 768px) { + .table th { + min-width: 90px; + } + + .table th:first-child { + width: 100%; + } +} + @media only screen and (min-width: 1200px) { .table th { - min-width: 145px; + min-width: 150px; } } diff --git a/web/src/layout/detail/repositories/Summary.test.tsx b/web/src/layout/detail/repositories/Summary.test.tsx index db29be8f..b5e34d7b 100644 --- a/web/src/layout/detail/repositories/Summary.test.tsx +++ b/web/src/layout/detail/repositories/Summary.test.tsx @@ -68,7 +68,7 @@ describe('Summary', () => { expect(screen.getAllByText('100')).toHaveLength(5); expect(screen.getAllByText('85')).toHaveLength(3); expect(screen.getAllByText('70')).toHaveLength(3); - expect(screen.getAllByText('n/a')).toHaveLength(10); + expect(screen.getAllByText('n/a')).toHaveLength(16); }); }); diff --git a/web/src/layout/detail/repositories/Summary.tsx b/web/src/layout/detail/repositories/Summary.tsx index f7612100..adf658a0 100644 --- a/web/src/layout/detail/repositories/Summary.tsx +++ b/web/src/layout/detail/repositories/Summary.tsx @@ -30,24 +30,28 @@ const Summary = (props: Props) => { Repository - {CATEGORY_ICONS[ScoreType.Global]} - Global + {CATEGORY_ICONS[ScoreType.Global]} + Global {CATEGORY_ICONS[ScoreType.Documentation]} - Documentation + Documentation {CATEGORY_ICONS[ScoreType.License]} - License + License {CATEGORY_ICONS[ScoreType.BestPractices]} - Best Practices + Best Practices {CATEGORY_ICONS[ScoreType.Security]} - Security + Security + + + {CATEGORY_ICONS[ScoreType.Legal]} + Legal @@ -105,6 +109,9 @@ const Summary = (props: Props) => { + + + ); })} diff --git a/web/src/layout/detail/repositories/__fixtures__/Summary/1.json b/web/src/layout/detail/repositories/__fixtures__/Summary/1.json index 4eff8d48..97c110b2 100644 --- a/web/src/layout/detail/repositories/__fixtures__/Summary/1.json +++ b/web/src/layout/detail/repositories/__fixtures__/Summary/1.json @@ -163,6 +163,9 @@ "report_kind": "Primary", "security": { "security_policy": false + }, + "legal": { + "trademark_footer": true } }, "errors": null, diff --git a/web/src/layout/detail/repositories/__snapshots__/Summary.test.tsx.snap b/web/src/layout/detail/repositories/__snapshots__/Summary.test.tsx.snap index 09670489..236daca7 100644 --- a/web/src/layout/detail/repositories/__snapshots__/Summary.test.tsx.snap +++ b/web/src/layout/detail/repositories/__snapshots__/Summary.test.tsx.snap @@ -41,7 +41,7 @@ exports[`Summary creates snapshot 1`] = ` scope="col" > - + Global @@ -86,7 +88,7 @@ exports[`Summary creates snapshot 1`] = ` Documentation @@ -103,18 +105,17 @@ exports[`Summary creates snapshot 1`] = ` height="1em" stroke="currentColor" stroke-width="0" - viewBox="0 0 14 16" + viewBox="0 0 512 512" width="1em" xmlns="http://www.w3.org/2000/svg" > License @@ -131,17 +132,23 @@ exports[`Summary creates snapshot 1`] = ` height="1em" stroke="currentColor" stroke-width="0" - viewBox="0 0 512 512" + viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" > - + + + + Best Practices @@ -168,11 +175,39 @@ exports[`Summary creates snapshot 1`] = ` Security + + + + + + + + Legal + + @@ -256,6 +291,19 @@ exports[`Summary creates snapshot 1`] = `
+ +
+ + n/a + +
+
+ +
+ + n/a + +
+
+ +
+ + n/a + +
+
+ +
+ + n/a + +
+
+ +
+ + n/a + +
+
+ +
+ + n/a + +
+ diff --git a/web/src/layout/detail/repositories/__snapshots__/index.test.tsx.snap b/web/src/layout/detail/repositories/__snapshots__/index.test.tsx.snap index e0b9d65a..d0949af2 100644 --- a/web/src/layout/detail/repositories/__snapshots__/index.test.tsx.snap +++ b/web/src/layout/detail/repositories/__snapshots__/index.test.tsx.snap @@ -50,7 +50,7 @@ exports[`RepositoriesList creates snapshot 1`] = ` scope="col" > - + Global @@ -95,7 +97,7 @@ exports[`RepositoriesList creates snapshot 1`] = ` Documentation @@ -112,18 +114,17 @@ exports[`RepositoriesList creates snapshot 1`] = ` height="1em" stroke="currentColor" stroke-width="0" - viewBox="0 0 14 16" + viewBox="0 0 512 512" width="1em" xmlns="http://www.w3.org/2000/svg" > License @@ -140,17 +141,23 @@ exports[`RepositoriesList creates snapshot 1`] = ` height="1em" stroke="currentColor" stroke-width="0" - viewBox="0 0 512 512" + viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" > - + + + + Best Practices @@ -177,11 +184,39 @@ exports[`RepositoriesList creates snapshot 1`] = ` Security + + + + + + + + Legal + + @@ -301,6 +336,19 @@ exports[`RepositoriesList creates snapshot 1`] = `
+ +
+ + n/a + +
+
+ +
+ + n/a + +
+
+ +
+ + n/a + +
+
+ +
+ + n/a + +
+
+ +
+ + n/a + +
+
+ +
+ + n/a + +
+ @@ -1870,13 +1983,12 @@ exports[`RepositoriesList creates snapshot 1`] = ` height="1em" stroke="currentColor" stroke-width="0" - viewBox="0 0 14 16" + viewBox="0 0 512 512" width="1em" xmlns="http://www.w3.org/2000/svg" >
- + + + +
{ icon={CATEGORY_ICONS[ScoreType.Security]} score={repo.score.security} /> + ); })} diff --git a/web/src/layout/search/Card.test.tsx b/web/src/layout/search/Card.test.tsx index d2702551..f57d2f7e 100644 --- a/web/src/layout/search/Card.test.tsx +++ b/web/src/layout/search/Card.test.tsx @@ -42,6 +42,7 @@ const defaultProps = { documentation: 75, global: 89, license: 80, + legal: 75, score_kind: ScoreKind.Primary, security: 100, }, diff --git a/web/src/layout/search/Card.tsx b/web/src/layout/search/Card.tsx index b3e85ab9..4f0bab61 100644 --- a/web/src/layout/search/Card.tsx +++ b/web/src/layout/search/Card.tsx @@ -5,10 +5,10 @@ import { useNavigate } from 'react-router-dom'; import { Project } from '../../types'; import CartegoryBadge from '../common/badges/CategoryBadge'; import MaturityBadge from '../common/badges/MaturityBadge'; +import CategoriesSummary from '../common/CategoriesSummary'; import ExternalLink from '../common/ExternalLink'; import Image from '../common/Image'; import RoundScore from '../common/RoundScore'; -import ScoreSummary from '../common/ScoreSummary'; import styles from './Card.module.css'; import RepositorySection from './RepositorySection'; @@ -92,7 +92,7 @@ const Card = (props: Props) => {

{props.project.description}

- +
Updated {moment.unix(props.project.updated_at).fromNow()} diff --git a/web/src/layout/search/__snapshots__/Card.test.tsx.snap b/web/src/layout/search/__snapshots__/Card.test.tsx.snap index f6129abf..90a20fb2 100644 --- a/web/src/layout/search/__snapshots__/Card.test.tsx.snap +++ b/web/src/layout/search/__snapshots__/Card.test.tsx.snap @@ -221,65 +221,64 @@ exports[`Card creates snapshot 1`] = ` class="d-none d-md-block d-lg-none d-xl-block d-lg-none d-xl-block" >
- 89 +
+ 89 +
- - - - - - - Documentation - - - Docs - -
-
+ + + + + + Documentation + +
75
- - - - - - - License - -
-
+ + + + + + License + +
80
-
-
- - - - - - - Best Practices - -
-
+ + + + + + + + + Best Practices + +
100
+ style="width: calc(100% - 5px);" + > +
+
- - - - - - + + + + + Security + +
+
- Security - + 100 +
+
+
+
+
+
+
+
+
+ + + + + + + Legal + +
- 100 + 75
+ style="width: calc(75% - 5px);" + > +
+
diff --git a/web/src/styles/default.scss b/web/src/styles/default.scss index cd8f5c4b..45e0b4c8 100644 --- a/web/src/styles/default.scss +++ b/web/src/styles/default.scss @@ -26,6 +26,11 @@ $container-max-widths: ( --rm-yellow: #f9c74f; --rm-orange: #f8961e; --rm-red: #f94144; + + --rm-rgb-green: 144, 190, 109; + --rm-rgb-yellow: 249, 199, 79; + --rm-rgb-orange: 248, 150, 30; + --rm-rgb-red: 249, 65, 68; } html, diff --git a/web/src/types.ts b/web/src/types.ts index ffe5fd08..9606bae9 100644 --- a/web/src/types.ts +++ b/web/src/types.ts @@ -128,11 +128,12 @@ export enum LinterId { } export enum ScoreType { + BestPractices = 'best_practices', Documentation = 'documentation', + Global = 'global', + Legal = 'legal', License = 'license', - BestPractices = 'best_practices', Security = 'security', - Global = 'global', } export enum SortDirection {