Skip to content

Commit f97987d

Browse files
authored
Merge pull request #329 from aws/jurredr/form-item-list
Added "list" form item, detailedList icon colors & filterActions
2 parents b1ffe41 + c0c2921 commit f97987d

28 files changed

+650
-77
lines changed

.github/workflows/e2e_tests.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: E2E Tests
2+
on:
3+
pull_request:
4+
branches: [main, feature/*, fix/*]
5+
types: [opened, reopened, ready_for_review, synchronize]
6+
jobs:
7+
chromium-e2e:
8+
name: Chromium E2E Tests
9+
if: github.event.pull_request.draft == false
10+
runs-on: macos-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
with:
14+
fetch-depth: 20
15+
- uses: actions/setup-node@v4
16+
with:
17+
node-version: '20'
18+
registry-url: 'https://registry.npmjs.org'
19+
scope: '@aws'
20+
- name: Install
21+
run: npm ci
22+
- name: Build
23+
run: npm run build
24+
- name: Run Chromium E2E tests
25+
run: npm run tests:e2e:chromium
26+
- uses: actions/upload-artifact@v4
27+
if: ${{ !cancelled() }}
28+
with:
29+
name: chromium-test-snapshots
30+
path: ./ui-tests/__test__/__image_snapshots__/chromium
31+
retention-days: 30
32+
33+
webkit-e2e:
34+
name: Webkit E2E Tests
35+
if: github.event.pull_request.draft == false
36+
runs-on: macos-latest
37+
steps:
38+
- uses: actions/checkout@v4
39+
with:
40+
fetch-depth: 20
41+
- uses: actions/setup-node@v4
42+
with:
43+
node-version: '20'
44+
registry-url: 'https://registry.npmjs.org'
45+
scope: '@aws'
46+
- name: Install
47+
run: npm ci
48+
- name: Build
49+
run: npm run build
50+
- name: Run Webkit E2E tests
51+
run: npm run tests:e2e:webkit
52+
- uses: actions/upload-artifact@v4
53+
if: ${{ !cancelled() }}
54+
with:
55+
name: webkit-test-snapshots
56+
path: ./ui-tests/__test__/__image_snapshots__/webkit
57+
retention-days: 30

.github/workflows/new_pr.yml

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,7 @@ jobs:
3636
run: npm ci
3737
- name: Build
3838
run: npm run build
39-
- name: Run Unit and E2E tests
40-
run: npm run tests:unit && npm run tests:e2e
39+
- name: Run Unit tests
40+
run: npm run tests:unit
4141
- name: Run Lint
42-
run: npm run lint
43-
- uses: actions/upload-artifact@v4
44-
if: ${{ !cancelled() }}
45-
with:
46-
name: test-snapshots
47-
path: ./ui-tests/__test__/__image_snapshots__
48-
retention-days: 30
42+
run: npm run lint

example/src/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export enum Commands {
2323

2424
NOTIFY = '/show-notification',
2525
CLEAR = '/clear',
26+
CLEAR_CONTEXT_ITEMS = '/clear-context-items',
2627
CLEAR_LOGS = '/clear-logs',
2728
SHOW_CUSTOM_FORM = '/show-custom-form',
2829
VOTE = '/vote'

example/src/config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,11 @@ export const QuickActionCommands: QuickActionCommandGroup[] = [
228228
icon: MynahIcons.TRASH,
229229
description: 'Clears all the messages in this tab.',
230230
},
231+
{
232+
command: Commands.CLEAR_CONTEXT_ITEMS,
233+
icon: MynahIcons.TRASH,
234+
description: 'Clears all context items for this tab.',
235+
},
231236
{
232237
command: Commands.CLEAR_LOGS,
233238
icon: MynahIcons.CANCEL,

example/src/main.ts

Lines changed: 139 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,14 @@ export const createMynahUI = (initialData?: MynahUIDataModel): MynahUI => {
9898
});
9999
}
100100
Log(`Prompt options change for tab <b>${tabId}</b>:<br/>
101-
${
102-
optionsValues
103-
? `<br/>Options:<br/>${Object.keys(optionsValues)
104-
.map((optionId) => {
105-
return `<b>${optionId}</b>: ${(optionsValues as Record<string, string>)[optionId] ?? ''}`;
106-
})
107-
.join('<br/>')}`
108-
: ''
109-
}
101+
${optionsValues
102+
? `<br/>Options:<br/>${Object.keys(optionsValues)
103+
.map((optionId) => {
104+
return `<b>${optionId}</b>: ${(optionsValues as Record<string, string>)[optionId] ?? ''}`;
105+
})
106+
.join('<br/>')}`
107+
: ''
108+
}
110109
`);
111110
},
112111
onPromptInputButtonClick: (tabId, buttonId) => {
@@ -146,6 +145,11 @@ export const createMynahUI = (initialData?: MynahUIDataModel): MynahUI => {
146145
},
147146
});
148147

148+
const argumentsItemId1 = generateUID();
149+
150+
const envItemId1 = generateUID();
151+
const envItemId2 = generateUID();
152+
149153
const mcpSheet = mynahUI.openDetailedList({
150154
detailedList: sampleMCPList,
151155
events: {
@@ -175,6 +179,17 @@ export const createMynahUI = (initialData?: MynahUIDataModel): MynahUI => {
175179
}]
176180
},
177181
list: [],
182+
filterActions: [
183+
{
184+
id: 'cancel-mcp',
185+
text: 'Cancel',
186+
},
187+
{
188+
id: 'save-mcp',
189+
text: 'Save',
190+
status: 'primary'
191+
}
192+
],
178193
filterOptions: [
179194
{
180195
type: 'select',
@@ -199,6 +214,77 @@ export const createMynahUI = (initialData?: MynahUIDataModel): MynahUI => {
199214
description: 'Seconds',
200215
id: generateUID()
201216
},
217+
{
218+
id: generateUID(),
219+
type: 'list',
220+
title: 'Arguments',
221+
mandatory: false,
222+
items: [
223+
{
224+
id: argumentsItemId1,
225+
type: 'textinput',
226+
},
227+
],
228+
value: [
229+
{
230+
persistent: true,
231+
values: {
232+
[argumentsItemId1]: '-y',
233+
}
234+
},
235+
{
236+
persistent: false,
237+
values: {
238+
[argumentsItemId1]: '@modelcontextprotocol/server-filesystem',
239+
}
240+
},
241+
{
242+
persistent: false,
243+
values: {
244+
[argumentsItemId1]: '/Users/username/Desktop',
245+
}
246+
},
247+
{
248+
persistent: false,
249+
values: {
250+
[argumentsItemId1]: '/path/to/other/allowed/dir',
251+
}
252+
}
253+
]
254+
},
255+
{
256+
id: generateUID(),
257+
type: 'list',
258+
title: 'Environment variables',
259+
items: [
260+
{
261+
id: envItemId1,
262+
title: 'Name',
263+
type: 'textinput',
264+
},
265+
{
266+
id: envItemId2,
267+
title: 'Value',
268+
type: 'textinput',
269+
}
270+
],
271+
value: [
272+
{
273+
persistent: true,
274+
values: {
275+
[envItemId1]: 'some_env',
276+
[envItemId2]: 'AJSKJLE!@)(UD'
277+
}
278+
},
279+
{
280+
persistent: false,
281+
values: {
282+
[envItemId1]: 'some_other_env',
283+
[envItemId2]: '12kjlkj!dddaa'
284+
}
285+
}
286+
]
287+
},
202288
],
203289
});
204290
}
@@ -207,8 +293,8 @@ export const createMynahUI = (initialData?: MynahUIDataModel): MynahUI => {
207293
onClose: () => {
208294
Log('Sheet closed');
209295
},
210-
onTitleActionClick: (button)=>{
211-
if(button.id === 'back-to-mcp-list'){
296+
onTitleActionClick: (button) => {
297+
if (button.id === 'back-to-mcp-list') {
212298
mcpSheet.update(sampleMCPList);
213299
}
214300
}
@@ -1052,11 +1138,10 @@ here to see if it gets cut off properly as expected, with an ellipsis through cs
10521138
Log(`New prompt on tab: <b>${tabId}</b><br/>
10531139
prompt: <b>${prompt.prompt !== undefined && prompt.prompt !== '' ? prompt.prompt : '{command only}'}</b><br/>
10541140
command: <b>${prompt.command ?? '{none}'}</b><br/>
1055-
options: <b>{${
1056-
Object.keys(prompt.options ?? {})
1057-
.map((op) => `'${op}': '${prompt.options?.[op] as string}'`)
1058-
.join(',') ?? ''
1059-
}}</b><br/>
1141+
options: <b>{${Object.keys(prompt.options ?? {})
1142+
.map((op) => `'${op}': '${prompt.options?.[op] as string}'`)
1143+
.join(',') ?? ''
1144+
}}</b><br/>
10601145
context: <b>[${(prompt.context ?? []).map((ctx) => `${JSON.stringify(ctx)}`).join(']</b>, <b>[')}]`);
10611146
if (tabId === 'tab-1') {
10621147
mynahUI.updateStore(tabId, {
@@ -1220,15 +1305,14 @@ here to see if it gets cut off properly as expected, with an ellipsis through cs
12201305
Log(`Body action clicked in message <b>${messageId}</b>:<br/>
12211306
Action Id: <b>${action.id}</b><br/>
12221307
Action Text: <b>${action.text}</b><br/>
1223-
${
1224-
action.formItemValues
1225-
? `<br/>Options:<br/>${Object.keys(action.formItemValues)
1226-
.map((optionId) => {
1227-
return `<b>${optionId}</b>: ${(action.formItemValues as Record<string, string>)[optionId] ?? ''}`;
1228-
})
1229-
.join('<br/>')}`
1230-
: ''
1231-
}
1308+
${action.formItemValues
1309+
? `<br/>Options:<br/>${Object.keys(action.formItemValues)
1310+
.map((optionId) => {
1311+
return `<b>${optionId}</b>: ${(action.formItemValues as Record<string, string>)[optionId] ?? ''}`;
1312+
})
1313+
.join('<br/>')}`
1314+
: ''
1315+
}
12321316
`);
12331317
},
12341318
onQuickCommandGroupActionClick: (tabId: string, action) => {
@@ -1288,15 +1372,14 @@ here to see if it gets cut off properly as expected, with an ellipsis through cs
12881372
event.preventDefault();
12891373
event.stopImmediatePropagation();
12901374
Log(`Form keypress Enter submit on tab <b>${tabId}</b>:<br/>
1291-
${
1292-
formData
1293-
? `<br/>Options:<br/>${Object.keys(formData)
1294-
.map((optionId) => {
1295-
return `<b>${optionId}</b>: ${(formData as Record<string, string>)[optionId] ?? ''}`;
1296-
})
1297-
.join('<br/>')}`
1298-
: ''
1299-
}
1375+
${formData
1376+
? `<br/>Options:<br/>${Object.keys(formData)
1377+
.map((optionId) => {
1378+
return `<b>${optionId}</b>: ${(formData as Record<string, string>)[optionId] ?? ''}`;
1379+
})
1380+
.join('<br/>')}`
1381+
: ''
1382+
}
13001383
`);
13011384
return true;
13021385
}
@@ -1306,15 +1389,14 @@ here to see if it gets cut off properly as expected, with an ellipsis through cs
13061389
Log(`Custom form action clicked for tab <b>${tabId}</b>:<br/>
13071390
Action Id: <b>${action.id}</b><br/>
13081391
Action Text: <b>${action.text}</b><br/>
1309-
${
1310-
action.formItemValues
1311-
? `<br/>Options:<br/>${Object.keys(action.formItemValues)
1312-
.map((optionId) => {
1313-
return `<b>${optionId}</b>: ${(action.formItemValues as Record<string, string>)[optionId] ?? ''}`;
1314-
})
1315-
.join('<br/>')}`
1316-
: ''
1317-
}
1392+
${action.formItemValues
1393+
? `<br/>Options:<br/>${Object.keys(action.formItemValues)
1394+
.map((optionId) => {
1395+
return `<b>${optionId}</b>: ${(action.formItemValues as Record<string, string>)[optionId] ?? ''}`;
1396+
})
1397+
.join('<br/>')}`
1398+
: ''
1399+
}
13181400
`);
13191401
},
13201402
onChatItemEngagement: (tabId, messageId, engagement) => {
@@ -1361,6 +1443,11 @@ here to see if it gets cut off properly as expected, with an ellipsis through cs
13611443
chatItems: [],
13621444
});
13631445
break;
1446+
case Commands.CLEAR_CONTEXT_ITEMS:
1447+
mynahUI.updateStore(tabId, {
1448+
contextCommands: [],
1449+
});
1450+
break;
13641451
case Commands.CLEAR_LOGS:
13651452
LogClear();
13661453
break;
@@ -1671,13 +1758,13 @@ used as a context to generate this message.`,
16711758
mynahUI.updateStore(tabId, {
16721759
...(optionalParts != null
16731760
? {
1674-
promptInputProgress: {
1675-
status: 'info',
1676-
...(percentage > 50 ? { text: 'Almost done...' } : {}),
1677-
valueText: `${parseInt(percentage.toString())}%`,
1678-
value: percentage,
1679-
},
1680-
}
1761+
promptInputProgress: {
1762+
status: 'info',
1763+
...(percentage > 50 ? { text: 'Almost done...' } : {}),
1764+
valueText: `${parseInt(percentage.toString())}%`,
1765+
value: percentage,
1766+
},
1767+
}
16811768
: {}),
16821769
});
16831770
return false;
@@ -1710,8 +1797,8 @@ used as a context to generate this message.`,
17101797
}
17111798
Log(`Stream ended with details: <br/>
17121799
${Object.keys(cardDetails)
1713-
.map((key) => `${key}: <b>${cardDetails[key].toString()}</b>`)
1714-
.join('<br/>')}
1800+
.map((key) => `${key}: <b>${cardDetails[key].toString()}</b>`)
1801+
.join('<br/>')}
17151802
`);
17161803
mynahUI.addChatItem(tabId, { ...defaultFollowUps, messageId: generateUID() });
17171804
streamingMessageId = null;

0 commit comments

Comments
 (0)