generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 83
feat(q): builderid "paid tier" flow #1197
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
447543e
build: update service model for bearer-token-service.json
justinmk3 c35f542
feat(paidtier): detect Free Tier, show "Upgrade" button
justinmk3 c29af67
feat(paidtier): "/manage" quickaction
justinmk3 cc3ad01
feat(paidtier): Chat UI gets AWS Account ID from user
justinmk3 e5f57a5
fix(paidtier): ux changes
justinmk3 4b02b88
fix(paidtier): skip for non-builderid user
justinmk3 59268fd
fix(paidtier): ux changes: Chat UI does *not* get AWS Account ID
justinmk3 b28d87d
fix(paidtier): ux changes
justinmk3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,6 +58,13 @@ import { | |
| import { ChatHistory, ChatHistoryList } from './features/history' | ||
| import { pairProgrammingModeOff, pairProgrammingModeOn, programmerModeCard } from './texts/pairProgramming' | ||
| import { getModelSelectionChatItem } from './texts/modelSelection' | ||
| import { | ||
| freeTierLimitSticky, | ||
| upgradeSuccessSticky, | ||
| upgradePendingSticky, | ||
| plansAndPricingTitle, | ||
| freeTierLimitDirective, | ||
| } from './texts/paidTier' | ||
|
|
||
| export interface InboundChatApi { | ||
| addChatResponse(params: ChatResult, tabId: string, isPartialResult: boolean): void | ||
|
|
@@ -458,7 +465,13 @@ export const createMynahUi = ( | |
| messager.onCreatePrompt(action.formItemValues![ContextPrompt.PromptNameFieldId]) | ||
| } | ||
| }, | ||
| onFormTextualItemKeyPress: (event: KeyboardEvent, formData: Record<string, string>, itemId: string) => { | ||
| onFormTextualItemKeyPress: ( | ||
| event: KeyboardEvent, | ||
| formData: Record<string, string>, | ||
| itemId: string, | ||
| _tabId: string, | ||
| _eventId?: string | ||
| ) => { | ||
| if (itemId === ContextPrompt.PromptNameFieldId && event.key === 'Enter') { | ||
| event.preventDefault() | ||
| messager.onCreatePrompt(formData[ContextPrompt.PromptNameFieldId]) | ||
|
|
@@ -488,6 +501,14 @@ export const createMynahUi = ( | |
| } | ||
| messager.onPromptInputOptionChange({ tabId, optionsValues }) | ||
| }, | ||
| onPromptInputButtonClick: (tabId, buttonId, eventId) => { | ||
| const payload: ButtonClickParams = { | ||
| tabId, | ||
| messageId: 'not-a-message', | ||
| buttonId: buttonId, | ||
| } | ||
| messager.onPromptInputButtonClick(payload) | ||
| }, | ||
| onMessageDismiss: (tabId, messageId) => { | ||
| if (messageId === programmerModeCard.messageId) { | ||
| programmingModeCardActive = false | ||
|
|
@@ -836,7 +857,99 @@ export const createMynahUi = ( | |
| }) | ||
| } | ||
|
|
||
| /** | ||
| * Adjusts the UI when the user changes to/from free-tier/paid-tier. | ||
| * Shows a message if the user reaches free-tier limit. | ||
| * Shows a message if the user just upgraded to paid-tier. | ||
| */ | ||
| const onPaidTierModeChange = (tabId: string, mode: string | undefined) => { | ||
| if (!mode || !['freetier', 'freetier-limit', 'upgrade-pending', 'paidtier'].includes(mode)) { | ||
| return false // invalid mode | ||
| } | ||
|
|
||
| tabId = !!tabId ? tabId : getOrCreateTabId()! | ||
| const store = mynahUi.getTabData(tabId).getStore() || {} | ||
|
|
||
| // Detect if the tab is already showing the "Upgrade Q" UI. | ||
| const isFreeTierLimitUi = store.promptInputStickyCard?.messageId === freeTierLimitSticky.messageId | ||
| const isUpgradePendingUi = store.promptInputStickyCard?.messageId === upgradePendingSticky.messageId | ||
| const isPlansAndPricingTab = plansAndPricingTitle === store.tabTitle | ||
|
|
||
| if (mode === 'freetier-limit') { | ||
| mynahUi.updateStore(tabId, { | ||
| promptInputStickyCard: freeTierLimitSticky, | ||
| }) | ||
|
|
||
| if (!isFreeTierLimitUi) { | ||
| // TODO: how to set a warning icon on the user's failed prompt? | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this a launch blocking TODO?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a cosmetic issue that will need to be done as a followup. May require changes to mynah-ui. |
||
| // | ||
| // const chatItems = store.chatItems ?? [] | ||
| // const lastPrompt = chatItems.filter(ci => ci.type === ChatItemType.PROMPT).at(-1) | ||
| // for (const c of chatItems) { | ||
| // c.body = 'xxx / ' + c.type | ||
| // c.icon = 'warning' | ||
| // c.iconStatus = 'warning' | ||
| // c.status = 'warning' | ||
| // } | ||
| // | ||
| // if (lastPrompt && lastPrompt.messageId) { | ||
| // lastPrompt.icon = 'warning' | ||
| // lastPrompt.iconStatus = 'warning' | ||
| // lastPrompt.status = 'warning' | ||
| // | ||
| // // Decorate the failed prompt with a warning icon. | ||
| // // mynahUi.updateChatAnswerWithMessageId(tabId, lastPrompt.messageId, lastPrompt) | ||
| // } | ||
| // | ||
| // mynahUi.updateStore(tabId, { | ||
| // chatItems: chatItems, | ||
| // }) | ||
| } else { | ||
| // Show directive only on 2nd chat attempt, not the initial attempt. | ||
| mynahUi.addChatItem(tabId, freeTierLimitDirective) | ||
| } | ||
| } else if (mode === 'upgrade-pending') { | ||
| // Change the sticky banner to show a progress spinner. | ||
| const card: typeof freeTierLimitSticky = { | ||
| ...(isFreeTierLimitUi ? freeTierLimitSticky : upgradePendingSticky), | ||
| icon: 'progress', | ||
| } | ||
| mynahUi.updateStore(tabId, { | ||
| // Show a progress ribbon. | ||
| promptInputVisible: true, | ||
| promptInputStickyCard: isFreeTierLimitUi ? card : null, | ||
| }) | ||
| } else if (mode === 'paidtier') { | ||
| mynahUi.updateStore(tabId, { | ||
| promptInputStickyCard: null, | ||
| promptInputVisible: !isPlansAndPricingTab, | ||
| }) | ||
| if (isFreeTierLimitUi || isUpgradePendingUi || isPlansAndPricingTab) { | ||
| // Transitioning from 'upgrade-pending' to upgrade success. | ||
| const card: typeof upgradeSuccessSticky = { | ||
| ...upgradeSuccessSticky, | ||
| canBeDismissed: !isPlansAndPricingTab, | ||
| } | ||
| mynahUi.updateStore(tabId, { | ||
| promptInputStickyCard: card, | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| mynahUi.updateStore(tabId, { | ||
| // promptInputButtons: mode === 'freetier-limit' ? [upgradeQButton] : [], | ||
| // promptInputDisabledState: mode === 'freetier-limit', | ||
| }) | ||
|
|
||
| return true | ||
| } | ||
|
|
||
| const updateChat = (params: ChatUpdateParams) => { | ||
| // HACK: Special field sent by `agenticChatController.ts:setPaidTierMode()`. | ||
| if (onPaidTierModeChange(params.tabId, (params as any).paidTierMode as string)) { | ||
| return | ||
| } | ||
|
|
||
| const isChatLoading = params.state?.inProgress | ||
| mynahUi.updateStore(params.tabId, { | ||
| loadingChat: isChatLoading, | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,202 @@ | ||
| import { ChatItem, ChatItemButton, ChatItemFormItem, ChatItemType, TextBasedFormItem } from '@aws/mynah-ui' | ||
|
|
||
| export const plansAndPricingTitle = 'Plans & Pricing' | ||
| export const paidTierLearnMoreUrl = 'https://aws.amazon.com/q/pricing/' | ||
| export const qProName = 'Q Developer Pro' | ||
|
|
||
| export const upgradeQButton: ChatItemButton = { | ||
| id: 'paidtier-upgrade-q', | ||
| flash: 'once', | ||
| fillState: 'always', | ||
| position: 'inside', | ||
| icon: 'external', | ||
| // https://github.com/aws/mynah-ui/blob/main/src/components/icon/icons/q.svg | ||
| // https://github.com/aws/mynah-ui/blob/main/src/components/icon/icons/rocket.svg | ||
| // icon: MynahIcons.Q, | ||
| description: `Upgrade to ${qProName}`, | ||
| text: `Subscribe to ${qProName}`, | ||
| status: 'primary', | ||
| disabled: false, | ||
| } | ||
|
|
||
| export const learnMoreButton: ChatItemButton = { | ||
| id: 'paidtier-upgrade-q-learnmore', | ||
| fillState: 'hover', | ||
| // position: 'inside', | ||
| icon: 'external', | ||
| description: `Learn about ${qProName}`, | ||
| text: 'Learn more', | ||
| status: 'info', | ||
| disabled: false, | ||
| } | ||
|
|
||
| export const continueUpgradeQButton: ChatItemButton = { | ||
| id: 'paidtier-upgrade-q-continue', | ||
| icon: 'rocket', | ||
| flash: 'once', | ||
| fillState: 'hover', | ||
| position: 'inside', | ||
| // description: `Link an AWS account to upgrade ${qProName}`, | ||
| text: 'Continue', | ||
| disabled: false, | ||
| } | ||
|
|
||
| export const freeTierLimitCard: ChatItem = { | ||
| type: ChatItemType.ANSWER, | ||
| // Note: starts with a non-breaking space to workaround https://github.com/aws/mynah-ui/issues/349 | ||
| title: ' Monthly request limit reached', | ||
| messageId: 'freetier-limit', | ||
| status: 'warning', | ||
| buttons: [], | ||
| icon: 'warning', | ||
| // iconStatus: 'success', | ||
| header: { | ||
| icon: 'warning', | ||
| iconStatus: 'warning', | ||
| body: `Upgrade to ${qProName}`, | ||
| }, | ||
| canBeDismissed: false, | ||
| fullWidth: true, | ||
| body: `To increase your limit, subscribe to ${qProName}. During the upgrade, you'll be asked to link your Builder ID to the AWS account that will be billed the monthly subscription fee. Learn more about [pricing >](${paidTierLearnMoreUrl})`, | ||
| } | ||
|
|
||
| export const freeTierLimitDirective: ChatItem = { | ||
| type: ChatItemType.DIRECTIVE, | ||
| // title: '...', | ||
| // header: { }, | ||
| messageId: 'freetier-limit-directive', | ||
| fullWidth: true, | ||
| contentHorizontalAlignment: 'center', | ||
| canBeDismissed: false, | ||
| body: 'Unable to send. Monthly invocation limit met for this month.', | ||
| } | ||
|
|
||
| /** "Banner" (sticky card) shown above the chat prompt. */ | ||
| export const freeTierLimitSticky: Partial<ChatItem> = { | ||
| messageId: 'freetier-limit-banner', | ||
| title: freeTierLimitCard.title, | ||
| body: freeTierLimitCard.body, | ||
| buttons: [upgradeQButton], | ||
| canBeDismissed: false, | ||
| icon: 'warning', | ||
| // iconStatus: 'warning', | ||
| } | ||
|
|
||
| export const upgradePendingSticky: Partial<ChatItem> = { | ||
| messageId: 'upgrade-pending-banner', | ||
| // Note: starts with a non-breaking space to workaround https://github.com/aws/mynah-ui/issues/349 | ||
| body: ' Waiting for subscription status...', | ||
| status: 'info', | ||
| buttons: [], | ||
| canBeDismissed: true, | ||
| icon: 'progress', | ||
| // iconStatus: 'info', | ||
| } | ||
|
|
||
| export const upgradeSuccessSticky: Partial<ChatItem> = { | ||
| messageId: 'upgrade-success-banner', | ||
| // body: `Successfully upgraded to ${qProName}.`, | ||
| status: 'success', | ||
| buttons: [], | ||
| // icon: 'q', | ||
| // iconStatus: 'success', | ||
| header: { | ||
| icon: 'ok-circled', | ||
| iconStatus: 'success', | ||
| body: `Successfully upgraded to ${qProName}.`, | ||
| // status: { | ||
| // status: 'success', | ||
| // position: 'right', | ||
| // text: `Successfully upgraded to ${qProName}.`, | ||
| // }, | ||
| }, | ||
| canBeDismissed: true, | ||
| } | ||
|
|
||
| export const paidTierInfoCard: ChatItem = { | ||
| type: ChatItemType.ANSWER, | ||
| title: 'UPGRADE TO AMAZON Q PRO', | ||
| buttons: [upgradeQButton], | ||
| header: { | ||
| icon: 'q', | ||
| iconStatus: 'primary', | ||
| body: `This feature requires a subscription to ${qProName}.`, | ||
| status: { | ||
| status: 'info', | ||
| icon: 'q', | ||
| }, | ||
| }, | ||
| body: `Upgrade to ${qProName}. [Learn More...](${paidTierLearnMoreUrl})`, | ||
| messageId: 'paidtier-info', | ||
| fullWidth: true, | ||
| canBeDismissed: true, | ||
| snapToTop: true, | ||
| } | ||
|
|
||
| export const paidTierSuccessCard: ChatItem = { | ||
| type: ChatItemType.ANSWER, | ||
| title: 'UPGRADED TO AMAZON Q PRO', | ||
| header: { | ||
| icon: 'q', | ||
| iconStatus: 'primary', | ||
| body: `Welcome to ${qProName}`, | ||
| status: { | ||
| status: 'success', | ||
| icon: 'q', | ||
| text: 'Success', | ||
| }, | ||
| }, | ||
| messageId: 'paidtier-success', | ||
| fullWidth: true, | ||
| canBeDismissed: true, | ||
| body: `Upgraded to ${qProName}\n\n[Learn More...](${paidTierLearnMoreUrl})`, | ||
| snapToTop: true, | ||
| } | ||
|
|
||
| export const paidTierPromptInput: TextBasedFormItem = { | ||
| placeholder: '111111111111', | ||
| type: 'textinput', | ||
| id: 'paid-tier', | ||
| tooltip: `Upgrade to ${qProName}`, | ||
| value: 'true', | ||
| icon: 'magic', | ||
| } | ||
|
|
||
| export const paidTierStep0: ChatItem = { | ||
| type: ChatItemType.DIRECTIVE, | ||
| body: `You have upgraded to ${qProName}`, | ||
| } | ||
|
|
||
| export const paidTierStep1: ChatItem = { | ||
| type: ChatItemType.DIRECTIVE, | ||
| body: `You have upgraded to ${qProName}`, | ||
| } | ||
|
|
||
| /** "Upgrade Q" form with a "AWS account id" user-input textbox. */ | ||
| export const paidTierUpgradeForm: ChatItem = { | ||
| type: ChatItemType.ANSWER, | ||
| status: 'info', | ||
| fullWidth: true, | ||
| // title: 'Connect AWS account and upgrade', | ||
| body: ` | ||
| # Connect AWS account and upgrade | ||
|
|
||
| Provide your AWS account number to enable your ${qProName} subscription. Upon confirming the subscription, your AWS account will begin to be charged. | ||
|
|
||
| [Learn More...](${paidTierLearnMoreUrl}) | ||
| `, | ||
| formItems: [ | ||
| { | ||
| id: 'awsAccountId', | ||
| type: 'textinput', | ||
| title: 'AWS account ID', | ||
| description: '12-digit AWS account ID', | ||
| // tooltip: `Link an AWS account to upgrade to ${qProName}`, | ||
| validationPatterns: { | ||
| patterns: [{ pattern: '[0-9]{12}', errorMessage: 'Must be a valid 12-digit AWS account ID' }], | ||
| }, | ||
| }, | ||
| ], | ||
| buttons: [continueUpgradeQButton], | ||
| snapToTop: true, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
whats this TODO for?
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.
Requires protocol changes in https://github.com/aws/language-server-runtimes to integrate the changes from aws/mynah-ui#322 .
Not a blocker for this PR.