@aleph-alpha/chat-kit 1.14.0 → 1.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{CkInput.vue_vue_type_script_setup_true_lang-BVZ7FG88.js → CkInput.vue_vue_type_script_setup_true_lang-DedLzDoO.js} +157 -82
- package/dist/components/base/CkAgentMessage/CkAgentMessage.vue.d.ts.map +1 -1
- package/dist/components/base/CkHistoryItem/CkHistoryItem.stories.d.ts.map +1 -1
- package/dist/components/base/CkHistoryItem/CkHistoryItem.vue.d.ts.map +1 -1
- package/dist/components/base/CkHistoryWrapper/CkHistoryWrapper.stories.d.ts.map +1 -1
- package/dist/components/composed/CkHistory/CkHistory.stories.d.ts +15 -0
- package/dist/components/composed/CkHistory/CkHistory.stories.d.ts.map +1 -1
- package/dist/components/composed/CkHistory/CkHistory.vue.d.ts +6 -0
- package/dist/components/composed/CkHistory/CkHistory.vue.d.ts.map +1 -1
- package/dist/components/composed/CkHistory/types.d.ts +33 -0
- package/dist/components/composed/CkHistory/types.d.ts.map +1 -1
- package/dist/components/index.js +1 -1
- package/dist/handlers/index.js +1 -1
- package/dist/handlers/useChatKitLabels.d.ts +5 -0
- package/dist/handlers/useChatKitLabels.d.ts.map +1 -1
- package/dist/helpers/formatRelativeTime.d.ts +10 -0
- package/dist/helpers/formatRelativeTime.d.ts.map +1 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/{useChatKitLabels-BxNkTzr2.js → useChatKitLabels-BC6ItJc6.js} +2 -1
- package/package.json +1 -1
- package/src/components/base/CkAgentMessage/CkAgentMessage.spec.ts +6 -12
- package/src/components/base/CkAgentMessage/CkAgentMessage.vue +24 -15
- package/src/components/base/CkHistoryItem/CkHistoryItem.spec.ts +0 -2
- package/src/components/base/CkHistoryItem/CkHistoryItem.stories.ts +0 -6
- package/src/components/base/CkHistoryItem/CkHistoryItem.vue +2 -3
- package/src/components/base/CkHistoryWrapper/CkHistoryWrapper.stories.ts +23 -23
- package/src/components/composed/CkConversation/CkConversation.spec.ts +8 -35
- package/src/components/composed/CkHistory/CkHistory.spec.ts +107 -0
- package/src/components/composed/CkHistory/CkHistory.stories.ts +91 -3
- package/src/components/composed/CkHistory/CkHistory.vue +94 -44
- package/src/components/composed/CkHistory/types.ts +33 -0
- package/src/handlers/useChatKitLabels.spec.ts +1 -0
- package/src/handlers/useChatKitLabels.ts +6 -0
- package/src/helpers/formatRelativeTime.ts +49 -0
- package/src/helpers/index.ts +1 -0
- package/src/index.ts +3 -0
|
@@ -3,23 +3,32 @@ defineOptions({ name: 'CkAgentMessage' });
|
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
5
|
<template>
|
|
6
|
-
<div
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
<div
|
|
7
|
+
class="border-border-surface-default flex w-full flex-col gap-6 border-b pb-6"
|
|
8
|
+
>
|
|
9
|
+
<div v-if="$slots.icon || $slots.header" class="flex items-center gap-3">
|
|
10
|
+
<div
|
|
11
|
+
v-if="$slots.icon"
|
|
12
|
+
data-testid="ck-agent-message-icon"
|
|
13
|
+
class="flex flex-shrink-0 items-center justify-center"
|
|
14
|
+
>
|
|
15
|
+
<slot name="icon" />
|
|
16
|
+
</div>
|
|
17
|
+
<span
|
|
18
|
+
v-if="$slots.header"
|
|
19
|
+
data-testid="ck-agent-message-header"
|
|
20
|
+
class="body-14-regular text-content-on-surface-muted min-w-0 flex-1 [word-break:break-word]"
|
|
21
|
+
>
|
|
15
22
|
<slot name="header" />
|
|
16
23
|
</span>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div class="text-content-on-surface-primary text-base leading-7">
|
|
27
|
+
<slot />
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div v-if="$slots.footer" class="flex items-center gap-4">
|
|
31
|
+
<slot name="footer" />
|
|
23
32
|
</div>
|
|
24
33
|
</div>
|
|
25
34
|
</template>
|
|
@@ -9,13 +9,11 @@ describe('CkHistoryItem', () => {
|
|
|
9
9
|
props: {
|
|
10
10
|
title: 'Thread A',
|
|
11
11
|
metaStart: 'Mon',
|
|
12
|
-
metaEnd: 'Berlin',
|
|
13
12
|
},
|
|
14
13
|
});
|
|
15
14
|
|
|
16
15
|
expect(screen.getByText('Thread A')).toBeInTheDocument();
|
|
17
16
|
expect(screen.getByText('Mon')).toBeInTheDocument();
|
|
18
|
-
expect(screen.getByText('Berlin')).toBeInTheDocument();
|
|
19
17
|
});
|
|
20
18
|
|
|
21
19
|
it('emits action-click when the action button is clicked', async () => {
|
|
@@ -18,7 +18,6 @@ const meta: Meta<typeof CkHistoryItem> = {
|
|
|
18
18
|
args: {
|
|
19
19
|
title: 'Project Proposal Overview',
|
|
20
20
|
metaStart: 'Today',
|
|
21
|
-
metaEnd: 'Innsbruck',
|
|
22
21
|
actionTooltip: 'More actions',
|
|
23
22
|
},
|
|
24
23
|
argTypes: {
|
|
@@ -58,7 +57,6 @@ function handleActionClick() {
|
|
|
58
57
|
<CkHistoryItem
|
|
59
58
|
title="Project Proposal Overview"
|
|
60
59
|
meta-start="Today"
|
|
61
|
-
meta-end="Innsbruck"
|
|
62
60
|
action-tooltip="More actions"
|
|
63
61
|
@action-click="handleActionClick"
|
|
64
62
|
/>
|
|
@@ -72,7 +70,6 @@ import { CkHistoryItem } from '@aleph-alpha/chat-kit';
|
|
|
72
70
|
<CkHistoryItem
|
|
73
71
|
title="Project Proposal Overview"
|
|
74
72
|
meta-start="Today"
|
|
75
|
-
meta-end="Innsbruck"
|
|
76
73
|
action-tooltip="More actions"
|
|
77
74
|
is-active
|
|
78
75
|
/>
|
|
@@ -86,7 +83,6 @@ import { CkHistoryItem } from '@aleph-alpha/chat-kit';
|
|
|
86
83
|
<CkHistoryItem
|
|
87
84
|
title="Project Proposal Overview"
|
|
88
85
|
meta-start="Today"
|
|
89
|
-
meta-end="Innsbruck"
|
|
90
86
|
action-tooltip="More actions"
|
|
91
87
|
:show-action-on-hover="false"
|
|
92
88
|
/>
|
|
@@ -108,7 +104,6 @@ import { CkHistoryItem } from '@aleph-alpha/chat-kit';
|
|
|
108
104
|
<CkHistoryItem
|
|
109
105
|
title="Project Proposal Overview"
|
|
110
106
|
meta-start="Today"
|
|
111
|
-
meta-end="Innsbruck"
|
|
112
107
|
action-popover
|
|
113
108
|
action-aria-label="Chat options"
|
|
114
109
|
>
|
|
@@ -182,7 +177,6 @@ export const AlwaysShowAction: Story = {
|
|
|
182
177
|
export const NoMeta: Story = {
|
|
183
178
|
args: {
|
|
184
179
|
metaStart: '',
|
|
185
|
-
metaEnd: '',
|
|
186
180
|
},
|
|
187
181
|
render: renderStory,
|
|
188
182
|
parameters: { docs: { source: { code: noMetaTemplateSource } } },
|
|
@@ -122,11 +122,10 @@ const actionColumnClass = computed(() => [
|
|
|
122
122
|
* underneath the icon.
|
|
123
123
|
*/
|
|
124
124
|
const actionButtonClass = computed(() => [
|
|
125
|
-
'relative z-10 inline-flex size-8 shrink-0 items-center justify-center rounded-sm border
|
|
125
|
+
'relative z-10 inline-flex size-8 shrink-0 items-center justify-center rounded-sm border-0 text-content-on-surface-primary outline-hidden transition-colors',
|
|
126
126
|
'[&_svg]:size-4 [&_svg]:shrink-0',
|
|
127
127
|
'focus-visible:ring-0 focus-visible:outline-none',
|
|
128
|
-
pointerOnAction.value &&
|
|
129
|
-
'bg-background-surface-muted-subtle border-border-button-outlined',
|
|
128
|
+
pointerOnAction.value && 'bg-background-surface-muted-subtle',
|
|
130
129
|
]);
|
|
131
130
|
|
|
132
131
|
// Popover panel surface is `background/surface/secondary` to match the
|
|
@@ -33,10 +33,14 @@ import { CkHistoryWrapper, CkHistoryItem } from '@aleph-alpha/chat-kit';
|
|
|
33
33
|
|
|
34
34
|
<template>
|
|
35
35
|
<CkHistoryWrapper>
|
|
36
|
-
<CkHistoryItem title="Project Proposal Overview" meta-start="Today"
|
|
37
|
-
<CkHistoryItem title="
|
|
38
|
-
<CkHistoryItem title="
|
|
39
|
-
<CkHistoryItem title="
|
|
36
|
+
<CkHistoryItem title="Project Proposal Overview" meta-start="Today" is-active />
|
|
37
|
+
<CkHistoryItem title="Customer onboarding flow" meta-start="Yesterday" />
|
|
38
|
+
<CkHistoryItem title="Refactor notes" meta-start="2 days ago" />
|
|
39
|
+
<CkHistoryItem title="Quarterly review prep" meta-start="3 days ago" />
|
|
40
|
+
<CkHistoryItem title="Sprint retro notes" meta-start="4 days ago" />
|
|
41
|
+
<CkHistoryItem title="Travel plans 2026" meta-start="1 week ago" />
|
|
42
|
+
<CkHistoryItem title="API design review" meta-start="2 weeks ago" />
|
|
43
|
+
<CkHistoryItem title="Bug triage session" meta-start="3 weeks ago" />
|
|
40
44
|
</CkHistoryWrapper>
|
|
41
45
|
</template>`;
|
|
42
46
|
|
|
@@ -48,7 +52,10 @@ import { CkHistoryWrapper, CkHistoryItem } from '@aleph-alpha/chat-kit';
|
|
|
48
52
|
<CkHistoryWrapper :with-gap="false">
|
|
49
53
|
<CkHistoryItem title="Thread A" meta-start="Today" />
|
|
50
54
|
<CkHistoryItem title="Thread B" meta-start="Yesterday" />
|
|
51
|
-
<CkHistoryItem title="Thread C" meta-start="
|
|
55
|
+
<CkHistoryItem title="Thread C" meta-start="2 days ago" />
|
|
56
|
+
<CkHistoryItem title="Thread D" meta-start="3 days ago" />
|
|
57
|
+
<CkHistoryItem title="Thread E" meta-start="4 days ago" />
|
|
58
|
+
<CkHistoryItem title="Thread F" meta-start="1 week ago" />
|
|
52
59
|
</CkHistoryWrapper>
|
|
53
60
|
</template>`;
|
|
54
61
|
|
|
@@ -65,24 +72,15 @@ export const Default: Story = {
|
|
|
65
72
|
{
|
|
66
73
|
title: 'Project Proposal Overview',
|
|
67
74
|
metaStart: 'Today',
|
|
68
|
-
metaEnd: 'Innsbruck',
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
title: 'Project Proposal Overview',
|
|
72
|
-
metaStart: 'Today',
|
|
73
|
-
metaEnd: 'Innsbruck',
|
|
74
75
|
isActive: true,
|
|
75
76
|
},
|
|
76
|
-
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
|
|
83
|
-
metaStart: 'Today',
|
|
84
|
-
metaEnd: 'Innsbruck',
|
|
85
|
-
},
|
|
77
|
+
{ title: 'Customer onboarding flow', metaStart: 'Yesterday' },
|
|
78
|
+
{ title: 'Refactor notes', metaStart: '2 days ago' },
|
|
79
|
+
{ title: 'Quarterly review prep', metaStart: '3 days ago' },
|
|
80
|
+
{ title: 'Sprint retro notes', metaStart: '4 days ago' },
|
|
81
|
+
{ title: 'Travel plans 2026', metaStart: '1 week ago' },
|
|
82
|
+
{ title: 'API design review', metaStart: '2 weeks ago' },
|
|
83
|
+
{ title: 'Bug triage session', metaStart: '3 weeks ago' },
|
|
86
84
|
];
|
|
87
85
|
|
|
88
86
|
function handleActionClick() {
|
|
@@ -99,7 +97,6 @@ export const Default: Story = {
|
|
|
99
97
|
:key="index"
|
|
100
98
|
:title="item.title"
|
|
101
99
|
:meta-start="item.metaStart"
|
|
102
|
-
:meta-end="item.metaEnd"
|
|
103
100
|
:is-active="item.isActive"
|
|
104
101
|
action-tooltip="More actions"
|
|
105
102
|
@action-click="handleActionClick"
|
|
@@ -128,7 +125,10 @@ export const WithoutGap: Story = {
|
|
|
128
125
|
const items = [
|
|
129
126
|
{ title: 'Thread A', metaStart: 'Today' },
|
|
130
127
|
{ title: 'Thread B', metaStart: 'Yesterday' },
|
|
131
|
-
{ title: 'Thread C', metaStart: '
|
|
128
|
+
{ title: 'Thread C', metaStart: '2 days ago' },
|
|
129
|
+
{ title: 'Thread D', metaStart: '3 days ago' },
|
|
130
|
+
{ title: 'Thread E', metaStart: '4 days ago' },
|
|
131
|
+
{ title: 'Thread F', metaStart: '1 week ago' },
|
|
132
132
|
];
|
|
133
133
|
return { args, items };
|
|
134
134
|
},
|
|
@@ -132,56 +132,36 @@ describe('CkConversation', () => {
|
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
it('hides the icon area when no agentAvatarImage, no agentAvatarFallback, and no agent-message-icon slot', () => {
|
|
135
|
-
|
|
135
|
+
render(CkConversation, {
|
|
136
136
|
props: { messages: [agentMessage()] },
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
-
const agentMessageEl = container.querySelector(
|
|
140
|
-
'.flex.w-full.items-start.gap-2',
|
|
141
|
-
);
|
|
142
|
-
expect(agentMessageEl).toBeInTheDocument();
|
|
143
139
|
expect(
|
|
144
|
-
|
|
145
|
-
'.flex.flex-shrink-0.items-center.justify-center',
|
|
146
|
-
),
|
|
140
|
+
screen.queryByTestId('ck-agent-message-icon'),
|
|
147
141
|
).not.toBeInTheDocument();
|
|
148
142
|
});
|
|
149
143
|
|
|
150
144
|
it('shows the icon area when agentAvatarFallback is provided', () => {
|
|
151
|
-
|
|
145
|
+
render(CkConversation, {
|
|
152
146
|
props: { messages: [agentMessage()], agentAvatarFallback: 'AI' },
|
|
153
147
|
});
|
|
154
148
|
|
|
155
|
-
|
|
156
|
-
'.flex.w-full.items-start.gap-2',
|
|
157
|
-
);
|
|
158
|
-
expect(
|
|
159
|
-
agentMessageEl?.querySelector(
|
|
160
|
-
'.flex.flex-shrink-0.items-center.justify-center',
|
|
161
|
-
),
|
|
162
|
-
).toBeInTheDocument();
|
|
149
|
+
expect(screen.getByTestId('ck-agent-message-icon')).toBeInTheDocument();
|
|
163
150
|
});
|
|
164
151
|
|
|
165
152
|
it('shows the icon area when agentAvatarImage URL is provided', () => {
|
|
166
|
-
|
|
153
|
+
render(CkConversation, {
|
|
167
154
|
props: {
|
|
168
155
|
messages: [agentMessage()],
|
|
169
156
|
agentAvatarImage: 'https://example.com/icon.png',
|
|
170
157
|
},
|
|
171
158
|
});
|
|
172
159
|
|
|
173
|
-
|
|
174
|
-
'.flex.w-full.items-start.gap-2',
|
|
175
|
-
);
|
|
176
|
-
expect(
|
|
177
|
-
agentMessageEl?.querySelector(
|
|
178
|
-
'.flex.flex-shrink-0.items-center.justify-center',
|
|
179
|
-
),
|
|
180
|
-
).toBeInTheDocument();
|
|
160
|
+
expect(screen.getByTestId('ck-agent-message-icon')).toBeInTheDocument();
|
|
181
161
|
});
|
|
182
162
|
|
|
183
163
|
it('shows the icon area when agent-message-icon slot is provided', () => {
|
|
184
|
-
|
|
164
|
+
render(CkConversation, {
|
|
185
165
|
props: { messages: [agentMessage()] },
|
|
186
166
|
slots: {
|
|
187
167
|
'agent-message-icon': '<span data-testid="custom-icon">🤖</span>',
|
|
@@ -189,14 +169,7 @@ describe('CkConversation', () => {
|
|
|
189
169
|
});
|
|
190
170
|
|
|
191
171
|
expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
|
|
192
|
-
|
|
193
|
-
'.flex.w-full.items-start.gap-2',
|
|
194
|
-
);
|
|
195
|
-
expect(
|
|
196
|
-
agentMessageEl?.querySelector(
|
|
197
|
-
'.flex.flex-shrink-0.items-center.justify-center',
|
|
198
|
-
),
|
|
199
|
-
).toBeInTheDocument();
|
|
172
|
+
expect(screen.getByTestId('ck-agent-message-icon')).toBeInTheDocument();
|
|
200
173
|
});
|
|
201
174
|
});
|
|
202
175
|
|
|
@@ -170,12 +170,119 @@ describe('CkHistory', () => {
|
|
|
170
170
|
expect(emitted().select).toBeUndefined();
|
|
171
171
|
});
|
|
172
172
|
|
|
173
|
+
it('renders a relative time label under each row by default', () => {
|
|
174
|
+
const conversations = [
|
|
175
|
+
makeConversation({ id: 'c-1', updatedAt: NOW - 60 * 60 * 24 }),
|
|
176
|
+
makeConversation({ id: 'c-2', updatedAt: NOW - 60 * 60 * 24 * 3 }),
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
render(CkHistory, {
|
|
180
|
+
props: {
|
|
181
|
+
conversations,
|
|
182
|
+
hrefResolver,
|
|
183
|
+
timeFormatter: (s: number) => {
|
|
184
|
+
const days = Math.round((NOW - s) / (60 * 60 * 24));
|
|
185
|
+
return days === 1 ? 'Yesterday' : `${days} days ago`;
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
expect(screen.getByText('Yesterday')).toBeInTheDocument();
|
|
191
|
+
expect(screen.getByText('3 days ago')).toBeInTheDocument();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('hides the time label when timeFormatter returns an empty string', () => {
|
|
195
|
+
const conversations = [makeConversation({ id: 'c-1', updatedAt: NOW })];
|
|
196
|
+
|
|
197
|
+
const { container } = render(CkHistory, {
|
|
198
|
+
props: {
|
|
199
|
+
conversations,
|
|
200
|
+
hrefResolver,
|
|
201
|
+
timeFormatter: () => '',
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const metaElements = container.querySelectorAll('.label-12-medium');
|
|
206
|
+
expect(metaElements).toHaveLength(0);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe('collapsed limit / Show all', () => {
|
|
210
|
+
const manyConversations = Array.from({ length: 8 }, (_, i) =>
|
|
211
|
+
makeConversation({ id: `c-${i + 1}`, title: `Thread ${i + 1}` }),
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
it('shows only collapsedLimit rows and a "Show all" button when there are more conversations', () => {
|
|
215
|
+
render(CkHistory, {
|
|
216
|
+
props: {
|
|
217
|
+
conversations: manyConversations,
|
|
218
|
+
hrefResolver,
|
|
219
|
+
collapsedLimit: 5,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const links = screen.getAllByRole('link');
|
|
224
|
+
expect(links).toHaveLength(5);
|
|
225
|
+
expect(screen.getByTestId('ck-history-show-all')).toBeInTheDocument();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('does not show the "Show all" button when conversations fit within the limit', () => {
|
|
229
|
+
render(CkHistory, {
|
|
230
|
+
props: {
|
|
231
|
+
conversations: manyConversations.slice(0, 3),
|
|
232
|
+
hrefResolver,
|
|
233
|
+
collapsedLimit: 5,
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
expect(
|
|
238
|
+
screen.queryByTestId('ck-history-show-all'),
|
|
239
|
+
).not.toBeInTheDocument();
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('reveals all conversations when "Show all" is clicked', async () => {
|
|
243
|
+
const user = userEvent.setup();
|
|
244
|
+
|
|
245
|
+
render(CkHistory, {
|
|
246
|
+
props: {
|
|
247
|
+
conversations: manyConversations,
|
|
248
|
+
hrefResolver,
|
|
249
|
+
collapsedLimit: 5,
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
expect(screen.getAllByRole('link')).toHaveLength(5);
|
|
254
|
+
|
|
255
|
+
await user.click(screen.getByTestId('ck-history-show-all'));
|
|
256
|
+
|
|
257
|
+
expect(screen.getAllByRole('link')).toHaveLength(8);
|
|
258
|
+
expect(
|
|
259
|
+
screen.queryByTestId('ck-history-show-all'),
|
|
260
|
+
).not.toBeInTheDocument();
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('shows all conversations when collapsedLimit is 0', () => {
|
|
264
|
+
render(CkHistory, {
|
|
265
|
+
props: {
|
|
266
|
+
conversations: manyConversations,
|
|
267
|
+
hrefResolver,
|
|
268
|
+
collapsedLimit: 0,
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
expect(screen.getAllByRole('link')).toHaveLength(8);
|
|
273
|
+
expect(
|
|
274
|
+
screen.queryByTestId('ck-history-show-all'),
|
|
275
|
+
).not.toBeInTheDocument();
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
173
279
|
describe('#item slot', () => {
|
|
174
280
|
interface ItemSlotProps {
|
|
175
281
|
conversation: Conversation;
|
|
176
282
|
href: string;
|
|
177
283
|
isActive: boolean;
|
|
178
284
|
title: string;
|
|
285
|
+
time: string | undefined;
|
|
179
286
|
select: (event: MouseEvent) => void;
|
|
180
287
|
edit: () => void;
|
|
181
288
|
delete: () => void;
|
|
@@ -35,14 +35,38 @@ const sampleConversations: Conversation[] = [
|
|
|
35
35
|
id: 'c-5',
|
|
36
36
|
title: 'Quarterly review prep',
|
|
37
37
|
createdAt: NOW - ONE_DAY * 30,
|
|
38
|
-
updatedAt: NOW - ONE_DAY *
|
|
38
|
+
updatedAt: NOW - ONE_DAY * 3,
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
id: 'c-6',
|
|
42
42
|
title: 'Travel plans 2026',
|
|
43
43
|
createdAt: NOW - ONE_DAY * 60,
|
|
44
|
+
updatedAt: NOW - ONE_DAY * 4,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'c-7',
|
|
48
|
+
title: 'Sprint retro notes',
|
|
49
|
+
createdAt: NOW - ONE_DAY * 20,
|
|
50
|
+
updatedAt: NOW - ONE_DAY * 5,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'c-8',
|
|
54
|
+
title: 'API design review',
|
|
55
|
+
createdAt: NOW - ONE_DAY * 25,
|
|
56
|
+
updatedAt: NOW - ONE_DAY * 7,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'c-9',
|
|
60
|
+
title: 'Bug triage session',
|
|
61
|
+
createdAt: NOW - ONE_DAY * 40,
|
|
44
62
|
updatedAt: NOW - ONE_DAY * 14,
|
|
45
63
|
},
|
|
64
|
+
{
|
|
65
|
+
id: 'c-10',
|
|
66
|
+
title: 'Team standup summary',
|
|
67
|
+
createdAt: NOW - ONE_DAY * 50,
|
|
68
|
+
updatedAt: NOW - ONE_DAY * 21,
|
|
69
|
+
},
|
|
46
70
|
];
|
|
47
71
|
|
|
48
72
|
const defaultHrefResolver = (id: string) => `/chat/${id}`;
|
|
@@ -66,6 +90,8 @@ const meta: Meta<typeof CkHistory> = {
|
|
|
66
90
|
activeId: { control: 'text' },
|
|
67
91
|
showAction: { control: 'boolean' },
|
|
68
92
|
showActionOnHover: { control: 'boolean' },
|
|
93
|
+
collapsedLimit: { control: 'number' },
|
|
94
|
+
maxHeight: { control: 'text' },
|
|
69
95
|
},
|
|
70
96
|
};
|
|
71
97
|
|
|
@@ -184,7 +210,7 @@ function onDelete(c: Conversation) { /* confirm + delete */ }
|
|
|
184
210
|
@delete="onDelete"
|
|
185
211
|
>
|
|
186
212
|
<template
|
|
187
|
-
#item="{ conversation, isActive, title, edit, delete: del }"
|
|
213
|
+
#item="{ conversation, isActive, title, time, edit, delete: del }"
|
|
188
214
|
>
|
|
189
215
|
<RouterLink
|
|
190
216
|
:to="{ name: 'chat', params: { id: conversation.id } }"
|
|
@@ -196,6 +222,7 @@ function onDelete(c: Conversation) { /* confirm + delete */ }
|
|
|
196
222
|
:href="href"
|
|
197
223
|
:is-active="isActive"
|
|
198
224
|
:title="title"
|
|
225
|
+
:meta-start="time"
|
|
199
226
|
action-popover
|
|
200
227
|
@click="navigate"
|
|
201
228
|
>
|
|
@@ -209,6 +236,22 @@ function onDelete(c: Conversation) { /* confirm + delete */ }
|
|
|
209
236
|
</CkHistory>
|
|
210
237
|
</template>`;
|
|
211
238
|
|
|
239
|
+
const withoutTimeTemplateSource = `<script setup lang="ts">
|
|
240
|
+
import { CkHistory, type Conversation } from '@aleph-alpha/chat-kit';
|
|
241
|
+
|
|
242
|
+
const conversations: Conversation[] = [/* ... */];
|
|
243
|
+
const hrefResolver = (id: string) => \`/chat/\${id}\`;
|
|
244
|
+
</script>
|
|
245
|
+
|
|
246
|
+
<template>
|
|
247
|
+
<CkHistory
|
|
248
|
+
:conversations="conversations"
|
|
249
|
+
:href-resolver="hrefResolver"
|
|
250
|
+
active-id="c-2"
|
|
251
|
+
:time-formatter="undefined"
|
|
252
|
+
/>
|
|
253
|
+
</template>`;
|
|
254
|
+
|
|
212
255
|
const renderStory = (args: Story['args']) => ({
|
|
213
256
|
components: { CkHistory },
|
|
214
257
|
setup() {
|
|
@@ -329,13 +372,14 @@ export const WithCustomItem: Story = {
|
|
|
329
372
|
@select="onSelect"
|
|
330
373
|
>
|
|
331
374
|
<template
|
|
332
|
-
#item="{ href, isActive, title, select, edit, delete: del }"
|
|
375
|
+
#item="{ href, isActive, title, time, select, edit, delete: del }"
|
|
333
376
|
>
|
|
334
377
|
<CkHistoryItem
|
|
335
378
|
as="a"
|
|
336
379
|
:href="href"
|
|
337
380
|
:is-active="isActive"
|
|
338
381
|
:title="title"
|
|
382
|
+
:meta-start="time"
|
|
339
383
|
action-popover
|
|
340
384
|
action-aria-label="Conversation options"
|
|
341
385
|
@click="select($event)"
|
|
@@ -371,3 +415,47 @@ export const WithCustomItem: Story = {
|
|
|
371
415
|
docs: { source: { code: withCustomItemTemplateSource } },
|
|
372
416
|
},
|
|
373
417
|
};
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Hides the relative time label by setting `time-formatter` to `undefined`.
|
|
421
|
+
* Rows display only the title (the pre-v1.14 default).
|
|
422
|
+
*/
|
|
423
|
+
export const WithoutTime: Story = {
|
|
424
|
+
args: {
|
|
425
|
+
conversations: sampleConversations,
|
|
426
|
+
hrefResolver: defaultHrefResolver,
|
|
427
|
+
activeId: 'c-2',
|
|
428
|
+
timeFormatter: undefined,
|
|
429
|
+
},
|
|
430
|
+
render: renderStory,
|
|
431
|
+
parameters: { docs: { source: { code: withoutTimeTemplateSource } } },
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* With 10 conversations and a `collapsedLimit` of 5, only the first 5 rows
|
|
436
|
+
* are shown initially. A "Show all" button at the bottom reveals the rest
|
|
437
|
+
* and makes the list scrollable (capped at `maxHeight`).
|
|
438
|
+
*/
|
|
439
|
+
export const CollapsedWithShowAll: Story = {
|
|
440
|
+
args: {
|
|
441
|
+
conversations: sampleConversations,
|
|
442
|
+
hrefResolver: defaultHrefResolver,
|
|
443
|
+
activeId: 'c-2',
|
|
444
|
+
collapsedLimit: 5,
|
|
445
|
+
maxHeight: '24rem',
|
|
446
|
+
},
|
|
447
|
+
render: renderStory,
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* All conversations visible without collapse — set `collapsedLimit` to `0`.
|
|
452
|
+
*/
|
|
453
|
+
export const NoCollapse: Story = {
|
|
454
|
+
args: {
|
|
455
|
+
conversations: sampleConversations,
|
|
456
|
+
hrefResolver: defaultHrefResolver,
|
|
457
|
+
activeId: 'c-2',
|
|
458
|
+
collapsedLimit: 0,
|
|
459
|
+
},
|
|
460
|
+
render: renderStory,
|
|
461
|
+
};
|