Skip to content
Commits on Source (3)
# [102.2.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v102.1.6...v102.2.0) (2024-11-14)
### Features
* **DuoChat:** Emit chat-slash event on slash commands opened ([07d8ed6](https://gitlab.com/gitlab-org/gitlab-ui/commit/07d8ed6062ca498bfcf7a2b156dcae6deaf7b08f))
## [102.1.6](https://gitlab.com/gitlab-org/gitlab-ui/compare/v102.1.5...v102.1.6) (2024-11-14)
......
{
"name": "@gitlab/ui",
"version": "102.1.6",
"version": "102.2.0",
"description": "GitLab UI Components",
"license": "MIT",
"main": "dist/index.js",
......
......@@ -1010,12 +1010,20 @@ describe('GlDuoChat', () => {
expect(findSlashCommandsCard().exists()).toBe(false);
});
it('does not render slash commands when prompt is "/"', async () => {
createComponent();
setPromptInput('/');
describe('when prompt is "/"', () => {
beforeEach(async () => {
createComponent();
setPromptInput('/');
await nextTick();
});
await nextTick();
expect(findSlashCommandsCard().exists()).toBe(false);
it('does not render slash', () => {
expect(findSlashCommandsCard().exists()).toBe(false);
});
it('does not emit chat-slash', () => {
expect(wrapper.emitted('chat-slash')).toBeUndefined();
});
});
});
......@@ -1031,24 +1039,6 @@ describe('GlDuoChat', () => {
expect(findSlashCommandsCard().exists()).toBe(false);
});
it('renders all slash commands when prompt is "/"', async () => {
createComponent({
propsData: {
slashCommands,
},
});
setPromptInput('/');
await nextTick();
expect(findSlashCommandsCard().exists()).toBe(true);
expect(findSlashCommands()).toHaveLength(slashCommands.length);
slashCommands.forEach((command, index) => {
expect(findSlashCommands().at(index).text()).toContain(command.name);
expect(findSlashCommands().at(index).text()).toContain(command.description);
});
});
it('prevents passing down invalid slash commands', () => {
expect(() => {
wrapper = shallowMount(GlDuoChat, {
......@@ -1075,20 +1065,28 @@ describe('GlDuoChat', () => {
});
describe('when the prompt includes the "/" character or no characters', () => {
it.each(['', '//', '\\', 'foo', '/foo'])(
'does not render the slash commands if prompt is "$prompt"',
async (prompt) => {
createComponent({
propsData: {
slashCommands,
},
});
setPromptInput(prompt);
beforeEach(() => {
createComponent({
propsData: {
slashCommands,
},
});
});
describe.each(['', '//', '\\', 'foo', '/foo'])('when prompt is "%s"', (prompt) => {
beforeEach(async () => {
setPromptInput(prompt);
await nextTick();
});
it('does not emit a chat-slash event', () => {
expect(wrapper.emitted('chat-slash')).toBeUndefined();
});
it('does not render the slash commands', () => {
expect(findSlashCommandsCard().exists()).toBe(false);
}
);
});
});
});
describe('when prompt presents a partial match to an existing slash command', () => {
......@@ -1125,6 +1123,32 @@ describe('GlDuoChat', () => {
);
});
});
describe('with slash commands and prompt "/"', () => {
beforeEach(async () => {
createComponent({
propsData: {
slashCommands,
},
});
setPromptInput('/');
await nextTick();
});
it('renders all slash commands', () => {
expect(findSlashCommandsCard().exists()).toBe(true);
expect(findSlashCommands()).toHaveLength(slashCommands.length);
slashCommands.forEach((command, index) => {
expect(findSlashCommands().at(index).text()).toContain(command.name);
expect(findSlashCommands().at(index).text()).toContain(command.description);
});
});
it('emits slash event', () => {
expect(wrapper.emitted('chat-slash')).toHaveLength(1);
});
});
});
describe('interaction', () => {
......
......@@ -151,6 +151,9 @@ export const Interactive = (args, { argTypes }) => ({
this.requestId += 1;
this.promptInFlight = false;
},
onChatSlash() {
this.loggerInfo += `Slash command menu opened\n\n`;
},
showChat() {
this.isHidden = false;
this.loggerInfo += `Chat opened\n\n`;
......@@ -278,6 +281,7 @@ export const Interactive = (args, { argTypes }) => ({
@send-chat-prompt="onSendChatPrompt"
@chat-hidden="onChatHidden"
@chat-cancel="onChatCancel"
@chat-slash="onChatSlash"
@insert-code-snippet="onInsertCodeSnippet"
@get-context-item-content="handleGetContextItemContent"
>
......
......@@ -357,6 +357,11 @@ export default {
this.scrollToBottom();
}
},
shouldShowSlashCommands(shouldShow) {
if (shouldShow) {
this.onShowSlashCommands();
}
},
},
created() {
this.handleScrollingTrottled = throttle(this.handleScrolling, 200); // Assume a 200ms throttle for example
......@@ -441,6 +446,12 @@ export default {
*/
this.$emit('track-feedback', event);
},
onShowSlashCommands() {
/**
* Emitted when user opens the slash commands menu
*/
this.$emit('chat-slash');
},
sendChatPromptOnEnter(e) {
const { metaKey, ctrlKey, altKey, shiftKey, isComposing } = e;
const isModifierKey = metaKey || ctrlKey || altKey || shiftKey;
......