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'), | ||||
|           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', | ||||
|   SAML: 'saml', | ||||
|   QUOTED_EMAIL_REPLY: 'quoted_email_reply', | ||||
|   CAPTAIN_CUSTOM_TOOLS: 'captain_custom_tools', | ||||
| }; | ||||
|  | ||||
| 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": { | ||||
|       "HEADER": "FAQs", | ||||
|       "ADD_NEW": "Create new FAQ", | ||||
|   | ||||
| @@ -304,6 +304,7 @@ | ||||
|     "CAPTAIN_ASSISTANTS": "Assistants", | ||||
|     "CAPTAIN_DOCUMENTS": "Documents", | ||||
|     "CAPTAIN_RESPONSES": "FAQs", | ||||
|     "CAPTAIN_TOOLS": "Tools", | ||||
|     "HOME": "Home", | ||||
|     "AGENTS": "Agents", | ||||
|     "AGENT_BOTS": "Bots", | ||||
|   | ||||
| @@ -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, | ||||
|       ], | ||||
|     }, | ||||
|   }, | ||||
| ]; | ||||
|   | ||||
| @@ -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
	 Shivam Mishra
					Shivam Mishra