Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- Reverses V1784026542: drops the showAggregateTabs column added to collections.
ALTER TABLE collections
DROP COLUMN "showAggregateTabs";
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Add the showAggregateTabs column to the collections table, defaulting to false.
ALTER TABLE collections
ADD COLUMN "showAggregateTabs" boolean DEFAULT false NOT NULL;
Comment thread
gaspergrom marked this conversation as resolved.
Outdated

-- Only LF Foundation (curated) collections get the in-depth aggregate tabs by default.
-- ssoUserId is only set for community/user-curated collections (see V1772438175), so
-- ssoUserId IS NULL identifies curated collections.
UPDATE collections
SET "showAggregateTabs" = true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this column? Can't we simply infer this from wether or not ssoUserId is null?

WHERE "ssoUserId" IS NULL;
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,17 @@
</lf-field>
</article>
</div>

<!-- Show aggregate tabs -->
<article class="mb-6">
<lf-field label-text="Show aggregate tabs">
<div class="flex items-center gap-2">
<lf-switch v-model="form.showAggregateTabs" size="small">
<span class="text-2xs text-gray-400">Show in-depth aggregate metric tabs on the public collection page</span>
</lf-switch>
</div>
</lf-field>
</article>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I don't think this is needed.

</div>
<lf-collection-add-projects-tab
v-if="activeTab === 'projects'"
Expand Down Expand Up @@ -221,6 +232,7 @@ import LfTabs from '@/ui-kit/tabs/Tabs.vue';
import LfTab from '@/ui-kit/tabs/Tab.vue';
import LfInput from '@/ui-kit/input/Input.vue';
import LfTextarea from '@/ui-kit/textarea/Textarea.vue';
import LfSwitch from '@/ui-kit/switch/Switch.vue';
import LfField from '@/ui-kit/field/Field.vue';
import LfFieldMessages from '@/ui-kit/field-messages/FieldMessages.vue';

Expand Down Expand Up @@ -260,6 +272,7 @@ const form = reactive<CollectionFormModel>({
color: '',
projects: [],
starred: false,
showAggregateTabs: true,
});

const rules = {
Expand Down Expand Up @@ -327,6 +340,7 @@ const onSubmit = () => {
starred: project?.starred || false,
})),
starred: !!form.starred,
showAggregateTabs: !!form.showAggregateTabs,
categoryId: form.categoryId,
slug: form.name.toLowerCase().replace(/ /g, '-'),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface CollectionModel {
projects: InsightsProjectModel[];
category: Category & {categoryGroupType: string, categoryGroupName: string};
starred?: boolean;
showAggregateTabs?: boolean;
}

