diff --git a/api/src/lib/organizations.ts b/api/src/lib/organizations.ts index cce648829..b1f8c021a 100644 --- a/api/src/lib/organizations.ts +++ b/api/src/lib/organizations.ts @@ -37,7 +37,7 @@ export const Organization = Type.Object({ name: Type.String({ description: "The organization's display name." }), slug: Type.String({ description: - "The organization's slug in LFX Insights, as in its organization page URL `https://insights.linuxfoundation.org/organization/{slug}`. It can change, for example when the organization is renamed. An empty string when the organization has no public page, so there is no page to link to.", + "The organization's slug in LFX Insights, as in its organization page URL `https://insights.linuxfoundation.org/company/{slug}`. It can change, for example when the organization is renamed. An empty string when the organization has no public page, so there is no page to link to.", }), logo: Type.String({ description: "URL of the organization's logo image. An empty string when it has none.", @@ -56,7 +56,7 @@ export const OrganizationParams = Type.Object({ slug: Type.String({ minLength: 1, description: - "The organization's slug, as in its organization page URL `https://insights.linuxfoundation.org/organization/{slug}` and in the `slug` the organization leaderboards return.", + "The organization's slug, as in its organization page URL `https://insights.linuxfoundation.org/company/{slug}` and in the `slug` the organization leaderboards return.", }), }); diff --git a/docs/knowledge/flow-caching.md b/docs/knowledge/flow-caching.md index 572dc99c4..151990ef3 100644 --- a/docs/knowledge/flow-caching.md +++ b/docs/knowledge/flow-caching.md @@ -61,7 +61,7 @@ or is cleared by a deploy or a manual workflow. in Redis. - **Uncached:** auth, health, events, chat, collections, community, `/api/security/**`, `/api/report`, project and collection pages, the API docs, OG and image routes. -- **Organization pages** (`/organization/**`, 1 day) and `/api/organization-page/**` (1 hour) turn +- **Company pages** (`/company/**`, 1 day) and `/api/organization-page/**` (1 hour) turn off stale-while-revalidate, so they expire in Redis at the TTL. All other rules keep Nitro's default stale-while-revalidate. Past the TTL, the next request gets diff --git a/frontend/app/components/modules/badges/components/badges-popover.vue b/frontend/app/components/modules/badges/components/badges-popover.vue index 6289b628a..3ba0a1e53 100644 --- a/frontend/app/components/modules/badges/components/badges-popover.vue +++ b/frontend/app/components/modules/badges/components/badges-popover.vue @@ -62,7 +62,7 @@ SPDX-License-Identifier: MIT @@ -89,6 +89,7 @@ import { computed } from 'vue'; import { LfxRoutes } from '~/components/shared/types/routes'; import LfxButton from '~/components/uikit/button/button.vue'; import LfxIcon from '~/components/uikit/icon/icon.vue'; +import { leaderboardSlug } from '~~/config/leaderboard-slugs'; import { tierConfigs, getTierTagStyle } from '../config/tiers.config'; import type { ProjectBadge } from '../types/badge.types'; diff --git a/frontend/app/components/modules/badges/config/badges/active-organizations.config.ts b/frontend/app/components/modules/badges/config/badges/active-organizations.config.ts index 669168962..2eb2fa1c8 100644 --- a/frontend/app/components/modules/badges/config/badges/active-organizations.config.ts +++ b/frontend/app/components/modules/badges/config/badges/active-organizations.config.ts @@ -4,8 +4,8 @@ import { BadgeTier, type BadgeConfig } from '../../types/badge.types'; export const activeOrganizationsBadgeConfig: BadgeConfig = { - title: 'Active organizations', - description: 'Unique organizations contributing in the last 12 months', + title: 'Active companies', + description: 'Unique companies contributing in the last 12 months', leaderboardKey: 'active-organizations', badgeImages: { [BadgeTier.BRONZE]: '/images/badges/active-organizations/bronze.png', diff --git a/frontend/app/components/modules/collection/components/details/badge-details.vue b/frontend/app/components/modules/collection/components/details/badge-details.vue index 3597a9f8a..d98441a30 100644 --- a/frontend/app/components/modules/collection/components/details/badge-details.vue +++ b/frontend/app/components/modules/collection/components/details/badge-details.vue @@ -54,7 +54,7 @@ SPDX-License-Identifier: MIT @@ -111,6 +111,7 @@ import { LfxRoutes } from '~/components/shared/types/routes'; import LfxIconButton from '~/components/uikit/icon-button/icon-button.vue'; import LfxPopover from '~/components/uikit/popover/popover.vue'; import LfxTooltip from '~/components/uikit/tooltip/tooltip.vue'; +import { leaderboardSlug } from '~~/config/leaderboard-slugs'; import type { ProjectInsights } from '~~/types/project'; const props = defineProps<{ diff --git a/frontend/app/components/modules/collection/components/details/dependency-column.vue b/frontend/app/components/modules/collection/components/details/dependency-column.vue index 1b00042c3..7f3388c1c 100644 --- a/frontend/app/components/modules/collection/components/details/dependency-column.vue +++ b/frontend/app/components/modules/collection/components/details/dependency-column.vue @@ -29,7 +29,7 @@ SPDX-License-Identifier: MIT :size="12" /> {{ props.project.organizationDependencyCount }} - {{ pluralize('organization', props.project.organizationDependencyCount) }} + {{ pluralize('company', props.project.organizationDependencyCount) }}
・ diff --git a/frontend/app/components/modules/collection/components/details/dependency-details.vue b/frontend/app/components/modules/collection/components/details/dependency-details.vue index 2d0067a70..bfbbd04fa 100644 --- a/frontend/app/components/modules/collection/components/details/dependency-details.vue +++ b/frontend/app/components/modules/collection/components/details/dependency-details.vue @@ -45,13 +45,13 @@ SPDX-License-Identifier: MIT
-

Organization dependency

+

Company dependency

{{ formatNumber(props.project.organizationDependencyCount) }} - {{ pluralize('organization', props.project.organizationDependencyCount) }} + {{ pluralize('company', props.project.organizationDependencyCount) }}

Other {{ formatNumber(otherOrganizationsCount) }} - {{ pluralize('organization', otherOrganizationsCount) }} + {{ pluralize('company', otherOrganizationsCount) }}

{{ otherOrganizationsPercentage }}% of all contributions

diff --git a/frontend/app/components/modules/collection/components/details/filters.vue b/frontend/app/components/modules/collection/components/details/filters.vue index 8ffe4bf47..f609375d5 100644 --- a/frontend/app/components/modules/collection/components/details/filters.vue +++ b/frontend/app/components/modules/collection/components/details/filters.vue @@ -71,7 +71,7 @@ SPDX-License-Identifier: MIT /> - Contributor/Organization dependency + Contributor/Company dependency Achievements diff --git a/frontend/app/components/modules/explore/components/explore-header.vue b/frontend/app/components/modules/explore/components/explore-header.vue index 673fddadd..6004bd37c 100644 --- a/frontend/app/components/modules/explore/components/explore-header.vue +++ b/frontend/app/components/modules/explore/components/explore-header.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: MIT most critical open source projects

- LFX Insights helps developers and their organizations make smarter decisions about the open source projects they + LFX Insights helps developers and their companies make smarter decisions about the open source projects they depend on

diff --git a/frontend/app/components/modules/leaderboards/components/sections/leaderboard-card.vue b/frontend/app/components/modules/leaderboards/components/sections/leaderboard-card.vue index 5e528aa16..626254f94 100644 --- a/frontend/app/components/modules/leaderboards/components/sections/leaderboard-card.vue +++ b/frontend/app/components/modules/leaderboards/components/sections/leaderboard-card.vue @@ -101,6 +101,7 @@ import LfxCard from '~/components/uikit/card/card.vue'; import LfxChip from '~/components/uikit/chip/chip.vue'; import LfxIconButton from '~/components/uikit/icon-button/icon-button.vue'; import LfxIcon from '~/components/uikit/icon/icon.vue'; +import { leaderboardSlug } from '~~/config/leaderboard-slugs'; import type { Leaderboard } from '~~/types/leaderboard/leaderboard'; import LfxTableHeader from './table-header.vue'; @@ -115,7 +116,7 @@ const props = defineProps<{ const isHovered = ref(false); const navigateToLeaderboard = () => { - router.push({ name: LfxRoutes.LEADERBOARD, params: { key: props.config.key as string } }); + router.push({ name: LfxRoutes.LEADERBOARD, params: { key: leaderboardSlug(props.config.key) } }); }; const handleCardClick = (event: MouseEvent) => { @@ -135,7 +136,7 @@ const handleShare = () => { const resolvedRoute = router.resolve({ name: LfxRoutes.LEADERBOARD, - params: { key: props.config.key as string }, + params: { key: leaderboardSlug(props.config.key) }, }); const url = new URL(resolvedRoute.href, window.location.origin); diff --git a/frontend/app/components/modules/leaderboards/components/sections/leaderboard-mobile-nav.vue b/frontend/app/components/modules/leaderboards/components/sections/leaderboard-mobile-nav.vue index 60bd1c22d..dcf0a1a4a 100644 --- a/frontend/app/components/modules/leaderboards/components/sections/leaderboard-mobile-nav.vue +++ b/frontend/app/components/modules/leaderboards/components/sections/leaderboard-mobile-nav.vue @@ -29,7 +29,7 @@ SPDX-License-Identifier: MIT @@ -66,6 +66,7 @@ import { LfxRoutes } from '~/components/shared/types/routes'; import useScroll from '~/components/shared/utils/scroll'; import LfxIcon from '~/components/uikit/icon/icon.vue'; import LfxModal from '~/components/uikit/modal/modal.vue'; +import { leaderboardSlug } from '~~/config/leaderboard-slugs'; import leaderboardConfigs from '../../config/index.config'; diff --git a/frontend/app/components/modules/leaderboards/components/sections/leaderboard-sidebar.vue b/frontend/app/components/modules/leaderboards/components/sections/leaderboard-sidebar.vue index 7b8fd9c27..1f4d80524 100644 --- a/frontend/app/components/modules/leaderboards/components/sections/leaderboard-sidebar.vue +++ b/frontend/app/components/modules/leaderboards/components/sections/leaderboard-sidebar.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: MIT @@ -27,6 +27,7 @@ import { computed } from 'vue'; import { LfxRoutes } from '~/components/shared/types/routes'; import LfxIcon from '~/components/uikit/icon/icon.vue'; +import { leaderboardSlug } from '~~/config/leaderboard-slugs'; import leaderboardConfigs from '../../config/index.config'; diff --git a/frontend/app/components/modules/leaderboards/config/most-active-organizations.config.ts b/frontend/app/components/modules/leaderboards/config/most-active-organizations.config.ts index 44e3894e9..b74d8d053 100644 --- a/frontend/app/components/modules/leaderboards/config/most-active-organizations.config.ts +++ b/frontend/app/components/modules/leaderboards/config/most-active-organizations.config.ts @@ -7,12 +7,12 @@ import type { LeaderboardConfig } from './types/leaderboard.types'; export const mostActiveOrganizationsConfig: LeaderboardConfig = { key: 'active-organizations', - name: 'Most active organizations', + name: 'Most active companies', description: - 'These projects brought together the largest number of distinct contributing organizations in the past 12 months.', + 'These projects brought together the largest number of distinct contributing companies in the past 12 months.', icon: 'buildings', dataDisplay: LfxProjectIntegerRowDisplay, minimizedDataDisplay: LfxProjectIntegerMinimizedRowDisplay, entityLabel: 'Project', - metricLabel: 'Organizations (12M)', + metricLabel: 'Companies (12M)', }; diff --git a/frontend/app/components/modules/leaderboards/config/top-100-organizations.config.ts b/frontend/app/components/modules/leaderboards/config/top-100-organizations.config.ts index 2525567fe..41d920395 100644 --- a/frontend/app/components/modules/leaderboards/config/top-100-organizations.config.ts +++ b/frontend/app/components/modules/leaderboards/config/top-100-organizations.config.ts @@ -7,12 +7,12 @@ import type { LeaderboardConfig } from './types/leaderboard.types'; export const top100OrganizationsConfig: LeaderboardConfig = { key: 'organizations', - name: 'Top 100 organizations', + name: 'Top 100 companies', description: - 'Most influential organizations based on the total number of contributions made over the last 12 months.', + 'Most influential companies based on the total number of contributions made over the last 12 months.', icon: 'building-flag', dataDisplay: LfxOrganizationRowDisplay, minimizedDataDisplay: LfxOrganizationMinimizedRowDisplay, - entityLabel: 'Organization', + entityLabel: 'Company', metricLabel: 'Contributions (12M)', }; diff --git a/frontend/app/components/modules/organization/components/header.vue b/frontend/app/components/modules/organization/components/header.vue index 7c6a7bbc5..28e97c4a2 100644 --- a/frontend/app/components/modules/organization/components/header.vue +++ b/frontend/app/components/modules/organization/components/header.vue @@ -228,7 +228,7 @@ const handleShare = () => { url.hash = ''; openShareModal({ url: url.toString(), - title: `LFX Insights | ${props.organization?.displayName || 'Organization'}`, + title: `LFX Insights | ${props.organization?.displayName || 'Company'}`, area: props.organization?.displayName, }); }; diff --git a/frontend/app/components/modules/organization/components/overview/activity-chart.vue b/frontend/app/components/modules/organization/components/overview/activity-chart.vue index 2aa6e0ecf..db1696400 100644 --- a/frontend/app/components/modules/organization/components/overview/activity-chart.vue +++ b/frontend/app/components/modules/organization/components/overview/activity-chart.vue @@ -73,7 +73,7 @@ import type { OrgActivityTimeseries } from '~~/types/organization-page'; const route = useRoute(); const orgSlug = route.params.orgSlug as string; const { organization } = storeToRefs(useOrganizationPageStore()); -const orgDisplayName = computed(() => organization.value?.displayName || 'this organization'); +const orgDisplayName = computed(() => organization.value?.displayName || 'this company'); const currentYear = new Date().getFullYear().toString(); const queryKey = computed(() => [TanstackKey.ORGANIZATION_PAGE_ACTIVITY, orgSlug]); diff --git a/frontend/app/components/modules/organization/components/overview/contributors-chart.vue b/frontend/app/components/modules/organization/components/overview/contributors-chart.vue index d47bb32ae..25d4daae0 100644 --- a/frontend/app/components/modules/organization/components/overview/contributors-chart.vue +++ b/frontend/app/components/modules/organization/components/overview/contributors-chart.vue @@ -73,7 +73,7 @@ import type { OrgContributorTimeseries } from '~~/types/organization-page'; const route = useRoute(); const orgSlug = route.params.orgSlug as string; const { organization } = storeToRefs(useOrganizationPageStore()); -const orgDisplayName = computed(() => organization.value?.displayName || 'this organization'); +const orgDisplayName = computed(() => organization.value?.displayName || 'this company'); const currentYear = new Date().getFullYear().toString(); const queryKey = computed(() => [TanstackKey.ORGANIZATION_PAGE_CONTRIBUTORS_TIMESERIES, orgSlug]); diff --git a/frontend/app/components/modules/organization/components/overview/kpi-row.vue b/frontend/app/components/modules/organization/components/overview/kpi-row.vue index 1132548d3..08e9d1c13 100644 --- a/frontend/app/components/modules/organization/components/overview/kpi-row.vue +++ b/frontend/app/components/modules/organization/components/overview/kpi-row.vue @@ -79,7 +79,7 @@ import type { OrganizationKpis } from '~~/types/organization-page'; const route = useRoute(); const orgSlug = route.params.orgSlug as string; const { organization } = storeToRefs(useOrganizationPageStore()); -const orgDisplayName = computed(() => organization.value?.displayName || 'this organization'); +const orgDisplayName = computed(() => organization.value?.displayName || 'this company'); const queryKey = computed(() => [TanstackKey.ORGANIZATION_PAGE_KPIS, orgSlug]); diff --git a/frontend/app/components/modules/organization/components/overview/locked-contributors-section.vue b/frontend/app/components/modules/organization/components/overview/locked-contributors-section.vue index b0559b84f..9e70189ee 100644 --- a/frontend/app/components/modules/organization/components/overview/locked-contributors-section.vue +++ b/frontend/app/components/modules/organization/components/overview/locked-contributors-section.vue @@ -24,7 +24,7 @@ SPDX-License-Identifier: MIT size="medium" > Open in LFX - + organization.value?.displayName || 'your organization'); +const orgDisplayName = computed(() => organization.value?.displayName || 'your company'); diff --git a/frontend/app/components/shared/layout/search/search.vue b/frontend/app/components/shared/layout/search/search.vue index 1f9a9ed3b..b0e9a2078 100644 --- a/frontend/app/components/shared/layout/search/search.vue +++ b/frontend/app/components/shared/layout/search/search.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: MIT class="text-neutral-400 font-normal" :size="14" /> -

Search projects, repositories, collections, or organizations

+

Search projects, repositories, collections, or companies

${Number.isNaN(data.value) ? 0 : data.value} - ${params.seriesName}s + ${pluralize(params.seriesName || '', Number(data.value))} ${ Number.isNaN(data.percentage) ? 0 : data.percentage diff --git a/frontend/app/pages/collection/details/[slug]/contributors.vue b/frontend/app/pages/collection/details/[slug]/contributors.vue index a89ad0f33..6509305a8 100644 --- a/frontend/app/pages/collection/details/[slug]/contributors.vue +++ b/frontend/app/pages/collection/details/[slug]/contributors.vue @@ -38,7 +38,7 @@ const title = computed(() => const description = computed(() => collection.value?.name ? `See who contributes across every project in the ${collection.value.name} collection, ` + - 'with insights on maintainers, top contributors, and organizations.' + 'with insights on maintainers, top contributors, and companies.' : 'See who contributes across every project in this collection.', ); diff --git a/frontend/app/pages/collection/details/[slug]/development.vue b/frontend/app/pages/collection/details/[slug]/development.vue index 6501f6f12..04284628b 100644 --- a/frontend/app/pages/collection/details/[slug]/development.vue +++ b/frontend/app/pages/collection/details/[slug]/development.vue @@ -38,7 +38,7 @@ const title = computed(() => const description = computed(() => collection.value?.name ? `See development activity aggregated across every project in the ${collection.value.name} collection.` - : 'See active contributors and organizations aggregated across every project in this collection.', + : 'See active contributors and companies aggregated across every project in this collection.', ); useSeoMeta({ diff --git a/frontend/app/pages/organization/[orgSlug].vue b/frontend/app/pages/company/[orgSlug].vue similarity index 95% rename from frontend/app/pages/organization/[orgSlug].vue rename to frontend/app/pages/company/[orgSlug].vue index 29232e252..f37d633ea 100644 --- a/frontend/app/pages/organization/[orgSlug].vue +++ b/frontend/app/pages/company/[orgSlug].vue @@ -12,7 +12,7 @@ SPDX-License-Identifier: MIT v-else-if="!isLoading && !data" class="w-full flex justify-center py-20 text-neutral-500 text-sm" > - Organization not found. + Company not found.
@@ -44,7 +44,7 @@ const { isLoading, data, suspense, isError, error } = useQuery { await suspense(); if (isError.value) { - const statusMessage = error.value?.message || 'Organization Not Found'; + const statusMessage = error.value?.message || 'Company Not Found'; if (import.meta.server) { throw createError({ statusCode: 404, statusMessage }); diff --git a/frontend/app/pages/organization/[orgSlug]/index.vue b/frontend/app/pages/company/[orgSlug]/index.vue similarity index 96% rename from frontend/app/pages/organization/[orgSlug]/index.vue rename to frontend/app/pages/company/[orgSlug]/index.vue index cf0d6e169..19dda4fd6 100644 --- a/frontend/app/pages/organization/[orgSlug]/index.vue +++ b/frontend/app/pages/company/[orgSlug]/index.vue @@ -24,7 +24,7 @@ const title = computed(() => const description = computed(() => organization.value ? organization.value.description || `Explore ${organization.value.displayName}'s open source contributions` - : 'Explore organization insights on LFX', + : 'Explore company insights on LFX', ); const url = computed(() => `${config.public.appUrl}${route.fullPath}`); diff --git a/frontend/app/pages/leaderboards/[key].vue b/frontend/app/pages/leaderboards/[key].vue index 0a9f7599b..18bf2e8e8 100644 --- a/frontend/app/pages/leaderboards/[key].vue +++ b/frontend/app/pages/leaderboards/[key].vue @@ -14,9 +14,23 @@ import { computed } from 'vue'; import LfxLeaderboardDetail from '~/components/modules/leaderboards/components/views/leaderboard-detail.vue'; import leaderboardConfigs from '~/components/modules/leaderboards/config/index.config'; +import { leaderboardKeyFromSlug, legacyLeaderboardSlug } from '~~/config/leaderboard-slugs'; + +definePageMeta({ + middleware: [ + (to) => { + const slug = legacyLeaderboardSlug(String(to.params.key ?? '')); + if (!slug) return; + return navigateTo(to.fullPath.replace(/^\/leaderboards\/[^/?#]+/i, `/leaderboards/${slug}`), { + redirectCode: 301, + replace: true, + }); + }, + ], +}); const route = useRoute(); -const leaderboardKey = computed(() => route.params.key as string); +const leaderboardKey = computed(() => leaderboardKeyFromSlug(route.params.key as string)); const config = computed(() => leaderboardConfigs.find((c) => c.key === leaderboardKey.value)); const title = computed(() => config.value?.name || 'Leaderboard'); diff --git a/frontend/app/pages/organization/[...slug].vue b/frontend/app/pages/organization/[...slug].vue new file mode 100644 index 000000000..2366b12c4 --- /dev/null +++ b/frontend/app/pages/organization/[...slug].vue @@ -0,0 +1,20 @@ + + + + diff --git a/frontend/app/pages/project/[slug]/contributors.vue b/frontend/app/pages/project/[slug]/contributors.vue index b41471119..f829e8bac 100644 --- a/frontend/app/pages/project/[slug]/contributors.vue +++ b/frontend/app/pages/project/[slug]/contributors.vue @@ -26,13 +26,13 @@ const title = computed(() => { if (!name) return 'LFX Insights'; const widgetName = widget && lfxWidgets[widget as Widget]?.name?.length ? lfxWidgets[widget as Widget]?.name : 'Contributors Insights'; - return widget ? `${name} ${widgetName} | LFX Insights` : `${name} Contributors & Organizations | LFX Insights`; + return widget ? `${name} ${widgetName} | LFX Insights` : `${name} Contributors & Companies | LFX Insights`; }); const description = computed(() => project.value?.name ? `See who contributes to ${project.value.name}, ` + - `with insights on maintainers, top contributors, and organizations in open source.` - : 'See who contributes to this project, with insights on maintainers, top contributors, and organizations.', + `with insights on maintainers, top contributors, and companies in open source.` + : 'See who contributes to this project, with insights on maintainers, top contributors, and companies.', ); const imageAlt = computed(() => `${project.value?.name} Contributors Insights - LFX Insights`); diff --git a/frontend/app/pages/project/[slug]/repository-group/[groupSlug]/contributors.vue b/frontend/app/pages/project/[slug]/repository-group/[groupSlug]/contributors.vue index c618fc20b..2fddb6284 100644 --- a/frontend/app/pages/project/[slug]/repository-group/[groupSlug]/contributors.vue +++ b/frontend/app/pages/project/[slug]/repository-group/[groupSlug]/contributors.vue @@ -32,7 +32,7 @@ const title = computed(() => { const description = computed( () => `See who contributes to ${project?.value?.name} ${selectedRepositoryGroup.value?.name}, ` + - `with insights on maintainers, top contributors, and organizations in open source.`, + `with insights on maintainers, top contributors, and companies in open source.`, ); const imageAlt = computed(() => `${selectedRepositoryGroup.value?.name} Repositories Contributors - LFX Insights`); diff --git a/frontend/app/pages/project/[slug]/repository/[name]/contributors.vue b/frontend/app/pages/project/[slug]/repository/[name]/contributors.vue index 04010e200..ec7d7b3c3 100644 --- a/frontend/app/pages/project/[slug]/repository/[name]/contributors.vue +++ b/frontend/app/pages/project/[slug]/repository/[name]/contributors.vue @@ -34,7 +34,7 @@ const title = computed( const description = computed( () => `See who contributes to ${project?.value?.name} ${repoName.value}, ` + - `with insights on maintainers, top contributors, and organizations in open source.`, + `with insights on maintainers, top contributors, and companies in open source.`, ); const imageAlt = computed(() => `${project.value?.name} ${repoName.value} Repository Contributors - LFX Insights`); diff --git a/frontend/app/pages/report/cncf-france.vue b/frontend/app/pages/report/cncf-france.vue index cf3ae28b5..53e2589e9 100644 --- a/frontend/app/pages/report/cncf-france.vue +++ b/frontend/app/pages/report/cncf-france.vue @@ -15,7 +15,7 @@ const country = { code: 'FR', name: 'France', adjective: 'French' }; const title = 'Cloud Native in France | LFX Insights'; const description = - 'Explore code contributions to CNCF projects from people in France and from organizations with French HQ. Powered by the Linux Foundation.'; + 'Explore code contributions to CNCF projects from people in France and from companies with French HQ. Powered by the Linux Foundation.'; useSeoMeta({ title, diff --git a/frontend/config/health-breakdown-templates.ts b/frontend/config/health-breakdown-templates.ts index 3b78002ce..d76efe9b8 100644 --- a/frontend/config/health-breakdown-templates.ts +++ b/frontend/config/health-breakdown-templates.ts @@ -247,7 +247,7 @@ const getMaintainerDescription = (band: CategoryBand, signals: HealthBreakdownRe const maintainerCount = signals.busFactorCount ?? 0; if (band === 'success') { - return `Responsive maintainers, ${maintainerCount} active maintainer${maintainerCount === 1 ? '' : 's'} with merge rights, a stable contributor pipeline, and contributors spanning ${orgCount} organization${orgCount === 1 ? '' : 's'}.`; + return `Responsive maintainers, ${maintainerCount} active maintainer${maintainerCount === 1 ? '' : 's'} with merge rights, a stable contributor pipeline, and contributors spanning ${orgCount} ${orgCount === 1 ? 'company' : 'companies'}.`; } if (band === 'warning') { const teamDetail = @@ -255,9 +255,7 @@ const getMaintainerDescription = (band: CategoryBand, signals: HealthBreakdownRe ? 'A single active maintainer' : `A small team of ${maintainerCount} active maintainers`; const orgDetail = - orgCount <= 1 - ? 'limited organizational diversity' - : `contributors across ${orgCount} organizations`; + orgCount <= 1 ? 'limited company diversity' : `contributors across ${orgCount} companies`; return `${teamDetail} with slow response times, no contributor growth, and ${orgDetail}.`; } const isUnresponsive = @@ -366,7 +364,7 @@ const getCategoryUnavailableDescription = ( const availableSignals: string[] = []; if (signals?.responsivenessAvailable) availableSignals.push('maintainer responsiveness'); if (signals?.busFactorAvailable) availableSignals.push('bus factor'); - if (signals?.orgDiversityAvailable) availableSignals.push('organization diversity'); + if (signals?.orgDiversityAvailable) availableSignals.push('company diversity'); const namedAvailable = availableSignals.length > 0 ? `Only ${availableSignals.join(', ')} ${availableSignals.length === 1 ? 'is' : 'are'} available.` @@ -486,25 +484,25 @@ export const getOrgDiversityRow = (signals: HealthBreakdownResults): SignalRow = if (!signals.orgDiversityAvailable || signals.orgDiversityScore === null) { return { status: 'no-data', - description: blockedSignalDescription('Organization diversity', signals), + description: blockedSignalDescription('Company diversity', signals), }; } const count = signals.orgCount ?? 0; if (signals.orgDiversityScore >= 4) { - return { status: 'positive', description: `Contributors span ${count} organizations.` }; + return { status: 'positive', description: `Contributors span ${count} companies.` }; } if (signals.orgDiversityScore >= 2) { return { status: 'warning', - description: `Contributors come from ${count} organization${count === 1 ? '' : 's'} only.`, + description: `Contributors come from ${count} ${count === 1 ? 'company' : 'companies'} only.`, }; } return { status: 'negative', description: count > 0 - ? `Contributors span ${count} organization${count === 1 ? '' : 's'}, but most repositories lack organizational diversity.` - : 'No organization affiliation data is available for contributors.', + ? `Contributors span ${count} ${count === 1 ? 'company' : 'companies'}, but most repositories lack company diversity.` + : 'No company affiliation data is available for contributors.', }; }; diff --git a/frontend/config/leaderboard-slugs.test.ts b/frontend/config/leaderboard-slugs.test.ts new file mode 100644 index 000000000..adba64300 --- /dev/null +++ b/frontend/config/leaderboard-slugs.test.ts @@ -0,0 +1,38 @@ +// Copyright (c) 2025 The Linux Foundation and each contributor. +// SPDX-License-Identifier: MIT +import { describe, expect, test } from 'vitest'; + +import { + leaderboardKeyFromSlug, + leaderboardSlug, + legacyLeaderboardSlug, +} from './leaderboard-slugs'; + +describe('leaderboard slugs', () => { + test('maps the company leaderboards to their URL slugs and back', () => { + expect(leaderboardSlug('organizations')).toBe('companies'); + expect(leaderboardSlug('active-organizations')).toBe('active-companies'); + expect(leaderboardKeyFromSlug('companies')).toBe('organizations'); + expect(leaderboardKeyFromSlug('active-companies')).toBe('active-organizations'); + }); + + test('passes other keys and slugs through unchanged', () => { + expect(leaderboardSlug('contributors')).toBe('contributors'); + expect(leaderboardKeyFromSlug('contributors')).toBe('contributors'); + expect(leaderboardKeyFromSlug('organizations')).toBe('organizations'); + }); + + test('ignores inherited object properties', () => { + expect(leaderboardKeyFromSlug('constructor')).toBe('constructor'); + expect(leaderboardKeyFromSlug('__proto__')).toBe('__proto__'); + expect(leaderboardSlug('toString')).toBe('toString'); + }); + + test('finds the company slug for old leaderboard URL segments in any case', () => { + expect(legacyLeaderboardSlug('organizations')).toBe('companies'); + expect(legacyLeaderboardSlug('Active-Organizations')).toBe('active-companies'); + expect(legacyLeaderboardSlug('ORGANIZATIONS')).toBe('companies'); + expect(legacyLeaderboardSlug('companies')).toBeUndefined(); + expect(legacyLeaderboardSlug('constructor')).toBeUndefined(); + }); +}); diff --git a/frontend/config/leaderboard-slugs.ts b/frontend/config/leaderboard-slugs.ts new file mode 100644 index 000000000..69f7ace6a --- /dev/null +++ b/frontend/config/leaderboard-slugs.ts @@ -0,0 +1,24 @@ +// Copyright (c) 2025 The Linux Foundation and each contributor. +// SPDX-License-Identifier: MIT + +// URL slugs that differ from the leaderboard key (the key is also the Tinybird `leaderboardType`). +const slugByKey: Record = { + organizations: 'companies', + 'active-organizations': 'active-companies', +}; + +const keyBySlug: Record = Object.fromEntries( + Object.entries(slugByKey).map(([key, slug]) => [slug, key]), +); + +export const leaderboardSlug = (key: string): string => + Object.hasOwn(slugByKey, key) ? slugByKey[key]! : key; + +export const leaderboardKeyFromSlug = (slug: string): string => + Object.hasOwn(keyBySlug, slug) ? keyBySlug[slug]! : slug; + +// Old leaderboard URL segments (any case) that now redirect to a company slug. +export const legacyLeaderboardSlug = (segment: string): string | undefined => { + const key = segment.toLowerCase(); + return Object.hasOwn(slugByKey, key) ? slugByKey[key] : undefined; +}; diff --git a/frontend/docs/.vitepress/config.ts b/frontend/docs/.vitepress/config.ts index 697e5ad0c..f8cdf3dc4 100644 --- a/frontend/docs/.vitepress/config.ts +++ b/frontend/docs/.vitepress/config.ts @@ -92,7 +92,7 @@ export default defineConfig({ { text: 'LFX Data Copilot', link: '/features/lfx-data-copilot/index.md' }, { text: 'Repository Groups', link: '/features/repository-groups/index.md' }, { text: 'Community Collections', link: '/features/community-collections/index.md' }, - { text: 'Organization Page', link: '/features/organization-page/index.md' }, + { text: 'Company Page', link: '/features/organization-page/index.md' }, ], }, { diff --git a/frontend/docs/features/community-collections/index.md b/frontend/docs/features/community-collections/index.md index 50f52e0b9..a34db7830 100644 --- a/frontend/docs/features/community-collections/index.md +++ b/frontend/docs/features/community-collections/index.md @@ -46,7 +46,7 @@ The Projects tab lists all projects in the collection as a sortable table. Each - **Impact** — a pill showing the project's Impact tier (Foundational, Major, Moderate, or Minor) with the underlying score. Projects without an impact score show **N/A**. --> - **Contributors** — contributor count (sortable) -- **Contributor / Organization dependency** — concentration risk indicators +- **Contributor / Company dependency** — concentration risk indicators - **Achievements** — earned badges An **Only LF projects** toggle lets you filter the list to Linux Foundation–hosted projects only. @@ -60,11 +60,11 @@ A **date range picker** in the tab bar scopes all widgets on that tab to a speci **Contributors** — contributor-focused metrics aggregated across the collection: - Contributors leaderboard -- Organizations leaderboard +- Companies leaderboard - Active contributors -- Active organizations +- Active companies - Contributor dependency -- Organization dependency +- Company dependency - Quarterly contributor retention - Geographical distribution diff --git a/frontend/docs/features/organization-page/index.md b/frontend/docs/features/organization-page/index.md index 969f6d170..ce5b37c5f 100644 --- a/frontend/docs/features/organization-page/index.md +++ b/frontend/docs/features/organization-page/index.md @@ -1,10 +1,10 @@ -# Organization Page +# Company Page -Use the Organization Page to understand how your company contributes to critical open source projects — who is contributing, which projects you're involved in, and how your engagement has changed over time. +Use the Company Page to understand how your company contributes to critical open source projects — who is contributing, which projects you're involved in, and how your engagement has changed over time. ## Key Metrics -Three numbers at the top of the page give you an at-a-glance health check of your organization's open source activity over the **last 2 years**: +Three numbers at the top of the page give you an at-a-glance health check of your company's open source activity over the **last 2 years**: - **Active contributors** — how many of your employees made at least one code contribution (commit, pull request, or code review). Shows a year-over-year trend so you can see if engagement is growing or declining. - **Maintainer roles** — how many maintainer or owner roles your contributors held across all projects in the last 2 years. A higher number signals deeper trust and influence in those communities. @@ -12,11 +12,11 @@ Three numbers at the top of the page give you an at-a-glance health check of you ## Contributions Over Time -A bar chart showing your organization's total code contributions per year for the last 10 years. Use it to spot periods of growth, sustained investment, or pullback across your open source program. +A bar chart showing your company's total code contributions per year for the last 10 years. Use it to spot periods of growth, sustained investment, or pullback across your open source program. ## Contributors Over Time -A bar chart showing how many unique contributors your organization had per year over the last 10 years. Pair it with the Contributions chart to distinguish between a growing team and a shrinking one that's working harder. +A bar chart showing how many unique contributors your company had per year over the last 10 years. Pair it with the Contributions chart to distinguish between a growing team and a shrinking one that's working harder. ## Critical Projects @@ -24,7 +24,7 @@ A ranked table of the projects your contributors were involved in over the **las Each project row shows: -- **Technical influence** — your organization's share of code contributions relative to what the whole project community produced, expressed as one of four levels: +- **Technical influence** — your company's share of code contributions relative to what the whole project community produced, expressed as one of four levels: - **Leading** — a large share; your team is a primary driver of the project. - **Contributing** — a meaningful share; consistent and committed involvement. - **Participating** — a small but non-zero share; actively helping. diff --git a/frontend/docs/introduction/contributor-affiliations/index.md b/frontend/docs/introduction/contributor-affiliations/index.md index 3f559495f..e0334b820 100644 --- a/frontend/docs/introduction/contributor-affiliations/index.md +++ b/frontend/docs/introduction/contributor-affiliations/index.md @@ -1,8 +1,8 @@ # Contributor Affiliations -Contributor affiliations map individual contributors to the organizations they represent. This is one of the most important data points in LFX Insights — it powers the Organizations Leaderboard, Organization Dependency metrics, and helps answer the question: *which companies are investing in this project?* +Contributor affiliations map individual contributors to the companies they represent. This is one of the most important data points in LFX Insights — it powers the Companies Leaderboard, Company Dependency metrics, and helps answer the question: *which companies are investing in this project?* -Getting affiliations right is hard. Contributors change jobs, use personal email addresses, and contribute across multiple organizations. GitHub profile data alone is often incomplete or outdated. LFX Insights uses a multi-signal enrichment process to build the most accurate picture possible. +Getting affiliations right is hard. Contributors change jobs, use personal email addresses, and contribute across multiple companies. GitHub profile data alone is often incomplete or outdated. LFX Insights uses a multi-signal enrichment process to build the most accurate picture possible. ## How We Determine Affiliations @@ -12,17 +12,17 @@ We combine signals from multiple sources, each with different levels of confiden These are signals we can observe from publicly available data: -- **Git commit emails** — The email address in a commit's author field often contains an organizational domain (e.g., `jane@company.com`). This is one of the most common affiliation signals. +- **Git commit emails** — The email address in a commit's author field often contains a company domain (e.g., `jane@company.com`). This is one of the most common affiliation signals. - **GitHub profile** — A contributor's GitHub profile may list their employer, organization memberships, or a company-affiliated email address. - **Social profiles** — LinkedIn and other linked profiles can indicate current employment. -- **Email domains** — We maintain a mapping of known organizational email domains to their parent companies, including subsidiaries and acquisitions. +- **Email domains** — We maintain a mapping of known company email domains to their parent companies, including subsidiaries and acquisitions. ### LF-Internal Signals For contributors who have a Linux Foundation ID (LF ID), we can access additional high-confidence data: - **LF ID profile** — Contributors may have employer information stored in their LF ID account. -- **LF membership records** — Organizational membership data from the Linux Foundation's records. +- **LF membership records** — Company membership data from the Linux Foundation's records. These internal signals are typically more reliable than public signals because they are self-reported and verified through the LF's membership processes. @@ -39,8 +39,8 @@ The enrichment process runs continuously as new data is ingested, so affiliation Contributors often appear under multiple identities — different email addresses, usernames, or social accounts. Our platform runs several services to clean and deduplicate this data: - **Identity matching** — We merge multiple identities that belong to the same person into a single contributor profile. -- **Organization normalization** — We resolve different names for the same organization (e.g., "Google LLC", "Google Inc.", "Alphabet") into a canonical entity. -- **Historical tracking** — We maintain affiliation history so that past contributions are attributed to the correct organization at the time they were made. +- **Company normalization** — We resolve different names for the same company (e.g., "Google LLC", "Google Inc.", "Alphabet") into a canonical entity. +- **Historical tracking** — We maintain affiliation history so that past contributions are attributed to the correct company at the time they were made. For more details on how we handle data quality across the platform, see [Data Quality](/introduction/data-quality/). @@ -52,7 +52,7 @@ To review your affiliations: 1. **Log in** to your [LF ID](https://myprofile.lfx.linuxfoundation.org/) account 2. **Navigate** to your profile and select the "Work History & Affiliations" tab -3. **Review** your current and historical organization affiliations +3. **Review** your current and historical company affiliations 4. **Edit** any incorrect affiliations — for example, updating your current employer or correcting a past affiliation date range ![LFX Profile - Work History & Affiliations](../../images/my-lfx-profile.png) diff --git a/frontend/docs/introduction/data-quality/index.md b/frontend/docs/introduction/data-quality/index.md index f96301179..73f62c5b3 100644 --- a/frontend/docs/introduction/data-quality/index.md +++ b/frontend/docs/introduction/data-quality/index.md @@ -16,7 +16,7 @@ Here are some examples of the challenges we face: - Frequently change employers - Add personal or hobby projects to their open-source profiles -**Organizations** +**Companies** - Have complex corporate structures with nested subsidiaries - Rename, merge, or restructure @@ -38,7 +38,7 @@ We collect raw data from third-party sources like GitHub via our Community Data ### Step 2: Data Onboarding -We ingest data into LFX systems and structure it for analysis. This includes linking identities, mapping contributors to organizations, and parsing contribution records. +We ingest data into LFX systems and structure it for analysis. This includes linking identities, mapping contributors to companies, and parsing contribution records. ### Step 3: AI-Powered Enrichment & Deduplication diff --git a/frontend/docs/introduction/lf-oss-index/index.md b/frontend/docs/introduction/lf-oss-index/index.md index 48900e853..0d3fcb095 100644 --- a/frontend/docs/introduction/lf-oss-index/index.md +++ b/frontend/docs/introduction/lf-oss-index/index.md @@ -4,7 +4,7 @@ How we define which projects are included in Insights. ## What is the LF Open Source Index? -The LF Open Source Index is a curated view of the most critical open source projects powering our modern digital infrastructure. It defines the scope of projects shown in LFX Insights, helping developers, maintainers, and organizations understand what’s truly foundational to the open source ecosystem. +The LF Open Source Index is a curated view of the most critical open source projects powering our modern digital infrastructure. It defines the scope of projects shown in LFX Insights, helping developers, maintainers, and companies understand what’s truly foundational to the open source ecosystem. ## Which projects are included @@ -69,7 +69,7 @@ The following table details the parameters used in the calculation, along with t | created_since | 1 | 120 | Time since the project was created (in months) | Older project has higher chance of being widely used or being dependent upon. | | updated_since | -1 | 120 | Time since the project was last updated (in months) | Unmaintained projects with no recent commits have higher chance of being less relied upon. | | **contributor_count** | **2** | 5000 | Count of project contributors (with commits) | Different contributors involvement indicates project's importance. | -| org_count | 1 | 10 | Count of distinct organizations that contributors belong to | Indicates cross-organization dependency. | +| org_count | 1 | 10 | Count of distinct companies that contributors belong to | Indicates cross-company dependency. | | commit_frequency | 1 | 1000 | Average number of commits per week in the last year | Higher code churn has slight indication of project's importance. Also, higher susceptibility to vulnerabilities. | | recent_releases_count | 0.5 | 26 | Number of releases in the last year | Frequent releases indicates user dependency. Lower weight since this is not always used. | | closed_issues_count | 0.5 | 5000 | Number of issues closed in the last 90 days | Indicates high contributor involvement and focus on closing user issues. Lower weight since it is dependent on project contributors. | diff --git a/frontend/docs/introduction/maintainers/index.md b/frontend/docs/introduction/maintainers/index.md index 7a15683d8..f35f40d1c 100644 --- a/frontend/docs/introduction/maintainers/index.md +++ b/frontend/docs/introduction/maintainers/index.md @@ -2,7 +2,7 @@ ## Overview -LFX Insights automatically identifies and tracks [maintainer](../../more/glossary/index.md) information across open source repositories to provide visibility into project governance and leadership structures. This data helps organizations understand project stewardship and contributor roles. +LFX Insights automatically identifies and tracks [maintainer](../../more/glossary/index.md) information across open source repositories to provide visibility into project governance and leadership structures. This data helps companies understand project stewardship and contributor roles. ## Data Collection Process @@ -42,7 +42,7 @@ From maintainer files, we extract: - **Display names** and contact information, including email addresses when available. - **Roles and titles** — as listed in the file (e.g., "Lead Maintainer", "Core Developer", "Security Lead"). - **Normalized roles** — a standardized role assigned based on context. -- **Organizational affiliations** when available. +- **Company affiliations** when available. ### Identity Resolution diff --git a/frontend/docs/introduction/what-is-insights/index.md b/frontend/docs/introduction/what-is-insights/index.md index c71b71aa8..726a07c31 100644 --- a/frontend/docs/introduction/what-is-insights/index.md +++ b/frontend/docs/introduction/what-is-insights/index.md @@ -2,7 +2,7 @@ # What is LFX Insights? -LFX Insights helps developers and their organizations make smarter decisions about the open source projects they depend on. +LFX Insights helps developers and their companies make smarter decisions about the open source projects they depend on. Before adding a new dependency, you’ve probably asked yourself: Is this open source project actively maintained? Is it secure and trustworthy? Will it still be around in a year? @@ -13,7 +13,7 @@ Think of Insights as a health check for open source projects - a platform With LFX Insights, you can: - Quickly assess a project’s overall health - with an at-a-glance summary of key activity, community, and security signals. -- Understand who is behind a project - see contributor affiliations and organization-level insights, not just anonymous GitHub handles. +- Understand who is behind a project - see contributor affiliations and company-level insights, not just anonymous GitHub handles. - See whether a project follows security best practices - including vulnerability management, documentation quality, and governance signals. - Track adoption and momentum - through benchmarks, usage patterns, and trends across the open source ecosystem. diff --git a/frontend/docs/metrics/contributors/index.md b/frontend/docs/metrics/contributors/index.md index 8156104e0..8a2fcb7eb 100644 --- a/frontend/docs/metrics/contributors/index.md +++ b/frontend/docs/metrics/contributors/index.md @@ -1,6 +1,6 @@ # Contributors Metrics Explained -This page provides concise explanations of the metrics available on the Contributors page of LFX Insights. These metrics help you understand who is contributing to an open source project on behalf of which organizations. +This page provides concise explanations of the metrics available on the Contributors page of LFX Insights. These metrics help you understand who is contributing to an open source project on behalf of which companies. ## Contributors Leaderboard @@ -8,9 +8,9 @@ This page provides concise explanations of the metrics available on the Contribu **Why it matters:** Helps identify the most active individuals in a project. Useful for recognizing key contributors, assessing engagement, and understanding who is driving the project forward. -## Organizations Leaderboard +## Companies Leaderboard -**What it is:** A ranked list of organizations contributing to the project, based on aggregated contributions from their affiliated members. +**What it is:** A ranked list of companies contributing to the project, based on aggregated contributions from their affiliated members. **Why it matters:** Shows which companies or institutions are backing the project. Indicates corporate support, resource allocation, and long-term investment. @@ -20,11 +20,11 @@ This page provides concise explanations of the metrics available on the Contribu **Why it matters:** Gives a snapshot of current community engagement. A high number signals a vibrant, collaborative project. -## Active Organizations +## Active Companies -**What it is:** The number of unique organizations with affiliated contributors active in the project over a selected period. +**What it is:** The number of unique companies with affiliated contributors active in the project over a selected period. -**Why it matters:** Shows organizational diversity. Broad participation makes a project more resilient and less reliant on any one group. +**Why it matters:** Shows company diversity. Broad participation makes a project more resilient and less reliant on any one group. ## Contributor Dependency @@ -32,11 +32,11 @@ This page provides concise explanations of the metrics available on the Contribu **Why it matters:** Highlights risk areas if key contributors leave. Useful for sustainability planning and succession strategy. -## Organization Dependency +## Company Dependency -**What it is:** Analyzes how much of the project’s contributions come from a small number of organizations. +**What it is:** Analyzes how much of the project’s contributions come from a small number of companies. -**Why it matters:** Reveals potential over-reliance on single entities. Projects with diverse organizational support are generally more robust. +**Why it matters:** Reveals potential over-reliance on single entities. Projects with diverse company support are generally more robust. ## Quarterly Contributor Retention diff --git a/frontend/docs/metrics/health-score/index.md b/frontend/docs/metrics/health-score/index.md index 58f610b7b..f48af901e 100644 --- a/frontend/docs/metrics/health-score/index.md +++ b/frontend/docs/metrics/health-score/index.md @@ -92,13 +92,13 @@ Counts the number of people who are actively maintaining the project, taking the - **3 pts:** 1 active maintainer - **0 pts:** No active maintainers -#### 1.3 Organizational Diversity (max 7 pts) +#### 1.3 Company Diversity (max 7 pts) -Measures how many distinct organizations the active maintainers are affiliated with, using contributor affiliation data. Projects maintained by contributors from multiple independent organizations are more resilient to any single organization withdrawing support. +Measures how many distinct companies the active maintainers are affiliated with, using contributor affiliation data. Projects maintained by contributors from multiple independent companies are more resilient to any single company withdrawing support. -- **7 pts:** Maintainers from 3 or more organizations -- **5 pts:** Maintainers from 2 organizations -- **2 pts:** All maintainers from 1 organization +- **7 pts:** Maintainers from 3 or more companies +- **5 pts:** Maintainers from 2 companies +- **2 pts:** All maintainers from 1 company - **0 pts:** Affiliation unknown ### 2. Security and Supply Chain (0–35 pts) diff --git a/frontend/docs/more/faq/index.md b/frontend/docs/more/faq/index.md index 201fd3b47..e56f0bf12 100644 --- a/frontend/docs/more/faq/index.md +++ b/frontend/docs/more/faq/index.md @@ -30,7 +30,7 @@ The Health Score is one of two independent assessments. It measures maintainer h **How often are the metrics updated?** Most project data is refreshed daily. Some metrics tied to contributor identity or external data sources may update less frequently. -## Contributors & Organizations +## Contributors & Companies **How do you track contributor activity across different platforms and email addresses?** We use AI-assisted identity resolution to unify contributor profiles across multiple handles and domains. Manual review and community feedback also help improve accuracy. @@ -38,8 +38,8 @@ We use AI-assisted identity resolution to unify contributor profiles across mult **Why are my contributions not showing up?** This usually happens if we haven’t correctly linked your identity or if contributions occurred under an unrecognized alias. Please refer to [How You Can Help to Improve Data Quality](../../introduction/data-quality/index.md#how-you-can-help-to-improve-data-quality) to learn how to report incorrect data. -**Why is my organization not properly affiliated to our contributions?** -We do organizational affiliation based on publicly available profile data (e.g. from GitHub), email domains, and other public and private signals. Nevertheless, it happens that affiliations are not correct. Please refer to [ How You Can Help to Improve Data Quality](../../introduction/data-quality/index.md#how-you-can-help-to-improve-data-quality) to learn how to report incorrect affiliations. +**Why is my company not properly affiliated to our contributions?** +We do company affiliation based on publicly available profile data (e.g. from GitHub), email domains, and other public and private signals. Nevertheless, it happens that affiliations are not correct. Please refer to [ How You Can Help to Improve Data Quality](../../introduction/data-quality/index.md#how-you-can-help-to-improve-data-quality) to learn how to report incorrect affiliations. ## Data Quality and Corrections @@ -47,7 +47,7 @@ We do organizational affiliation based on publicly available profile data (e.g. Our data comes from our internal [Community Data Platform](https://github.com/CrowdDotDev/crowd.dev), which covers 20+ different sources. Learn more about [Data Sources](../../introduction/data-sources/index.md). **Why is open source data so difficult to get right?** -There’s no single source of truth, and most data comes from weak control data sources. For example: Contributors use multiple emails, organizations have complex naming conventions, and projects span diverse platforms. +There’s no single source of truth, and most data comes from weak control data sources. For example: Contributors use multiple emails, companies have complex naming conventions, and projects span diverse platforms. **Q: How do you ensure accuracy in your contributor and project data?** We use a multi-step process involving AI enrichment, human curation, and direct user feedback. Our goal is 90%+ correctness in production data. Learn more about [Data Quality](../../introduction/data-quality/index.md). diff --git a/frontend/docs/more/glossary/index.md b/frontend/docs/more/glossary/index.md index 3ff6ce0be..eaf146e03 100644 --- a/frontend/docs/more/glossary/index.md +++ b/frontend/docs/more/glossary/index.md @@ -12,7 +12,7 @@ An activity, performed by an individual, that is counted as Collaboration. Colla ## Collection -A named group of open source projects organized around a common theme, organization, foundation, technology, or purpose. Collections help users discover, explore, and compare related projects, such as all CNCF-hosted projects, critical non-Linux Foundation projects, or top-ranked initiatives. There are two types of collections in LFX Insights: [Curated Collections](#curated-collection) and [Community Collections](#community-collection). +A named group of open source projects organized around a common theme, company, foundation, technology, or purpose. Collections help users discover, explore, and compare related projects, such as all CNCF-hosted projects, critical non-Linux Foundation projects, or top-ranked initiatives. There are two types of collections in LFX Insights: [Curated Collections](#curated-collection) and [Community Collections](#community-collection). ## Community Collection @@ -28,7 +28,7 @@ A recorded change to a project's source code, typically including code additions ## Contributor -Any individual who actively participates in the development or maintenance of an open source project. This includes writing code, reviewing pull requests, reporting issues, or updating documentation. In LFX Insights, contributors are identified through activity in version control systems and other platforms, and can be analyzed by metrics such as activity level, organization affiliation, and contribution history. +Any individual who actively participates in the development or maintenance of an open source project. This includes writing code, reviewing pull requests, reporting issues, or updating documentation. In LFX Insights, contributors are identified through activity in version control systems and other platforms, and can be analyzed by metrics such as activity level, company affiliation, and contribution history. ## Maintainer @@ -51,9 +51,9 @@ Tracked tasks, bugs, feature requests, or discussions opened within a project's Merging is the process of integrating changes from a pull request into the main branch of a project’s codebase. In LFX Insights, a successful merge indicates that the proposed code has passed any required reviews or checks and is now part of the official project history. -## Organization +## Company -A legal or corporate entity that is actively involved in open source development. This includes companies, foundations, academic institutions, and government agencies. We identify organizations based on contributor email domains, GitHub affiliation, and verified project ownership. Organizations are used to group activity, assess influence, and analyze ecosystem-level participation across projects. +A legal or corporate entity that is actively involved in open source development. This covers businesses, foundations, academic institutions, and government agencies. We identify companies based on contributor email domains, GitHub affiliation, and verified project ownership. Companies are used to group activity, assess influence, and analyze ecosystem-level participation across projects. ## Project diff --git a/frontend/public/llms.txt b/frontend/public/llms.txt index e23619386..69ea11417 100644 --- a/frontend/public/llms.txt +++ b/frontend/public/llms.txt @@ -6,7 +6,7 @@ LFX Insights provides data-driven insights for 13,000+ open source projects, tracking over 1 billion activities across 20+ data sources. It answers two key questions: "Is my project healthy?" and "Is this project trustworthy?" -Backed by the Linux Foundation, Insights offers the deepest contributor profile data and organization affiliation mapping in the industry. +Backed by the Linux Foundation, Insights offers the deepest contributor profile data and company affiliation mapping in the industry. ## Main Pages @@ -22,7 +22,7 @@ Backed by the Linux Foundation, Insights offers the deepest contributor profile - **Project Health Metrics**: Development velocity, contributor diversity, release cadence - **Security Insights**: Vulnerability tracking, security posture assessment -- **Contributor Analytics**: Individual and organizational contribution tracking +- **Contributor Analytics**: Individual and company contribution tracking - **Community Voice**: Sentiment analysis from community discussions - **Popularity Metrics**: GitHub stars, forks, downloads, adoption trends - **Collections**: "Spotify playlists for open source" — curated project groupings diff --git a/frontend/server/api/organization-page/[orgSlug].get.ts b/frontend/server/api/organization-page/[orgSlug].get.ts index 6009db4fe..327ce455e 100644 --- a/frontend/server/api/organization-page/[orgSlug].get.ts +++ b/frontend/server/api/organization-page/[orgSlug].get.ts @@ -29,7 +29,7 @@ export default defineEventHandler(async (event): Promise => }); if (!res.data?.length) { - throw createError({ statusCode: 404, statusMessage: 'Organization not found' }); + throw createError({ statusCode: 404, statusMessage: 'Company not found' }); } const raw = res.data[0]; diff --git a/frontend/server/api/organization-page/[orgSlug]/kpis.get.ts b/frontend/server/api/organization-page/[orgSlug]/kpis.get.ts index 746e2ec80..ca8cc55de 100644 --- a/frontend/server/api/organization-page/[orgSlug]/kpis.get.ts +++ b/frontend/server/api/organization-page/[orgSlug]/kpis.get.ts @@ -17,7 +17,7 @@ export default defineEventHandler(async (event): Promise => { }); if (!res.data?.length) { - throw createError({ statusCode: 404, statusMessage: 'Organization not found' }); + throw createError({ statusCode: 404, statusMessage: 'Company not found' }); } return res.data[0]; diff --git a/frontend/server/api/seo/sitemap/leaderboards.ts b/frontend/server/api/seo/sitemap/leaderboards.ts index 46563a580..797318b5c 100644 --- a/frontend/server/api/seo/sitemap/leaderboards.ts +++ b/frontend/server/api/seo/sitemap/leaderboards.ts @@ -1,6 +1,7 @@ // Copyright (c) 2025 The Linux Foundation and each contributor. // SPDX-License-Identifier: MIT +import { leaderboardSlug } from '~~/config/leaderboard-slugs'; import { fetchFromTinybird } from '~~/server/data/tinybird/tinybird'; export default defineSitemapEventHandler(async () => { @@ -9,6 +10,6 @@ export default defineSitemapEventHandler(async () => { {}, ); return res.data.map((item) => ({ - loc: `/leaderboards/${item.leaderboardType}`, + loc: `/leaderboards/${leaderboardSlug(item.leaderboardType)}`, })); }); diff --git a/frontend/setup/caching.test.ts b/frontend/setup/caching.test.ts index dc69f77f3..bbfd06091 100644 --- a/frontend/setup/caching.test.ts +++ b/frontend/setup/caching.test.ts @@ -91,9 +91,9 @@ describe('caching configuration', () => { expect(dev.routeRules['/api/**']?.cache).toBeUndefined(); }); - test('organization page routes disable stale-while-revalidate in production only', async () => { + test('company page routes disable stale-while-revalidate in production only', async () => { const prod = await loadCachingConfig('production'); - expect(prod.routeRules['/organization/**']?.cache).toEqual({ + expect(prod.routeRules['/company/**']?.cache).toEqual({ maxAge: 86400, base: 'redis', swr: false, @@ -105,7 +105,7 @@ describe('caching configuration', () => { }); const dev = await loadCachingConfig('development'); - expect(dev.routeRules['/organization/**']).toBeUndefined(); + expect(dev.routeRules['/company/**']).toBeUndefined(); expect(dev.routeRules['/api/organization-page/**']).toBeUndefined(); }); diff --git a/frontend/setup/caching.ts b/frontend/setup/caching.ts index 0de728f52..a38c7ef61 100644 --- a/frontend/setup/caching.ts +++ b/frontend/setup/caching.ts @@ -59,6 +59,7 @@ export default { routeRules: { '/auth/callback': { redirect: '/api/auth/callback' }, '/callback': { redirect: '/api/auth/callback' }, + // Old /organization and /leaderboards URLs redirect from page middleware (case-insensitive). '/api/auth/**': { prerender: false, index: false, cache: false, headers: noCacheHeaders }, '/_og/**': { cache: false }, // The `/**` catch-all cache rule below wraps every route in Nitro's cachedEventHandler, @@ -117,7 +118,7 @@ export default { '/docs/api/**': { cache: false }, // Stale-while-revalidate is off so a stale cached 200 cannot mask a blocked org's 404. '/api/organization-page/**': { cache: { maxAge: shortCache, base: 'redis', swr: false } }, - '/organization/**': { cache: { maxAge: longCache, base: 'redis', swr: false } }, + '/company/**': { cache: { maxAge: longCache, base: 'redis', swr: false } }, '**': { cache: { maxAge: longCache, base: 'redis' } }, } : {}), diff --git a/frontend/test/config/health-breakdown-templates-org-diversity.test.ts b/frontend/test/config/health-breakdown-templates-org-diversity.test.ts index 4d3fa0b0b..b3c1c7f90 100644 --- a/frontend/test/config/health-breakdown-templates-org-diversity.test.ts +++ b/frontend/test/config/health-breakdown-templates-org-diversity.test.ts @@ -8,7 +8,7 @@ import { } from '../../config/health-breakdown-templates'; import type { HealthBreakdownResults } from '../../types/overview/responses.types'; -describe('Organization Diversity label capitalization IN-1238', () => { +describe('Company Diversity label capitalization IN-1238', () => { const defaultSignals: HealthBreakdownResults = { responsivenessAvailable: false, busFactorAvailable: false, @@ -23,13 +23,13 @@ describe('Organization Diversity label capitalization IN-1238', () => { isExcluded: false, }; - test('getOrgDiversityRow outputs full word "organization diversity"', () => { + test('getOrgDiversityRow outputs full word "company diversity"', () => { const result = getOrgDiversityRow(defaultSignals); expect(result.status).toBe('no-data'); - expect(result.description).toContain('organization diversity'); + expect(result.description).toContain('company diversity'); }); - test('getCategoryDescription includes "organization diversity" in signal list', () => { + test('getCategoryDescription includes "company diversity" in signal list', () => { const signals: HealthBreakdownResults = { ...defaultSignals, responsivenessAvailable: true, @@ -39,7 +39,7 @@ describe('Organization Diversity label capitalization IN-1238', () => { const result = getCategoryDescription('maintainer', null, false, signals); expect(result).toContain('maintainer responsiveness'); expect(result).toContain('bus factor'); - expect(result).toContain('organization diversity'); + expect(result).toContain('company diversity'); }); test('getCategoryDescription with only org diversity uses full word', () => { @@ -48,6 +48,6 @@ describe('Organization Diversity label capitalization IN-1238', () => { orgDiversityAvailable: true, }; const result = getCategoryDescription('maintainer', null, false, signals); - expect(result).toContain('organization diversity'); + expect(result).toContain('company diversity'); }); });