Merge branch 'develop' into feat/voice-as-twilio-capability

This commit is contained in:
Muhsin Keloth
2026-04-08 12:09:59 +04:00
committed by GitHub
41 changed files with 1201 additions and 394 deletions
@@ -23,6 +23,12 @@ const meta = {
installationTypes: [INSTALLATION_TYPES.CLOUD, INSTALLATION_TYPES.ENTERPRISE],
};
const metaCustomTools = {
permissions: ['administrator', 'agent'],
featureFlag: FEATURE_FLAGS.CAPTAIN_CUSTOM_TOOLS,
installationTypes: [INSTALLATION_TYPES.CLOUD, INSTALLATION_TYPES.ENTERPRISE],
};
const metaV2 = {
permissions: ['administrator', 'agent'],
featureFlag: FEATURE_FLAGS.CAPTAIN_V2,
@@ -46,7 +52,7 @@ const assistantRoutes = [
path: frontendURL('accounts/:accountId/captain/:assistantId/tools'),
component: CustomToolsIndex,
name: 'captain_tools_index',
meta,
meta: metaCustomTools,
},
{
path: frontendURL('accounts/:accountId/captain/:assistantId/scenarios'),
@@ -5,13 +5,14 @@ import { FEATURE_FLAGS } from 'dashboard/featureFlags';
import { usePolicy } from 'dashboard/composables/usePolicy';
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';
import CreateCustomToolDialog from 'dashboard/components-next/captain/pageComponents/customTool/CreateCustomToolDialog.vue';
import CustomToolCard from 'dashboard/components-next/captain/pageComponents/customTool/CustomToolCard.vue';
import DeleteDialog from 'dashboard/components-next/captain/pageComponents/DeleteDialog.vue';
const store = useStore();
const { isFeatureFlagEnabled } = usePolicy();
const { isFeatureFlagEnabled, shouldShowPaywall } = usePolicy();
const SOFT_LIMIT = 10;
const isV2 = computed(() => isFeatureFlagEnabled(FEATURE_FLAGS.CAPTAIN_V2));
@@ -80,7 +81,9 @@ const onDeleteSuccess = () => {
};
onMounted(() => {
fetchCustomTools();
if (!shouldShowPaywall(FEATURE_FLAGS.CAPTAIN_CUSTOM_TOOLS)) {
fetchCustomTools();
}
});
</script>
@@ -89,6 +92,7 @@ onMounted(() => {
:header-title="$t('CAPTAIN.CUSTOM_TOOLS.HEADER')"
:button-label="$t('CAPTAIN.CUSTOM_TOOLS.ADD_NEW')"
:button-policy="['administrator']"
:feature-flag="FEATURE_FLAGS.CAPTAIN_CUSTOM_TOOLS"
:total-count="customToolsMeta.totalCount"
:current-page="customToolsMeta.page"
:show-pagination-footer="!isFetching && !!customTools.length"
@@ -98,6 +102,10 @@ onMounted(() => {
@update:current-page="onPageChange"
@click="openCreateDialog"
>
<template #paywall>
<CaptainPaywall feature-prefix="CAPTAIN.CUSTOM_TOOLS" />
</template>
<template #emptyState>
<CustomToolsPageEmptyState @click="openCreateDialog" />
</template>
@@ -1,4 +1,5 @@
<script setup>
import { useAdmin } from 'dashboard/composables/useAdmin';
import Icon from 'next/icon/Icon.vue';
import ButtonV4 from 'next/button/Button.vue';
@@ -22,6 +23,11 @@ defineProps({
});
const emit = defineEmits(['upgrade']);
// Cloud agents land on this modal too, but billing is admin-only — they need
// the escalation message instead of a button they cannot use. Mirrors the
// pattern in UpgradePage.vue.
const { isAdmin } = useAdmin();
</script>
<template>
@@ -47,11 +53,14 @@ const emit = defineEmits(['upgrade']);
/>
<p class="text-sm font-normal text-n-slate-11">
{{ $t(`${featurePrefix}.${i18nKey}.UPGRADE_PROMPT`) }}
<span v-if="!isOnChatwootCloud && !isSuperAdmin">
<span v-if="isOnChatwootCloud && !isAdmin">
{{ $t('GENERAL_SETTINGS.LIMIT_MESSAGES.NON_ADMIN') }}
</span>
<span v-else-if="!isOnChatwootCloud && !isSuperAdmin">
{{ $t(`${featurePrefix}.ENTERPRISE_PAYWALL.ASK_ADMIN`) }}
</span>
</p>
<template v-if="isOnChatwootCloud">
<template v-if="isOnChatwootCloud && isAdmin">
<ButtonV4 blue solid md @click="emit('upgrade')">
{{ $t(`${featurePrefix}.PAYWALL.UPGRADE_NOW`) }}
</ButtonV4>
@@ -59,7 +68,7 @@ const emit = defineEmits(['upgrade']);
{{ $t(`${featurePrefix}.PAYWALL.CANCEL_ANYTIME`) }}
</span>
</template>
<template v-else-if="isSuperAdmin">
<template v-else-if="!isOnChatwootCloud && isSuperAdmin">
<a href="/super_admin" class="block w-full">
<ButtonV4 solid blue md class="w-full">
{{ $t(`${featurePrefix}.PAYWALL.UPGRADE_NOW`) }}
@@ -1,5 +1,8 @@
<script setup>
import { ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAlert } from 'dashboard/composables';
import { stripInlineBase64Images } from 'dashboard/helper/editorHelper';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
@@ -11,7 +14,9 @@ const props = defineProps({
});
const emit = defineEmits(['updateSignature']);
const signature = ref(props.messageSignature);
const { t } = useI18n();
const signature = ref(props.messageSignature ?? '');
watch(
() => props.messageSignature ?? '',
newValue => {
@@ -20,6 +25,15 @@ watch(
);
const updateSignature = () => {
const { sanitizedContent, hasInlineImages } = stripInlineBase64Images(
signature.value || ''
);
signature.value = sanitizedContent.trim();
if (hasInlineImages) {
useAlert(
t('PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.INLINE_IMAGE_WARNING')
);
}
emit('updateSignature', signature.value);
};
</script>