chore: track events for estimates and importers (#1012)

This commit is contained in:
Aaryan Khandelwal 2023-05-05 15:45:38 +05:30 committed by GitHub
parent b34cf0c471
commit 93c105c495
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 133 additions and 18 deletions

View File

@ -63,7 +63,11 @@ const IntegrationGuide = () => {
services. This tool will guide you to relocate the issue to Plane. services. This tool will guide you to relocate the issue to Plane.
</div> </div>
</div> </div>
<a href="https://docs.plane.so" target="_blank" rel="noopener noreferrer"> <a
href="https://docs.plane.so/importers/github"
target="_blank"
rel="noopener noreferrer"
>
<div className="flex flex-shrink-0 cursor-pointer items-center gap-2 whitespace-nowrap text-sm font-medium text-[#3F76FF] hover:text-opacity-80"> <div className="flex flex-shrink-0 cursor-pointer items-center gap-2 whitespace-nowrap text-sm font-medium text-[#3F76FF] hover:text-opacity-80">
Read More Read More
<ArrowRightIcon width={"18px"} color={"#3F76FF"} /> <ArrowRightIcon width={"18px"} color={"#3F76FF"} />
@ -124,7 +128,7 @@ const IntegrationGuide = () => {
{importerServices ? ( {importerServices ? (
importerServices.length > 0 ? ( importerServices.length > 0 ? (
<div className="space-y-2"> <div className="space-y-2">
<div className="divide-y"> <div className="divide-y divide-brand-base">
{importerServices.map((service) => ( {importerServices.map((service) => (
<SingleImport <SingleImport
key={service.id} key={service.id}

View File

@ -6,6 +6,8 @@ import { TrashIcon } from "@heroicons/react/24/outline";
import { renderShortDateWithYearFormat } from "helpers/date-time.helper"; import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
// types // types
import { IImporterService } from "types"; import { IImporterService } from "types";
// constants
import { IMPORTERS_EXPORTERS_LIST } from "constants/workspace";
type Props = { type Props = {
service: IImporterService; service: IImporterService;
@ -13,17 +15,16 @@ type Props = {
handleDelete: () => void; handleDelete: () => void;
}; };
const importersList: { [key: string]: string } = {
github: "GitHub",
};
export const SingleImport: React.FC<Props> = ({ service, refreshing, handleDelete }) => ( export const SingleImport: React.FC<Props> = ({ service, refreshing, handleDelete }) => (
<div className="flex items-center justify-between gap-2 py-3"> <div className="flex items-center justify-between gap-2 py-3">
<div> <div>
<h4 className="flex items-center gap-2 text-sm"> <h4 className="flex items-center gap-2 text-sm">
<span> <span>
Import from <span className="font-medium">{importersList[service.service]}</span> to{" "} Import from{" "}
<span className="font-medium">{service.project_detail.name}</span> <span className="font-medium">
{IMPORTERS_EXPORTERS_LIST.find((i) => i.provider === service.service)?.title}
</span>{" "}
to <span className="font-medium">{service.project_detail.name}</span>
</span> </span>
<span <span
className={`rounded px-2 py-0.5 text-xs capitalize ${ className={`rounded px-2 py-0.5 text-xs capitalize ${

View File

@ -1,10 +1,14 @@
// services // services
import APIService from "services/api.service"; import APIService from "services/api.service";
// types // types
import type { IEstimate, IEstimateFormData, IEstimatePoint } from "types"; import type { IEstimate, IEstimateFormData } from "types";
import trackEventServices from "services/track-event.service";
const { NEXT_PUBLIC_API_BASE_URL } = process.env; const { NEXT_PUBLIC_API_BASE_URL } = process.env;
const trackEvent =
process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1";
class ProjectEstimateServices extends APIService { class ProjectEstimateServices extends APIService {
constructor() { constructor() {
super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000");
@ -16,7 +20,11 @@ class ProjectEstimateServices extends APIService {
data: IEstimateFormData data: IEstimateFormData
): Promise<any> { ): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/`, data) return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/`, data)
.then((response) => response?.data) .then((response) => {
if (trackEvent)
trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_CREATE");
return response?.data;
})
.catch((error) => { .catch((error) => {
throw error?.response; throw error?.response;
}); });
@ -32,7 +40,11 @@ class ProjectEstimateServices extends APIService {
`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/`, `/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/`,
data data
) )
.then((response) => response?.data) .then((response) => {
if (trackEvent)
trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_UPDATE");
return response?.data;
})
.catch((error) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });
@ -64,7 +76,11 @@ class ProjectEstimateServices extends APIService {
return this.delete( return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/` `/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/`
) )
.then((response) => response?.data) .then((response) => {
if (trackEvent)
trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_DELETE");
return response?.data;
})
.catch((error) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });

View File

@ -1,10 +1,14 @@
import APIService from "services/api.service"; import APIService from "services/api.service";
import trackEventServices from "services/track-event.service";
import { IGithubRepoInfo, IGithubServiceImportFormData } from "types"; import { IGithubRepoInfo, IGithubServiceImportFormData } from "types";
const { NEXT_PUBLIC_API_BASE_URL } = process.env; const { NEXT_PUBLIC_API_BASE_URL } = process.env;
const integrationServiceType: string = "github"; const trackEvent =
process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1";
const integrationServiceType: string = "github";
class GithubIntegrationService extends APIService { class GithubIntegrationService extends APIService {
constructor() { constructor() {
super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000");
@ -41,7 +45,11 @@ class GithubIntegrationService extends APIService {
`/api/workspaces/${workspaceSlug}/projects/importers/${integrationServiceType}/`, `/api/workspaces/${workspaceSlug}/projects/importers/${integrationServiceType}/`,
data data
) )
.then((response) => response?.data) .then((response) => {
if (trackEvent)
trackEventServices.trackImporterEvent(response?.data, "GITHUB_IMPORTER_CREATE");
return response?.data;
})
.catch((error) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });

View File

@ -1,9 +1,14 @@
import APIService from "services/api.service"; import APIService from "services/api.service";
import trackEventServices from "services/track-event.service";
// types // types
import { IAppIntegration, IImporterService, IWorkspaceIntegration } from "types"; import { IAppIntegration, IImporterService, IWorkspaceIntegration } from "types";
const { NEXT_PUBLIC_API_BASE_URL } = process.env; const { NEXT_PUBLIC_API_BASE_URL } = process.env;
const trackEvent =
process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1";
class IntegrationService extends APIService { class IntegrationService extends APIService {
constructor() { constructor() {
super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000");
@ -49,7 +54,12 @@ class IntegrationService extends APIService {
importerId: string importerId: string
): Promise<any> { ): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/importers/${service}/${importerId}/`) return this.delete(`/api/workspaces/${workspaceSlug}/importers/${service}/${importerId}/`)
.then((res) => res?.data) .then((response) => {
const eventName = service === "github" ? "GITHUB_IMPORTER_DELETE" : "JIRA_IMPORTER_DELETE";
if (trackEvent) trackEventServices.trackImporterEvent(response?.data, eventName);
return response?.data;
})
.catch((error) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });

View File

@ -1,10 +1,14 @@
import APIService from "services/api.service"; import APIService from "services/api.service";
import trackEventServices from "services/track-event.service";
// types // types
import { IJiraMetadata, IJiraResponse, IJiraImporterForm } from "types"; import { IJiraMetadata, IJiraResponse, IJiraImporterForm } from "types";
const { NEXT_PUBLIC_API_BASE_URL } = process.env; const { NEXT_PUBLIC_API_BASE_URL } = process.env;
const trackEvent =
process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1";
class JiraImportedService extends APIService { class JiraImportedService extends APIService {
constructor() { constructor() {
super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000");
@ -22,7 +26,11 @@ class JiraImportedService extends APIService {
async createJiraImporter(workspaceSlug: string, data: IJiraImporterForm): Promise<IJiraResponse> { async createJiraImporter(workspaceSlug: string, data: IJiraImporterForm): Promise<IJiraResponse> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/importers/jira/`, data) return this.post(`/api/workspaces/${workspaceSlug}/projects/importers/jira/`, data)
.then((response) => response?.data) .then((response) => {
if (trackEvent)
trackEventServices.trackImporterEvent(response?.data, "JIRA_IMPORTER_CREATE");
return response?.data;
})
.catch((error) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });

View File

@ -7,6 +7,7 @@ const trackEvent =
// types // types
import type { import type {
ICycle, ICycle,
IEstimate,
IGptResponse, IGptResponse,
IIssue, IIssue,
IIssueComment, IIssueComment,
@ -45,7 +46,10 @@ type PagesEventType = "PAGE_CREATE" | "PAGE_UPDATE" | "PAGE_DELETE";
type ViewEventType = "VIEW_CREATE" | "VIEW_UPDATE" | "VIEW_DELETE"; type ViewEventType = "VIEW_CREATE" | "VIEW_UPDATE" | "VIEW_DELETE";
type IssueCommentType = "ISSUE_COMMENT_CREATE" | "ISSUE_COMMENT_UPDATE" | "ISSUE_COMMENT_DELETE"; type IssueCommentEventType =
| "ISSUE_COMMENT_CREATE"
| "ISSUE_COMMENT_UPDATE"
| "ISSUE_COMMENT_DELETE";
export type MiscellaneousEventType = export type MiscellaneousEventType =
| "TOGGLE_CYCLE_ON" | "TOGGLE_CYCLE_ON"
@ -73,6 +77,13 @@ type IssueLabelEventType = "ISSUE_LABEL_CREATE" | "ISSUE_LABEL_UPDATE" | "ISSUE_
type GptEventType = "ASK_GPT" | "USE_GPT_RESPONSE_IN_ISSUE" | "USE_GPT_RESPONSE_IN_PAGE_BLOCK"; type GptEventType = "ASK_GPT" | "USE_GPT_RESPONSE_IN_ISSUE" | "USE_GPT_RESPONSE_IN_PAGE_BLOCK";
type IssueEstimateEventType = "ESTIMATE_CREATE" | "ESTIMATE_UPDATE" | "ESTIMATE_DELETE";
type ImporterEventType =
| "GITHUB_IMPORTER_CREATE"
| "GITHUB_IMPORTER_DELETE"
| "JIRA_IMPORTER_CREATE"
| "JIRA_IMPORTER_DELETE";
class TrackEventServices extends APIService { class TrackEventServices extends APIService {
constructor() { constructor() {
super("/"); super("/");
@ -209,7 +220,7 @@ class TrackEventServices extends APIService {
async trackIssueCommentEvent( async trackIssueCommentEvent(
data: Partial<IIssueComment> | any, data: Partial<IIssueComment> | any,
eventName: IssueCommentType eventName: IssueCommentEventType
): Promise<any> { ): Promise<any> {
let payload: any; let payload: any;
if (eventName !== "ISSUE_COMMENT_DELETE") if (eventName !== "ISSUE_COMMENT_DELETE")
@ -549,6 +560,61 @@ class TrackEventServices extends APIService {
}, },
}); });
} }
async trackIssueEstimateEvent(
data: { estimate: IEstimate },
eventName: IssueEstimateEventType
): Promise<any> {
let payload: any;
if (eventName === "ESTIMATE_DELETE") payload = data;
else
payload = {
workspaceId: data?.estimate?.workspace_detail?.id,
workspaceName: data?.estimate?.workspace_detail?.name,
workspaceSlug: data?.estimate?.workspace_detail?.slug,
projectId: data?.estimate?.project_detail?.id,
projectName: data?.estimate?.project_detail?.name,
projectIdentifier: data?.estimate?.project_detail?.identifier,
estimateId: data.estimate?.id,
};
return this.request({
url: "/api/track-event",
method: "POST",
data: {
eventName,
extra: {
...payload,
},
},
});
}
async trackImporterEvent(data: any, eventName: ImporterEventType): Promise<any> {
let payload: any;
if (eventName === "GITHUB_IMPORTER_DELETE" || eventName === "JIRA_IMPORTER_DELETE")
payload = data;
else
payload = {
workspaceId: data?.workspace_detail?.id,
workspaceName: data?.workspace_detail?.name,
workspaceSlug: data?.workspace_detail?.slug,
projectId: data?.project_detail?.id,
projectName: data?.project_detail?.name,
projectIdentifier: data?.project_detail?.identifier,
};
return this.request({
url: "/api/track-event",
method: "POST",
data: {
eventName,
extra: {
...payload,
},
},
});
}
} }
const trackEventServices = new TrackEventServices(); const trackEventServices = new TrackEventServices();

View File

@ -8,7 +8,9 @@ export interface IEstimate {
updated_by: string; updated_by: string;
points: IEstimatePoint[]; points: IEstimatePoint[];
project: string; project: string;
project_detail: IProject;
workspace: string; workspace: string;
workspace_detail: IWorkspace;
} }
export interface IEstimatePoint { export interface IEstimatePoint {