-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ai-chat-log): add new AI Chat Log components (#3927)
- Loading branch information
1 parent
52b8bad
commit 3302f72
Showing
39 changed files
with
14,708 additions
and
13 deletions.
There are no files selected for viewing
This file contains 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,6 @@ | ||
--- | ||
"@twilio-paste/ai-chat-log": major | ||
"@twilio-paste/core": minor | ||
--- | ||
|
||
[AIChatLog]: Added a new AIChatLog component to the library to display interactions between AI entities |
This file contains 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,6 @@ | ||
--- | ||
"@twilio-paste/button-group": patch | ||
"@twilio-paste/core": patch | ||
--- | ||
|
||
[Button Group] allow unattached button groups to wrap to another line |
This file contains 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,6 @@ | ||
--- | ||
"@twilio-paste/button": patch | ||
"@twilio-paste/core": patch | ||
--- | ||
|
||
[Button] Add border radius 20 to size="reset" buttons which can be overridden by passing a border radius token to variant="reset" and size="reset" buttons |
This file contains 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,5 @@ | ||
--- | ||
"@twilio-paste/codemods": minor | ||
--- | ||
|
||
[Codemods] new export (ai-chat-log) |
This file contains 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 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
35 changes: 35 additions & 0 deletions
35
packages/paste-core/components/ai-chat-log/__tests__/AIChatLogger.spec.tsx
This file contains 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,35 @@ | ||
import { render, screen } from "@testing-library/react"; | ||
import * as React from "react"; | ||
|
||
import { AIChatLogger, AIChatMessage, AIChatMessageBody } from "../src"; | ||
import type { AIChat } from "../src/useAIChatLogger"; | ||
|
||
const chats: AIChat[] = [ | ||
{ | ||
id: "uid1", | ||
variant: "bot", | ||
content: ( | ||
<AIChatMessage variant="bot"> | ||
<AIChatMessageBody>hi</AIChatMessageBody> | ||
</AIChatMessage> | ||
), | ||
}, | ||
{ | ||
id: "uid2", | ||
variant: "user", | ||
content: ( | ||
<AIChatMessage variant="user"> | ||
<AIChatMessageBody>hello</AIChatMessageBody> | ||
</AIChatMessage> | ||
), | ||
}, | ||
]; | ||
|
||
describe("ChatLogger", () => { | ||
it("should render", () => { | ||
render(<AIChatLogger aiChats={chats} />); | ||
expect(screen.getByRole("log")).toBeDefined(); | ||
expect(screen.getByRole("list")).toBeDefined(); | ||
expect(screen.getAllByRole("listitem")).toHaveLength(2); | ||
}); | ||
}); |
118 changes: 118 additions & 0 deletions
118
packages/paste-core/components/ai-chat-log/__tests__/aiChatLog.spec.tsx
This file contains 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,118 @@ | ||
import { render, screen } from "@testing-library/react"; | ||
import * as React from "react"; | ||
|
||
import { | ||
AIChatLog, | ||
AIChatMessage, | ||
AIChatMessageActionCard, | ||
AIChatMessageActionGroup, | ||
AIChatMessageAuthor, | ||
AIChatMessageBody, | ||
AIChatMessageLoading, | ||
} from "../src"; | ||
|
||
const ExampleAIChatLog: React.FC<React.PropsWithChildren> = () => ( | ||
<AIChatLog> | ||
<AIChatMessage variant="bot"> | ||
<AIChatMessageAuthor aria-label="AI said" data-testid="author"> | ||
Good Bot | ||
</AIChatMessageAuthor> | ||
<AIChatMessageBody size="default">Lorem ipsum dolor.</AIChatMessageBody> | ||
<AIChatMessageActionGroup data-testid="action_group"> | ||
<AIChatMessageActionCard aria-label="action" data-testid="action"> | ||
Is this helpful? | ||
</AIChatMessageActionCard> | ||
</AIChatMessageActionGroup> | ||
<AIChatMessageLoading onStopLoading={() => {}} data-testid="loading" /> | ||
</AIChatMessage> | ||
</AIChatLog> | ||
); | ||
|
||
const CustomExampleAIChatLog: React.FC<React.PropsWithChildren> = () => ( | ||
<AIChatLog element="FOO_AI_LOG"> | ||
<AIChatMessage variant="bot" element="FOO_AI_CHAT_MESSAGE"> | ||
<AIChatMessageAuthor aria-label="AI said" data-testid="author" element="FOO_AI_CHAT_MESSAGE_AUTHOR"> | ||
Good Bot | ||
</AIChatMessageAuthor> | ||
<AIChatMessageBody size="default" element="FOO_AI_CHAT_MESSAGE_BODY"> | ||
Lorem ipsum dolor. | ||
</AIChatMessageBody> | ||
<AIChatMessageActionGroup data-testid="action_group" element="FOO_AI_CHAT_MESSAGE_ACTION_GROUP"> | ||
<AIChatMessageActionCard | ||
aria-label="Feedback form" | ||
data-testid="action" | ||
element="FOO_AI_CHAT_MESSAGE_ACTION_CARD" | ||
> | ||
Is this helpful? | ||
</AIChatMessageActionCard> | ||
</AIChatMessageActionGroup> | ||
<AIChatMessageLoading onStopLoading={() => {}} data-testid="loading" element="FOO_AI_CHAT_MESSAGE_LOADING" /> | ||
</AIChatMessage> | ||
</AIChatLog> | ||
); | ||
|
||
describe("AIChatLog", () => { | ||
it("should render", () => { | ||
render(<ExampleAIChatLog />); | ||
expect(screen.getByRole("log")).toBeDefined(); | ||
expect(screen.getByRole("list")).toBeDefined(); | ||
}); | ||
}); | ||
|
||
describe("Customization", () => { | ||
it("should set element data attribute", () => { | ||
render(<ExampleAIChatLog />); | ||
|
||
expect(screen.getByRole("log").getAttribute("data-paste-element")).toEqual("AI_CHAT_LOG"); | ||
expect(screen.getByRole("list").getAttribute("data-paste-element")).toEqual("AI_CHAT_LOG_LIST"); | ||
expect(screen.getAllByRole("listitem")[0].getAttribute("data-paste-element")).toEqual("AI_CHAT_MESSAGE"); | ||
expect(screen.getByTestId("author").getAttribute("data-paste-element")).toEqual("AI_CHAT_MESSAGE_AUTHOR"); | ||
expect(screen.getByTestId("author").firstElementChild?.getAttribute("data-paste-element")).toEqual( | ||
"AI_CHAT_MESSAGE_AUTHOR_BOT_AVATAR", | ||
); | ||
expect(screen.getByText("Lorem ipsum dolor.").getAttribute("data-paste-element")).toEqual("AI_CHAT_MESSAGE_BODY"); | ||
expect(screen.getByTestId("action_group").getAttribute("data-paste-element")).toEqual( | ||
"AI_CHAT_MESSAGE_ACTION_GROUP", | ||
); | ||
expect(screen.getByTestId("action").getAttribute("data-paste-element")).toEqual("AI_CHAT_MESSAGE_ACTION_CARD"); | ||
expect(screen.getByTestId("loading").getAttribute("data-paste-element")).toEqual("AI_CHAT_MESSAGE_LOADING"); | ||
expect(screen.getByTestId("loading").firstElementChild?.getAttribute("data-paste-element")).toEqual( | ||
"AI_CHAT_MESSAGE_LOADING_SKELETON", | ||
); | ||
expect(screen.getByTestId("loading").lastElementChild?.getAttribute("data-paste-element")).toEqual( | ||
"AI_CHAT_MESSAGE_LOADING_STOP_LOADING", | ||
); | ||
expect( | ||
screen.getByTestId("loading").lastElementChild?.firstElementChild?.getAttribute("data-paste-element"), | ||
).toEqual("AI_CHAT_MESSAGE_LOADING_STOP_BUTTON"); | ||
}); | ||
|
||
it("should set custom element data attribute", () => { | ||
render(<CustomExampleAIChatLog />); | ||
|
||
expect(screen.getByRole("log").getAttribute("data-paste-element")).toEqual("FOO_AI_LOG"); | ||
expect(screen.getByRole("list").getAttribute("data-paste-element")).toEqual("FOO_AI_LOG_LIST"); | ||
expect(screen.getAllByRole("listitem")[0].getAttribute("data-paste-element")).toEqual("FOO_AI_CHAT_MESSAGE"); | ||
expect(screen.getByTestId("author").getAttribute("data-paste-element")).toEqual("FOO_AI_CHAT_MESSAGE_AUTHOR"); | ||
expect(screen.getByTestId("author").firstElementChild?.getAttribute("data-paste-element")).toEqual( | ||
"FOO_AI_CHAT_MESSAGE_AUTHOR_BOT_AVATAR", | ||
); | ||
expect(screen.getByText("Lorem ipsum dolor.").getAttribute("data-paste-element")).toEqual( | ||
"FOO_AI_CHAT_MESSAGE_BODY", | ||
); | ||
expect(screen.getByTestId("action_group").getAttribute("data-paste-element")).toEqual( | ||
"FOO_AI_CHAT_MESSAGE_ACTION_GROUP", | ||
); | ||
expect(screen.getByTestId("action").getAttribute("data-paste-element")).toEqual("FOO_AI_CHAT_MESSAGE_ACTION_CARD"); | ||
expect(screen.getByTestId("loading").getAttribute("data-paste-element")).toEqual("FOO_AI_CHAT_MESSAGE_LOADING"); | ||
expect(screen.getByTestId("loading").firstElementChild?.getAttribute("data-paste-element")).toEqual( | ||
"FOO_AI_CHAT_MESSAGE_LOADING_SKELETON", | ||
); | ||
expect(screen.getByTestId("loading").lastElementChild?.getAttribute("data-paste-element")).toEqual( | ||
"FOO_AI_CHAT_MESSAGE_LOADING_STOP_LOADING", | ||
); | ||
expect( | ||
screen.getByTestId("loading").lastElementChild?.firstElementChild?.getAttribute("data-paste-element"), | ||
).toEqual("FOO_AI_CHAT_MESSAGE_LOADING_STOP_BUTTON"); | ||
}); | ||
}); |
88 changes: 88 additions & 0 deletions
88
packages/paste-core/components/ai-chat-log/__tests__/useAIChatLogger.spec.tsx
This file contains 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,88 @@ | ||
import { act, renderHook } from "@testing-library/react"; | ||
import * as React from "react"; | ||
|
||
import { AIChatMessage, AIChatMessageBody, useAIChatLogger } from "../src"; | ||
|
||
const aiChat = { | ||
id: "custom-id-123", | ||
variant: "bot", | ||
content: ( | ||
<AIChatMessage variant="bot"> | ||
<AIChatMessageBody>hi</AIChatMessageBody> | ||
</AIChatMessage> | ||
), | ||
} as const; | ||
|
||
describe("useAIChatLogger", () => { | ||
it("returns expected result with defaults", () => { | ||
const { result } = renderHook(() => useAIChatLogger()); | ||
|
||
expect(result.current).toMatchObject({ | ||
aiChats: [], | ||
pop: expect.any(Function), | ||
push: expect.any(Function), | ||
}); | ||
}); | ||
|
||
it("returns expected result with initialization", () => { | ||
const { result } = renderHook(() => useAIChatLogger(aiChat)); | ||
|
||
expect(result.current.aiChats).toHaveLength(1); | ||
expect(result.current.pop).toBeInstanceOf(Function); | ||
expect(result.current.push).toBeInstanceOf(Function); | ||
expect(result.current.aiChats[0]).toMatchObject(aiChat); | ||
}); | ||
|
||
describe("push", () => { | ||
it("pushes new aiChats with an id", () => { | ||
const { result } = renderHook(() => useAIChatLogger()); | ||
expect(result.current.aiChats).toHaveLength(0); | ||
|
||
act(() => { | ||
result.current.push(aiChat); | ||
}); | ||
|
||
expect(result.current.aiChats).toHaveLength(1); | ||
expect(result.current.aiChats[0]).toMatchObject(aiChat); | ||
}); | ||
|
||
it("pushes new aiChats without an id", () => { | ||
const { result } = renderHook(() => useAIChatLogger()); | ||
expect(result.current.aiChats).toHaveLength(0); | ||
|
||
act(() => { | ||
const chatWithoutCustomId = { ...aiChat, id: undefined }; | ||
result.current.push(chatWithoutCustomId); | ||
}); | ||
|
||
expect(result.current.aiChats).toHaveLength(1); | ||
expect(result.current.aiChats[0]).toMatchObject({ | ||
id: expect.stringMatching(/^uid/), | ||
}); | ||
}); | ||
}); | ||
|
||
describe("pop", () => { | ||
it("pops aiChats with an id", () => { | ||
const { result } = renderHook(() => useAIChatLogger(aiChat)); | ||
expect(result.current.aiChats).toHaveLength(1); | ||
|
||
act(() => { | ||
result.current.pop(aiChat.id); | ||
}); | ||
|
||
expect(result.current.aiChats).toHaveLength(0); | ||
}); | ||
|
||
it("pops aiChats without an id", () => { | ||
const { result } = renderHook(() => useAIChatLogger(aiChat)); | ||
expect(result.current.aiChats).toHaveLength(1); | ||
|
||
act(() => { | ||
result.current.pop(); | ||
}); | ||
|
||
expect(result.current.aiChats).toHaveLength(0); | ||
}); | ||
}); | ||
}); |
This file contains 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,3 @@ | ||
const { build } = require("../../../../tools/build/esbuild"); | ||
|
||
build(require("./package.json")); |
This file contains 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,79 @@ | ||
{ | ||
"name": "@twilio-paste/ai-chat-log", | ||
"version": "0.0.0", | ||
"category": "data display", | ||
"status": "production", | ||
"description": "Ai chat log.", | ||
"author": "Twilio Inc.", | ||
"license": "MIT", | ||
"main:dev": "src/index.tsx", | ||
"main": "dist/index.js", | ||
"module": "dist/index.es.js", | ||
"types": "dist/index.d.ts", | ||
"sideEffects": false, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"scripts": { | ||
"build": "yarn clean && NODE_ENV=production node build.js && tsc", | ||
"build:js": "NODE_ENV=development node build.js", | ||
"build:typedocs": "tsx ../../../../tools/build/generate-type-docs", | ||
"clean": "rm -rf ./dist", | ||
"tsc": "tsc" | ||
}, | ||
"peerDependencies": { | ||
"@twilio-paste/anchor": "^12.1.0", | ||
"@twilio-paste/animation-library": "^2.0.0", | ||
"@twilio-paste/avatar": "^9.0.0", | ||
"@twilio-paste/box": "^10.2.0", | ||
"@twilio-paste/button": "^14.0.0", | ||
"@twilio-paste/color-contrast-utils": "^5.0.0", | ||
"@twilio-paste/customization": "^8.1.1", | ||
"@twilio-paste/design-tokens": "^10.3.0", | ||
"@twilio-paste/icons": "^12.0.0", | ||
"@twilio-paste/screen-reader-only": "^13.0.0", | ||
"@twilio-paste/skeleton-loader": "^6.1.0", | ||
"@twilio-paste/spinner": "^14.0.0", | ||
"@twilio-paste/stack": "^8.0.0", | ||
"@twilio-paste/style-props": "^9.1.1", | ||
"@twilio-paste/styling-library": "^3.0.0", | ||
"@twilio-paste/text": "^10.0.0", | ||
"@twilio-paste/theme": "^11.0.1", | ||
"@twilio-paste/types": "^6.0.0", | ||
"@twilio-paste/uid-library": "^2.0.0", | ||
"@types/react": "^16.8.6 || ^17.0.2 || ^18.0.27", | ||
"@types/react-dom": "^16.8.6 || ^17.0.2 || ^18.0.10", | ||
"react": "^16.8.6 || ^17.0.2 || ^18.0.0", | ||
"react-dom": "^16.8.6 || ^17.0.2 || ^18.0.0" | ||
}, | ||
"devDependencies": { | ||
"@twilio-paste/anchor": "^12.1.0", | ||
"@twilio-paste/animation-library": "^2.0.0", | ||
"@twilio-paste/avatar": "^9.1.0", | ||
"@twilio-paste/box": "^10.2.0", | ||
"@twilio-paste/button": "^14.1.0", | ||
"@twilio-paste/color-contrast-utils": "^5.0.0", | ||
"@twilio-paste/customization": "^8.1.1", | ||
"@twilio-paste/design-tokens": "^10.3.0", | ||
"@twilio-paste/icons": "^12.2.1", | ||
"@twilio-paste/screen-reader-only": "^13.1.1", | ||
"@twilio-paste/skeleton-loader": "^6.1.0", | ||
"@twilio-paste/spinner": "^14.1.1", | ||
"@twilio-paste/stack": "^8.1.0", | ||
"@twilio-paste/style-props": "^9.1.1", | ||
"@twilio-paste/styling-library": "^3.0.0", | ||
"@twilio-paste/text": "^10.1.0", | ||
"@twilio-paste/theme": "^11.0.1", | ||
"@twilio-paste/types": "^6.0.0", | ||
"@twilio-paste/uid-library": "^2.0.0", | ||
"@types/react": "^18.0.27", | ||
"@types/react-dom": "^18.0.10", | ||
"react": "^18.0.0", | ||
"react-dom": "^18.0.0", | ||
"tsx": "^4.0.0", | ||
"typescript": "^4.9.4" | ||
} | ||
} |
Oops, something went wrong.