feat: add welcome card
This commit is contained in:
@@ -182,7 +182,8 @@ const handleCreateAssistant = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<slot name="headerActions" />
|
||||
<slot name="search" />
|
||||
<div
|
||||
v-if="!showPaywall && buttonLabel"
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useMapGetter } from 'dashboard/composables/store';
|
||||
|
||||
const currentUser = useMapGetter('getCurrentUser');
|
||||
|
||||
const firstName = computed(() => {
|
||||
const name = currentUser.value?.name?.trim();
|
||||
return name ? name.split(' ')[0] : 'there';
|
||||
});
|
||||
|
||||
// The summary is generated by the model from the assistant's stats using the
|
||||
// captain_overview_summary.liquid prompt (lib/integrations/openai/openai_prompts).
|
||||
// DUMMY: stands in for an LLM-generated summary. In production this markdown
|
||||
// string would come back from the model after we feed it the assistant's
|
||||
// stats; numbers are emphasised with **bold** so we can highlight them.
|
||||
const welcomeMarkdown = computed(
|
||||
() =>
|
||||
`Hey ${firstName.value}, your assistant handled **1,248 conversations** this month and saved your team **612 hours** of work. Auto-resolution climbed **4.1%** while keeping handoffs low. Knowledge coverage is running strong as well.\n\nI'd keep an eye out for credits, you seem to have exhaused nearly **80%** of it.`
|
||||
);
|
||||
|
||||
// Split the markdown on **bold** runs so we can render emphasised numbers as
|
||||
// brand-highlighted spans with Tailwind (instead of styling raw HTML).
|
||||
const segments = computed(() => {
|
||||
const parts = [];
|
||||
const regex = /\*\*(.+?)\*\*/g;
|
||||
let lastIndex = 0;
|
||||
let match = regex.exec(welcomeMarkdown.value);
|
||||
while (match) {
|
||||
if (match.index > lastIndex) {
|
||||
parts.push({ text: welcomeMarkdown.value.slice(lastIndex, match.index) });
|
||||
}
|
||||
parts.push({ text: match[1], bold: true });
|
||||
lastIndex = regex.lastIndex;
|
||||
match = regex.exec(welcomeMarkdown.value);
|
||||
}
|
||||
if (lastIndex < welcomeMarkdown.value.length) {
|
||||
parts.push({ text: welcomeMarkdown.value.slice(lastIndex) });
|
||||
}
|
||||
return parts.map((part, index) => ({ ...part, key: index }));
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex items-center gap-1.5 text-n-slate-10">
|
||||
<span class="i-lucide-sparkles size-3.5" />
|
||||
<span class="text-xs">
|
||||
{{ $t('CAPTAIN.OVERVIEW.WELCOME.LABEL') }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-lg leading-relaxed text-n-slate-12">
|
||||
<template v-for="segment in segments" :key="segment.key">
|
||||
<span v-if="segment.bold" class="font-bold tabular-nums text-n-brand">{{
|
||||
segment.text
|
||||
}}</span>
|
||||
<template v-else>{{ segment.text }}</template>
|
||||
</template>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
@@ -394,15 +394,14 @@
|
||||
"HEADER_KNOW_MORE": "Know more",
|
||||
"OVERVIEW": {
|
||||
"HEADER": "Overview",
|
||||
"WELCOME": {
|
||||
"LABEL": "Captain summary"
|
||||
},
|
||||
"INBOX_BANNER": {
|
||||
"TEXT": "This assistant isn't connected to any inbox yet, so it won't respond to conversations.",
|
||||
"ACTION": "Connect inbox",
|
||||
"DISMISS": "Dismiss"
|
||||
},
|
||||
"PERFORMANCE": {
|
||||
"TITLE": "Performance",
|
||||
"SUBTITLE": "How this assistant is doing"
|
||||
},
|
||||
"RANGES": {
|
||||
"DAYS": "{count}d"
|
||||
},
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
|
||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||
|
||||
import PageLayout from 'dashboard/components-next/captain/PageLayout.vue';
|
||||
import WelcomeCard from 'dashboard/components-next/captain/pageComponents/overview/WelcomeCard.vue';
|
||||
import MetricCard from 'dashboard/components-next/captain/pageComponents/overview/MetricCard.vue';
|
||||
import KnowledgeCard from 'dashboard/components-next/captain/pageComponents/overview/KnowledgeCard.vue';
|
||||
import ResponseQualityCard from 'dashboard/components-next/captain/pageComponents/overview/ResponseQualityCard.vue';
|
||||
@@ -80,38 +81,29 @@ const metrics = computed(() => [
|
||||
:show-know-more="false"
|
||||
:feature-flag="FEATURE_FLAGS.CAPTAIN"
|
||||
>
|
||||
<template #headerActions>
|
||||
<div class="flex items-center gap-1 p-1 rounded-lg bg-n-alpha-1 shrink-0">
|
||||
<button
|
||||
v-for="range in ranges"
|
||||
:key="range"
|
||||
type="button"
|
||||
class="px-3 py-1 text-sm font-medium rounded-md transition-colors"
|
||||
:class="
|
||||
selectedRange === range
|
||||
? 'bg-n-solid-active text-n-slate-12 shadow-sm'
|
||||
: 'text-n-slate-11 hover:text-n-slate-12'
|
||||
"
|
||||
@click="selectedRange = range"
|
||||
>
|
||||
{{ $t('CAPTAIN.OVERVIEW.RANGES.DAYS', { count: range }) }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<template #body>
|
||||
<div class="flex flex-col gap-6">
|
||||
<InboxBanner />
|
||||
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="text-base font-medium text-n-slate-12">
|
||||
{{ $t('CAPTAIN.OVERVIEW.PERFORMANCE.TITLE') }}
|
||||
</h3>
|
||||
<p class="text-sm text-n-slate-11">
|
||||
{{ $t('CAPTAIN.OVERVIEW.PERFORMANCE.SUBTITLE') }}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center gap-1 p-1 rounded-lg bg-n-alpha-1 shrink-0"
|
||||
>
|
||||
<button
|
||||
v-for="range in ranges"
|
||||
:key="range"
|
||||
type="button"
|
||||
class="px-3 py-1 text-sm font-medium rounded-md transition-colors"
|
||||
:class="
|
||||
selectedRange === range
|
||||
? 'bg-n-solid-active text-n-slate-12 shadow-sm'
|
||||
: 'text-n-slate-11 hover:text-n-slate-12'
|
||||
"
|
||||
@click="selectedRange = range"
|
||||
>
|
||||
{{ $t('CAPTAIN.OVERVIEW.RANGES.DAYS', { count: range }) }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<WelcomeCard />
|
||||
|
||||
<div
|
||||
class="grid grid-cols-1 gap-px overflow-hidden border rounded-xl sm:grid-cols-2 lg:grid-cols-3 bg-n-weak border-n-weak"
|
||||
|
||||
Reference in New Issue
Block a user