-
Notifications
You must be signed in to change notification settings - Fork 215
feat: conversations widget #2700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Size Change: +27.4 kB (+0.52%) Total Size: 5.26 MB
ℹ️ View Unchanged
|
Wiz Scan Summary
To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension. |
pauldambra
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, and then did a very nit-picky review since as soon as it's out there we'll get coupled to the decision we learn to like least :rolling_on_the_floor_laughing:
didn't run it
and only thought loosely about the security since we talked about the implementation in person and this follows it as far as i can tell
| "disable_conversations": [ | ||
| "false", | ||
| "true" | ||
| ], | ||
| "conversations": [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, going through with a nitpicking mindset :)
we could have conversations: false, instead of disable_conversations: true
but arguably disable_conversations is more clear
|
|
||
| const calls = (mockPosthog._send_request as jest.Mock).mock.calls | ||
| const getMessagesCall = calls.find((call) => call[0].url.includes('/widget/messages/')) | ||
| expect(getMessagesCall[0].url).not.toContain('distinct_id=') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very nitpicky... we could be including the actual distinct id but not keyed by distinct_id=
so really we should test the distinct id
| private _widgetSessionId: string | ||
|
|
||
| constructor( | ||
| config: ConversationsRemoteConfig, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| config: ConversationsRemoteConfig, | |
| private readonly _config: ConversationsRemoteConfig, |
nitpick that you can avoid having to declare and assign to a field this way
(really very stylistic though - don't think there's a right and wrong)
| } | ||
|
|
||
| // Track message sent | ||
| this._posthog.capture('$conversations_message_sent', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should maybe exclude these $conversations_etc events from billing
and then set up tracking in the billing report
so that this is free while in beta
but it's not going to be sooo many events so maybe OK to have it be the event cost for now
| this._pollMessages() | ||
|
|
||
| // Set up interval | ||
| this._pollIntervalId = window?.setInterval(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should listen to document visibility and pause and resume this polling when the page is not visible
(it's one of the things that stops a browser freezing a tab)
and it saves us handling API calls for tabs nobody is on
(not blocking now, but as a follow-up)
| * SECURITY: This is the key for access control. Only the browser that created | ||
| * the widget_session_id can access tickets associated with it. | ||
| */ | ||
| getOrCreateWidgetSessionId(): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
silly check,... since we default to local storage in persistence
i guess this means if you have multiple tabs open they all have the same chat messages
i assume that's ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, that's correct as you could accidentally close one
| */ | ||
| function extractHostname(domain: string): string | null { | ||
| // Remove protocol if present | ||
| let hostname = domain.replace(/^https?:\/\//, '') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
silly nit pick that this won't work for capacitor (and maybe electron)
and that might be OK
| /** | ||
| * Whether conversations are enabled for this team | ||
| */ | ||
| enabled: boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could also avoid this by just returning false or nothing when disabled
and that is the signal that it isn't enabled
not a biggie, but we're sending enabled: true over the wire billions and billions of times but can avoid it
| greetingText?: string | ||
|
|
||
| /** | ||
| * Primary color for the widget UI | ||
| */ | ||
| color?: string | ||
|
|
||
| /** | ||
| * Placeholder text for the message input | ||
| */ | ||
| placeholderText?: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could also nest some of these under customization: {}?
i feel like as the amount of options grows a flat list will get annoying
but it's nit-picky
| /** | ||
| * Visual state of the conversations widget | ||
| */ | ||
| export enum ConversationsWidgetState { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://www.totaltypescript.com/why-i-dont-like-typescript-enums
could just be export const ConversationsWidgetState = 'open' | 'closed'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enum PackStatus {
Draft = 0,
Approved = 1,
Shipped = 2,
}
// [0, "Draft", 1, "Approved", 2, "Shipped"]
console.log(Object.keys(PackStatus));
WAT?!?
Problem
Conversations widget version 1
Changes
Adding conversations extension
Release info Sub-libraries affected
Libraries affected
Checklist
If releasing new changes
pnpm changesetto generate a changeset file