feat: New Assistants Edit Page (#11920)

# Pull Request Template

## Description

Fixes https://linear.app/chatwoot/issue/CW-4602/assistants-edit-page

### Screenshots
<img width="1650" height="890" alt="image"
src="https://github.com/user-attachments/assets/f9834cd3-9cf3-4173-8d33-1aad04d8991e"
/>
<img width="1650" height="890" alt="image"
src="https://github.com/user-attachments/assets/a628328a-fdfd-4ee7-86b5-2a1945e0c114"
/>

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
Sivin Varghese
2025-07-12 17:02:10 +05:30
committed by GitHub
parent 1b02ebec68
commit 18eb53acf4
11 changed files with 634 additions and 14 deletions

View File

@@ -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);
}
});
</script>
<template>
<AssistantSettings v-if="isCaptainV2Enabled" />
<PageLayout
v-else
:header-title="assistant?.name"
:show-pagination-footer="false"
:is-fetching="isFetching"

View File

@@ -0,0 +1,154 @@
<script setup>
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);
}
});
</script>
<template>
<SettingsPageLayout
:breadcrumb-items="breadcrumbItems"
:is-fetching="isFetching"
class="[&>div]:max-w-[80rem]"
>
<template #body>
<div class="flex flex-col gap-6">
<div class="flex flex-col gap-6">
<SettingsHeader
:heading="t('CAPTAIN.ASSISTANTS.SETTINGS.BASIC_SETTINGS.TITLE')"
:description="
t('CAPTAIN.ASSISTANTS.SETTINGS.BASIC_SETTINGS.DESCRIPTION')
"
/>
<AssistantBasicSettingsForm
:assistant="assistant"
@submit="handleSubmit"
/>
</div>
<span class="h-px w-full bg-n-weak mt-2" />
<div class="flex flex-col gap-6">
<SettingsHeader
:heading="t('CAPTAIN.ASSISTANTS.SETTINGS.SYSTEM_SETTINGS.TITLE')"
:description="
t('CAPTAIN.ASSISTANTS.SETTINGS.SYSTEM_SETTINGS.DESCRIPTION')
"
/>
<AssistantSystemSettingsForm
:assistant="assistant"
@submit="handleSubmit"
/>
</div>
</div>
</template>
<template #controls>
<div class="flex flex-col gap-6">
<SettingsHeader
:heading="t('CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.TITLE')"
:description="
t('CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.DESCRIPTION')
"
/>
<div class="flex flex-col gap-6">
<AssistantControlItems
v-for="item in controlItems"
:key="item.name"
:control-item="item"
/>
</div>
</div>
</template>
</SettingsPageLayout>
</template>

View File

@@ -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';