feat: add custom tools page

This commit is contained in:
Shivam Mishra
2025-10-03 18:02:23 +05:30
parent a54ad12bf1
commit 3e3d5dda80
7 changed files with 141 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
<script setup>
import EmptyStateLayout from 'dashboard/components-next/EmptyStateLayout.vue';
import Button from 'dashboard/components-next/button/Button.vue';
const emit = defineEmits(['click']);
const onClick = () => {
emit('click');
};
</script>
<template>
<EmptyStateLayout
:title="$t('CAPTAIN.CUSTOM_TOOLS.EMPTY_STATE.TITLE')"
:subtitle="$t('CAPTAIN.CUSTOM_TOOLS.EMPTY_STATE.SUBTITLE')"
:action-perms="['administrator']"
>
<template #empty-state-item>
<div class="min-h-[600px]" />
</template>
<template #actions>
<Button
:label="$t('CAPTAIN.CUSTOM_TOOLS.ADD_NEW')"
icon="i-lucide-plus"
@click="onClick"
/>
</template>
</EmptyStateLayout>
</template>

View File

@@ -232,6 +232,11 @@ const menuItems = computed(() => {
label: t('SIDEBAR.CAPTAIN_RESPONSES'),
to: accountScopedRoute('captain_responses_index'),
},
{
name: 'Tools',
label: t('SIDEBAR.CAPTAIN_TOOLS'),
to: accountScopedRoute('captain_tools_index'),
},
],
},
{

View File

@@ -41,6 +41,7 @@ export const FEATURE_FLAGS = {
CAPTAIN_V2: 'captain_integration_v2',
SAML: 'saml',
QUOTED_EMAIL_REPLY: 'quoted_email_reply',
CAPTAIN_CUSTOM_TOOLS: 'captain_custom_tools',
};
export const PREMIUM_FEATURES = [

View File

@@ -750,6 +750,18 @@
}
}
},
"CUSTOM_TOOLS": {
"HEADER": "Tools",
"ADD_NEW": "Create a new tool",
"EMPTY_STATE": {
"TITLE": "No custom tools available",
"SUBTITLE": "Create custom tools to connect your assistant with external APIs and services, enabling it to fetch data and perform actions on your behalf.",
"FEATURE_SPOTLIGHT": {
"TITLE": "Custom Tools",
"NOTE": "Custom tools allow your assistant to interact with external APIs and services. Create tools to fetch data, perform actions, or integrate with your existing systems to enhance your assistant's capabilities."
}
}
},
"RESPONSES": {
"HEADER": "FAQs",
"ADD_NEW": "Create new FAQ",

View File

@@ -304,6 +304,7 @@
"CAPTAIN_ASSISTANTS": "Assistants",
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",

View File

@@ -10,6 +10,7 @@ import AssistantGuidelinesIndex from './assistants/guidelines/Index.vue';
import AssistantScenariosIndex from './assistants/scenarios/Index.vue';
import DocumentsIndex from './documents/Index.vue';
import ResponsesIndex from './responses/Index.vue';
import CustomToolsIndex from './tools/Index.vue';
export const routes = [
{
@@ -124,4 +125,17 @@ export const routes = [
],
},
},
{
path: frontendURL('accounts/:accountId/captain/tools'),
component: CustomToolsIndex,
name: 'captain_tools_index',
meta: {
permissions: ['administrator', 'agent'],
featureFlag: FEATURE_FLAGS.CAPTAIN_CUSTOM_TOOLS,
installationTypes: [
INSTALLATION_TYPES.CLOUD,
INSTALLATION_TYPES.ENTERPRISE,
],
},
},
];

View File

@@ -0,0 +1,79 @@
<script setup>
import { computed, onMounted } from 'vue';
import { useMapGetter, useStore } from 'dashboard/composables/store';
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
import PageLayout from 'dashboard/components-next/captain/PageLayout.vue';
import CaptainPaywall from 'dashboard/components-next/captain/pageComponents/Paywall.vue';
import CustomToolsPageEmptyState from 'dashboard/components-next/captain/pageComponents/emptyStates/CustomToolsPageEmptyState.vue';
const store = useStore();
const uiFlags = useMapGetter('captainCustomTools/getUIFlags');
const customTools = useMapGetter('captainCustomTools/getRecords');
const isFetching = computed(() => uiFlags.value.fetchingList);
const customToolsMeta = useMapGetter('captainCustomTools/getMeta');
const fetchCustomTools = (page = 1) => {
store.dispatch('captainCustomTools/get', { page });
};
const onPageChange = page => fetchCustomTools(page);
onMounted(() => {
fetchCustomTools();
});
</script>
<template>
<PageLayout
:header-title="$t('CAPTAIN.CUSTOM_TOOLS.HEADER')"
:button-label="$t('CAPTAIN.CUSTOM_TOOLS.ADD_NEW')"
:button-policy="['administrator']"
:total-count="customToolsMeta.totalCount"
:current-page="customToolsMeta.page"
:show-pagination-footer="!isFetching && !!customTools.length"
:is-fetching="isFetching"
:is-empty="!customTools.length"
:feature-flag="FEATURE_FLAGS.CAPTAIN_CUSTOM_TOOLS"
@update:current-page="onPageChange"
>
<template #paywall>
<CaptainPaywall />
</template>
<template #emptyState>
<CustomToolsPageEmptyState />
</template>
<template #body>
<div class="flex flex-col gap-4">
<div
v-for="tool in customTools"
:key="tool.id"
class="border border-slate-100 dark:border-slate-800 rounded-lg p-4"
>
<h3 class="text-base font-medium text-slate-900 dark:text-slate-100">
{{ tool.title }}
</h3>
<p
v-if="tool.description"
class="text-sm text-slate-600 dark:text-slate-400 mt-1"
>
{{ tool.description }}
</p>
<div class="flex items-center gap-2 mt-2">
<span
class="text-xs px-2 py-1 rounded bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300"
>
{{ tool.http_method }}
</span>
<span class="text-xs text-slate-500 dark:text-slate-400 truncate">
{{ tool.endpoint_url }}
</span>
</div>
</div>
</div>
</template>
</PageLayout>
</template>