From 265a5353984c295c62c17b78d3c7a50ac24a4d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Thu, 15 Oct 2026 22:05:01 +0200 Subject: [PATCH 1/7] feat: add platform configs for octolens mention sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs linuxfoundation/lfx-cdp-insights-ops#748 Signed-off-by: Uroš Marolt --- .../src/assets/images/identities/bluesky.svg | 3 +++ .../assets/images/identities/instagram.svg | 3 +++ .../src/assets/images/identities/medium.svg | 3 +++ .../assets/images/identities/producthunt.svg | 3 +++ .../src/assets/images/identities/tiktok.svg | 3 +++ .../src/assets/images/identities/youtube.svg | 4 ++++ .../src/config/identities/bluesky/config.ts | 20 ++++++++++++++++ .../src/config/identities/facebook/config.ts | 14 +++++++---- frontend/src/config/identities/index.ts | 12 ++++++++++ .../src/config/identities/instagram/config.ts | 20 ++++++++++++++++ .../src/config/identities/medium/config.ts | 19 +++++++++++++++ .../config/identities/producthunt/config.ts | 20 ++++++++++++++++ .../src/config/identities/tiktok/config.ts | 20 ++++++++++++++++ .../src/config/identities/youtube/config.ts | 18 ++++++++++++++ .../config/integrations/octolens/config.ts | 17 +++++++++++++ .../modules/contributor/types/Contributor.ts | 23 +++++++++++------- .../filterTypes/ActivityTypeFilter.vue | 24 ++++++++++++++++--- 17 files changed, 211 insertions(+), 15 deletions(-) create mode 100644 frontend/src/assets/images/identities/bluesky.svg create mode 100644 frontend/src/assets/images/identities/instagram.svg create mode 100644 frontend/src/assets/images/identities/medium.svg create mode 100644 frontend/src/assets/images/identities/producthunt.svg create mode 100644 frontend/src/assets/images/identities/tiktok.svg create mode 100644 frontend/src/assets/images/identities/youtube.svg create mode 100644 frontend/src/config/identities/bluesky/config.ts create mode 100644 frontend/src/config/identities/instagram/config.ts create mode 100644 frontend/src/config/identities/medium/config.ts create mode 100644 frontend/src/config/identities/producthunt/config.ts create mode 100644 frontend/src/config/identities/tiktok/config.ts create mode 100644 frontend/src/config/identities/youtube/config.ts diff --git a/frontend/src/assets/images/identities/bluesky.svg b/frontend/src/assets/images/identities/bluesky.svg new file mode 100644 index 0000000000..15ebb7af75 --- /dev/null +++ b/frontend/src/assets/images/identities/bluesky.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/images/identities/instagram.svg b/frontend/src/assets/images/identities/instagram.svg new file mode 100644 index 0000000000..92c110243d --- /dev/null +++ b/frontend/src/assets/images/identities/instagram.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/images/identities/medium.svg b/frontend/src/assets/images/identities/medium.svg new file mode 100644 index 0000000000..16f475f257 --- /dev/null +++ b/frontend/src/assets/images/identities/medium.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/images/identities/producthunt.svg b/frontend/src/assets/images/identities/producthunt.svg new file mode 100644 index 0000000000..e47e52b446 --- /dev/null +++ b/frontend/src/assets/images/identities/producthunt.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/images/identities/tiktok.svg b/frontend/src/assets/images/identities/tiktok.svg new file mode 100644 index 0000000000..c8833968d5 --- /dev/null +++ b/frontend/src/assets/images/identities/tiktok.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/images/identities/youtube.svg b/frontend/src/assets/images/identities/youtube.svg new file mode 100644 index 0000000000..29cc6e9446 --- /dev/null +++ b/frontend/src/assets/images/identities/youtube.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/config/identities/bluesky/config.ts b/frontend/src/config/identities/bluesky/config.ts new file mode 100644 index 0000000000..cb6d4845e3 --- /dev/null +++ b/frontend/src/config/identities/bluesky/config.ts @@ -0,0 +1,20 @@ +import type { IdentityConfig } from '@/config/identities'; + +const image = new URL('@/assets/images/identities/bluesky.svg', import.meta.url).href; + +const bluesky: IdentityConfig = { + key: 'bluesky', + name: 'Bluesky', + image, + member: { + urlPrefix: 'bsky.app/profile/', + url: ({ identity, attributes }) => + attributes?.url?.bluesky || + (identity.value ? `https://bsky.app/profile/${identity.value}` : null), + }, + activity: { + showLink: true, + }, +}; + +export default bluesky; diff --git a/frontend/src/config/identities/facebook/config.ts b/frontend/src/config/identities/facebook/config.ts index 32cade49e8..5db69ac646 100644 --- a/frontend/src/config/identities/facebook/config.ts +++ b/frontend/src/config/identities/facebook/config.ts @@ -1,14 +1,20 @@ import type { IdentityConfig } from '@/config/identities'; -const image = new URL( - '@/assets/images/identities/facebook.png', - import.meta.url, -).href; +const image = new URL('@/assets/images/identities/facebook.png', import.meta.url).href; const facebook: IdentityConfig = { key: 'facebook', name: 'Facebook', image, + member: { + urlPrefix: 'facebook.com/', + url: ({ identity, attributes }) => + attributes?.url?.facebook || + (identity.value ? `https://www.facebook.com/${identity.value}` : null), + }, + activity: { + showLink: true, + }, }; export default facebook; diff --git a/frontend/src/config/identities/index.ts b/frontend/src/config/identities/index.ts index 60107e5d3b..67d4a2f083 100644 --- a/frontend/src/config/identities/index.ts +++ b/frontend/src/config/identities/index.ts @@ -3,6 +3,7 @@ import type { ContributorIdentity, } from '@/modules/contributor/types/Contributor'; import type { OrganizationIdentity } from '@/modules/organization/types/Organization'; +import bluesky from './bluesky/config'; import confluence from './confluence/config'; import crunchbase from './crunchbase/config'; import cvent from './cvent/config'; @@ -16,16 +17,21 @@ import github from './github/config'; import gitlab from './gitlab/config'; import groupsio from './groupsio/config'; import hackernews from './hackernews/config'; +import instagram from './instagram/config'; import jira from './jira/config'; import lfid from './lfx/config'; import linkedin from './linkedin/config'; import mailinglist from './mailinglist/config'; +import medium from './medium/config'; import n8n from './n8n/config'; +import producthunt from './producthunt/config'; import reddit from './reddit/config'; import slack from './slack/config'; import stackoverflow from './stackoverflow/config'; +import tiktok from './tiktok/config'; import tnc from './tnc/config'; import twitter from './twitter/config'; +import youtube from './youtube/config'; import zapier from './zapier/config'; export interface IdentityConfig { @@ -86,4 +92,10 @@ export const lfIdentities: Record = { n8n, training_cert: tnc, zapier, + medium, + producthunt, + youtube, + bluesky, + tiktok, + instagram, }; diff --git a/frontend/src/config/identities/instagram/config.ts b/frontend/src/config/identities/instagram/config.ts new file mode 100644 index 0000000000..be85965305 --- /dev/null +++ b/frontend/src/config/identities/instagram/config.ts @@ -0,0 +1,20 @@ +import type { IdentityConfig } from '@/config/identities'; + +const image = new URL('@/assets/images/identities/instagram.svg', import.meta.url).href; + +const instagram: IdentityConfig = { + key: 'instagram', + name: 'Instagram', + image, + member: { + urlPrefix: 'instagram.com/', + url: ({ identity, attributes }) => + attributes?.url?.instagram || + (identity.value ? `https://www.instagram.com/${identity.value}` : null), + }, + activity: { + showLink: true, + }, +}; + +export default instagram; diff --git a/frontend/src/config/identities/medium/config.ts b/frontend/src/config/identities/medium/config.ts new file mode 100644 index 0000000000..07ec7538c5 --- /dev/null +++ b/frontend/src/config/identities/medium/config.ts @@ -0,0 +1,19 @@ +import type { IdentityConfig } from '@/config/identities'; + +const image = new URL('@/assets/images/identities/medium.svg', import.meta.url).href; + +const medium: IdentityConfig = { + key: 'medium', + name: 'Medium', + image, + member: { + urlPrefix: 'medium.com/@', + url: ({ identity, attributes }) => + attributes?.url?.medium || (identity.value ? `https://medium.com/@${identity.value}` : null), + }, + activity: { + showLink: true, + }, +}; + +export default medium; diff --git a/frontend/src/config/identities/producthunt/config.ts b/frontend/src/config/identities/producthunt/config.ts new file mode 100644 index 0000000000..8805d8ec9c --- /dev/null +++ b/frontend/src/config/identities/producthunt/config.ts @@ -0,0 +1,20 @@ +import type { IdentityConfig } from '@/config/identities'; + +const image = new URL('@/assets/images/identities/producthunt.svg', import.meta.url).href; + +const producthunt: IdentityConfig = { + key: 'producthunt', + name: 'Product Hunt', + image, + member: { + urlPrefix: 'producthunt.com/@', + url: ({ identity, attributes }) => + attributes?.url?.producthunt || + (identity.value ? `https://www.producthunt.com/@${identity.value}` : null), + }, + activity: { + showLink: true, + }, +}; + +export default producthunt; diff --git a/frontend/src/config/identities/tiktok/config.ts b/frontend/src/config/identities/tiktok/config.ts new file mode 100644 index 0000000000..99d0a5fe79 --- /dev/null +++ b/frontend/src/config/identities/tiktok/config.ts @@ -0,0 +1,20 @@ +import type { IdentityConfig } from '@/config/identities'; + +const image = new URL('@/assets/images/identities/tiktok.svg', import.meta.url).href; + +const tiktok: IdentityConfig = { + key: 'tiktok', + name: 'TikTok', + image, + member: { + urlPrefix: 'tiktok.com/@', + url: ({ identity, attributes }) => + attributes?.url?.tiktok || + (identity.value ? `https://www.tiktok.com/@${identity.value}` : null), + }, + activity: { + showLink: true, + }, +}; + +export default tiktok; diff --git a/frontend/src/config/identities/youtube/config.ts b/frontend/src/config/identities/youtube/config.ts new file mode 100644 index 0000000000..e59a991ab5 --- /dev/null +++ b/frontend/src/config/identities/youtube/config.ts @@ -0,0 +1,18 @@ +import type { IdentityConfig } from '@/config/identities'; + +const image = new URL('@/assets/images/identities/youtube.svg', import.meta.url).href; + +const youtube: IdentityConfig = { + key: 'youtube', + name: 'YouTube', + image, + member: { + urlPrefix: 'youtube.com/channel/', + url: ({ attributes }) => attributes?.url?.youtube || null, + }, + activity: { + showLink: true, + }, +}; + +export default youtube; diff --git a/frontend/src/config/integrations/octolens/config.ts b/frontend/src/config/integrations/octolens/config.ts index c0f019cd3d..22a33a0e51 100644 --- a/frontend/src/config/integrations/octolens/config.ts +++ b/frontend/src/config/integrations/octolens/config.ts @@ -2,6 +2,23 @@ import type { IntegrationConfig } from '@/config/integrations'; const image = new URL('@/assets/images/integrations/octolens.png', import.meta.url).href; +export const octolensMentionPlatforms = [ + 'github', + 'twitter', + 'linkedin', + 'reddit', + 'devto', + 'hackernews', + 'stackoverflow', + 'medium', + 'producthunt', + 'facebook', + 'youtube', + 'bluesky', + 'tiktok', + 'instagram', +]; + const octolens: IntegrationConfig = { key: 'octolens', name: 'Octolens', diff --git a/frontend/src/modules/contributor/types/Contributor.ts b/frontend/src/modules/contributor/types/Contributor.ts index c2e160b114..ba180aacb6 100644 --- a/frontend/src/modules/contributor/types/Contributor.ts +++ b/frontend/src/modules/contributor/types/Contributor.ts @@ -9,10 +9,17 @@ export interface ContributorAttribute { hubspot?: any; stackoverflow?: any; discourse?: any; + bluesky?: string; + facebook?: string; + instagram?: string; + medium?: string; + producthunt?: string; + tiktok?: string; + youtube?: string; } export interface ContributorMaintainerRole { - id: string + id: string; dateEnd: string | null; dateStart: string; memberId: string; @@ -92,13 +99,13 @@ export interface Contributor { activeDaysCount: string; activeOn: string[] | null; activityCount: string; - activityTypes:string[] | null; - attributes: Record + activityTypes: string[] | null; + attributes: Record; averageSentiment: number | null; - contributions: ContributorContribution[] + contributions: ContributorContribution[]; createdAt: string; displayName: string; - emails: string[] + emails: string[]; id: string; identities: ContributorIdentity[]; importHash: string | null; @@ -108,11 +115,11 @@ export interface Contributor { noMergeIds: string[] | null; numberOfOpenSourceContributions: number | null; organizations: Organization[]; - reach:ContributorReach; + reach: ContributorReach; score: number; toMergeIds: string[] | null; updatedAt: string; - username: Record + username: Record; verifiedEmails: string[]; unverifiedEmails: string[]; affiliations: ContributorAffiliation[]; @@ -120,7 +127,7 @@ export interface Contributor { id: string; name: string; activityCount: string; - }[], + }[]; maintainerRoles: ContributorMaintainerRole[]; activitySycning: MergeAction | null; } diff --git a/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue b/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue index c89d6cf55b..7750fcd8bb 100644 --- a/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue +++ b/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue @@ -23,6 +23,7 @@ import { useActivityTypeStore } from '@/modules/activity/store/type'; import { useLfSegmentsStore } from '@/modules/lf/segments/store'; import { lfIdentities } from '@/config/identities'; import useIntegrationsHelpers from '@/config/integrations/integrations.helpers'; +import octolens, { octolensMentionPlatforms } from '@/config/integrations/octolens/config'; interface FilterData { options?: MultiSelectFilterOptionGroup[] } @@ -65,11 +66,28 @@ const toOptionGroup = (platform: string, activityTypes: Record, + activeIntegrationsValue: string[], +): MultiSelectFilterOptionGroup | null => { + if (activeIntegrationsValue.includes(platform)) { + return toOptionGroup(platform, activityTypes); + } + if ( + activeIntegrationsValue.includes(octolens.key) + && octolensMentionPlatforms.includes(platform) + && activityTypes.mention + ) { + return toOptionGroup(platform, { mention: activityTypes.mention }); + } + return null; +}; + watch([types, activeIntegrations], ([typesValue, activeIntegrationsValue]) => { const platformsOptions = Object.entries(typesValue.default) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .filter(([platform, _]) => activeIntegrationsValue.includes(platform)) - .map(([platform, activityTypes]) => toOptionGroup(platform, activityTypes)); + .map(([platform, activityTypes]) => platformOptionGroup(platform, activityTypes, activeIntegrationsValue)) + .filter((group): group is MultiSelectFilterOptionGroup => group !== null); const customOptions = Object.entries(typesValue.custom) .map(([platform, activityTypes]) => toOptionGroup(platform, activityTypes)); From a57fa4c41434df6d1962257d7837c0f0432b7074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Thu, 15 Oct 2026 22:14:34 +0200 Subject: [PATCH 2/7] fix: build octolens profile links per identity and always offer their mention types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs linuxfoundation/lfx-cdp-insights-ops#748 Signed-off-by: Uroš Marolt --- frontend/src/config/identities/bluesky/config.ts | 5 ++--- frontend/src/config/identities/facebook/config.ts | 4 +--- frontend/src/config/identities/instagram/config.ts | 5 ++--- frontend/src/config/identities/medium/config.ts | 4 ++-- frontend/src/config/identities/producthunt/config.ts | 5 ++--- frontend/src/config/identities/tiktok/config.ts | 5 ++--- frontend/src/modules/contributor/types/Contributor.ts | 6 ------ .../filters/components/filterTypes/ActivityTypeFilter.vue | 8 ++------ 8 files changed, 13 insertions(+), 29 deletions(-) diff --git a/frontend/src/config/identities/bluesky/config.ts b/frontend/src/config/identities/bluesky/config.ts index cb6d4845e3..95bbb825a6 100644 --- a/frontend/src/config/identities/bluesky/config.ts +++ b/frontend/src/config/identities/bluesky/config.ts @@ -8,9 +8,8 @@ const bluesky: IdentityConfig = { image, member: { urlPrefix: 'bsky.app/profile/', - url: ({ identity, attributes }) => - attributes?.url?.bluesky || - (identity.value ? `https://bsky.app/profile/${identity.value}` : null), + url: ({ identity }) => + identity.value ? `https://bsky.app/profile/${identity.value.replace(/^@/, '')}` : null, }, activity: { showLink: true, diff --git a/frontend/src/config/identities/facebook/config.ts b/frontend/src/config/identities/facebook/config.ts index 5db69ac646..6b912fdbe0 100644 --- a/frontend/src/config/identities/facebook/config.ts +++ b/frontend/src/config/identities/facebook/config.ts @@ -8,9 +8,7 @@ const facebook: IdentityConfig = { image, member: { urlPrefix: 'facebook.com/', - url: ({ identity, attributes }) => - attributes?.url?.facebook || - (identity.value ? `https://www.facebook.com/${identity.value}` : null), + url: ({ identity }) => (identity.value ? `https://www.facebook.com/${identity.value}` : null), }, activity: { showLink: true, diff --git a/frontend/src/config/identities/instagram/config.ts b/frontend/src/config/identities/instagram/config.ts index be85965305..8e24ca2f14 100644 --- a/frontend/src/config/identities/instagram/config.ts +++ b/frontend/src/config/identities/instagram/config.ts @@ -8,9 +8,8 @@ const instagram: IdentityConfig = { image, member: { urlPrefix: 'instagram.com/', - url: ({ identity, attributes }) => - attributes?.url?.instagram || - (identity.value ? `https://www.instagram.com/${identity.value}` : null), + url: ({ identity }) => + identity.value ? `https://www.instagram.com/${identity.value.replace(/^@/, '')}` : null, }, activity: { showLink: true, diff --git a/frontend/src/config/identities/medium/config.ts b/frontend/src/config/identities/medium/config.ts index 07ec7538c5..03681ffaf2 100644 --- a/frontend/src/config/identities/medium/config.ts +++ b/frontend/src/config/identities/medium/config.ts @@ -8,8 +8,8 @@ const medium: IdentityConfig = { image, member: { urlPrefix: 'medium.com/@', - url: ({ identity, attributes }) => - attributes?.url?.medium || (identity.value ? `https://medium.com/@${identity.value}` : null), + url: ({ identity }) => + identity.value ? `https://medium.com/@${identity.value.replace(/^@/, '')}` : null, }, activity: { showLink: true, diff --git a/frontend/src/config/identities/producthunt/config.ts b/frontend/src/config/identities/producthunt/config.ts index 8805d8ec9c..27bb4a022b 100644 --- a/frontend/src/config/identities/producthunt/config.ts +++ b/frontend/src/config/identities/producthunt/config.ts @@ -8,9 +8,8 @@ const producthunt: IdentityConfig = { image, member: { urlPrefix: 'producthunt.com/@', - url: ({ identity, attributes }) => - attributes?.url?.producthunt || - (identity.value ? `https://www.producthunt.com/@${identity.value}` : null), + url: ({ identity }) => + identity.value ? `https://www.producthunt.com/@${identity.value.replace(/^@/, '')}` : null, }, activity: { showLink: true, diff --git a/frontend/src/config/identities/tiktok/config.ts b/frontend/src/config/identities/tiktok/config.ts index 99d0a5fe79..2e720d6ac9 100644 --- a/frontend/src/config/identities/tiktok/config.ts +++ b/frontend/src/config/identities/tiktok/config.ts @@ -8,9 +8,8 @@ const tiktok: IdentityConfig = { image, member: { urlPrefix: 'tiktok.com/@', - url: ({ identity, attributes }) => - attributes?.url?.tiktok || - (identity.value ? `https://www.tiktok.com/@${identity.value}` : null), + url: ({ identity }) => + identity.value ? `https://www.tiktok.com/@${identity.value.replace(/^@/, '')}` : null, }, activity: { showLink: true, diff --git a/frontend/src/modules/contributor/types/Contributor.ts b/frontend/src/modules/contributor/types/Contributor.ts index ba180aacb6..75d9ce2807 100644 --- a/frontend/src/modules/contributor/types/Contributor.ts +++ b/frontend/src/modules/contributor/types/Contributor.ts @@ -9,12 +9,6 @@ export interface ContributorAttribute { hubspot?: any; stackoverflow?: any; discourse?: any; - bluesky?: string; - facebook?: string; - instagram?: string; - medium?: string; - producthunt?: string; - tiktok?: string; youtube?: string; } diff --git a/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue b/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue index 7750fcd8bb..ffd996e83e 100644 --- a/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue +++ b/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue @@ -23,7 +23,7 @@ import { useActivityTypeStore } from '@/modules/activity/store/type'; import { useLfSegmentsStore } from '@/modules/lf/segments/store'; import { lfIdentities } from '@/config/identities'; import useIntegrationsHelpers from '@/config/integrations/integrations.helpers'; -import octolens, { octolensMentionPlatforms } from '@/config/integrations/octolens/config'; +import { octolensMentionPlatforms } from '@/config/integrations/octolens/config'; interface FilterData { options?: MultiSelectFilterOptionGroup[] } @@ -74,11 +74,7 @@ const platformOptionGroup = ( if (activeIntegrationsValue.includes(platform)) { return toOptionGroup(platform, activityTypes); } - if ( - activeIntegrationsValue.includes(octolens.key) - && octolensMentionPlatforms.includes(platform) - && activityTypes.mention - ) { + if (octolensMentionPlatforms.includes(platform) && activityTypes.mention) { return toOptionGroup(platform, { mention: activityTypes.mention }); } return null; From 733212b4cc6bdcdc3105ac43de38c56749aba900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Thu, 15 Oct 2026 22:18:41 +0200 Subject: [PATCH 3/7] fix: build youtube profile links from the channel id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs linuxfoundation/lfx-cdp-insights-ops#748 Signed-off-by: Uroš Marolt --- frontend/src/config/identities/youtube/config.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/config/identities/youtube/config.ts b/frontend/src/config/identities/youtube/config.ts index e59a991ab5..5a003effe5 100644 --- a/frontend/src/config/identities/youtube/config.ts +++ b/frontend/src/config/identities/youtube/config.ts @@ -8,7 +8,10 @@ const youtube: IdentityConfig = { image, member: { urlPrefix: 'youtube.com/channel/', - url: ({ attributes }) => attributes?.url?.youtube || null, + url: ({ identity, attributes }) => + identity.value + ? `https://www.youtube.com/channel/${identity.value}` + : attributes?.url?.youtube || null, }, activity: { showLink: true, From 4b6c6dfd99244b8e02e038340bd139d89c2d4f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Thu, 15 Oct 2026 22:21:26 +0200 Subject: [PATCH 4/7] fix: read active integrations from the integration store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs linuxfoundation/lfx-cdp-insights-ops#748 Signed-off-by: Uroš Marolt --- .../integrations/integrations.helpers.ts | 24 ++++++++++++------- .../filterTypes/ActivityTypeFilter.vue | 8 +++++-- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/frontend/src/config/integrations/integrations.helpers.ts b/frontend/src/config/integrations/integrations.helpers.ts index 1f6db2a145..edfc6cb3c6 100644 --- a/frontend/src/config/integrations/integrations.helpers.ts +++ b/frontend/src/config/integrations/integrations.helpers.ts @@ -1,15 +1,23 @@ -import { mapGetters } from '@/shared/vuex/vuex.helpers'; +import { useStore } from 'vuex'; +import type { IntegrationConfig } from '@/config/integrations/index'; import { lfIntegrations } from '@/config/integrations/index'; +interface StoredIntegration { + platform: string; + status?: string | null; +} + const useIntegrationsHelpers = () => { - const getActiveIntegrations = () => { - const { findByPlatform }: any = mapGetters('integrations'); + const store = useStore(); + + const getActiveIntegrations = (): IntegrationConfig[] => { + const integrations: StoredIntegration[] = store.getters['integration/array'] ?? []; - return Object.values(lfIntegrations()).map((config) => ({ - ...config, - ...(findByPlatform ? findByPlatform(config.key) : {}), - })) - .filter((integration) => integration.status); + return Object.values(lfIntegrations()).filter((config) => + integrations.some( + (integration) => integration.platform === config.key && !!integration.status, + ), + ); }; return { diff --git a/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue b/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue index ffd996e83e..7750fcd8bb 100644 --- a/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue +++ b/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue @@ -23,7 +23,7 @@ import { useActivityTypeStore } from '@/modules/activity/store/type'; import { useLfSegmentsStore } from '@/modules/lf/segments/store'; import { lfIdentities } from '@/config/identities'; import useIntegrationsHelpers from '@/config/integrations/integrations.helpers'; -import { octolensMentionPlatforms } from '@/config/integrations/octolens/config'; +import octolens, { octolensMentionPlatforms } from '@/config/integrations/octolens/config'; interface FilterData { options?: MultiSelectFilterOptionGroup[] } @@ -74,7 +74,11 @@ const platformOptionGroup = ( if (activeIntegrationsValue.includes(platform)) { return toOptionGroup(platform, activityTypes); } - if (octolensMentionPlatforms.includes(platform) && activityTypes.mention) { + if ( + activeIntegrationsValue.includes(octolens.key) + && octolensMentionPlatforms.includes(platform) + && activityTypes.mention + ) { return toOptionGroup(platform, { mention: activityTypes.mention }); } return null; From 2f50d69ef3d3f0ce45ed70b902480da2cb64d369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Fri, 16 Oct 2026 13:22:24 +0200 Subject: [PATCH 5/7] refactor: limit octolens platform configs to the platforms it emits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Octolens connector emits mentions from GitHub, X/Twitter, LinkedIn, Reddit, dev.to, Hacker News, Bluesky, TikTok, Instagram and YouTube. The mention filter now lists exactly those, and the unused Medium and Product Hunt configs and the Facebook change are dropped. Refs linuxfoundation/lfx-cdp-insights-ops#748 Signed-off-by: Uroš Marolt --- .../src/assets/images/identities/medium.svg | 3 --- .../assets/images/identities/producthunt.svg | 3 --- .../src/config/identities/facebook/config.ts | 7 ------- frontend/src/config/identities/index.ts | 4 ---- .../src/config/identities/medium/config.ts | 19 ------------------- .../config/identities/producthunt/config.ts | 19 ------------------- .../config/integrations/octolens/config.ts | 9 +++------ 7 files changed, 3 insertions(+), 61 deletions(-) delete mode 100644 frontend/src/assets/images/identities/medium.svg delete mode 100644 frontend/src/assets/images/identities/producthunt.svg delete mode 100644 frontend/src/config/identities/medium/config.ts delete mode 100644 frontend/src/config/identities/producthunt/config.ts diff --git a/frontend/src/assets/images/identities/medium.svg b/frontend/src/assets/images/identities/medium.svg deleted file mode 100644 index 16f475f257..0000000000 --- a/frontend/src/assets/images/identities/medium.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/images/identities/producthunt.svg b/frontend/src/assets/images/identities/producthunt.svg deleted file mode 100644 index e47e52b446..0000000000 --- a/frontend/src/assets/images/identities/producthunt.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/config/identities/facebook/config.ts b/frontend/src/config/identities/facebook/config.ts index 6b912fdbe0..6ac13e34b7 100644 --- a/frontend/src/config/identities/facebook/config.ts +++ b/frontend/src/config/identities/facebook/config.ts @@ -6,13 +6,6 @@ const facebook: IdentityConfig = { key: 'facebook', name: 'Facebook', image, - member: { - urlPrefix: 'facebook.com/', - url: ({ identity }) => (identity.value ? `https://www.facebook.com/${identity.value}` : null), - }, - activity: { - showLink: true, - }, }; export default facebook; diff --git a/frontend/src/config/identities/index.ts b/frontend/src/config/identities/index.ts index 67d4a2f083..60d6679b6a 100644 --- a/frontend/src/config/identities/index.ts +++ b/frontend/src/config/identities/index.ts @@ -22,9 +22,7 @@ import jira from './jira/config'; import lfid from './lfx/config'; import linkedin from './linkedin/config'; import mailinglist from './mailinglist/config'; -import medium from './medium/config'; import n8n from './n8n/config'; -import producthunt from './producthunt/config'; import reddit from './reddit/config'; import slack from './slack/config'; import stackoverflow from './stackoverflow/config'; @@ -92,8 +90,6 @@ export const lfIdentities: Record = { n8n, training_cert: tnc, zapier, - medium, - producthunt, youtube, bluesky, tiktok, diff --git a/frontend/src/config/identities/medium/config.ts b/frontend/src/config/identities/medium/config.ts deleted file mode 100644 index 03681ffaf2..0000000000 --- a/frontend/src/config/identities/medium/config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { IdentityConfig } from '@/config/identities'; - -const image = new URL('@/assets/images/identities/medium.svg', import.meta.url).href; - -const medium: IdentityConfig = { - key: 'medium', - name: 'Medium', - image, - member: { - urlPrefix: 'medium.com/@', - url: ({ identity }) => - identity.value ? `https://medium.com/@${identity.value.replace(/^@/, '')}` : null, - }, - activity: { - showLink: true, - }, -}; - -export default medium; diff --git a/frontend/src/config/identities/producthunt/config.ts b/frontend/src/config/identities/producthunt/config.ts deleted file mode 100644 index 27bb4a022b..0000000000 --- a/frontend/src/config/identities/producthunt/config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { IdentityConfig } from '@/config/identities'; - -const image = new URL('@/assets/images/identities/producthunt.svg', import.meta.url).href; - -const producthunt: IdentityConfig = { - key: 'producthunt', - name: 'Product Hunt', - image, - member: { - urlPrefix: 'producthunt.com/@', - url: ({ identity }) => - identity.value ? `https://www.producthunt.com/@${identity.value.replace(/^@/, '')}` : null, - }, - activity: { - showLink: true, - }, -}; - -export default producthunt; diff --git a/frontend/src/config/integrations/octolens/config.ts b/frontend/src/config/integrations/octolens/config.ts index 22a33a0e51..b9bd77d53c 100644 --- a/frontend/src/config/integrations/octolens/config.ts +++ b/frontend/src/config/integrations/octolens/config.ts @@ -2,6 +2,7 @@ import type { IntegrationConfig } from '@/config/integrations'; const image = new URL('@/assets/images/integrations/octolens.png', import.meta.url).href; +// The platforms whose mentions the Octolens connector emits. export const octolensMentionPlatforms = [ 'github', 'twitter', @@ -9,14 +10,10 @@ export const octolensMentionPlatforms = [ 'reddit', 'devto', 'hackernews', - 'stackoverflow', - 'medium', - 'producthunt', - 'facebook', - 'youtube', 'bluesky', 'tiktok', 'instagram', + 'youtube', ]; const octolens: IntegrationConfig = { @@ -24,7 +21,7 @@ const octolens: IntegrationConfig = { name: 'Octolens', image, description: - 'Mentions of LF projects on GitHub, X/Twitter, LinkedIn and more, matched to projects automatically.', + 'Mentions of LF projects on GitHub, X/Twitter, LinkedIn, Reddit, Bluesky and more, matched to projects automatically.', showProgress: false, autoManaged: true, }; From 3e952fdc75753a8af00fe434f712a2f991c0a5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Fri, 16 Oct 2026 13:28:13 +0200 Subject: [PATCH 6/7] fix: guard the activity type filter until types load and tidy octolens configs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reading active integrations made the filter's watch fire before activity types loaded, so it now tolerates missing types and runs immediately. The integration helper reuses the Integration type, the Octolens platform list is read-only and tied to the connector's allow-list, and the YouTube link no longer falls back to an attribute Octolens never needs. Refs linuxfoundation/lfx-cdp-insights-ops#748 Signed-off-by: Uroš Marolt --- frontend/src/config/identities/youtube/config.ts | 6 ++---- frontend/src/config/integrations/integrations.helpers.ts | 6 ++---- frontend/src/config/integrations/octolens/config.ts | 4 ++-- frontend/src/modules/contributor/types/Contributor.ts | 1 - .../filters/components/filterTypes/ActivityTypeFilter.vue | 5 +++-- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/frontend/src/config/identities/youtube/config.ts b/frontend/src/config/identities/youtube/config.ts index 5a003effe5..67a19ef9d9 100644 --- a/frontend/src/config/identities/youtube/config.ts +++ b/frontend/src/config/identities/youtube/config.ts @@ -8,10 +8,8 @@ const youtube: IdentityConfig = { image, member: { urlPrefix: 'youtube.com/channel/', - url: ({ identity, attributes }) => - identity.value - ? `https://www.youtube.com/channel/${identity.value}` - : attributes?.url?.youtube || null, + url: ({ identity }) => + identity.value ? `https://www.youtube.com/channel/${identity.value}` : null, }, activity: { showLink: true, diff --git a/frontend/src/config/integrations/integrations.helpers.ts b/frontend/src/config/integrations/integrations.helpers.ts index edfc6cb3c6..39f372de4c 100644 --- a/frontend/src/config/integrations/integrations.helpers.ts +++ b/frontend/src/config/integrations/integrations.helpers.ts @@ -1,11 +1,9 @@ import { useStore } from 'vuex'; import type { IntegrationConfig } from '@/config/integrations/index'; import { lfIntegrations } from '@/config/integrations/index'; +import type { Integration } from '@/modules/admin/modules/integration/types/Integration'; -interface StoredIntegration { - platform: string; - status?: string | null; -} +type StoredIntegration = Pick, 'status'> & { platform: string }; const useIntegrationsHelpers = () => { const store = useStore(); diff --git a/frontend/src/config/integrations/octolens/config.ts b/frontend/src/config/integrations/octolens/config.ts index b9bd77d53c..526cc0488f 100644 --- a/frontend/src/config/integrations/octolens/config.ts +++ b/frontend/src/config/integrations/octolens/config.ts @@ -2,8 +2,8 @@ import type { IntegrationConfig } from '@/config/integrations'; const image = new URL('@/assets/images/integrations/octolens.png', import.meta.url).href; -// The platforms whose mentions the Octolens connector emits. -export const octolensMentionPlatforms = [ +// Must match ENABLED_PLATFORMS in services/libs/connectors/src/connectors/octolens/mapper.ts. +export const octolensMentionPlatforms: readonly string[] = [ 'github', 'twitter', 'linkedin', diff --git a/frontend/src/modules/contributor/types/Contributor.ts b/frontend/src/modules/contributor/types/Contributor.ts index 12b37cf769..b3ce31d3dd 100644 --- a/frontend/src/modules/contributor/types/Contributor.ts +++ b/frontend/src/modules/contributor/types/Contributor.ts @@ -9,7 +9,6 @@ export interface ContributorAttribute { hubspot?: any; stackoverflow?: any; discourse?: any; - youtube?: string; } export interface ContributorMaintainerRole { diff --git a/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue b/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue index 7750fcd8bb..6b7b403c1f 100644 --- a/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue +++ b/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue @@ -85,11 +85,11 @@ const platformOptionGroup = ( }; watch([types, activeIntegrations], ([typesValue, activeIntegrationsValue]) => { - const platformsOptions = Object.entries(typesValue.default) + const platformsOptions = Object.entries(typesValue.default ?? {}) .map(([platform, activityTypes]) => platformOptionGroup(platform, activityTypes, activeIntegrationsValue)) .filter((group): group is MultiSelectFilterOptionGroup => group !== null); - const customOptions = Object.entries(typesValue.custom) + const customOptions = Object.entries(typesValue.custom ?? {}) .map(([platform, activityTypes]) => toOptionGroup(platform, activityTypes)); data.value.options = [ @@ -98,6 +98,7 @@ watch([types, activeIntegrations], ([typesValue, activeIntegrationsValue]) => { ]; }, { deep: true, + immediate: true, }); onMounted(async () => { From f789d2901377d688f3df75ac0415fecabef3c372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uro=C5=A1=20Marolt?= Date: Fri, 16 Oct 2026 13:56:38 +0200 Subject: [PATCH 7/7] fix: link custom-platform identities and keep the activity type filter in sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Identities grouped as custom (such as Bluesky, TikTok, Instagram and YouTube) now resolve their profile link with their own platform's config instead of 'custom'. The activity type filter re-fetches integrations when the project group changes, and the multi-select keeps its options in sync when they are replaced, preserving the current search. Refs linuxfoundation/lfx-cdp-insights-ops#748 Signed-off-by: Uroš Marolt --- .../filterTypes/ActivityTypeFilter.vue | 8 +- .../multiselect/MultiSelectTagsFilter.vue | 8 +- .../identities/config/useMemberIdentities.ts | 146 +++++++++--------- 3 files changed, 81 insertions(+), 81 deletions(-) diff --git a/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue b/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue index 6b7b403c1f..e7439be983 100644 --- a/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue +++ b/frontend/src/shared/modules/filters/components/filterTypes/ActivityTypeFilter.vue @@ -6,7 +6,7 @@ diff --git a/frontend/src/shared/modules/filters/components/filterTypes/multiselect/MultiSelectTagsFilter.vue b/frontend/src/shared/modules/filters/components/filterTypes/multiselect/MultiSelectTagsFilter.vue index 5eddbc7d4f..7934f248f3 100644 --- a/frontend/src/shared/modules/filters/components/filterTypes/multiselect/MultiSelectTagsFilter.vue +++ b/frontend/src/shared/modules/filters/components/filterTypes/multiselect/MultiSelectTagsFilter.vue @@ -38,7 +38,7 @@