diff --git a/models/presentation/src/index.ts b/models/presentation/src/index.ts index d5bb37f7a0..02bb3b0ff2 100644 --- a/models/presentation/src/index.ts +++ b/models/presentation/src/index.ts @@ -29,6 +29,7 @@ import { type DocAttributeRule, type DocCreateExtension, type DocCreateFunction, + type DocCreateAnalyticsPropsFunction, type DocRules, type FileOrBlob, type FilePreviewExtension, @@ -42,7 +43,14 @@ import presentation from './plugin' export { presentationId } from '@hcengineering/presentation/src/plugin' export { default } from './plugin' -export type { CreateExtensionKind, DocCreateExtension, DocCreateFunction, ObjectSearchCategory, ObjectSearchFactory } +export type { + CreateExtensionKind, + DocCreateExtension, + DocCreateFunction, + ObjectSearchCategory, + ObjectSearchFactory, + DocCreateAnalyticsPropsFunction +} @Model(presentation.class.ObjectSearchCategory, core.class.Doc, DOMAIN_MODEL) export class TObjectSearchCategory extends TDoc implements ObjectSearchCategory { @@ -76,6 +84,7 @@ export class TDocCreateExtension extends TDoc implements DocCreateExtension { components!: Record apply!: Resource + getAnalyticsProps?: Resource<(doc: Doc) => Record> } @Model(presentation.class.DocRules, core.class.Doc, DOMAIN_MODEL) diff --git a/packages/presentation/src/components/extensions/manager.ts b/packages/presentation/src/components/extensions/manager.ts index 19a1240557..87b44d9fb2 100644 --- a/packages/presentation/src/components/extensions/manager.ts +++ b/packages/presentation/src/components/extensions/manager.ts @@ -65,6 +65,20 @@ export class DocCreateExtensionManager { } } + async getAnalyticsProps (space: Space, data: DocData): Promise> { + let result: Record = {} + for (const e of this._extensions) { + if (e.getAnalyticsProps === undefined) continue + const state = get(this.getState(e._id)) + const fn = await getResource(e.getAnalyticsProps) + const props = fn?.(space, data, state) + + result = { ...result, ...props } + } + + return result + } + close (): void { this.query.unsubscribe() } diff --git a/packages/presentation/src/types.ts b/packages/presentation/src/types.ts index ce85b5a572..fad908bd4b 100644 --- a/packages/presentation/src/types.ts +++ b/packages/presentation/src/types.ts @@ -106,6 +106,12 @@ export type DocCreateFunction = ( phase: DocCreatePhase ) => Promise +export type DocCreateAnalyticsPropsFunction = ( + space: Space, + document: DocData, + extraData: Record +) => Record + /** * @public */ @@ -123,6 +129,7 @@ export interface DocCreateExtension extends Doc { components: Partial> apply: Resource + getAnalyticsProps?: Resource } export interface DocAttributeRule { diff --git a/plugins/tracker-resources/src/components/CreateIssue.svelte b/plugins/tracker-resources/src/components/CreateIssue.svelte index eca0c9e094..0404d988b7 100644 --- a/plugins/tracker-resources/src/components/CreateIssue.svelte +++ b/plugins/tracker-resources/src/components/CreateIssue.svelte @@ -575,10 +575,12 @@ descriptionBox?.removeDraft(false) isAssigneeTouched = false const d1 = Date.now() + const analyticsProps = await docCreateManager.getAnalyticsProps(currentProject, value) Analytics.handleEvent(TrackerEvents.IssueCreated, { ok: true, id: value.identifier, - project: currentProject.identifier + project: currentProject.identifier, + ...analyticsProps }) console.log('createIssue measure', result, Date.now() - d1) } catch (err: any) { diff --git a/services/github/github-resources/src/components/ConnectProject.svelte b/services/github/github-resources/src/components/ConnectProject.svelte index ef0ba4f978..966bb1cadc 100644 --- a/services/github/github-resources/src/components/ConnectProject.svelte +++ b/services/github/github-resources/src/components/ConnectProject.svelte @@ -53,7 +53,7 @@ return } - Analytics.handleEvent('Connect project to github') + Analytics.handleEvent('github.project.connected', { project: projectInst.identifier, repository: repository._id }) if (!client.getHierarchy().hasMixin(projectInst, github.mixin.GithubProject)) { // We need to add GithubProject mixin diff --git a/services/github/github-resources/src/components/GithubRepositories.svelte b/services/github/github-resources/src/components/GithubRepositories.svelte index 15912fb2b0..79e67994ee 100644 --- a/services/github/github-resources/src/components/GithubRepositories.svelte +++ b/services/github/github-resources/src/components/GithubRepositories.svelte @@ -20,6 +20,8 @@ showPopup } from '@hcengineering/ui' import { ObjectPresenter } from '@hcengineering/view-resources' + import { Analytics } from '@hcengineering/analytics' + import github from '../plugin' import ConnectProject from './ConnectProject.svelte' import { githubLanguageColors } from './languageColors' @@ -45,6 +47,10 @@ await client.update(prj, { $pull: { repositories: repository._id } }) + Analytics.handleEvent('github.project.disconnected', { + project: prj.identifier, + repository: repository._id + }) // // We need to delete all issues related to repository // const ops = client.apply('cleanup:' + repository._id) // const issuesQuery = await client.findAll( diff --git a/services/github/github-resources/src/index.ts b/services/github/github-resources/src/index.ts index e706a87ec1..17671aec21 100644 --- a/services/github/github-resources/src/index.ts +++ b/services/github/github-resources/src/index.ts @@ -4,7 +4,12 @@ import { type Data, type Ref, type Space, type TxOperations } from '@hcengineering/core' import { type Resources } from '@hcengineering/platform' -import { getClient, type DocCreateFunction, type DocCreatePhase } from '@hcengineering/presentation' +import { + getClient, + type DocCreateFunction, + type DocCreatePhase, + type DocCreateAnalyticsPropsFunction +} from '@hcengineering/presentation' import tracker, { type Issue } from '@hcengineering/tracker' import { type GithubIntegrationRepository } from '@hcengineering/github' import AuthenticationCheck from './components/AuthenticationCheck.svelte' @@ -51,6 +56,25 @@ async function updateIssue ( } } +function getCreateIssueAnalyticsProps ( + space: Space, + issue: Data, + settings: Record +): Record { + const hierarchy = getClient().getHierarchy() + if (hierarchy.hasMixin(space, github.mixin.GithubProject)) { + const repository = settings.repository as Ref + if (repository == null) return {} + + return { + github: true, + githubRepository: repository + } + } + + return {} +} + export default async (): Promise => ({ component: { Connect, @@ -85,6 +109,7 @@ export default async (): Promise => ({ const client = getClient() return spaces.some((it) => client.getHierarchy().hasMixin(it, github.mixin.GithubProject)) }, - UpdateIssue: updateIssue as DocCreateFunction + UpdateIssue: updateIssue as DocCreateFunction, + GetCreateIssueAnalyticsProps: getCreateIssueAnalyticsProps as DocCreateAnalyticsPropsFunction } }) diff --git a/services/github/model-github/src/index.ts b/services/github/model-github/src/index.ts index 1e904019af..203469cc1f 100644 --- a/services/github/model-github/src/index.ts +++ b/services/github/model-github/src/index.ts @@ -655,6 +655,7 @@ export function createModel (builder: Builder): void { builder.createDoc(presentation.class.DocCreateExtension, core.space.Model, { ofClass: tracker.class.Issue, apply: github.functions.UpdateIssue, + getAnalyticsProps: github.functions.GetCreateIssueAnalyticsProps, components: { createButton: github.component.GithubIssueInfoHeader } diff --git a/services/github/model-github/src/plugin.ts b/services/github/model-github/src/plugin.ts index 44cf12ff12..cc330ccdde 100644 --- a/services/github/model-github/src/plugin.ts +++ b/services/github/model-github/src/plugin.ts @@ -8,7 +8,11 @@ import github from '@hcengineering/github-resources/src/plugin' import { type ChatMessageViewlet } from '@hcengineering/chunter' import { type Doc, type Ref, type Space } from '@hcengineering/core' -import { type DocCreateFunction, type ObjectSearchCategory } from '@hcengineering/model-presentation' +import { + type DocCreateFunction, + type ObjectSearchCategory, + type DocCreateAnalyticsPropsFunction +} from '@hcengineering/model-presentation' import { type NotificationGroup } from '@hcengineering/notification' import type { AnyComponent } from '@hcengineering/ui' import { type ActionCategory, type Viewlet } from '@hcengineering/view' @@ -55,7 +59,8 @@ export default mergeIds(githubId, github, { }, functions: { ShowForRepositoryOnly: '' as Resource<(spaces: Space[]) => Promise>, - UpdateIssue: '' as Resource + UpdateIssue: '' as Resource, + GetCreateIssueAnalyticsProps: '' as Resource }, ids: { AssigneeNotification: '' as Ref,