fix(analytics): fix missing events from UI (#4026)

This commit is contained in:
Aseem Bansal 2022-02-07 22:52:59 +05:30 committed by GitHub
parent 52272d6561
commit 452d2c22b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 112 additions and 5 deletions

View File

@ -55,6 +55,10 @@ task yarnLint(type: YarnTask, dependsOn: [yarnInstall, yarnGenerate]) {
args = ['run', 'lint']
}
task yarnLintFix(type: YarnTask, dependsOn: [yarnInstall, yarnGenerate]) {
args = ['run', 'lint-fix']
}
task yarnBuild(type: YarnTask, dependsOn: [yarnInstall, yarnTest, yarnLint]) {
args = ['run', 'build']
}

View File

@ -122,12 +122,15 @@ export interface EntitySectionViewEvent extends BaseEvent {
*/
export const EntityActionType = {
UpdateTags: 'UpdateTags',
UpdateTerms: 'UpdateTerms',
UpdateLinks: 'UpdateLinks',
UpdateOwnership: 'UpdateOwnership',
UpdateDocumentation: 'UpdateDocumentation',
UpdateDescription: 'UpdateDescription',
UpdateProperties: 'UpdateProperties',
UpdateSchemaDescription: 'UpdateSchemaDescription',
UpdateSchemaTags: 'UpdateSchemaTags',
UpdateSchemaTerms: 'UpdateSchemaTerms',
ClickExternalUrl: 'ClickExternalUrl',
};

View File

@ -8,6 +8,8 @@ import {
InstitutionalMemoryUpdate,
} from '../../../../types.generated';
import { useEntityRegistry } from '../../../useEntityRegistry';
import { useEntityData } from '../../shared/EntityContext';
import analytics, { EventType, EntityActionType } from '../../../analytics';
export type Props = {
authenticatedUserUrn?: string;
@ -93,6 +95,8 @@ export default function Documentation({
setStagedDocs(newStagedDocs);
};
const { urn, entityType } = useEntityData();
const onSave = async (record: any) => {
const row = await form.validateFields();
@ -113,6 +117,12 @@ export default function Documentation({
};
});
updateDocumentation({ elements: updatedInstitutionalMemory });
analytics.event({
type: EventType.EntityActionEvent,
actionType: EntityActionType.UpdateDescription,
entityType,
entityUrn: urn,
});
setEditingIndex(-1);
};
@ -130,6 +140,12 @@ export default function Documentation({
description: doc.description,
}));
updateDocumentation({ elements: updatedInstitutionalMemory });
analytics.event({
type: EventType.EntityActionEvent,
actionType: EntityActionType.UpdateDescription,
entityType,
entityUrn: urn,
});
setStagedDocs(newDocs);
};

View File

@ -9,6 +9,8 @@ import UpdateDescriptionModal from '../../../../shared/components/legacy/Descrip
import StripMarkdownText, { removeMarkdown } from '../../../../shared/components/styled/StripMarkdownText';
import MarkdownViewer from '../../../../shared/components/legacy/MarkdownViewer';
import SchemaEditableContext from '../../../../../shared/SchemaEditableContext';
import { useEntityData } from '../../../../shared/EntityContext';
import analytics, { EventType, EntityActionType } from '../../../../../analytics';
const EditIcon = styled(EditOutlined)`
cursor: pointer;
@ -89,6 +91,16 @@ export default function DescriptionField({ description, onUpdate, isEdited = fal
const [expanded, setExpanded] = useState(!overLimit);
const isSchemaEditable = React.useContext(SchemaEditableContext);
const onCloseModal = () => setShowAddModal(false);
const { urn, entityType } = useEntityData();
const sendAnalytics = () => {
analytics.event({
type: EventType.EntityActionEvent,
actionType: EntityActionType.UpdateSchemaDescription,
entityType,
entityUrn: urn,
});
};
const onUpdateModal = async (desc: string | null) => {
message.loading({ content: 'Updating...' });
@ -96,6 +108,7 @@ export default function DescriptionField({ description, onUpdate, isEdited = fal
await onUpdate(desc || '');
message.destroy();
message.success({ content: 'Updated!', duration: 2 });
sendAnalytics();
} catch (e: unknown) {
message.destroy();
if (e instanceof Error) message.error({ content: `Update Failed! \n ${e.message || ''}`, duration: 2 });

View File

@ -4,6 +4,7 @@ import { PlusOutlined } from '@ant-design/icons';
import { useGetAuthenticatedUser } from '../../../../useGetAuthenticatedUser';
import { useEntityData } from '../../EntityContext';
import { useAddLinkMutation } from '../../../../../graphql/mutations.generated';
import analytics, { EventType, EntityActionType } from '../../../../analytics';
type AddLinkProps = {
buttonProps?: Record<string, unknown>;
@ -13,7 +14,7 @@ type AddLinkProps = {
export const AddLinkModal = ({ buttonProps, refetch }: AddLinkProps) => {
const [isModalVisible, setIsModalVisible] = useState(false);
const user = useGetAuthenticatedUser();
const { urn } = useEntityData();
const { urn, entityType } = useEntityData();
const [addLinkMutation] = useAddLinkMutation();
const [form] = Form.useForm();
@ -34,6 +35,12 @@ export const AddLinkModal = ({ buttonProps, refetch }: AddLinkProps) => {
variables: { input: { linkUrl: formData.url, label: formData.label, resourceUrn: urn } },
});
message.success({ content: 'Link Added', duration: 2 });
analytics.event({
type: EventType.EntityActionEvent,
entityType,
entityUrn: urn,
actionType: EntityActionType.UpdateLinks,
});
} catch (e: unknown) {
message.destroy();
if (e instanceof Error) {

View File

@ -7,6 +7,8 @@ import { useRemoveOwnerMutation } from '../../../../../graphql/mutations.generat
import { EntityType, Owner } from '../../../../../types.generated';
import { CustomAvatar } from '../../../../shared/avatar';
import { useEntityRegistry } from '../../../../useEntityRegistry';
import analytics, { EventType, EntityActionType } from '../../../../analytics';
import { useEntityData } from '../../EntityContext';
type Props = {
entityUrn: string;
@ -24,6 +26,7 @@ const OwnerTag = styled(Tag)`
export const ExpandedOwner = ({ entityUrn, owner, refetch }: Props) => {
const entityRegistry = useEntityRegistry();
const { entityType } = useEntityData();
const [removeOwnerMutation] = useRemoveOwnerMutation();
let name = '';
@ -47,6 +50,12 @@ export const ExpandedOwner = ({ entityUrn, owner, refetch }: Props) => {
},
});
message.success({ content: 'Owner Removed', duration: 2 });
analytics.event({
type: EventType.EntityActionEvent,
actionType: EntityActionType.UpdateOwnership,
entityType,
entityUrn,
});
} catch (e: unknown) {
message.destroy();
if (e instanceof Error) {

View File

@ -18,6 +18,7 @@ import { useEntityRegistry } from '../../../../useEntityRegistry';
import LineageExplorer from '../../../../lineage/LineageExplorer';
import CompactContext from '../../../../shared/CompactContext';
import DynamicTab from '../../tabs/Entity/weaklyTypedAspects/DynamicTab';
import analytics, { EventType } from '../../../../analytics';
type Props<T, U> = {
urn: string;
@ -124,6 +125,12 @@ export const EntityProfile = <T, U>({
tabParams?: Record<string, any>;
method?: 'push' | 'replace';
}) => {
analytics.event({
type: EventType.EntitySectionViewEvent,
entityType,
entityUrn: urn,
section: tabName.toLowerCase(),
});
history[method](getEntityPath(entityType, urn, entityRegistry, false, tabName, tabParams));
},
[history, entityType, urn, entityRegistry],

View File

@ -10,6 +10,7 @@ import { IconStyleType } from '../../../../Entity';
import { ANTD_GRAY } from '../../../constants';
import { useEntityData } from '../../../EntityContext';
import { useEntityPath } from '../utils';
import analytics, { EventType, EntityActionType } from '../../../../../analytics';
const LogoContainer = styled.span`
margin-right: 10px;
@ -105,6 +106,16 @@ export const EntityHeader = () => {
const entityPath = useEntityPath(entityType, urn);
const externalUrl = entityData?.externalUrl || undefined;
const hasExternalUrl = !!externalUrl;
const sendAnalytics = () => {
analytics.event({
type: EventType.EntityActionEvent,
actionType: EntityActionType.ClickExternalUrl,
entityType,
entityUrn: urn,
});
};
const entityCount = entityData?.entityCount;
const typeIcon = entityRegistry.getIcon(entityType, 12, IconStyleType.ACCENT);
const container = entityData?.container;
@ -146,7 +157,11 @@ export const EntityHeader = () => {
<EntityTitle level={3}>{entityData?.name || ' '}</EntityTitle>
</Link>
</MainHeaderContent>
{hasExternalUrl && <ExternalLinkButton href={externalUrl}>View in {platformName}</ExternalLinkButton>}
{hasExternalUrl && (
<ExternalLinkButton href={externalUrl} onClick={sendAnalytics}>
View in {platformName}
</ExternalLinkButton>
)}
<Tooltip title="Copy URN. An URN uniquely identifies an entity on DataHub.">
<Button
icon={copiedUrn ? <CheckOutlined /> : <CopyOutlined />}

View File

@ -8,6 +8,7 @@ import { CorpUser, EntityType, OwnerEntityType, SearchResult } from '../../../..
import { useEntityRegistry } from '../../../../../../useEntityRegistry';
import { useEntityData } from '../../../../EntityContext';
import { CustomAvatar } from '../../../../../../shared/avatar';
import analytics, { EventType, EntityActionType } from '../../../../../../analytics';
type Props = {
visible: boolean;
@ -40,7 +41,7 @@ type SelectedActor = {
export const AddOwnerModal = ({ visible, onClose, refetch }: Props) => {
const entityRegistry = useEntityRegistry();
const { urn } = useEntityData();
const { urn, entityType } = useEntityData();
const [selectedActor, setSelectedActor] = useState<SelectedActor | undefined>(undefined);
const [userSearch, { data: userSearchData }] = useGetSearchResultsLazyQuery();
const [groupSearch, { data: groupSearchData }] = useGetSearchResultsLazyQuery();
@ -70,6 +71,12 @@ export const AddOwnerModal = ({ visible, onClose, refetch }: Props) => {
},
});
message.success({ content: 'Owner Added', duration: 2 });
analytics.event({
type: EventType.EntityActionEvent,
actionType: EntityActionType.UpdateOwnership,
entityType,
entityUrn: urn,
});
} catch (e: unknown) {
message.destroy();
if (e instanceof Error) {

View File

@ -151,6 +151,7 @@ export default function AddTagTermModal({
let urnToAdd = '';
let input = {};
let actionType = EntityActionType.UpdateSchemaTags;
if (selectedType === EntityType.Tag) {
urnToAdd = `urn:li:tag:${selectedName}`;
input = {
@ -159,6 +160,11 @@ export default function AddTagTermModal({
subResource: entitySubresource,
subResourceType: entitySubresource ? SubResourceType.DatasetField : null,
};
if (entitySubresource) {
actionType = EntityActionType.UpdateSchemaTags;
} else {
actionType = EntityActionType.UpdateTags;
}
}
if (selectedType === EntityType.GlossaryTerm) {
urnToAdd = `urn:li:glossaryTerm:${selectedName}`;
@ -168,14 +174,20 @@ export default function AddTagTermModal({
subResource: entitySubresource,
subResourceType: entitySubresource ? SubResourceType.DatasetField : null,
};
if (entitySubresource) {
actionType = EntityActionType.UpdateSchemaTerms;
} else {
actionType = EntityActionType.UpdateTerms;
}
}
analytics.event({
type: EventType.EntityActionEvent,
actionType: EntityActionType.UpdateTags,
entityType,
entityUrn,
actionType,
});
mutation({
variables: {
input,

View File

@ -117,7 +117,7 @@ export default function TagTermGroup({
const termToRemove = editableGlossaryTerms?.terms?.find((term) => term.term.urn === urnToRemove);
Modal.confirm({
title: `Do you want to remove ${termToRemove?.term.name} term?`,
content: `Are you sure you want to remove the ${termToRemove?.term.name} tag?`,
content: `Are you sure you want to remove the ${termToRemove?.term.name} term?`,
onOk() {
if (entityUrn) {
removeTermMutation({

View File

@ -0,0 +1,14 @@
describe('analytics', () => {
it('can go to a dataset and see analytics in Section Views', () => {
cy.login();
cy.visit("/analytics");
cy.contains("documentation").should('not.exist');
cy.visit("/chart/urn:li:chart:(looker,baz1)");
cy.get("#rc-tabs-0-panel-Dashboards").click({ force: true });
cy.visit("/analytics");
cy.contains("documentation");
});
})