export interface CollectionRequest {
Expand All @@ -25,6 +26,7 @@ export interface CollectionRequest {
color?: string;
slug: string;
starred: boolean;
showAggregateTabs: boolean;
Comment thread
gaspergrom marked this conversation as resolved.
Outdated
Comment thread
Copilot marked this conversation as resolved.
Outdated
projects: {
id: string;
starred: boolean;
Expand All @@ -40,4 +42,5 @@ export interface CollectionFormModel {
color: string;
projects: InsightsProjectModel[];
starred: boolean;
showAggregateTabs: boolean;
}
4 changes: 2 additions & 2 deletions scripts/cli
Original file line number Diff line number Diff line change
Expand Up @@ -1182,14 +1182,14 @@ while test $# -gt 0; do
exit
;;
service-restart-fe-dev)
IGNORED_SERVICES=("frontend" "python-worker" "job-generator" "webhook-api" "profiles-worker" "organizations-enrichment-worker" "merge-suggestions-worker" "members-enrichment-worker" "exports-worker" "entity-merging-worker")
IGNORED_SERVICES=("frontend" "python-worker" "job-generator" "webhook-api" "profiles-worker" "organizations-enrichment-worker" "merge-suggestions-worker" "members-enrichment-worker" "exports-worker" "entity-merging-worker" "automatic-projects-discovery-worker" "pcc-sync-worker" "projects-evaluation-worker" "bq-dataset-ingest" "cargo-worker" "dockerhub-sync" "github-repos-enricher" "go-worker" "maven-worker" "npm-worker" "nuget-worker" "osv-worker" "pypi-worker" "rubygems-worker" "security-contacts-worker")
DEV=1
kill_all_containers
service_start
exit
;;
clean-start-fe-dev)
IGNORED_SERVICES=("frontend" "python-worker" "job-generator" "webhook-api" "profiles-worker" "organizations-enrichment-worker" "merge-suggestions-worker" "members-enrichment-worker" "exports-worker" "entity-merging-worker" "cache-worker" "categorization-worker" "cron-service" "data-sink-worker" "git-integration" "integration-run-worker" "integration-stream-worker" "nango-webhook-api" "nango-worker" "script-executor-worker" "search-sync-api" "search-sync-worker" "security-best-practices-worker" "snowflake-connectors-worker")
IGNORED_SERVICES=("frontend" "python-worker" "job-generator" "webhook-api" "profiles-worker" "organizations-enrichment-worker" "merge-suggestions-worker" "members-enrichment-worker" "exports-worker" "entity-merging-worker" "cache-worker" "categorization-worker" "cron-service" "data-sink-worker" "git-integration" "integration-run-worker" "integration-stream-worker" "nango-webhook-api" "nango-worker" "script-executor-worker" "search-sync-api" "search-sync-worker" "security-best-practices-worker" "snowflake-connectors-worker" "automatic-projects-discovery-worker" "pcc-sync-worker" "projects-evaluation-worker" "bq-dataset-ingest" "cargo-worker" "dockerhub-sync" "github-repos-enricher" "go-worker" "maven-worker" "npm-worker" "nuget-worker" "osv-worker" "pypi-worker" "rubygems-worker" "security-contacts-worker")
CLEAN_START=1
DEV=1
start
Expand Down
10 changes: 8 additions & 2 deletions services/libs/data-access-layer/src/collections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface ICreateCollection {
name: string
slug?: string
starred: boolean
showAggregateTabs?: boolean
isPrivate?: boolean
ssoUserId?: string | null
logoUrl?: string | null
Expand Down Expand Up @@ -93,6 +94,7 @@ export enum CollectionField {
SLUG = 'slug',
SSO_USER_ID = 'ssoUserId',
STARRED = 'starred',
SHOW_AGGREGATE_TABS = 'showAggregateTabs',
UPDATED_AT = 'updatedAt',
DELETED_AT = 'deletedAt',
}
Expand Down Expand Up @@ -144,12 +146,16 @@ export async function createCollection(
logoUrl: null,
imageUrl: null,
color: null,
// Only LF Foundation (curated) collections get aggregate tabs by default.
// ssoUserId is only set for community/user-curated collections, so
// ssoUserId being unset identifies curated collections (see V1784026542).
showAggregateTabs: !collection.ssoUserId,
...collection,
}
return qx.selectOne(
`
INSERT INTO collections (name, description, slug, "categoryId", starred, "logoUrl", "imageUrl", color)
Comment thread
gaspergrom marked this conversation as resolved.
VALUES ($(name), $(description), $(slug), $(categoryId), $(starred), $(logoUrl), $(imageUrl), $(color))
INSERT INTO collections (name, description, slug, "categoryId", starred, "logoUrl", "imageUrl", color, "showAggregateTabs")
VALUES ($(name), $(description), $(slug), $(categoryId), $(starred), $(logoUrl), $(imageUrl), $(color), $(showAggregateTabs))
RETURNING *
`,
data,
Expand Down
50 changes: 50 additions & 0 deletions services/libs/tinybird/pipes/collection_insights_aggregate.pipe
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
DESCRIPTION >
Comment thread
joanagmaia marked this conversation as resolved.
Comment thread
joanagmaia marked this conversation as resolved.
- `collection_insights_aggregate.pipe` serves aggregate insights metrics for a collection.
- Returns a single row with metrics aggregated across every project in the collection, not one row per project.
- Parameters:
- `collectionSlug`: Required collection slug. insights_projects_populated_ds.collectionsSlugs already lists
every collection each project belongs to (see insightsProjects_filtered.pipe for the same filter pattern),
so this pipe resolves collection membership directly rather than requiring the caller to first look up a
project id list.
- Response:
- `projectCount`: count of distinct projects in the collection.
- `uniqueContributorCount`: total unique contributors across all projects in the collection, deduplicated (a contributor active on multiple projects in the collection is counted once).
- `avgHealthScore`: average of each project's health score in the collection, rounded.

TAGS "Insights, Widget", "Collection"

NODE collection_insights_aggregate_projects
DESCRIPTION >
Resolves the collection's member projects to their segment ids and health scores directly via
collectionsSlugs, matching the same has(collectionsSlugs, ...) filter already used by
insightsProjects_filtered.pipe.

SQL >
%
SELECT id, segmentId, healthScore
FROM insights_projects_populated_ds
WHERE
enabled = 1
AND has(
collectionsSlugs,
{{ String(collectionSlug, description="Filter by collection slug", required=True) }}
Comment thread
joanagmaia marked this conversation as resolved.
)
Comment thread
joanagmaia marked this conversation as resolved.
Comment thread
joanagmaia marked this conversation as resolved.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing empty segmentId filter

Medium Severity

The projects node does not exclude rows where segmentId is an empty string before those ids feed the activity IN filter. Elsewhere (e.g. leaderboards_members, health_score_copy) empty segmentId values are dropped. Matching on '' can pull unrelated activity rows and inflate uniqueContributorCount.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit cc3b759. Configure here.


NODE collection_insights_aggregate_results
DESCRIPTION >
Aggregates health score across matched projects and counts unique contributors across their segments in one pass

SQL >
SELECT
(SELECT count(distinct id) FROM collection_insights_aggregate_projects) AS projectCount,
uniq(ar.memberId) AS uniqueContributorCount,
(SELECT round(avg(healthScore)) FROM collection_insights_aggregate_projects) AS avgHealthScore
FROM activityRelations_deduplicated_cleaned_bucket_union AS ar
WHERE
ar.memberId != ''
AND ar.segmentId IN (SELECT segmentId FROM collection_insights_aggregate_projects)
Comment thread
gaspergrom marked this conversation as resolved.
Comment thread
gaspergrom marked this conversation as resolved.
Comment thread
gaspergrom marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
gaspergrom marked this conversation as resolved.
AND (ar.type, ar.platform) IN (
SELECT activityType, platform
FROM activityTypes
WHERE isCodeContribution = 1 OR isCollaboration = 1
)
Comment on lines +38 to +50
Comment on lines +38 to +50
Loading