diff --git a/app/javascript/dashboard/components-next/breadcrumb/Breadcrumb.vue b/app/javascript/dashboard/components-next/breadcrumb/Breadcrumb.vue index 8ca325607..8a1b26e90 100644 --- a/app/javascript/dashboard/components-next/breadcrumb/Breadcrumb.vue +++ b/app/javascript/dashboard/components-next/breadcrumb/Breadcrumb.vue @@ -15,8 +15,8 @@ const emit = defineEmits(['click']); const { t } = useI18n(); -const onClick = event => { - emit('click', event); +const onClick = (item, index) => { + emit('click', item, index); }; @@ -24,22 +24,25 @@ const onClick = event => { + + + {{ item.label }} - - - - {{ item.emoji ? item.emoji : '' }} {{ item.label }} - - + + + + {{ item.emoji ? item.emoji : '' }} {{ item.label }} + diff --git a/app/javascript/dashboard/components-next/captain/SettingsPageLayout.vue b/app/javascript/dashboard/components-next/captain/SettingsPageLayout.vue new file mode 100644 index 000000000..4a48794b3 --- /dev/null +++ b/app/javascript/dashboard/components-next/captain/SettingsPageLayout.vue @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/javascript/dashboard/components-next/captain/pageComponents/assistant/settings/AssistantBasicSettingsForm.vue b/app/javascript/dashboard/components-next/captain/pageComponents/assistant/settings/AssistantBasicSettingsForm.vue new file mode 100644 index 000000000..236791793 --- /dev/null +++ b/app/javascript/dashboard/components-next/captain/pageComponents/assistant/settings/AssistantBasicSettingsForm.vue @@ -0,0 +1,151 @@ + + + + + + + + + + + + + {{ t('CAPTAIN.ASSISTANTS.FORM.FEATURES.TITLE') }} + + + + + {{ t('CAPTAIN.ASSISTANTS.FORM.FEATURES.ALLOW_CONVERSATION_FAQS') }} + + + + {{ t('CAPTAIN.ASSISTANTS.FORM.FEATURES.ALLOW_MEMORIES') }} + + + + + + + + + diff --git a/app/javascript/dashboard/components-next/captain/pageComponents/assistant/settings/AssistantControlItems.vue b/app/javascript/dashboard/components-next/captain/pageComponents/assistant/settings/AssistantControlItems.vue new file mode 100644 index 000000000..2bbede899 --- /dev/null +++ b/app/javascript/dashboard/components-next/captain/pageComponents/assistant/settings/AssistantControlItems.vue @@ -0,0 +1,43 @@ + + + + + + + {{ controlItem.name }} + + + + + + + {{ controlItem.description }} + + + diff --git a/app/javascript/dashboard/components-next/captain/pageComponents/assistant/settings/AssistantSystemSettingsForm.vue b/app/javascript/dashboard/components-next/captain/pageComponents/assistant/settings/AssistantSystemSettingsForm.vue new file mode 100644 index 000000000..b86bdacb4 --- /dev/null +++ b/app/javascript/dashboard/components-next/captain/pageComponents/assistant/settings/AssistantSystemSettingsForm.vue @@ -0,0 +1,125 @@ + + + + + + + + + + + {{ t('CAPTAIN.ASSISTANTS.FORM.TEMPERATURE.LABEL') }} + + + + {{ state.temperature }} + + + {{ t('CAPTAIN.ASSISTANTS.FORM.TEMPERATURE.DESCRIPTION') }} + + + + + + + + diff --git a/app/javascript/dashboard/featureFlags.js b/app/javascript/dashboard/featureFlags.js index 1a6ada9fa..98234539b 100644 --- a/app/javascript/dashboard/featureFlags.js +++ b/app/javascript/dashboard/featureFlags.js @@ -36,6 +36,7 @@ export const FEATURE_FLAGS = { REPORT_V4: 'report_v4', CHANNEL_INSTAGRAM: 'channel_instagram', CONTACT_CHATWOOT_SUPPORT_TEAM: 'contact_chatwoot_support_team', + CAPTAIN_V2: 'captain_integration_v2', }; export const PREMIUM_FEATURES = [ @@ -44,4 +45,5 @@ export const PREMIUM_FEATURES = [ FEATURE_FLAGS.CUSTOM_ROLES, FEATURE_FLAGS.AUDIT_LOGS, FEATURE_FLAGS.HELP_CENTER, + FEATURE_FLAGS.CAPTAIN_V2, ]; diff --git a/app/javascript/dashboard/i18n/locale/en/integrations.json b/app/javascript/dashboard/i18n/locale/en/integrations.json index b3e091722..fc8cff644 100644 --- a/app/javascript/dashboard/i18n/locale/en/integrations.json +++ b/app/javascript/dashboard/i18n/locale/en/integrations.json @@ -478,6 +478,37 @@ "ERROR_MESSAGE": "There was an error updating the assistant, please try again.", "NOT_FOUND": "Could not find the assistant. Please try again." }, + "SETTINGS": { + "BREADCRUMB": { + "ASSISTANT": "Assistant" + }, + "BASIC_SETTINGS": { + "TITLE": "Basic settings", + "DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human." + }, + "SYSTEM_SETTINGS": { + "TITLE": "System settings", + "DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human." + }, + "CONTROL_ITEMS": { + "TITLE": "The Fun Stuff", + "DESCRIPTION": "Add more control to the assistant. (a bit more visual like a story : Query guardrail → scenarios → output) Nudges user to actually utilise these.", + "OPTIONS": { + "GUARDRAILS": { + "TITLE": "Guardrails", + "DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic." + }, + "SCENARIOS": { + "TITLE": "Scenarios", + "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”" + }, + "RESPONSE_GUIDELINES": { + "TITLE": "Response guidelines", + "DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?" + } + } + } + }, "OPTIONS": { "EDIT_ASSISTANT": "Edit Assistant", "DELETE_ASSISTANT": "Delete Assistant", diff --git a/app/javascript/dashboard/routes/dashboard/captain/assistants/Edit.vue b/app/javascript/dashboard/routes/dashboard/captain/assistants/Edit.vue index 8b64e2663..2b2506934 100644 --- a/app/javascript/dashboard/routes/dashboard/captain/assistants/Edit.vue +++ b/app/javascript/dashboard/routes/dashboard/captain/assistants/Edit.vue @@ -5,10 +5,13 @@ import { useStore } from 'dashboard/composables/store'; import { useMapGetter } from 'dashboard/composables/store'; import { useAlert } from 'dashboard/composables'; import { useI18n } from 'vue-i18n'; +import { FEATURE_FLAGS } from 'dashboard/featureFlags'; import PageLayout from 'dashboard/components-next/captain/PageLayout.vue'; import EditAssistantForm from '../../../../components-next/captain/pageComponents/assistant/EditAssistantForm.vue'; import AssistantPlayground from 'dashboard/components-next/captain/assistant/AssistantPlayground.vue'; +import AssistantSettings from 'dashboard/routes/dashboard/captain/assistants/settings/Settings.vue'; + const route = useRoute(); const store = useStore(); const { t } = useI18n(); @@ -19,6 +22,16 @@ const assistant = computed(() => store.getters['captainAssistants/getRecord'](Number(assistantId)) ); +const isFeatureEnabledonAccount = useMapGetter( + 'accounts/isFeatureEnabledonAccount' +); +const currentAccountId = useMapGetter('getCurrentAccountId'); + +const isCaptainV2Enabled = isFeatureEnabledonAccount.value( + currentAccountId.value, + FEATURE_FLAGS.CAPTAIN_V2 +); + const isAssistantAvailable = computed(() => !!assistant.value?.id); const handleSubmit = async updatedAssistant => { @@ -36,14 +49,16 @@ const handleSubmit = async updatedAssistant => { }; onMounted(() => { - if (!isAssistantAvailable.value) { + if (!isAssistantAvailable.value || !isCaptainV2Enabled) { store.dispatch('captainAssistants/show', assistantId); } }); + +import { computed, onMounted } from 'vue'; +import { useRoute } from 'vue-router'; +import { useI18n } from 'vue-i18n'; +import { useAlert } from 'dashboard/composables'; +import { useStore } from 'dashboard/composables/store'; +import { useMapGetter } from 'dashboard/composables/store'; +import SettingsPageLayout from 'dashboard/components-next/captain/SettingsPageLayout.vue'; +import SettingsHeader from 'dashboard/components-next/captain/pageComponents/settings/SettingsHeader.vue'; +import AssistantBasicSettingsForm from 'dashboard/components-next/captain/pageComponents/assistant/settings/AssistantBasicSettingsForm.vue'; +import AssistantSystemSettingsForm from 'dashboard/components-next/captain/pageComponents/assistant/settings/AssistantSystemSettingsForm.vue'; +import AssistantControlItems from 'dashboard/components-next/captain/pageComponents/assistant/settings/AssistantControlItems.vue'; + +const { t } = useI18n(); +const route = useRoute(); +const store = useStore(); +const assistantId = route.params.assistantId; +const uiFlags = useMapGetter('captainAssistants/getUIFlags'); +const isFetching = computed(() => uiFlags.value.fetchingItem); +const assistant = computed(() => + store.getters['captainAssistants/getRecord'](Number(assistantId)) +); + +const isAssistantAvailable = computed(() => !!assistant.value?.id); + +const controlItems = computed(() => { + return [ + { + name: t( + 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.GUARDRAILS.TITLE' + ), + description: t( + 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.GUARDRAILS.DESCRIPTION' + ), + // routeName: 'captain_assistants_guardrails_index', + }, + { + name: t( + 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.SCENARIOS.TITLE' + ), + description: t( + 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.SCENARIOS.DESCRIPTION' + ), + // routeName: 'captain_assistants_scenarios_index', + }, + { + name: t( + 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.RESPONSE_GUIDELINES.TITLE' + ), + description: t( + 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.RESPONSE_GUIDELINES.DESCRIPTION' + ), + // routeName: 'captain_assistants_guidelines_index', + }, + ]; +}); + +const breadcrumbItems = computed(() => { + const activeControlItem = controlItems.value?.find( + item => item.routeName === route.name + ); + + return [ + { + label: t('CAPTAIN.ASSISTANTS.SETTINGS.BREADCRUMB.ASSISTANT'), + routeName: 'captain_assistants_index', + }, + { label: assistant.value?.name, routeName: 'captain_assistants_edit' }, + ...(activeControlItem + ? [ + { + label: activeControlItem.name, + routeName: activeControlItem.routeName, + }, + ] + : []), + ]; +}); + +const handleSubmit = async updatedAssistant => { + try { + await store.dispatch('captainAssistants/update', { + id: assistantId, + ...updatedAssistant, + }); + useAlert(t('CAPTAIN.ASSISTANTS.EDIT.SUCCESS_MESSAGE')); + } catch (error) { + const errorMessage = + error?.message || t('CAPTAIN.ASSISTANTS.EDIT.ERROR_MESSAGE'); + useAlert(errorMessage); + } +}; + +onMounted(() => { + if (!isAssistantAvailable.value) { + store.dispatch('captainAssistants/show', assistantId); + } +}); + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/javascript/dashboard/routes/dashboard/captain/captain.routes.js b/app/javascript/dashboard/routes/dashboard/captain/captain.routes.js index 17afeca14..7294a7433 100644 --- a/app/javascript/dashboard/routes/dashboard/captain/captain.routes.js +++ b/app/javascript/dashboard/routes/dashboard/captain/captain.routes.js @@ -3,6 +3,7 @@ import { INSTALLATION_TYPES } from 'dashboard/constants/installationTypes'; import { frontendURL } from '../../../helper/URLHelper'; import AssistantIndex from './assistants/Index.vue'; import AssistantEdit from './assistants/Edit.vue'; +// import AssistantSettings from './assistants/settings/Settings.vue'; import AssistantInboxesIndex from './assistants/inboxes/Index.vue'; import DocumentsIndex from './documents/Index.vue'; import ResponsesIndex from './responses/Index.vue'; diff --git a/config/features.yml b/config/features.yml index 5171b1c01..d41f705ad 100644 --- a/config/features.yml +++ b/config/features.yml @@ -176,3 +176,7 @@ - name: notion_integration display_name: Notion Integration enabled: false +- name: captain_integration_v2 + display_name: Captain V2 + enabled: false + premium: true
+ {{ t('CAPTAIN.ASSISTANTS.FORM.TEMPERATURE.DESCRIPTION') }} +