Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/aws-lsp-antlr4-runtimes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"webpack": "webpack"
},
"dependencies": {
"@aws/language-server-runtimes": "^0.2.96",
"@aws/language-server-runtimes": "^0.2.97",
"@aws/lsp-antlr4": "*",
"antlr4-c3": "^3.4.1",
"antlr4ng": "^3.0.4"
Expand Down
2 changes: 1 addition & 1 deletion app/aws-lsp-codewhisperer-runtimes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"local-build": "node scripts/local-build.js"
},
"dependencies": {
"@aws/language-server-runtimes": "^0.2.96",
"@aws/language-server-runtimes": "^0.2.97",
"@aws/lsp-codewhisperer": "*",
"copyfiles": "^2.4.1",
"cross-env": "^7.0.3",
Expand Down
2 changes: 1 addition & 1 deletion app/aws-lsp-identity-runtimes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"compile": "tsc --build"
},
"dependencies": {
"@aws/language-server-runtimes": "^0.2.96",
"@aws/language-server-runtimes": "^0.2.97",
"@aws/lsp-identity": "^0.0.1"
}
}
2 changes: 1 addition & 1 deletion app/aws-lsp-json-runtimes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"webpack": "webpack"
},
"dependencies": {
"@aws/language-server-runtimes": "^0.2.96",
"@aws/language-server-runtimes": "^0.2.97",
"@aws/lsp-json": "*"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion app/aws-lsp-notification-runtimes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"compile": "tsc --build"
},
"dependencies": {
"@aws/language-server-runtimes": "^0.2.96",
"@aws/language-server-runtimes": "^0.2.97",
"@aws/lsp-notification": "^0.0.1"
}
}
2 changes: 1 addition & 1 deletion app/aws-lsp-yaml-json-webworker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"serve:webpack": "NODE_ENV=development webpack serve"
},
"dependencies": {
"@aws/language-server-runtimes": "^0.2.96",
"@aws/language-server-runtimes": "^0.2.97",
"@aws/lsp-json": "*",
"@aws/lsp-yaml": "*"
},
Expand Down
2 changes: 1 addition & 1 deletion app/aws-lsp-yaml-runtimes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"webpack": "webpack"
},
"dependencies": {
"@aws/language-server-runtimes": "^0.2.96",
"@aws/language-server-runtimes": "^0.2.97",
"@aws/lsp-yaml": "*"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion app/hello-world-lsp-runtimes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
"dependencies": {
"@aws/hello-world-lsp": "^0.0.1",
"@aws/language-server-runtimes": "^0.2.96"
"@aws/language-server-runtimes": "^0.2.97"
},
"devDependencies": {
"@types/chai": "^4.3.5",
Expand Down
4 changes: 2 additions & 2 deletions chat-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
},
"dependencies": {
"@aws/chat-client-ui-types": "^0.1.40",
"@aws/language-server-runtimes-types": "^0.1.34",
"@aws/mynah-ui": "^4.35.3"
"@aws/language-server-runtimes-types": "^0.1.39",
"@aws/mynah-ui": "^4.35.4"
},
"devDependencies": {
"@types/jsdom": "^21.1.6",
Expand Down
2 changes: 1 addition & 1 deletion chat-client/src/client/chat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('Chat', () => {

assert.calledWithExactly(clientApi.postMessage.thirdCall, {
command: TAB_ADD_NOTIFICATION_METHOD,
params: { tabId: initialTabId },
params: { tabId: initialTabId, restoredTab: undefined },
})

assert.calledWithExactly(clientApi.postMessage.lastCall, {
Expand Down
31 changes: 31 additions & 0 deletions chat-client/src/client/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,13 @@ import {
InfoLinkClickParams,
LINK_CLICK_NOTIFICATION_METHOD,
LIST_CONVERSATIONS_REQUEST_METHOD,
LIST_RULES_REQUEST_METHOD,
LIST_MCP_SERVERS_REQUEST_METHOD,
LinkClickParams,
ListConversationsParams,
ListConversationsResult,
ListRulesParams,
ListRulesResult,
ListMcpServersParams,
ListMcpServersResult,
MCP_SERVER_CLICK_REQUEST_METHOD,
Expand All @@ -74,11 +77,18 @@ import {
OPEN_TAB_REQUEST_METHOD,
OpenTabParams,
OpenTabResult,
PINNED_CONTEXT_ADD_NOTIFICATION_METHOD,
PINNED_CONTEXT_NOTIFICATION_METHOD,
PINNED_CONTEXT_REMOVE_NOTIFICATION_METHOD,
PROMPT_INPUT_OPTION_CHANGE_METHOD,
PinnedContextParams,
PromptInputOptionChangeParams,
QUICK_ACTION_REQUEST_METHOD,
QuickActionParams,
READY_NOTIFICATION_METHOD,
RULE_CLICK_REQUEST_METHOD,
RuleClickParams,
RuleClickResult,
SOURCE_LINK_CLICK_NOTIFICATION_METHOD,
SourceLinkClickParams,
TAB_ADD_NOTIFICATION_METHOD,
Expand Down Expand Up @@ -193,9 +203,18 @@ export const createChat = (
case CONTEXT_COMMAND_NOTIFICATION_METHOD:
mynahApi.sendContextCommands(message.params as ContextCommandParams)
break
case PINNED_CONTEXT_NOTIFICATION_METHOD:
mynahApi.sendPinnedContext(message.params as PinnedContextParams)
break
case LIST_CONVERSATIONS_REQUEST_METHOD:
mynahApi.listConversations(message.params as ListConversationsResult)
break
case LIST_RULES_REQUEST_METHOD:
mynahApi.listRules(message.params as ListRulesResult)
break
case RULE_CLICK_REQUEST_METHOD:
mynahApi.ruleClicked(message.params as RuleClickResult)
break
case CONVERSATION_CLICK_REQUEST_METHOD:
mynahApi.conversationClicked(message.params as ConversationClickResult)
break
Expand Down Expand Up @@ -432,6 +451,18 @@ export const createChat = (
onOpenSettings: (settingKey: string) => {
sendMessageToClient({ command: OPEN_SETTINGS, params: { settingKey } })
},
onRuleClick: (params: RuleClickParams) => {
sendMessageToClient({ command: RULE_CLICK_REQUEST_METHOD, params })
},
listRules: (params: ListRulesParams) => {
sendMessageToClient({ command: LIST_RULES_REQUEST_METHOD, params })
},
onAddPinnedContext: (params: PinnedContextParams) => {
sendMessageToClient({ command: PINNED_CONTEXT_ADD_NOTIFICATION_METHOD, params })
},
onRemovePinnedContext: (params: PinnedContextParams) => {
sendMessageToClient({ command: PINNED_CONTEXT_REMOVE_NOTIFICATION_METHOD, params })
},
}

const messager = new Messager(chatApi)
Expand Down
2 changes: 1 addition & 1 deletion chat-client/src/client/features/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const ChatHistory = {
TabBarButtonId: 'history_sheet',
} as const

interface MynahDetailedList {
export interface MynahDetailedList {
update: (data: DetailedList) => void
close: () => void
changeTarget: (direction: 'up' | 'down', snapOnLastAndFirst?: boolean) => void
Expand Down
191 changes: 191 additions & 0 deletions chat-client/src/client/features/rules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import { MynahIconsType, MynahUI, DetailedListItem, DetailedListItemGroup, MynahIcons } from '@aws/mynah-ui'
import { Messager } from '../messager'
import { ListRulesResult } from '@aws/language-server-runtimes-types'
import { RulesFolder } from '@aws/language-server-runtimes-types'
import { MynahDetailedList } from './history'

export const ContextRule = {
CreateRuleId: 'create-rule',
CancelButtonId: 'cancel-create-rule',
SubmitButtonId: 'submit-create-rule',
RuleNameFieldId: 'rule-name',
} as const

export class RulesList {
rulesList: MynahDetailedList | undefined
tabId: string = ''

constructor(
private mynahUi: MynahUI,
private messager: Messager
) {}

private onRuleFolderClick = (groupName: string) => {
this.messager.onRuleClick({ tabId: this.tabId, type: 'folder', id: groupName })
}

private onRuleClick = (item: DetailedListItem) => {
if (item.id) {
if (item.id === ContextRule.CreateRuleId) {
this.rulesList?.close()
this.mynahUi.showCustomForm(
this.tabId,
[
{
id: ContextRule.RuleNameFieldId,
type: 'textinput',
mandatory: true,
autoFocus: true,
title: 'Rule name',
placeholder: 'Enter rule name',
validationPatterns: {
patterns: [
{
pattern: /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,99}$/,
errorMessage:
'Use only letters, numbers, hyphens, and underscores, starting with a letter or number. Maximum 100 characters.',
},
],
},
description:
"This will create a [rule name].md file in your project's .amazonq/rules folder.",
},
],
[
{
id: ContextRule.CancelButtonId,
text: 'Cancel',
status: 'clear',
waitMandatoryFormItems: false,
},
{
id: ContextRule.SubmitButtonId,
text: 'Create',
status: 'main',
waitMandatoryFormItems: true,
},
],
`Create a rule`
)
} else {
this.messager.onRuleClick({ tabId: this.tabId, type: 'rule', id: item.id })
}
}
}

showLoading(tabId: string) {
this.tabId = tabId
const rulesList = this.mynahUi.openTopBarButtonOverlay({
tabId: this.tabId,
topBarButtonOverlay: {
list: [{ groupName: 'Loading rules...' }],
selectable: false,
},
events: {
onGroupClick: this.onRuleFolderClick,
onItemClick: this.onRuleClick,
onClose: this.onClose,
onKeyPress: this.onKeyPress,
},
})

this.rulesList = {
...rulesList,
changeTarget: () => {},
getTargetElementId: () => {
return undefined
},
}
}

show(params: ListRulesResult) {
this.tabId = params.tabId
if (this.rulesList) {
this.rulesList.update({
filterOptions: params.filterOptions?.map(option => ({
...option,
icon: option.icon as MynahIconsType,
})),
list: convertRulesListToDetailedListGroup(params.rules),
selectable: 'clickable',
})
} else {
const rulesList = this.mynahUi.openTopBarButtonOverlay({
tabId: this.tabId,
topBarButtonOverlay: {
list: convertRulesListToDetailedListGroup(params.rules),
selectable: 'clickable',
},
events: {
onGroupClick: this.onRuleFolderClick,
onItemClick: this.onRuleClick,
onClose: this.onClose,
onKeyPress: this.onKeyPress,
},
})

this.rulesList = {
...rulesList,
changeTarget: () => {},
getTargetElementId: () => {
return undefined
},
}
}
}

private onKeyPress = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
this.close()
}
}

close() {
this.rulesList?.close()
}

private onClose = () => {
this.rulesList = undefined
}
}

const createRuleListItem: DetailedListItem = {
description: 'Create a new rule',
icon: MynahIcons.LIST_ADD,
id: ContextRule.CreateRuleId,
}

export function convertRulesListToDetailedListGroup(rules: RulesFolder[]): DetailedListItemGroup[] {
return rules
.map(
ruleFolder =>
({
groupName: ruleFolder.folderName,
actions: [
{
id: ruleFolder.folderName,
icon: convertRuleStatusToIcon(ruleFolder.active),
status: 'clear',
},
],
icon: MynahIcons.FOLDER,
childrenIndented: true,
children: ruleFolder.rules.map(rule => ({
id: rule.id,
icon: MynahIcons.CHECK_LIST,
description: rule.name,
actions: [{ id: rule.id, icon: convertRuleStatusToIcon(rule.active), status: 'clear' }],
})),
}) as DetailedListItemGroup
)
.concat({ children: [createRuleListItem] })
}

function convertRuleStatusToIcon(status: boolean | 'indeterminate'): MynahIcons | undefined {
if (status === true) {
return MynahIcons.OK
} else if (status === 'indeterminate') {
return MynahIcons.MINUS
}
return undefined
}
Loading
Loading