mirror of
https://github.com/lingble/chatwoot.git
synced 2025-10-31 19:17:48 +00:00
feat: add custom tools page
This commit is contained in:
@@ -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>
|
||||||
@@ -232,6 +232,11 @@ const menuItems = computed(() => {
|
|||||||
label: t('SIDEBAR.CAPTAIN_RESPONSES'),
|
label: t('SIDEBAR.CAPTAIN_RESPONSES'),
|
||||||
to: accountScopedRoute('captain_responses_index'),
|
to: accountScopedRoute('captain_responses_index'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Tools',
|
||||||
|
label: t('SIDEBAR.CAPTAIN_TOOLS'),
|
||||||
|
to: accountScopedRoute('captain_tools_index'),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export const FEATURE_FLAGS = {
|
|||||||
CAPTAIN_V2: 'captain_integration_v2',
|
CAPTAIN_V2: 'captain_integration_v2',
|
||||||
SAML: 'saml',
|
SAML: 'saml',
|
||||||
QUOTED_EMAIL_REPLY: 'quoted_email_reply',
|
QUOTED_EMAIL_REPLY: 'quoted_email_reply',
|
||||||
|
CAPTAIN_CUSTOM_TOOLS: 'captain_custom_tools',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PREMIUM_FEATURES = [
|
export const PREMIUM_FEATURES = [
|
||||||
|
|||||||
@@ -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": {
|
"RESPONSES": {
|
||||||
"HEADER": "FAQs",
|
"HEADER": "FAQs",
|
||||||
"ADD_NEW": "Create new FAQ",
|
"ADD_NEW": "Create new FAQ",
|
||||||
|
|||||||
@@ -304,6 +304,7 @@
|
|||||||
"CAPTAIN_ASSISTANTS": "Assistants",
|
"CAPTAIN_ASSISTANTS": "Assistants",
|
||||||
"CAPTAIN_DOCUMENTS": "Documents",
|
"CAPTAIN_DOCUMENTS": "Documents",
|
||||||
"CAPTAIN_RESPONSES": "FAQs",
|
"CAPTAIN_RESPONSES": "FAQs",
|
||||||
|
"CAPTAIN_TOOLS": "Tools",
|
||||||
"HOME": "Home",
|
"HOME": "Home",
|
||||||
"AGENTS": "Agents",
|
"AGENTS": "Agents",
|
||||||
"AGENT_BOTS": "Bots",
|
"AGENT_BOTS": "Bots",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import AssistantGuidelinesIndex from './assistants/guidelines/Index.vue';
|
|||||||
import AssistantScenariosIndex from './assistants/scenarios/Index.vue';
|
import AssistantScenariosIndex from './assistants/scenarios/Index.vue';
|
||||||
import DocumentsIndex from './documents/Index.vue';
|
import DocumentsIndex from './documents/Index.vue';
|
||||||
import ResponsesIndex from './responses/Index.vue';
|
import ResponsesIndex from './responses/Index.vue';
|
||||||
|
import CustomToolsIndex from './tools/Index.vue';
|
||||||
|
|
||||||
export const routes = [
|
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,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -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>
|
||||||
Reference in New Issue
Block a user