Skip to content

Commit ce42f59

Browse files
authored
Merge pull request #33766 from storybookjs/norbert/share-channel-events
Telemetry: Add share events
2 parents 5e1084c + d5cc36a commit ce42f59

File tree

9 files changed

+54
-22
lines changed

9 files changed

+54
-22
lines changed

code/.eslintrc.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,9 @@ module.exports = {
160160
'import-x/no-named-as-default-member': 'warn',
161161
'react/destructuring-assignment': 'warn',
162162

163-
// This warns about importing interfaces and types in a normal import, it's arguably better to import with the `type` prefix separate from the runtime imports,
164-
// I leave this as a warning right now because we haven't really decided yet, and the codebase is riddled with errors if I set to 'error'.
163+
// Our codebase is mostly TypeScript, and typescript will warn when imports are not found.
165164
// It IS set to 'error' for JS files.
166-
'import-x/named': 'warn',
165+
'import-x/named': 'off',
167166
},
168167
},
169168
{

code/core/src/core-events/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ enum events {
9696
OPEN_IN_EDITOR_RESPONSE = 'openInEditorResponse',
9797
// Emitted when the manager UI sets up a focus trap
9898
MANAGER_INERT_ATTRIBUTE_CHANGED = 'managerInertAttributeChanged',
99+
100+
SHARE_STORY_LINK = 'shareStoryLink',
101+
SHARE_ISOLATE_MODE = 'shareIsolateMode',
102+
SHARE_POPOVER_OPENED = 'sharePopoverOpened',
99103
}
100104

101105
// Enables: `import Events from ...`
@@ -167,6 +171,9 @@ export const {
167171
OPEN_IN_EDITOR_REQUEST,
168172
OPEN_IN_EDITOR_RESPONSE,
169173
MANAGER_INERT_ATTRIBUTE_CHANGED,
174+
SHARE_STORY_LINK,
175+
SHARE_ISOLATE_MODE,
176+
SHARE_POPOVER_OPENED,
170177
} = events;
171178

172179
export * from './data/create-new-story';

code/core/src/core-server/presets/common-preset.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { initCreateNewStoryChannel } from '../server-channel/create-new-story-ch
3434
import { initFileSearchChannel } from '../server-channel/file-search-channel';
3535
import { initGhostStoriesChannel } from '../server-channel/ghost-stories-channel';
3636
import { initOpenInEditorChannel } from '../server-channel/open-in-editor-channel';
37-
import { initPreviewInitializedChannel } from '../server-channel/preview-initialized-channel';
37+
import { initTelemetryChannel } from '../server-channel/telemetry-channel';
3838
import { initializeChecklist } from '../utils/checklist';
3939
import { defaultFavicon, defaultStaticDirs } from '../utils/constants';
4040
import { initializeSaveStory } from '../utils/save-story/save-story';
@@ -271,7 +271,7 @@ export const experimental_serverChannel = async (
271271
initCreateNewStoryChannel(channel, options, coreOptions);
272272
initGhostStoriesChannel(channel, options, coreOptions);
273273
initOpenInEditorChannel(channel, options, coreOptions);
274-
initPreviewInitializedChannel(channel, options, coreOptions);
274+
initTelemetryChannel(channel, options);
275275

276276
return channel;
277277
};

code/core/src/core-server/server-channel/preview-initialized-channel.test.ts renamed to code/core/src/core-server/server-channel/telemetry-channel.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
22

3-
import { makePayload } from './preview-initialized-channel';
3+
import { makePayload } from './telemetry-channel';
44

55
describe('makePayload', () => {
66
beforeEach(() => {

code/core/src/core-server/server-channel/preview-initialized-channel.ts renamed to code/core/src/core-server/server-channel/telemetry-channel.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import type { Channel } from 'storybook/internal/channels';
2-
import { PREVIEW_INITIALIZED } from 'storybook/internal/core-events';
2+
import {
3+
PREVIEW_INITIALIZED,
4+
SHARE_ISOLATE_MODE,
5+
SHARE_POPOVER_OPENED,
6+
SHARE_STORY_LINK,
7+
} from 'storybook/internal/core-events';
38
import { type InitPayload, telemetry } from 'storybook/internal/telemetry';
49
import { type CacheEntry, getLastEvents } from 'storybook/internal/telemetry';
510
import { getSessionId } from 'storybook/internal/telemetry';
6-
import type { CoreConfig, Options } from 'storybook/internal/types';
11+
import type { Options } from 'storybook/internal/types';
712

813
export const makePayload = (
914
userAgent: string,
@@ -24,13 +29,9 @@ export const makePayload = (
2429
return payload;
2530
};
2631

27-
export function initPreviewInitializedChannel(
28-
channel: Channel,
29-
options: Options,
30-
_coreConfig: CoreConfig
31-
) {
32-
channel.on(PREVIEW_INITIALIZED, async ({ userAgent }) => {
33-
if (!options.disableTelemetry) {
32+
export function initTelemetryChannel(channel: Channel, options: Options) {
33+
if (!options.disableTelemetry) {
34+
channel.on(PREVIEW_INITIALIZED, async ({ userAgent }) => {
3435
try {
3536
const sessionId = await getSessionId();
3637
const lastEvents = await getLastEvents();
@@ -40,9 +41,16 @@ export function initPreviewInitializedChannel(
4041
const payload = makePayload(userAgent, lastInit, sessionId);
4142
telemetry('preview-first-load', payload);
4243
}
43-
} catch (e) {
44-
// do nothing
45-
}
46-
}
47-
});
44+
} catch {}
45+
});
46+
channel.on(SHARE_POPOVER_OPENED, async () => {
47+
telemetry('share', { action: 'popover-opened' });
48+
});
49+
channel.on(SHARE_STORY_LINK, async () => {
50+
telemetry('share', { action: 'story-link-copied' });
51+
});
52+
channel.on(SHARE_ISOLATE_MODE, async () => {
53+
telemetry('share', { action: 'isolate-mode-opened' });
54+
});
55+
}
4856
}

code/core/src/manager/components/preview/tools/share.stories.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { global } from '@storybook/global';
55
import type { StoryObj } from '@storybook/react-vite';
66

77
import { ManagerContext } from 'storybook/manager-api';
8-
import { expect, screen, waitFor } from 'storybook/test';
8+
import { expect, fn, screen, waitFor } from 'storybook/test';
99

1010
import { shareTool } from './share';
1111

@@ -15,6 +15,7 @@ const managerContext = {
1515
refId: undefined,
1616
},
1717
api: {
18+
emit: fn().mockName('api::emit'),
1819
getShortcutKeys: () => ({
1920
copyStoryLink: ['alt', 'shift', 'l'],
2021
openInIsolation: ['alt', 'shift', 'i'],

code/core/src/manager/components/preview/tools/share.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
import React, { useMemo, useState } from 'react';
1+
import React, { useEffect, useMemo, useState } from 'react';
22

33
import { Button, PopoverProvider, TooltipLinkList } from 'storybook/internal/components';
4+
import {
5+
SHARE_ISOLATE_MODE,
6+
SHARE_POPOVER_OPENED,
7+
SHARE_STORY_LINK,
8+
} from 'storybook/internal/core-events';
49
import type { Addon_BaseType } from 'storybook/internal/types';
510

611
import { global } from '@storybook/global';
@@ -71,6 +76,10 @@ const ShareMenu = React.memo(function ShareMenu({
7176
const copyStoryLink = shortcutKeys?.copyStoryLink;
7277
const openInIsolation = shortcutKeys?.openInIsolation;
7378

79+
useEffect(() => {
80+
api.emit(SHARE_POPOVER_OPENED);
81+
}, [api]);
82+
7483
const links = useMemo(() => {
7584
const copyTitle = copied ? 'Copied!' : 'Copy story link';
7685
const originHrefs = api.getStoryHrefs(storyId, { base: 'origin', refId });
@@ -84,6 +93,7 @@ const ShareMenu = React.memo(function ShareMenu({
8493
icon: <LinkIcon />,
8594
right: enableShortcuts ? <Shortcut keys={copyStoryLink} /> : null,
8695
onClick: () => {
96+
api.emit(SHARE_STORY_LINK, originHrefs.managerHref);
8797
copy(originHrefs.managerHref);
8898
setCopied(true);
8999
setTimeout(() => setCopied(false), 2000);
@@ -94,6 +104,9 @@ const ShareMenu = React.memo(function ShareMenu({
94104
title: 'Open in isolation mode',
95105
icon: <ShareAltIcon />,
96106
right: enableShortcuts ? <Shortcut keys={openInIsolation} /> : null,
107+
onClick: () => {
108+
api.emit(SHARE_ISOLATE_MODE, originHrefs.previewHref);
109+
},
97110
href: originHrefs.previewHref,
98111
target: '_blank',
99112
rel: 'noopener noreferrer',

code/core/src/manager/globals/exports.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,9 @@ export default {
615615
'SET_WHATS_NEW_CACHE',
616616
'SHARED_STATE_CHANGED',
617617
'SHARED_STATE_SET',
618+
'SHARE_ISOLATE_MODE',
619+
'SHARE_POPOVER_OPENED',
620+
'SHARE_STORY_LINK',
618621
'STORIES_COLLAPSE_ALL',
619622
'STORIES_EXPAND_ALL',
620623
'STORY_ARGS_UPDATED',

code/core/src/telemetry/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export type EventType =
4343
| 'migrate'
4444
| 'preview-first-load'
4545
| 'doctor'
46+
| 'share'
4647
| 'ghost-stories';
4748
export interface Dependency {
4849
version: string | undefined;

0 commit comments

Comments
 (0)