Compare commits
25
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afa7f2d325 | ||
|
|
91bfc47f01 | ||
|
|
862e33e7b9 | ||
|
|
7d2307d343 | ||
|
|
69b818896a | ||
|
|
01d17674e6 | ||
|
|
689525ce85 | ||
|
|
6abecdfd43 | ||
|
|
7ac8e857c7 | ||
|
|
418d9cce27 | ||
|
|
eba12567e9 | ||
|
|
d230bb68d0 | ||
|
|
7babcfe622 | ||
|
|
f31666f877 | ||
|
|
4c1a047c94 | ||
|
|
c853d07f02 | ||
|
|
fb1aa085cf | ||
|
|
e8a01ace41 | ||
|
|
01363042ce | ||
|
|
5bf39d20e5 | ||
|
|
90352b3a20 | ||
|
|
ba8df900e3 | ||
|
|
9b75d9bd1b | ||
|
|
ec6c3b3571 | ||
|
|
48ba273730 |
@@ -159,7 +159,7 @@ gem 'working_hours'
|
|||||||
gem 'pg_search'
|
gem 'pg_search'
|
||||||
|
|
||||||
# Subscriptions, Billing
|
# Subscriptions, Billing
|
||||||
gem 'stripe'
|
gem 'stripe', '17.2.0.pre.alpha.2'
|
||||||
|
|
||||||
## - helper gems --##
|
## - helper gems --##
|
||||||
## to populate db with sample data
|
## to populate db with sample data
|
||||||
|
|||||||
+2
-2
@@ -902,7 +902,7 @@ GEM
|
|||||||
squasher (0.7.2)
|
squasher (0.7.2)
|
||||||
stackprof (0.2.25)
|
stackprof (0.2.25)
|
||||||
statsd-ruby (1.5.0)
|
statsd-ruby (1.5.0)
|
||||||
stripe (8.5.0)
|
stripe (17.2.0.pre.alpha.2)
|
||||||
telephone_number (1.4.20)
|
telephone_number (1.4.20)
|
||||||
test-prof (1.2.1)
|
test-prof (1.2.1)
|
||||||
thor (1.4.0)
|
thor (1.4.0)
|
||||||
@@ -1110,7 +1110,7 @@ DEPENDENCIES
|
|||||||
spring-watcher-listen
|
spring-watcher-listen
|
||||||
squasher
|
squasher
|
||||||
stackprof
|
stackprof
|
||||||
stripe
|
stripe (= 17.2.0.pre.alpha.2)
|
||||||
telephone_number
|
telephone_number
|
||||||
test-prof
|
test-prof
|
||||||
tidewave
|
tidewave
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ module BillingHelper
|
|||||||
# Return false if not plans are configured, so that no checks are enforced
|
# Return false if not plans are configured, so that no checks are enforced
|
||||||
return false if default_plan.blank?
|
return false if default_plan.blank?
|
||||||
|
|
||||||
account.custom_attributes['plan_name'].nil? || account.custom_attributes['plan_name'] == default_plan['name']
|
# Handle both string and hash formats for default_plan
|
||||||
|
default_plan_name = default_plan.is_a?(Hash) ? default_plan['name'] : default_plan
|
||||||
|
|
||||||
|
account.custom_attributes['plan_name'].nil? || account.custom_attributes['plan_name'] == default_plan_name
|
||||||
end
|
end
|
||||||
|
|
||||||
def conversations_this_month(account)
|
def conversations_this_month(account)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import AddAccountModal from './components/app/AddAccountModal.vue';
|
|
||||||
import LoadingState from './components/widgets/LoadingState.vue';
|
import LoadingState from './components/widgets/LoadingState.vue';
|
||||||
import NetworkNotification from './components/NetworkNotification.vue';
|
import NetworkNotification from './components/NetworkNotification.vue';
|
||||||
import UpdateBanner from './components/app/UpdateBanner.vue';
|
import UpdateBanner from './components/app/UpdateBanner.vue';
|
||||||
@@ -25,7 +24,6 @@ export default {
|
|||||||
name: 'App',
|
name: 'App',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
AddAccountModal,
|
|
||||||
LoadingState,
|
LoadingState,
|
||||||
NetworkNotification,
|
NetworkNotification,
|
||||||
UpdateBanner,
|
UpdateBanner,
|
||||||
@@ -51,7 +49,6 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showAddAccountModal: false,
|
|
||||||
latestChatwootVersion: null,
|
latestChatwootVersion: null,
|
||||||
reconnectService: null,
|
reconnectService: null,
|
||||||
};
|
};
|
||||||
@@ -64,21 +61,12 @@ export default {
|
|||||||
authUIFlags: 'getAuthUIFlags',
|
authUIFlags: 'getAuthUIFlags',
|
||||||
accountUIFlags: 'accounts/getUIFlags',
|
accountUIFlags: 'accounts/getUIFlags',
|
||||||
}),
|
}),
|
||||||
hasAccounts() {
|
|
||||||
const { accounts = [] } = this.currentUser || {};
|
|
||||||
return accounts.length > 0;
|
|
||||||
},
|
|
||||||
hideOnOnboardingView() {
|
hideOnOnboardingView() {
|
||||||
return !isOnOnboardingView(this.$route);
|
return !isOnOnboardingView(this.$route);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
currentUser() {
|
|
||||||
if (!this.hasAccounts) {
|
|
||||||
this.showAddAccountModal = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
currentAccountId: {
|
currentAccountId: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler() {
|
handler() {
|
||||||
@@ -156,7 +144,6 @@ export default {
|
|||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
<AddAccountModal :show="showAddAccountModal" :has-accounts="hasAccounts" />
|
|
||||||
<WootSnackbarBox />
|
<WootSnackbarBox />
|
||||||
<NetworkNotification />
|
<NetworkNotification />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
import ButtonGroup from 'dashboard/components-next/buttonGroup/ButtonGroup.vue';
|
||||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||||
@@ -55,17 +56,17 @@ useKeyboardEvents(keyboardEvents);
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<ButtonGroup
|
||||||
class="flex flex-col justify-center items-center absolute top-36 xl:top-24 ltr:right-2 rtl:left-2 bg-n-solid-2 border border-n-weak rounded-full gap-2 p-1"
|
class="flex flex-col justify-center items-center absolute top-36 xl:top-24 ltr:right-2 rtl:left-2 bg-n-solid-2/90 backdrop-blur-lg border border-n-weak/50 rounded-full gap-1.5 p-1.5 shadow-sm transition-shadow duration-200 hover:shadow"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
v-tooltip.top="$t('CONVERSATION.SIDEBAR.CONTACT')"
|
v-tooltip.top="$t('CONVERSATION.SIDEBAR.CONTACT')"
|
||||||
ghost
|
ghost
|
||||||
slate
|
slate
|
||||||
sm
|
sm
|
||||||
class="!rounded-full"
|
class="!rounded-full transition-all duration-[250ms] ease-out active:!scale-95 active:!brightness-105 active:duration-75"
|
||||||
:class="{
|
:class="{
|
||||||
'bg-n-alpha-2': isContactSidebarOpen,
|
'bg-n-alpha-2 active:shadow-sm': isContactSidebarOpen,
|
||||||
}"
|
}"
|
||||||
icon="i-ph-user-bold"
|
icon="i-ph-user-bold"
|
||||||
@click="handleConversationSidebarToggle"
|
@click="handleConversationSidebarToggle"
|
||||||
@@ -75,13 +76,14 @@ useKeyboardEvents(keyboardEvents);
|
|||||||
v-tooltip.bottom="$t('CONVERSATION.SIDEBAR.COPILOT')"
|
v-tooltip.bottom="$t('CONVERSATION.SIDEBAR.COPILOT')"
|
||||||
ghost
|
ghost
|
||||||
slate
|
slate
|
||||||
class="!rounded-full"
|
|
||||||
:class="{
|
|
||||||
'bg-n-alpha-2 !text-n-iris-9': isCopilotPanelOpen,
|
|
||||||
}"
|
|
||||||
sm
|
sm
|
||||||
|
class="!rounded-full transition-all duration-[250ms] ease-out active:!scale-95 active:duration-75"
|
||||||
|
:class="{
|
||||||
|
'bg-n-alpha-2 !text-n-iris-9 active:!brightness-105 active:shadow-sm':
|
||||||
|
isCopilotPanelOpen,
|
||||||
|
}"
|
||||||
icon="i-woot-captain"
|
icon="i-woot-captain"
|
||||||
@click="handleCopilotSidebarToggle"
|
@click="handleCopilotSidebarToggle"
|
||||||
/>
|
/>
|
||||||
</div>
|
</ButtonGroup>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ const props = defineProps({
|
|||||||
enableCannedResponses: { type: Boolean, default: true },
|
enableCannedResponses: { type: Boolean, default: true },
|
||||||
enabledMenuOptions: { type: Array, default: () => [] },
|
enabledMenuOptions: { type: Array, default: () => [] },
|
||||||
enableCaptainTools: { type: Boolean, default: false },
|
enableCaptainTools: { type: Boolean, default: false },
|
||||||
|
signature: { type: String, default: '' },
|
||||||
|
allowSignature: { type: Boolean, default: false },
|
||||||
|
sendWithSignature: { type: Boolean, default: false },
|
||||||
|
channelType: { type: String, default: '' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(['update:modelValue']);
|
||||||
@@ -100,6 +104,10 @@ watch(
|
|||||||
:enable-canned-responses="enableCannedResponses"
|
:enable-canned-responses="enableCannedResponses"
|
||||||
:enabled-menu-options="enabledMenuOptions"
|
:enabled-menu-options="enabledMenuOptions"
|
||||||
:enable-captain-tools="enableCaptainTools"
|
:enable-captain-tools="enableCaptainTools"
|
||||||
|
:signature="signature"
|
||||||
|
:allow-signature="allowSignature"
|
||||||
|
:send-with-signature="sendWithSignature"
|
||||||
|
:channel-type="channelType"
|
||||||
@input="handleInput"
|
@input="handleInput"
|
||||||
@focus="handleFocus"
|
@focus="handleFocus"
|
||||||
@blur="handleBlur"
|
@blur="handleBlur"
|
||||||
|
|||||||
+5
-2
@@ -14,6 +14,7 @@ import {
|
|||||||
} from 'dashboard/helper/portalHelper';
|
} from 'dashboard/helper/portalHelper';
|
||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
|
|
||||||
|
import ButtonGroup from 'dashboard/components-next/buttonGroup/ButtonGroup.vue';
|
||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
|
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
|
||||||
|
|
||||||
@@ -140,11 +141,12 @@ const updateArticleStatus = async ({ value }) => {
|
|||||||
:disabled="!articleId"
|
:disabled="!articleId"
|
||||||
@click="previewArticle"
|
@click="previewArticle"
|
||||||
/>
|
/>
|
||||||
<div class="flex items-center">
|
<ButtonGroup class="flex items-center">
|
||||||
<Button
|
<Button
|
||||||
:label="t('HELP_CENTER.EDIT_ARTICLE_PAGE.HEADER.PUBLISH')"
|
:label="t('HELP_CENTER.EDIT_ARTICLE_PAGE.HEADER.PUBLISH')"
|
||||||
size="sm"
|
size="sm"
|
||||||
class="ltr:rounded-r-none rtl:rounded-l-none"
|
class="ltr:rounded-r-none rtl:rounded-l-none"
|
||||||
|
no-animation
|
||||||
:is-loading="isArticlePublishing"
|
:is-loading="isArticlePublishing"
|
||||||
:disabled="
|
:disabled="
|
||||||
status === ARTICLE_STATUSES.PUBLISHED ||
|
status === ARTICLE_STATUSES.PUBLISHED ||
|
||||||
@@ -159,6 +161,7 @@ const updateArticleStatus = async ({ value }) => {
|
|||||||
icon="i-lucide-chevron-down"
|
icon="i-lucide-chevron-down"
|
||||||
size="sm"
|
size="sm"
|
||||||
:disabled="!articleId"
|
:disabled="!articleId"
|
||||||
|
no-animation
|
||||||
class="ltr:rounded-l-none rtl:rounded-r-none"
|
class="ltr:rounded-l-none rtl:rounded-r-none"
|
||||||
@click.stop="showArticleActionMenu = !showArticleActionMenu"
|
@click.stop="showArticleActionMenu = !showArticleActionMenu"
|
||||||
/>
|
/>
|
||||||
@@ -170,7 +173,7 @@ const updateArticleStatus = async ({ value }) => {
|
|||||||
/>
|
/>
|
||||||
</OnClickOutside>
|
</OnClickOutside>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ const setSignature = () => {
|
|||||||
|
|
||||||
const toggleMessageSignature = () => {
|
const toggleMessageSignature = () => {
|
||||||
setSignatureFlagForInbox(props.channelType, !sendWithSignature.value);
|
setSignatureFlagForInbox(props.channelType, !sendWithSignature.value);
|
||||||
setSignature();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Added this watch to dynamically set signature on target inbox change.
|
// Added this watch to dynamically set signature on target inbox change.
|
||||||
|
|||||||
+14
-8
@@ -199,16 +199,20 @@ const handleInboxAction = ({ value, action, ...rest }) => {
|
|||||||
state.attachedFiles = [];
|
state.attachedFiles = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeTargetInbox = value => {
|
const removeSignatureFromMessage = () => {
|
||||||
v$.value.$reset();
|
// Always remove the signature from message content when inbox/contact is removed
|
||||||
// Remove the signature from message content
|
// to ensure no leftover signature content remains
|
||||||
// Based on the Advance Editor (used in isEmailOrWebWidget) and Plain editor(all other inboxes except WhatsApp)
|
const signatureToRemove = inboxTypes.value.isEmailOrWebWidget
|
||||||
if (props.sendWithSignature) {
|
? props.messageSignature
|
||||||
const signatureToRemove = inboxTypes.value.isEmailOrWebWidget
|
: extractTextFromMarkdown(props.messageSignature);
|
||||||
? props.messageSignature
|
if (signatureToRemove) {
|
||||||
: extractTextFromMarkdown(props.messageSignature);
|
|
||||||
state.message = removeSignature(state.message, signatureToRemove);
|
state.message = removeSignature(state.message, signatureToRemove);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeTargetInbox = value => {
|
||||||
|
v$.value.$reset();
|
||||||
|
removeSignatureFromMessage();
|
||||||
emit('updateTargetInbox', value);
|
emit('updateTargetInbox', value);
|
||||||
state.attachedFiles = [];
|
state.attachedFiles = [];
|
||||||
};
|
};
|
||||||
@@ -216,6 +220,7 @@ const removeTargetInbox = value => {
|
|||||||
const clearSelectedContact = () => {
|
const clearSelectedContact = () => {
|
||||||
emit('clearSelectedContact');
|
emit('clearSelectedContact');
|
||||||
state.attachedFiles = [];
|
state.attachedFiles = [];
|
||||||
|
removeSignatureFromMessage();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClickInsertEmoji = emoji => {
|
const onClickInsertEmoji = emoji => {
|
||||||
@@ -354,6 +359,7 @@ const shouldShowMessageEditor = computed(() => {
|
|||||||
:is-email-or-web-widget-inbox="inboxTypes.isEmailOrWebWidget"
|
:is-email-or-web-widget-inbox="inboxTypes.isEmailOrWebWidget"
|
||||||
:has-errors="validationStates.isMessageInvalid"
|
:has-errors="validationStates.isMessageInvalid"
|
||||||
:has-attachments="state.attachedFiles.length > 0"
|
:has-attachments="state.attachedFiles.length > 0"
|
||||||
|
:channel-type="inboxChannelType"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<AttachmentPreviews
|
<AttachmentPreviews
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const props = defineProps({
|
|||||||
hasAttachments: { type: Boolean, default: false },
|
hasAttachments: { type: Boolean, default: false },
|
||||||
sendWithSignature: { type: Boolean, default: false },
|
sendWithSignature: { type: Boolean, default: false },
|
||||||
messageSignature: { type: String, default: '' },
|
messageSignature: { type: String, default: '' },
|
||||||
|
channelType: { type: String, default: '' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@@ -90,6 +91,10 @@ const replaceText = async message => {
|
|||||||
"
|
"
|
||||||
enable-variables
|
enable-variables
|
||||||
:show-character-count="false"
|
:show-character-count="false"
|
||||||
|
:signature="messageSignature"
|
||||||
|
allow-signature
|
||||||
|
:send-with-signature="sendWithSignature"
|
||||||
|
:channel-type="channelType"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const props = defineProps({
|
|||||||
icon: { type: [String, Object, Function], default: '' },
|
icon: { type: [String, Object, Function], default: '' },
|
||||||
trailingIcon: { type: Boolean, default: false },
|
trailingIcon: { type: Boolean, default: false },
|
||||||
isLoading: { type: Boolean, default: false },
|
isLoading: { type: Boolean, default: false },
|
||||||
|
noAnimation: { type: Boolean, default: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
const slots = useSlots();
|
const slots = useSlots();
|
||||||
@@ -179,12 +180,18 @@ const STYLE_CONFIG = {
|
|||||||
md: 'text-sm font-medium',
|
md: 'text-sm font-medium',
|
||||||
lg: 'text-base',
|
lg: 'text-base',
|
||||||
},
|
},
|
||||||
|
clickAnimation: {
|
||||||
|
xs: 'active:enabled:scale-[0.97]',
|
||||||
|
sm: 'active:enabled:scale-[0.97]',
|
||||||
|
md: 'active:enabled:scale-[0.98]',
|
||||||
|
lg: 'active:enabled:scale-[0.98]',
|
||||||
|
},
|
||||||
justify: {
|
justify: {
|
||||||
start: 'justify-start',
|
start: 'justify-start',
|
||||||
center: 'justify-center',
|
center: 'justify-center',
|
||||||
end: 'justify-end',
|
end: 'justify-end',
|
||||||
},
|
},
|
||||||
base: 'inline-flex items-center min-w-0 gap-2 transition-all duration-200 ease-in-out border-0 rounded-lg outline-1 outline disabled:opacity-50',
|
base: 'inline-flex items-center min-w-0 gap-2 transition-all duration-100 ease-out border-0 rounded-lg outline-1 outline disabled:opacity-50',
|
||||||
};
|
};
|
||||||
|
|
||||||
const variantClasses = computed(() => {
|
const variantClasses = computed(() => {
|
||||||
@@ -221,6 +228,12 @@ const linkButtonClasses = computed(() => {
|
|||||||
|
|
||||||
return classes.join(' ');
|
return classes.join(' ');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const animationClasses = computed(() => {
|
||||||
|
return props.noAnimation
|
||||||
|
? ''
|
||||||
|
: STYLE_CONFIG.clickAnimation[computedSize.value];
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -230,6 +243,7 @@ const linkButtonClasses = computed(() => {
|
|||||||
[STYLE_CONFIG.base]: true,
|
[STYLE_CONFIG.base]: true,
|
||||||
[isLink ? linkButtonClasses : buttonClasses]: true,
|
[isLink ? linkButtonClasses : buttonClasses]: true,
|
||||||
[STYLE_CONFIG.fontSize[computedSize]]: true,
|
[STYLE_CONFIG.fontSize[computedSize]]: true,
|
||||||
|
[animationClasses]: true,
|
||||||
[STYLE_CONFIG.justify[computedJustify]]: true,
|
[STYLE_CONFIG.justify[computedJustify]]: true,
|
||||||
'flex-row-reverse': trailingIcon && !isIconOnly,
|
'flex-row-reverse': trailingIcon && !isIconOnly,
|
||||||
}"
|
}"
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
noAnimation: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:class="
|
||||||
|
noAnimation
|
||||||
|
? ''
|
||||||
|
: 'has-[button:not(:disabled):active]:scale-[0.98] transition-transform duration-150 ease-out'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
|
import { OnClickOutside } from '@vueuse/components';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useMapGetter } from 'dashboard/composables/store.js';
|
||||||
import { usePolicy } from 'dashboard/composables/usePolicy';
|
import { usePolicy } from 'dashboard/composables/usePolicy';
|
||||||
|
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
import BackButton from 'dashboard/components/widgets/BackButton.vue';
|
import BackButton from 'dashboard/components/widgets/BackButton.vue';
|
||||||
import PaginationFooter from 'dashboard/components-next/pagination/PaginationFooter.vue';
|
import PaginationFooter from 'dashboard/components-next/pagination/PaginationFooter.vue';
|
||||||
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
||||||
import Policy from 'dashboard/components/policy.vue';
|
import Policy from 'dashboard/components/policy.vue';
|
||||||
|
import AssistantSwitcher from 'dashboard/components-next/captain/pageComponents/switcher/AssistantSwitcher.vue';
|
||||||
|
import CreateAssistantDialog from 'dashboard/components-next/captain/pageComponents/assistant/CreateAssistantDialog.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
currentPage: {
|
currentPage: {
|
||||||
@@ -56,11 +62,32 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
showAssistantSwitcher: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['click', 'close', 'update:currentPage']);
|
const emit = defineEmits(['click', 'close', 'update:currentPage']);
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
const { shouldShowPaywall } = usePolicy();
|
const { shouldShowPaywall } = usePolicy();
|
||||||
|
|
||||||
|
const showAssistantSwitcherDropdown = ref(false);
|
||||||
|
const createAssistantDialogRef = ref(null);
|
||||||
|
|
||||||
|
const assistants = useMapGetter('captainAssistants/getRecords');
|
||||||
|
|
||||||
|
const currentAssistantId = computed(() => route.params.assistantId);
|
||||||
|
|
||||||
|
const activeAssistantName = computed(() => {
|
||||||
|
return (
|
||||||
|
assistants.value?.find(
|
||||||
|
assistant => assistant.id === Number(currentAssistantId.value)
|
||||||
|
)?.name || ''
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const showPaywall = computed(() => {
|
const showPaywall = computed(() => {
|
||||||
return shouldShowPaywall(props.featureFlag);
|
return shouldShowPaywall(props.featureFlag);
|
||||||
});
|
});
|
||||||
@@ -72,6 +99,15 @@ const handleButtonClick = () => {
|
|||||||
const handlePageChange = event => {
|
const handlePageChange = event => {
|
||||||
emit('update:currentPage', event);
|
emit('update:currentPage', event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleAssistantSwitcher = () => {
|
||||||
|
showAssistantSwitcherDropdown.value = !showAssistantSwitcherDropdown.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreateAssistant = () => {
|
||||||
|
showAssistantSwitcherDropdown.value = false;
|
||||||
|
createAssistantDialogRef.value.dialogRef.open();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -82,9 +118,48 @@ const handlePageChange = event => {
|
|||||||
class="flex items-start lg:items-center justify-between w-full py-6 lg:py-0 lg:h-20 gap-4 lg:gap-2 flex-col lg:flex-row"
|
class="flex items-start lg:items-center justify-between w-full py-6 lg:py-0 lg:h-20 gap-4 lg:gap-2 flex-col lg:flex-row"
|
||||||
>
|
>
|
||||||
<div class="flex gap-4 items-center">
|
<div class="flex gap-4 items-center">
|
||||||
<BackButton v-if="backUrl" :to="backUrl" />
|
<BackButton v-if="backUrl" :back-url="backUrl" />
|
||||||
<slot name="headerTitle">
|
<slot name="headerTitle">
|
||||||
<span class="text-xl font-medium text-n-slate-12">
|
<div v-if="showAssistantSwitcher" class="flex items-center gap-2">
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<span
|
||||||
|
v-if="activeAssistantName"
|
||||||
|
class="text-xl font-medium truncate text-n-slate-12"
|
||||||
|
>
|
||||||
|
{{ activeAssistantName }}
|
||||||
|
</span>
|
||||||
|
<div v-if="activeAssistantName" class="relative group">
|
||||||
|
<OnClickOutside
|
||||||
|
@trigger="showAssistantSwitcherDropdown = false"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
icon="i-lucide-chevron-down"
|
||||||
|
variant="ghost"
|
||||||
|
color="slate"
|
||||||
|
size="xs"
|
||||||
|
class="rounded-md group-hover:bg-n-slate-3 hover:bg-n-slate-3 [&>span]:size-4"
|
||||||
|
@click="toggleAssistantSwitcher"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<AssistantSwitcher
|
||||||
|
v-if="showAssistantSwitcherDropdown"
|
||||||
|
class="absolute ltr:left-0 rtl:right-0 top-9"
|
||||||
|
@close="showAssistantSwitcherDropdown = false"
|
||||||
|
@create-assistant="handleCreateAssistant"
|
||||||
|
/>
|
||||||
|
</OnClickOutside>
|
||||||
|
</div>
|
||||||
|
<Icon
|
||||||
|
v-if="activeAssistantName"
|
||||||
|
icon="i-lucide-chevron-right"
|
||||||
|
class="size-6 text-n-slate-11"
|
||||||
|
/>
|
||||||
|
<span class="text-xl font-medium text-n-slate-11">
|
||||||
|
{{ headerTitle }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span v-else class="text-xl font-medium text-n-slate-12">
|
||||||
{{ headerTitle }}
|
{{ headerTitle }}
|
||||||
</span>
|
</span>
|
||||||
</slot>
|
</slot>
|
||||||
@@ -97,21 +172,24 @@ const handlePageChange = event => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div class="flex gap-2">
|
||||||
v-if="!showPaywall && buttonLabel"
|
<slot name="search" />
|
||||||
v-on-clickaway="() => emit('close')"
|
<div
|
||||||
class="relative group/campaign-button"
|
v-if="!showPaywall && buttonLabel"
|
||||||
>
|
v-on-clickaway="() => emit('close')"
|
||||||
<Policy :permissions="buttonPolicy">
|
class="relative group/captain-button"
|
||||||
<Button
|
>
|
||||||
:label="buttonLabel"
|
<Policy :permissions="buttonPolicy">
|
||||||
icon="i-lucide-plus"
|
<Button
|
||||||
size="sm"
|
:label="buttonLabel"
|
||||||
class="group-hover/campaign-button:brightness-110"
|
icon="i-lucide-plus"
|
||||||
@click="handleButtonClick"
|
size="sm"
|
||||||
/>
|
class="group-hover/captain-button:brightness-110"
|
||||||
</Policy>
|
@click="handleButtonClick"
|
||||||
<slot name="action" />
|
/>
|
||||||
|
</Policy>
|
||||||
|
<slot name="action" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<slot name="subHeader" />
|
<slot name="subHeader" />
|
||||||
@@ -144,5 +222,6 @@ const handlePageChange = event => {
|
|||||||
@update:current-page="handlePageChange"
|
@update:current-page="handlePageChange"
|
||||||
/>
|
/>
|
||||||
</footer>
|
</footer>
|
||||||
|
<CreateAssistantDialog ref="createAssistantDialogRef" type="create" />
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import PaginationFooter from 'dashboard/components-next/pagination/PaginationFooter.vue';
|
|
||||||
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
|
||||||
import Breadcrumb from 'dashboard/components-next/breadcrumb/Breadcrumb.vue';
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
isFetching: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
isEmpty: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
currentPage: {
|
|
||||||
type: Number,
|
|
||||||
default: 1,
|
|
||||||
},
|
|
||||||
totalCount: {
|
|
||||||
type: Number,
|
|
||||||
default: 100,
|
|
||||||
},
|
|
||||||
itemsPerPage: {
|
|
||||||
type: Number,
|
|
||||||
default: 25,
|
|
||||||
},
|
|
||||||
showPaginationFooter: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
breadcrumbItems: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:currentPage']);
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const handlePageChange = event => {
|
|
||||||
emit('update:currentPage', event);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBreadcrumbClick = item => {
|
|
||||||
router.push({
|
|
||||||
name: item.routeName,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<section
|
|
||||||
class="px-6 flex flex-col w-full h-screen overflow-y-auto bg-n-background"
|
|
||||||
>
|
|
||||||
<div class="max-w-[60rem] mx-auto flex flex-col w-full h-full mb-4">
|
|
||||||
<header class="mb-7 sticky top-0 bg-n-background pt-4 z-20">
|
|
||||||
<Breadcrumb :items="breadcrumbItems" @click="handleBreadcrumbClick" />
|
|
||||||
</header>
|
|
||||||
<main class="flex gap-16 w-full flex-1 pb-16">
|
|
||||||
<section
|
|
||||||
v-if="$slots.body || $slots.emptyState || isFetching"
|
|
||||||
class="flex flex-col w-full"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="isFetching"
|
|
||||||
class="flex items-center justify-center py-10 text-n-slate-11"
|
|
||||||
>
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
<div v-else-if="isEmpty">
|
|
||||||
<slot name="emptyState" />
|
|
||||||
</div>
|
|
||||||
<slot v-else name="body" />
|
|
||||||
</section>
|
|
||||||
<section v-if="$slots.controls" class="flex w-full">
|
|
||||||
<slot name="controls" />
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
<footer v-if="showPaginationFooter" class="sticky bottom-0 z-10 pb-4">
|
|
||||||
<PaginationFooter
|
|
||||||
:current-page="currentPage"
|
|
||||||
:total-items="totalCount"
|
|
||||||
:items-per-page="itemsPerPage"
|
|
||||||
@update:current-page="handlePageChange"
|
|
||||||
/>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
@@ -76,12 +76,11 @@ const handleAction = ({ action, value }) => {
|
|||||||
<template>
|
<template>
|
||||||
<CardLayout>
|
<CardLayout>
|
||||||
<div class="flex justify-between w-full gap-1">
|
<div class="flex justify-between w-full gap-1">
|
||||||
<router-link
|
<h6
|
||||||
:to="{ name: 'captain_assistants_edit', params: { assistantId: id } }"
|
class="text-base font-normal text-n-slate-12 line-clamp-1 hover:underline transition-colors"
|
||||||
class="text-base text-n-slate-12 line-clamp-1 hover:underline transition-colors"
|
|
||||||
>
|
>
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</router-link>
|
</h6>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div
|
<div
|
||||||
v-on-clickaway="() => toggleDropdown(false)"
|
v-on-clickaway="() => toggleDropdown(false)"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import NextButton from 'dashboard/components-next/button/Button.vue';
|
import NextButton from 'dashboard/components-next/button/Button.vue';
|
||||||
import MessageList from './MessageList.vue';
|
import MessageList from './MessageList.vue';
|
||||||
@@ -29,6 +29,16 @@ const resetConversation = () => {
|
|||||||
newMessage.value = '';
|
newMessage.value = '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Watch for assistant ID changes and reset conversation
|
||||||
|
watch(
|
||||||
|
() => assistantId,
|
||||||
|
(newId, oldId) => {
|
||||||
|
if (oldId && newId !== oldId) {
|
||||||
|
resetConversation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const sendMessage = async () => {
|
const sendMessage = async () => {
|
||||||
if (!newMessage.value.trim() || isLoading.value) return;
|
if (!newMessage.value.trim() || isLoading.value) return;
|
||||||
|
|
||||||
@@ -74,7 +84,7 @@ const sendMessage = async () => {
|
|||||||
</h3>
|
</h3>
|
||||||
<NextButton
|
<NextButton
|
||||||
ghost
|
ghost
|
||||||
size="small"
|
sm
|
||||||
icon="i-lucide-rotate-ccw"
|
icon="i-lucide-rotate-ccw"
|
||||||
@click="resetConversation"
|
@click="resetConversation"
|
||||||
/>
|
/>
|
||||||
@@ -97,7 +107,7 @@ const sendMessage = async () => {
|
|||||||
/>
|
/>
|
||||||
<NextButton
|
<NextButton
|
||||||
ghost
|
ghost
|
||||||
size="small"
|
sm
|
||||||
:disabled="!newMessage.trim()"
|
:disabled="!newMessage.trim()"
|
||||||
icon="i-lucide-send"
|
icon="i-lucide-send"
|
||||||
@click="sendMessage"
|
@click="sendMessage"
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
import { useMapGetter } from 'dashboard/composables/store';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { OnClickOutside } from '@vueuse/components';
|
|
||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
|
||||||
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
assistantId: {
|
|
||||||
type: [String, Number],
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(['update']);
|
|
||||||
const { t } = useI18n();
|
|
||||||
const isFilterOpen = ref(false);
|
|
||||||
|
|
||||||
const assistants = useMapGetter('captainAssistants/getRecords');
|
|
||||||
const assistantOptions = computed(() => [
|
|
||||||
{
|
|
||||||
label: t(`CAPTAIN.RESPONSES.FILTER.ALL_ASSISTANTS`),
|
|
||||||
value: 'all',
|
|
||||||
action: 'filter',
|
|
||||||
},
|
|
||||||
...assistants.value.map(assistant => ({
|
|
||||||
value: assistant.id,
|
|
||||||
label: assistant.name,
|
|
||||||
action: 'filter',
|
|
||||||
})),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const selectedAssistantLabel = computed(() => {
|
|
||||||
const assistant = assistantOptions.value.find(
|
|
||||||
option => option.value === props.assistantId
|
|
||||||
);
|
|
||||||
return t('CAPTAIN.RESPONSES.FILTER.ASSISTANT', {
|
|
||||||
selected: assistant ? assistant.label : '',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleAssistantFilterChange = ({ value }) => {
|
|
||||||
isFilterOpen.value = false;
|
|
||||||
emit('update', value);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<OnClickOutside @trigger="isFilterOpen = false">
|
|
||||||
<Button
|
|
||||||
:label="selectedAssistantLabel"
|
|
||||||
icon="i-lucide-chevron-down"
|
|
||||||
size="sm"
|
|
||||||
color="slate"
|
|
||||||
trailing-icon
|
|
||||||
class="max-w-48"
|
|
||||||
@click="isFilterOpen = !isFilterOpen"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DropdownMenu
|
|
||||||
v-if="isFilterOpen"
|
|
||||||
:menu-items="assistantOptions"
|
|
||||||
class="mt-2"
|
|
||||||
@action="handleAssistantFilterChange"
|
|
||||||
/>
|
|
||||||
</OnClickOutside>
|
|
||||||
</template>
|
|
||||||
+13
-3
@@ -18,7 +18,7 @@ const props = defineProps({
|
|||||||
validator: value => ['create', 'edit'].includes(value),
|
validator: value => ['create', 'edit'].includes(value),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const emit = defineEmits(['close']);
|
const emit = defineEmits(['close', 'created']);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|
||||||
@@ -35,8 +35,18 @@ const i18nKey = computed(
|
|||||||
() => `CAPTAIN.ASSISTANTS.${props.type.toUpperCase()}`
|
() => `CAPTAIN.ASSISTANTS.${props.type.toUpperCase()}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const createAssistant = assistantDetails =>
|
const createAssistant = async assistantDetails => {
|
||||||
store.dispatch('captainAssistants/create', assistantDetails);
|
try {
|
||||||
|
const newAssistant = await store.dispatch(
|
||||||
|
'captainAssistants/create',
|
||||||
|
assistantDetails
|
||||||
|
);
|
||||||
|
emit('created', newAssistant);
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error?.message || t(`${i18nKey.value}.ERROR_MESSAGE`);
|
||||||
|
useAlert(errorMessage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async updatedAssistant => {
|
const handleSubmit = async updatedAssistant => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
-333
@@ -1,333 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { reactive, computed, watch } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { useVuelidate } from '@vuelidate/core';
|
|
||||||
import { required, minLength } from '@vuelidate/validators';
|
|
||||||
import { useMapGetter } from 'dashboard/composables/store';
|
|
||||||
|
|
||||||
import Input from 'dashboard/components-next/input/Input.vue';
|
|
||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
|
||||||
import Editor from 'dashboard/components-next/Editor/Editor.vue';
|
|
||||||
import Accordion from 'dashboard/components-next/Accordion/Accordion.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
mode: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
validator: value => ['edit', 'create'].includes(value),
|
|
||||||
},
|
|
||||||
assistant: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(['submit']);
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const formState = {
|
|
||||||
uiFlags: useMapGetter('captainAssistants/getUIFlags'),
|
|
||||||
};
|
|
||||||
|
|
||||||
const initialState = {
|
|
||||||
name: '',
|
|
||||||
description: '',
|
|
||||||
productName: '',
|
|
||||||
welcomeMessage: '',
|
|
||||||
handoffMessage: '',
|
|
||||||
resolutionMessage: '',
|
|
||||||
instructions: '',
|
|
||||||
features: {
|
|
||||||
conversationFaqs: false,
|
|
||||||
memories: false,
|
|
||||||
citations: false,
|
|
||||||
},
|
|
||||||
temperature: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
const state = reactive({ ...initialState });
|
|
||||||
|
|
||||||
const validationRules = {
|
|
||||||
name: { required, minLength: minLength(1) },
|
|
||||||
description: { required, minLength: minLength(1) },
|
|
||||||
productName: { required, minLength: minLength(1) },
|
|
||||||
welcomeMessage: { minLength: minLength(1) },
|
|
||||||
handoffMessage: { minLength: minLength(1) },
|
|
||||||
resolutionMessage: { minLength: minLength(1) },
|
|
||||||
instructions: { minLength: minLength(1) },
|
|
||||||
};
|
|
||||||
|
|
||||||
const v$ = useVuelidate(validationRules, state);
|
|
||||||
|
|
||||||
const isLoading = computed(() => formState.uiFlags.value.creatingItem);
|
|
||||||
|
|
||||||
const getErrorMessage = field => {
|
|
||||||
return v$.value[field].$error ? v$.value[field].$errors[0].$message : '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const formErrors = computed(() => ({
|
|
||||||
name: getErrorMessage('name'),
|
|
||||||
description: getErrorMessage('description'),
|
|
||||||
productName: getErrorMessage('productName'),
|
|
||||||
welcomeMessage: getErrorMessage('welcomeMessage'),
|
|
||||||
handoffMessage: getErrorMessage('handoffMessage'),
|
|
||||||
resolutionMessage: getErrorMessage('resolutionMessage'),
|
|
||||||
instructions: getErrorMessage('instructions'),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const updateStateFromAssistant = assistant => {
|
|
||||||
const { config = {} } = assistant;
|
|
||||||
state.name = assistant.name;
|
|
||||||
state.description = assistant.description;
|
|
||||||
state.productName = config.product_name;
|
|
||||||
state.welcomeMessage = config.welcome_message;
|
|
||||||
state.handoffMessage = config.handoff_message;
|
|
||||||
state.resolutionMessage = config.resolution_message;
|
|
||||||
state.instructions = config.instructions;
|
|
||||||
state.features = {
|
|
||||||
conversationFaqs: config.feature_faq || false,
|
|
||||||
memories: config.feature_memory || false,
|
|
||||||
citations: config.feature_citation || false,
|
|
||||||
};
|
|
||||||
state.temperature = config.temperature || 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBasicInfoUpdate = async () => {
|
|
||||||
const result = await Promise.all([
|
|
||||||
v$.value.name.$validate(),
|
|
||||||
v$.value.description.$validate(),
|
|
||||||
v$.value.productName.$validate(),
|
|
||||||
]).then(results => results.every(Boolean));
|
|
||||||
if (!result) return;
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
name: state.name,
|
|
||||||
description: state.description,
|
|
||||||
config: {
|
|
||||||
...props.assistant.config,
|
|
||||||
product_name: state.productName,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
emit('submit', payload);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSystemMessagesUpdate = async () => {
|
|
||||||
const result = await Promise.all([
|
|
||||||
v$.value.welcomeMessage.$validate(),
|
|
||||||
v$.value.handoffMessage.$validate(),
|
|
||||||
v$.value.resolutionMessage.$validate(),
|
|
||||||
]).then(results => results.every(Boolean));
|
|
||||||
if (!result) return;
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
config: {
|
|
||||||
...props.assistant.config,
|
|
||||||
welcome_message: state.welcomeMessage,
|
|
||||||
handoff_message: state.handoffMessage,
|
|
||||||
resolution_message: state.resolutionMessage,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
emit('submit', payload);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleInstructionsUpdate = async () => {
|
|
||||||
const result = await v$.value.instructions.$validate();
|
|
||||||
if (!result) return;
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
config: {
|
|
||||||
...props.assistant.config,
|
|
||||||
temperature: state.temperature || 1,
|
|
||||||
instructions: state.instructions,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
emit('submit', payload);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFeaturesUpdate = () => {
|
|
||||||
const payload = {
|
|
||||||
config: {
|
|
||||||
...props.assistant.config,
|
|
||||||
feature_faq: state.features.conversationFaqs,
|
|
||||||
feature_memory: state.features.memories,
|
|
||||||
feature_citation: state.features.citations,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
emit('submit', payload);
|
|
||||||
};
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.assistant,
|
|
||||||
newAssistant => {
|
|
||||||
if (props.mode === 'edit' && newAssistant) {
|
|
||||||
updateStateFromAssistant(newAssistant);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<form class="flex flex-col gap-4" @submit.prevent="handleSubmit">
|
|
||||||
<!-- Basic Information Section -->
|
|
||||||
<Accordion
|
|
||||||
:title="t('CAPTAIN.ASSISTANTS.FORM.SECTIONS.BASIC_INFO')"
|
|
||||||
is-open
|
|
||||||
>
|
|
||||||
<div class="flex flex-col gap-4 pt-4">
|
|
||||||
<Input
|
|
||||||
v-model="state.name"
|
|
||||||
:label="t('CAPTAIN.ASSISTANTS.FORM.NAME.LABEL')"
|
|
||||||
:placeholder="t('CAPTAIN.ASSISTANTS.FORM.NAME.PLACEHOLDER')"
|
|
||||||
:message="formErrors.name"
|
|
||||||
:message-type="formErrors.name ? 'error' : 'info'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Editor
|
|
||||||
v-model="state.description"
|
|
||||||
:label="t('CAPTAIN.ASSISTANTS.FORM.DESCRIPTION.LABEL')"
|
|
||||||
:placeholder="t('CAPTAIN.ASSISTANTS.FORM.DESCRIPTION.PLACEHOLDER')"
|
|
||||||
:message="formErrors.description"
|
|
||||||
:message-type="formErrors.description ? 'error' : 'info'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Input
|
|
||||||
v-model="state.productName"
|
|
||||||
:label="t('CAPTAIN.ASSISTANTS.FORM.PRODUCT_NAME.LABEL')"
|
|
||||||
:placeholder="t('CAPTAIN.ASSISTANTS.FORM.PRODUCT_NAME.PLACEHOLDER')"
|
|
||||||
:message="formErrors.productName"
|
|
||||||
:message-type="formErrors.productName ? 'error' : 'info'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="flex justify-end">
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
:loading="isLoading"
|
|
||||||
@click="handleBasicInfoUpdate"
|
|
||||||
>
|
|
||||||
{{ t('CAPTAIN.ASSISTANTS.FORM.UPDATE') }}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Accordion>
|
|
||||||
|
|
||||||
<!-- Instructions Section -->
|
|
||||||
<Accordion :title="t('CAPTAIN.ASSISTANTS.FORM.SECTIONS.INSTRUCTIONS')">
|
|
||||||
<div class="flex flex-col gap-4">
|
|
||||||
<Editor
|
|
||||||
v-model="state.instructions"
|
|
||||||
:placeholder="t('CAPTAIN.ASSISTANTS.FORM.INSTRUCTIONS.PLACEHOLDER')"
|
|
||||||
:message="formErrors.instructions"
|
|
||||||
:max-length="20000"
|
|
||||||
:message-type="formErrors.instructions ? 'error' : 'info'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="flex flex-col gap-2 mt-4">
|
|
||||||
<label class="text-sm font-medium text-n-slate-12">
|
|
||||||
{{ t('CAPTAIN.ASSISTANTS.FORM.TEMPERATURE.LABEL') }}
|
|
||||||
</label>
|
|
||||||
<div class="flex items-center gap-4">
|
|
||||||
<input
|
|
||||||
v-model="state.temperature"
|
|
||||||
type="range"
|
|
||||||
min="0"
|
|
||||||
max="1"
|
|
||||||
step="0.1"
|
|
||||||
class="w-full"
|
|
||||||
/>
|
|
||||||
<span class="text-sm text-n-slate-12">{{ state.temperature }}</span>
|
|
||||||
</div>
|
|
||||||
<p class="text-sm text-n-slate-11 italic">
|
|
||||||
{{ t('CAPTAIN.ASSISTANTS.FORM.TEMPERATURE.DESCRIPTION') }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex justify-end">
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
:loading="isLoading"
|
|
||||||
:label="t('CAPTAIN.ASSISTANTS.FORM.UPDATE')"
|
|
||||||
@click="handleInstructionsUpdate"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Accordion>
|
|
||||||
|
|
||||||
<!-- Greeting Messages Section -->
|
|
||||||
<Accordion :title="t('CAPTAIN.ASSISTANTS.FORM.SECTIONS.SYSTEM_MESSAGES')">
|
|
||||||
<div class="flex flex-col gap-4 pt-4">
|
|
||||||
<Editor
|
|
||||||
v-model="state.handoffMessage"
|
|
||||||
:label="t('CAPTAIN.ASSISTANTS.FORM.HANDOFF_MESSAGE.LABEL')"
|
|
||||||
:placeholder="
|
|
||||||
t('CAPTAIN.ASSISTANTS.FORM.HANDOFF_MESSAGE.PLACEHOLDER')
|
|
||||||
"
|
|
||||||
:message="formErrors.handoffMessage"
|
|
||||||
:message-type="formErrors.handoffMessage ? 'error' : 'info'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Editor
|
|
||||||
v-model="state.resolutionMessage"
|
|
||||||
:label="t('CAPTAIN.ASSISTANTS.FORM.RESOLUTION_MESSAGE.LABEL')"
|
|
||||||
:placeholder="
|
|
||||||
t('CAPTAIN.ASSISTANTS.FORM.RESOLUTION_MESSAGE.PLACEHOLDER')
|
|
||||||
"
|
|
||||||
:message="formErrors.resolutionMessage"
|
|
||||||
:message-type="formErrors.resolutionMessage ? 'error' : 'info'"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="flex justify-end">
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
:loading="isLoading"
|
|
||||||
:label="t('CAPTAIN.ASSISTANTS.FORM.UPDATE')"
|
|
||||||
@click="handleSystemMessagesUpdate"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Accordion>
|
|
||||||
|
|
||||||
<!-- Features Section -->
|
|
||||||
<Accordion :title="t('CAPTAIN.ASSISTANTS.FORM.SECTIONS.FEATURES')">
|
|
||||||
<div class="flex flex-col gap-4 pt-4">
|
|
||||||
<div class="flex flex-col gap-2">
|
|
||||||
<label class="text-sm font-medium text-n-slate-12">
|
|
||||||
{{ t('CAPTAIN.ASSISTANTS.FORM.FEATURES.TITLE') }}
|
|
||||||
</label>
|
|
||||||
<div class="flex flex-col gap-2">
|
|
||||||
<label class="flex items-center gap-2">
|
|
||||||
<input
|
|
||||||
v-model="state.features.conversationFaqs"
|
|
||||||
type="checkbox"
|
|
||||||
/>
|
|
||||||
{{
|
|
||||||
t('CAPTAIN.ASSISTANTS.FORM.FEATURES.ALLOW_CONVERSATION_FAQS')
|
|
||||||
}}
|
|
||||||
</label>
|
|
||||||
<label class="flex items-center gap-2">
|
|
||||||
<input v-model="state.features.memories" type="checkbox" />
|
|
||||||
{{ t('CAPTAIN.ASSISTANTS.FORM.FEATURES.ALLOW_MEMORIES') }}
|
|
||||||
</label>
|
|
||||||
<label class="flex items-center gap-2">
|
|
||||||
<input v-model="state.features.citations" type="checkbox" />
|
|
||||||
{{ t('CAPTAIN.ASSISTANTS.FORM.FEATURES.ALLOW_CITATIONS') }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex justify-end">
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
:loading="isLoading"
|
|
||||||
:label="t('CAPTAIN.ASSISTANTS.FORM.UPDATE')"
|
|
||||||
@click="handleFeaturesUpdate"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Accordion>
|
|
||||||
</form>
|
|
||||||
</template>
|
|
||||||
+35
-2
@@ -3,6 +3,8 @@ import { reactive, computed, watch } from 'vue';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useVuelidate } from '@vuelidate/core';
|
import { useVuelidate } from '@vuelidate/core';
|
||||||
import { minLength } from '@vuelidate/validators';
|
import { minLength } from '@vuelidate/validators';
|
||||||
|
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||||
|
import { useAccount } from 'dashboard/composables/useAccount';
|
||||||
|
|
||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
import Editor from 'dashboard/components-next/Editor/Editor.vue';
|
import Editor from 'dashboard/components-next/Editor/Editor.vue';
|
||||||
@@ -17,10 +19,16 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(['submit']);
|
const emit = defineEmits(['submit']);
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const { isCloudFeatureEnabled } = useAccount();
|
||||||
|
|
||||||
|
const isCaptainV2Enabled = computed(() =>
|
||||||
|
isCloudFeatureEnabled(FEATURE_FLAGS.CAPTAIN_V2)
|
||||||
|
);
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
handoffMessage: '',
|
handoffMessage: '',
|
||||||
resolutionMessage: '',
|
resolutionMessage: '',
|
||||||
|
instructions: '',
|
||||||
temperature: 1,
|
temperature: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -29,6 +37,7 @@ const state = reactive({ ...initialState });
|
|||||||
const validationRules = {
|
const validationRules = {
|
||||||
handoffMessage: { minLength: minLength(1) },
|
handoffMessage: { minLength: minLength(1) },
|
||||||
resolutionMessage: { minLength: minLength(1) },
|
resolutionMessage: { minLength: minLength(1) },
|
||||||
|
instructions: { minLength: minLength(1) },
|
||||||
};
|
};
|
||||||
|
|
||||||
const v$ = useVuelidate(validationRules, state);
|
const v$ = useVuelidate(validationRules, state);
|
||||||
@@ -40,20 +49,30 @@ const getErrorMessage = field => {
|
|||||||
const formErrors = computed(() => ({
|
const formErrors = computed(() => ({
|
||||||
handoffMessage: getErrorMessage('handoffMessage'),
|
handoffMessage: getErrorMessage('handoffMessage'),
|
||||||
resolutionMessage: getErrorMessage('resolutionMessage'),
|
resolutionMessage: getErrorMessage('resolutionMessage'),
|
||||||
|
instructions: getErrorMessage('instructions'),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const updateStateFromAssistant = assistant => {
|
const updateStateFromAssistant = assistant => {
|
||||||
const { config = {} } = assistant;
|
const { config = {} } = assistant;
|
||||||
state.handoffMessage = config.handoff_message;
|
state.handoffMessage = config.handoff_message;
|
||||||
state.resolutionMessage = config.resolution_message;
|
state.resolutionMessage = config.resolution_message;
|
||||||
|
state.instructions = config.instructions;
|
||||||
state.temperature = config.temperature || 1;
|
state.temperature = config.temperature || 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSystemMessagesUpdate = async () => {
|
const handleSystemMessagesUpdate = async () => {
|
||||||
const result = await Promise.all([
|
const validations = [
|
||||||
v$.value.handoffMessage.$validate(),
|
v$.value.handoffMessage.$validate(),
|
||||||
v$.value.resolutionMessage.$validate(),
|
v$.value.resolutionMessage.$validate(),
|
||||||
]).then(results => results.every(Boolean));
|
];
|
||||||
|
|
||||||
|
if (!isCaptainV2Enabled.value) {
|
||||||
|
validations.push(v$.value.instructions.$validate());
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await Promise.all(validations).then(results =>
|
||||||
|
results.every(Boolean)
|
||||||
|
);
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
@@ -65,6 +84,10 @@ const handleSystemMessagesUpdate = async () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!isCaptainV2Enabled.value) {
|
||||||
|
payload.config.instructions = state.instructions;
|
||||||
|
}
|
||||||
|
|
||||||
emit('submit', payload);
|
emit('submit', payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -95,6 +118,16 @@ watch(
|
|||||||
:message-type="formErrors.resolutionMessage ? 'error' : 'info'"
|
:message-type="formErrors.resolutionMessage ? 'error' : 'info'"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Editor
|
||||||
|
v-if="!isCaptainV2Enabled"
|
||||||
|
v-model="state.instructions"
|
||||||
|
:label="t('CAPTAIN.ASSISTANTS.FORM.INSTRUCTIONS.LABEL')"
|
||||||
|
:placeholder="t('CAPTAIN.ASSISTANTS.FORM.INSTRUCTIONS.PLACEHOLDER')"
|
||||||
|
:message="formErrors.instructions"
|
||||||
|
:max-length="20000"
|
||||||
|
:message-type="formErrors.instructions ? 'error' : 'info'"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<label class="text-sm font-medium text-n-slate-12">
|
<label class="text-sm font-medium text-n-slate-12">
|
||||||
{{ t('CAPTAIN.ASSISTANTS.FORM.TEMPERATURE.LABEL') }}
|
{{ t('CAPTAIN.ASSISTANTS.FORM.TEMPERATURE.LABEL') }}
|
||||||
|
|||||||
+12
-1
@@ -8,6 +8,13 @@ import { parseAPIErrorResponse } from 'dashboard/store/utils/api';
|
|||||||
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
|
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
|
||||||
import DocumentForm from './DocumentForm.vue';
|
import DocumentForm from './DocumentForm.vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
assistantId: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['close']);
|
const emit = defineEmits(['close']);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@@ -48,7 +55,11 @@ defineExpose({ dialogRef });
|
|||||||
:show-confirm-button="false"
|
:show-confirm-button="false"
|
||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
>
|
>
|
||||||
<DocumentForm @submit="handleSubmit" @cancel="handleCancel" />
|
<DocumentForm
|
||||||
|
:assistant-id="assistantId"
|
||||||
|
@submit="handleSubmit"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
/>
|
||||||
<template #footer />
|
<template #footer />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
+9
-28
@@ -2,7 +2,7 @@
|
|||||||
import { reactive, computed, ref, nextTick } from 'vue';
|
import { reactive, computed, ref, nextTick } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useVuelidate } from '@vuelidate/core';
|
import { useVuelidate } from '@vuelidate/core';
|
||||||
import { required, minLength, requiredIf, url } from '@vuelidate/validators';
|
import { minLength, requiredIf, url } from '@vuelidate/validators';
|
||||||
import { useMapGetter } from 'dashboard/composables/store';
|
import { useMapGetter } from 'dashboard/composables/store';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
|
|
||||||
@@ -10,6 +10,13 @@ import Input from 'dashboard/components-next/input/Input.vue';
|
|||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
import ComboBox from 'dashboard/components-next/combobox/ComboBox.vue';
|
import ComboBox from 'dashboard/components-next/combobox/ComboBox.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
assistantId: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['submit', 'cancel']);
|
const emit = defineEmits(['submit', 'cancel']);
|
||||||
|
|
||||||
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
|
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
|
||||||
@@ -18,13 +25,11 @@ const { t } = useI18n();
|
|||||||
|
|
||||||
const formState = {
|
const formState = {
|
||||||
uiFlags: useMapGetter('captainDocuments/getUIFlags'),
|
uiFlags: useMapGetter('captainDocuments/getUIFlags'),
|
||||||
assistants: useMapGetter('captainAssistants/getRecords'),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
name: '',
|
name: '',
|
||||||
url: '',
|
url: '',
|
||||||
assistantId: null,
|
|
||||||
documentType: 'url',
|
documentType: 'url',
|
||||||
pdfFile: null,
|
pdfFile: null,
|
||||||
};
|
};
|
||||||
@@ -38,19 +43,11 @@ const validationRules = {
|
|||||||
url: requiredIf(() => state.documentType === 'url' && url),
|
url: requiredIf(() => state.documentType === 'url' && url),
|
||||||
minLength: requiredIf(() => state.documentType === 'url' && minLength(1)),
|
minLength: requiredIf(() => state.documentType === 'url' && minLength(1)),
|
||||||
},
|
},
|
||||||
assistantId: { required },
|
|
||||||
pdfFile: {
|
pdfFile: {
|
||||||
required: requiredIf(() => state.documentType === 'pdf'),
|
required: requiredIf(() => state.documentType === 'pdf'),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const assistantList = computed(() =>
|
|
||||||
formState.assistants.value.map(assistant => ({
|
|
||||||
value: assistant.id,
|
|
||||||
label: assistant.name,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
|
|
||||||
const documentTypeOptions = [
|
const documentTypeOptions = [
|
||||||
{ value: 'url', label: t('CAPTAIN.DOCUMENTS.FORM.TYPE.URL') },
|
{ value: 'url', label: t('CAPTAIN.DOCUMENTS.FORM.TYPE.URL') },
|
||||||
{ value: 'pdf', label: t('CAPTAIN.DOCUMENTS.FORM.TYPE.PDF') },
|
{ value: 'pdf', label: t('CAPTAIN.DOCUMENTS.FORM.TYPE.PDF') },
|
||||||
@@ -70,7 +67,6 @@ const getErrorMessage = (field, errorKey) => {
|
|||||||
|
|
||||||
const formErrors = computed(() => ({
|
const formErrors = computed(() => ({
|
||||||
url: getErrorMessage('url', 'URL'),
|
url: getErrorMessage('url', 'URL'),
|
||||||
assistantId: getErrorMessage('assistantId', 'ASSISTANT'),
|
|
||||||
pdfFile: getErrorMessage('pdfFile', 'PDF_FILE'),
|
pdfFile: getErrorMessage('pdfFile', 'PDF_FILE'),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -106,7 +102,7 @@ const openFileDialog = () => {
|
|||||||
|
|
||||||
const prepareDocumentDetails = () => {
|
const prepareDocumentDetails = () => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('document[assistant_id]', state.assistantId);
|
formData.append('document[assistant_id]', props.assistantId);
|
||||||
|
|
||||||
if (state.documentType === 'url') {
|
if (state.documentType === 'url') {
|
||||||
formData.append('document[external_link]', state.url);
|
formData.append('document[external_link]', state.url);
|
||||||
@@ -218,21 +214,6 @@ const handleSubmit = async () => {
|
|||||||
:placeholder="t('CAPTAIN.DOCUMENTS.FORM.NAME.PLACEHOLDER')"
|
:placeholder="t('CAPTAIN.DOCUMENTS.FORM.NAME.PLACEHOLDER')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<label for="assistant" class="mb-0.5 text-sm font-medium text-n-slate-12">
|
|
||||||
{{ t('CAPTAIN.DOCUMENTS.FORM.ASSISTANT.LABEL') }}
|
|
||||||
</label>
|
|
||||||
<ComboBox
|
|
||||||
id="assistant"
|
|
||||||
v-model="state.assistantId"
|
|
||||||
:options="assistantList"
|
|
||||||
:has-error="!!formErrors.assistantId"
|
|
||||||
:placeholder="t('CAPTAIN.DOCUMENTS.FORM.ASSISTANT.PLACEHOLDER')"
|
|
||||||
class="[&>div>button]:bg-n-alpha-black2"
|
|
||||||
:message="formErrors.assistantId"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex gap-3 justify-between items-center w-full">
|
<div class="flex gap-3 justify-between items-center w-full">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
+10
-2
@@ -3,6 +3,7 @@ import { ref, computed } from 'vue';
|
|||||||
import { useStore } from 'dashboard/composables/store';
|
import { useStore } from 'dashboard/composables/store';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
|
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
|
||||||
import ResponseForm from './ResponseForm.vue';
|
import ResponseForm from './ResponseForm.vue';
|
||||||
@@ -21,6 +22,7 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(['close']);
|
const emit = defineEmits(['close']);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
const dialogRef = ref(null);
|
const dialogRef = ref(null);
|
||||||
const responseForm = ref(null);
|
const responseForm = ref(null);
|
||||||
@@ -39,9 +41,15 @@ const createResponse = responseDetails =>
|
|||||||
const handleSubmit = async updatedResponse => {
|
const handleSubmit = async updatedResponse => {
|
||||||
try {
|
try {
|
||||||
if (props.type === 'edit') {
|
if (props.type === 'edit') {
|
||||||
await updateResponse(updatedResponse);
|
await updateResponse({
|
||||||
|
...updatedResponse,
|
||||||
|
assistant_id: route.params.assistantId,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
await createResponse(updatedResponse);
|
await createResponse({
|
||||||
|
...updatedResponse,
|
||||||
|
assistant_id: route.params.assistantId,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
useAlert(t(`${i18nKey.value}.SUCCESS_MESSAGE`));
|
useAlert(t(`${i18nKey.value}.SUCCESS_MESSAGE`));
|
||||||
dialogRef.value.close();
|
dialogRef.value.close();
|
||||||
|
|||||||
+2
-32
@@ -8,7 +8,6 @@ import { useMapGetter } from 'dashboard/composables/store';
|
|||||||
import Input from 'dashboard/components-next/input/Input.vue';
|
import Input from 'dashboard/components-next/input/Input.vue';
|
||||||
import Editor from 'dashboard/components-next/Editor/Editor.vue';
|
import Editor from 'dashboard/components-next/Editor/Editor.vue';
|
||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
import ComboBox from 'dashboard/components-next/combobox/ComboBox.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
mode: {
|
mode: {
|
||||||
@@ -21,18 +20,17 @@ const props = defineProps({
|
|||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['submit', 'cancel']);
|
const emit = defineEmits(['submit', 'cancel']);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const formState = {
|
const formState = {
|
||||||
uiFlags: useMapGetter('captainResponses/getUIFlags'),
|
uiFlags: useMapGetter('captainResponses/getUIFlags'),
|
||||||
assistants: useMapGetter('captainAssistants/getRecords'),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
question: '',
|
question: '',
|
||||||
answer: '',
|
answer: '',
|
||||||
assistantId: null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const state = reactive({ ...initialState });
|
const state = reactive({ ...initialState });
|
||||||
@@ -40,16 +38,8 @@ const state = reactive({ ...initialState });
|
|||||||
const validationRules = {
|
const validationRules = {
|
||||||
question: { required, minLength: minLength(1) },
|
question: { required, minLength: minLength(1) },
|
||||||
answer: { required, minLength: minLength(1) },
|
answer: { required, minLength: minLength(1) },
|
||||||
assistantId: { required },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const assistantList = computed(() =>
|
|
||||||
formState.assistants.value.map(assistant => ({
|
|
||||||
value: assistant.id,
|
|
||||||
label: assistant.name,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
|
|
||||||
const v$ = useVuelidate(validationRules, state);
|
const v$ = useVuelidate(validationRules, state);
|
||||||
|
|
||||||
const isLoading = computed(() => formState.uiFlags.value.creatingItem);
|
const isLoading = computed(() => formState.uiFlags.value.creatingItem);
|
||||||
@@ -63,7 +53,6 @@ const getErrorMessage = (field, errorKey) => {
|
|||||||
const formErrors = computed(() => ({
|
const formErrors = computed(() => ({
|
||||||
question: getErrorMessage('question', 'QUESTION'),
|
question: getErrorMessage('question', 'QUESTION'),
|
||||||
answer: getErrorMessage('answer', 'ANSWER'),
|
answer: getErrorMessage('answer', 'ANSWER'),
|
||||||
assistantId: getErrorMessage('assistantId', 'ASSISTANT'),
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const handleCancel = () => emit('cancel');
|
const handleCancel = () => emit('cancel');
|
||||||
@@ -71,7 +60,6 @@ const handleCancel = () => emit('cancel');
|
|||||||
const prepareDocumentDetails = () => ({
|
const prepareDocumentDetails = () => ({
|
||||||
question: state.question,
|
question: state.question,
|
||||||
answer: state.answer,
|
answer: state.answer,
|
||||||
assistant_id: state.assistantId,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
@@ -86,12 +74,11 @@ const handleSubmit = async () => {
|
|||||||
const updateStateFromResponse = response => {
|
const updateStateFromResponse = response => {
|
||||||
if (!response) return;
|
if (!response) return;
|
||||||
|
|
||||||
const { question, answer, assistant } = response;
|
const { question, answer } = response;
|
||||||
|
|
||||||
Object.assign(state, {
|
Object.assign(state, {
|
||||||
question,
|
question,
|
||||||
answer,
|
answer,
|
||||||
assistantId: assistant.id,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,7 +102,6 @@ watch(
|
|||||||
:message="formErrors.question"
|
:message="formErrors.question"
|
||||||
:message-type="formErrors.question ? 'error' : 'info'"
|
:message-type="formErrors.question ? 'error' : 'info'"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Editor
|
<Editor
|
||||||
v-model="state.answer"
|
v-model="state.answer"
|
||||||
:label="t('CAPTAIN.RESPONSES.FORM.ANSWER.LABEL')"
|
:label="t('CAPTAIN.RESPONSES.FORM.ANSWER.LABEL')"
|
||||||
@@ -124,22 +110,6 @@ watch(
|
|||||||
:max-length="10000"
|
:max-length="10000"
|
||||||
:message-type="formErrors.answer ? 'error' : 'info'"
|
:message-type="formErrors.answer ? 'error' : 'info'"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<label for="assistant" class="mb-0.5 text-sm font-medium text-n-slate-12">
|
|
||||||
{{ t('CAPTAIN.RESPONSES.FORM.ASSISTANT.LABEL') }}
|
|
||||||
</label>
|
|
||||||
<ComboBox
|
|
||||||
id="assistant"
|
|
||||||
v-model="state.assistantId"
|
|
||||||
:options="assistantList"
|
|
||||||
:has-error="!!formErrors.assistantId"
|
|
||||||
:placeholder="t('CAPTAIN.RESPONSES.FORM.ASSISTANT.PLACEHOLDER')"
|
|
||||||
class="[&>div>button]:bg-n-alpha-black2 [&>div>button:not(.focused)]:dark:outline-n-weak [&>div>button:not(.focused)]:hover:!outline-n-slate-6"
|
|
||||||
:message="formErrors.assistantId"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between w-full gap-3">
|
<div class="flex items-center justify-between w-full gap-3">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
+143
@@ -0,0 +1,143 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import { useMapGetter, useStore } from 'dashboard/composables/store.js';
|
||||||
|
|
||||||
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
import Avatar from 'dashboard/components-next/avatar/Avatar.vue';
|
||||||
|
|
||||||
|
const emit = defineEmits(['close', 'createAssistant']);
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
const assistants = useMapGetter('captainAssistants/getRecords');
|
||||||
|
|
||||||
|
const currentAssistantId = computed(() => route.params.assistantId);
|
||||||
|
|
||||||
|
const isAssistantActive = assistant => {
|
||||||
|
return assistant.id === Number(currentAssistantId.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchDataForRoute = async (routeName, assistantId) => {
|
||||||
|
const dataFetchMap = {
|
||||||
|
captain_assistants_responses_index: async () => {
|
||||||
|
await store.dispatch('captainResponses/get', { assistantId });
|
||||||
|
await store.dispatch('captainResponses/fetchPendingCount', assistantId);
|
||||||
|
},
|
||||||
|
captain_assistants_responses_pending: async () => {
|
||||||
|
await store.dispatch('captainResponses/get', {
|
||||||
|
assistantId,
|
||||||
|
status: 'pending',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
captain_assistants_documents_index: async () => {
|
||||||
|
await store.dispatch('captainDocuments/get', { assistantId });
|
||||||
|
},
|
||||||
|
captain_assistants_scenarios_index: async () => {
|
||||||
|
await store.dispatch('captainScenarios/get', { assistantId });
|
||||||
|
},
|
||||||
|
captain_assistants_playground_index: () => {
|
||||||
|
// Playground doesn't need pre-fetching, it loads on interaction
|
||||||
|
},
|
||||||
|
captain_assistants_inboxes_index: async () => {
|
||||||
|
await store.dispatch('captainInboxes/get', { assistantId });
|
||||||
|
},
|
||||||
|
captain_tools_index: async () => {
|
||||||
|
await store.dispatch('captainCustomTools/get', { page: 1 });
|
||||||
|
},
|
||||||
|
captain_assistants_settings_index: async () => {
|
||||||
|
await store.dispatch('captainAssistants/show', assistantId);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchFn = dataFetchMap[routeName];
|
||||||
|
if (fetchFn) {
|
||||||
|
await fetchFn();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAssistantChange = async assistant => {
|
||||||
|
if (isAssistantActive(assistant)) return;
|
||||||
|
|
||||||
|
const currentRouteName = route.name;
|
||||||
|
const targetRouteName =
|
||||||
|
currentRouteName || 'captain_assistants_responses_index';
|
||||||
|
|
||||||
|
await fetchDataForRoute(targetRouteName, assistant.id);
|
||||||
|
|
||||||
|
await router.push({
|
||||||
|
name: targetRouteName,
|
||||||
|
params: {
|
||||||
|
accountId: route.params.accountId,
|
||||||
|
assistantId: assistant.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
emit('close');
|
||||||
|
};
|
||||||
|
|
||||||
|
const openCreateAssistantDialog = () => {
|
||||||
|
emit('createAssistant');
|
||||||
|
emit('close');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="pt-5 pb-3 bg-n-alpha-3 backdrop-blur-[100px] outline outline-n-container outline-1 z-50 absolute w-[27.5rem] rounded-xl shadow-md flex flex-col gap-4"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between gap-4 px-6 pb-3 border-b border-n-alpha-2"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<h2
|
||||||
|
class="text-base font-medium cursor-pointer text-n-slate-12 w-fit hover:underline"
|
||||||
|
>
|
||||||
|
{{ t('CAPTAIN.ASSISTANT_SWITCHER.ASSISTANTS') }}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-n-slate-11">
|
||||||
|
{{ t('CAPTAIN.ASSISTANT_SWITCHER.SWITCH_ASSISTANT') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
:label="t('CAPTAIN.ASSISTANT_SWITCHER.NEW_ASSISTANT')"
|
||||||
|
color="slate"
|
||||||
|
icon="i-lucide-plus"
|
||||||
|
size="sm"
|
||||||
|
class="!bg-n-alpha-2 hover:!bg-n-alpha-3"
|
||||||
|
@click="openCreateAssistantDialog"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="assistants.length > 0" class="flex flex-col gap-2 px-4">
|
||||||
|
<Button
|
||||||
|
v-for="assistant in assistants"
|
||||||
|
:key="assistant.id"
|
||||||
|
:label="assistant.name"
|
||||||
|
variant="ghost"
|
||||||
|
color="slate"
|
||||||
|
trailing-icon
|
||||||
|
:icon="isAssistantActive(assistant) ? 'i-lucide-check' : ''"
|
||||||
|
class="!justify-end !px-2 !py-2 hover:!bg-n-alpha-2 [&>.i-lucide-check]:text-n-teal-10 h-9"
|
||||||
|
size="sm"
|
||||||
|
@click="handleAssistantChange(assistant)"
|
||||||
|
>
|
||||||
|
<span class="text-sm font-medium truncate text-n-slate-12">
|
||||||
|
{{ assistant.name || '' }}
|
||||||
|
</span>
|
||||||
|
<Avatar
|
||||||
|
v-if="assistant"
|
||||||
|
:name="assistant.name"
|
||||||
|
:size="20"
|
||||||
|
icon-name="i-lucide-bot"
|
||||||
|
rounded-full
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -96,6 +96,7 @@ watch(
|
|||||||
:label="selectedLabel"
|
:label="selectedLabel"
|
||||||
trailing-icon
|
trailing-icon
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
|
no-animation
|
||||||
class="justify-between w-full !px-3 !py-2.5 text-n-slate-12 font-normal group-hover/combobox:border-n-slate-6 focus:outline-n-brand"
|
class="justify-between w-full !px-3 !py-2.5 text-n-slate-12 font-normal group-hover/combobox:border-n-slate-6 focus:outline-n-brand"
|
||||||
:class="{
|
:class="{
|
||||||
focused: open,
|
focused: open,
|
||||||
|
|||||||
@@ -78,8 +78,10 @@ const handleSuggestion = opt => {
|
|||||||
</p>
|
</p>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{
|
:to="{
|
||||||
name: 'captain_assistants_index',
|
name: 'captain_assistants_create_index',
|
||||||
params: { accountId: route.params.accountId },
|
params: {
|
||||||
|
accountId: route.params.accountId,
|
||||||
|
},
|
||||||
}"
|
}"
|
||||||
class="text-n-slate-11 underline hover:text-n-slate-12"
|
class="text-n-slate-11 underline hover:text-n-slate-12"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
import ButtonGroup from 'dashboard/components-next/buttonGroup/ButtonGroup.vue';
|
||||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import { useMapGetter } from 'dashboard/composables/store';
|
import { useMapGetter } from 'dashboard/composables/store';
|
||||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||||
@@ -53,14 +54,17 @@ const toggleSidebar = () => {
|
|||||||
v-if="showCopilotLauncher"
|
v-if="showCopilotLauncher"
|
||||||
class="fixed bottom-4 ltr:right-4 rtl:left-4 z-50"
|
class="fixed bottom-4 ltr:right-4 rtl:left-4 z-50"
|
||||||
>
|
>
|
||||||
<div class="rounded-full bg-n-alpha-2 p-1">
|
<ButtonGroup
|
||||||
|
class="rounded-full bg-n-alpha-2 backdrop-blur-lg p-1 shadow hover:shadow-md"
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
icon="i-woot-captain"
|
icon="i-woot-captain"
|
||||||
class="!rounded-full !bg-n-solid-3 dark:!bg-n-alpha-2 !text-n-slate-12 text-xl"
|
no-animation
|
||||||
|
class="!rounded-full !bg-n-solid-3 dark:!bg-n-alpha-2 !text-n-slate-12 text-xl transition-all duration-200 ease-out hover:brightness-110"
|
||||||
lg
|
lg
|
||||||
@click="toggleSidebar"
|
@click="toggleSidebar"
|
||||||
/>
|
/>
|
||||||
</div>
|
</ButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
<template v-else />
|
<template v-else />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
import ButtonGroup from 'dashboard/components-next/buttonGroup/ButtonGroup.vue';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
isMobileSidebarOpen: {
|
isMobileSidebarOpen: {
|
||||||
@@ -45,14 +46,17 @@ const toggleSidebar = () => {
|
|||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<div class="rounded-full bg-n-alpha-2 p-1">
|
<ButtonGroup
|
||||||
|
class="rounded-full bg-n-alpha-2 backdrop-blur-lg p-1 shadow hover:shadow-md"
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
icon="i-lucide-menu"
|
icon="i-lucide-menu"
|
||||||
class="!rounded-full !bg-n-solid-3 dark:!bg-n-alpha-2 !text-n-slate-12 text-xl"
|
no-animation
|
||||||
|
class="!rounded-full !bg-n-solid-3 dark:!bg-n-alpha-2 !text-n-slate-12 text-xl transition-all duration-200 ease-out hover:brightness-110"
|
||||||
lg
|
lg
|
||||||
@click="toggleSidebar"
|
@click="toggleSidebar"
|
||||||
/>
|
/>
|
||||||
</div>
|
</ButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
<template v-else />
|
<template v-else />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -221,26 +221,70 @@ const menuItems = computed(() => {
|
|||||||
name: 'Captain',
|
name: 'Captain',
|
||||||
icon: 'i-woot-captain',
|
icon: 'i-woot-captain',
|
||||||
label: t('SIDEBAR.CAPTAIN'),
|
label: t('SIDEBAR.CAPTAIN'),
|
||||||
|
activeOn: ['captain_assistants_create_index'],
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: 'Assistants',
|
name: 'FAQs',
|
||||||
label: t('SIDEBAR.CAPTAIN_ASSISTANTS'),
|
label: t('SIDEBAR.CAPTAIN_RESPONSES'),
|
||||||
to: accountScopedRoute('captain_assistants_index'),
|
activeOn: [
|
||||||
|
'captain_assistants_responses_index',
|
||||||
|
'captain_assistants_responses_pending',
|
||||||
|
],
|
||||||
|
to: accountScopedRoute('captain_assistants_index', {
|
||||||
|
navigationPath: 'captain_assistants_responses_index',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Documents',
|
name: 'Documents',
|
||||||
label: t('SIDEBAR.CAPTAIN_DOCUMENTS'),
|
label: t('SIDEBAR.CAPTAIN_DOCUMENTS'),
|
||||||
to: accountScopedRoute('captain_documents_index'),
|
activeOn: ['captain_assistants_documents_index'],
|
||||||
|
to: accountScopedRoute('captain_assistants_index', {
|
||||||
|
navigationPath: 'captain_assistants_documents_index',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Responses',
|
name: 'Scenarios',
|
||||||
label: t('SIDEBAR.CAPTAIN_RESPONSES'),
|
label: t('SIDEBAR.CAPTAIN_SCENARIOS'),
|
||||||
to: accountScopedRoute('captain_responses_index'),
|
activeOn: ['captain_assistants_scenarios_index'],
|
||||||
|
to: accountScopedRoute('captain_assistants_index', {
|
||||||
|
navigationPath: 'captain_assistants_scenarios_index',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Playground',
|
||||||
|
label: t('SIDEBAR.CAPTAIN_PLAYGROUND'),
|
||||||
|
activeOn: ['captain_assistants_playground_index'],
|
||||||
|
to: accountScopedRoute('captain_assistants_index', {
|
||||||
|
navigationPath: 'captain_assistants_playground_index',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Inboxes',
|
||||||
|
label: t('SIDEBAR.CAPTAIN_INBOXES'),
|
||||||
|
activeOn: ['captain_assistants_inboxes_index'],
|
||||||
|
to: accountScopedRoute('captain_assistants_index', {
|
||||||
|
navigationPath: 'captain_assistants_inboxes_index',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Tools',
|
name: 'Tools',
|
||||||
label: t('SIDEBAR.CAPTAIN_TOOLS'),
|
label: t('SIDEBAR.CAPTAIN_TOOLS'),
|
||||||
to: accountScopedRoute('captain_tools_index'),
|
activeOn: ['captain_tools_index'],
|
||||||
|
to: accountScopedRoute('captain_assistants_index', {
|
||||||
|
navigationPath: 'captain_tools_index',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Settings',
|
||||||
|
label: t('SIDEBAR.CAPTAIN_SETTINGS'),
|
||||||
|
activeOn: [
|
||||||
|
'captain_assistants_settings_index',
|
||||||
|
'captain_assistants_guidelines_index',
|
||||||
|
'captain_assistants_guardrails_index',
|
||||||
|
],
|
||||||
|
to: accountScopedRoute('captain_assistants_index', {
|
||||||
|
navigationPath: 'captain_assistants_settings_index',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,19 +19,46 @@ export function useSidebarContext() {
|
|||||||
return '/';
|
return '/';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper to find route definition by name without resolving
|
||||||
|
const findRouteByName = name => {
|
||||||
|
const routes = router.getRoutes();
|
||||||
|
return routes.find(route => route.name === name);
|
||||||
|
};
|
||||||
|
|
||||||
const resolvePermissions = to => {
|
const resolvePermissions = to => {
|
||||||
if (to) return router.resolve(to)?.meta?.permissions ?? [];
|
if (!to) return [];
|
||||||
return [];
|
|
||||||
|
// If navigationPath param exists, get the target route definition
|
||||||
|
if (to.params?.navigationPath) {
|
||||||
|
const targetRoute = findRouteByName(to.params.navigationPath);
|
||||||
|
return targetRoute?.meta?.permissions ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return router.resolve(to)?.meta?.permissions ?? [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveFeatureFlag = to => {
|
const resolveFeatureFlag = to => {
|
||||||
if (to) return router.resolve(to)?.meta?.featureFlag || '';
|
if (!to) return '';
|
||||||
return '';
|
|
||||||
|
// If navigationPath param exists, get the target route definition
|
||||||
|
if (to.params?.navigationPath) {
|
||||||
|
const targetRoute = findRouteByName(to.params.navigationPath);
|
||||||
|
return targetRoute?.meta?.featureFlag || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return router.resolve(to)?.meta?.featureFlag || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveInstallationType = to => {
|
const resolveInstallationType = to => {
|
||||||
if (to) return router.resolve(to)?.meta?.installationTypes || [];
|
if (!to) return [];
|
||||||
return [];
|
|
||||||
|
// If navigationPath param exists, get the target route definition
|
||||||
|
if (to.params?.navigationPath) {
|
||||||
|
const targetRoute = findRouteByName(to.params.navigationPath);
|
||||||
|
return targetRoute?.meta?.installationTypes || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return router.resolve(to)?.meta?.installationTypes || [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const isAllowed = to => {
|
const isAllowed = to => {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue';
|
import { computed, ref, onMounted, nextTick } from 'vue';
|
||||||
|
import { useResizeObserver } from '@vueuse/core';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
initialActiveTab: {
|
initialActiveTab: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -22,6 +24,32 @@ const emit = defineEmits(['tabChanged']);
|
|||||||
|
|
||||||
const activeTab = computed(() => props.initialActiveTab);
|
const activeTab = computed(() => props.initialActiveTab);
|
||||||
|
|
||||||
|
const tabRefs = ref([]);
|
||||||
|
const indicatorStyle = ref({});
|
||||||
|
const enableTransition = ref(false);
|
||||||
|
|
||||||
|
const activeElement = computed(() => tabRefs.value[activeTab.value]);
|
||||||
|
|
||||||
|
const updateIndicator = () => {
|
||||||
|
if (!activeElement.value) return;
|
||||||
|
|
||||||
|
indicatorStyle.value = {
|
||||||
|
left: `${activeElement.value.offsetLeft}px`,
|
||||||
|
width: `${activeElement.value.offsetWidth}px`,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
useResizeObserver(activeElement, () => {
|
||||||
|
if (enableTransition.value || !activeElement.value) updateIndicator();
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
updateIndicator();
|
||||||
|
nextTick(() => {
|
||||||
|
enableTransition.value = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const selectTab = index => {
|
const selectTab = index => {
|
||||||
emit('tabChanged', props.tabs[index]);
|
emit('tabChanged', props.tabs[index]);
|
||||||
};
|
};
|
||||||
@@ -37,20 +65,30 @@ const showDivider = index => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex items-center h-8 rounded-lg bg-n-alpha-1 w-fit">
|
<div
|
||||||
|
class="relative flex items-center h-8 rounded-lg bg-n-alpha-1 w-fit transition-all duration-200 ease-out has-[button:active]:scale-[1.01]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="absolute rounded-lg bg-n-solid-active shadow-sm pointer-events-none h-8 outline-1 outline outline-n-container inset-y-0"
|
||||||
|
:class="{ 'transition-all duration-300 ease-out': enableTransition }"
|
||||||
|
:style="indicatorStyle"
|
||||||
|
/>
|
||||||
|
|
||||||
<template v-for="(tab, index) in tabs" :key="index">
|
<template v-for="(tab, index) in tabs" :key="index">
|
||||||
<button
|
<button
|
||||||
class="relative px-4 truncate py-1.5 text-sm border-0 outline-1 outline rounded-lg transition-colors duration-300 ease-in-out hover:text-n-brand"
|
:ref="el => (tabRefs[index] = el)"
|
||||||
|
class="relative z-10 px-4 truncate py-1.5 text-sm border-0 outline-1 outline-transparent rounded-lg transition-all duration-200 ease-out hover:text-n-brand active:scale-[1.02]"
|
||||||
:class="[
|
:class="[
|
||||||
activeTab === index
|
activeTab === index
|
||||||
? 'text-n-blue-text bg-n-solid-active outline-n-container dark:outline-transparent'
|
? 'text-n-blue-text scale-100'
|
||||||
: 'text-n-slate-10 outline-transparent h-8',
|
: 'text-n-slate-10 scale-[0.98]',
|
||||||
]"
|
]"
|
||||||
@click="selectTab(index)"
|
@click="selectTab(index)"
|
||||||
>
|
>
|
||||||
{{ tab.label }} {{ tab.count ? `(${tab.count})` : '' }}
|
{{ tab.label }} {{ tab.count ? `(${tab.count})` : '' }}
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
|
v-if="index < tabs.length - 1"
|
||||||
class="w-px h-3.5 rounded my-auto transition-colors duration-300 ease-in-out"
|
class="w-px h-3.5 rounded my-auto transition-colors duration-300 ease-in-out"
|
||||||
:class="
|
:class="
|
||||||
showDivider(index)
|
showDivider(index)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
CMD_RESOLVE_CONVERSATION,
|
CMD_RESOLVE_CONVERSATION,
|
||||||
} from 'dashboard/helper/commandbar/events';
|
} from 'dashboard/helper/commandbar/events';
|
||||||
|
|
||||||
|
import ButtonGroup from 'dashboard/components-next/buttonGroup/ButtonGroup.vue';
|
||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@@ -133,7 +134,7 @@ useEmitter(CMD_RESOLVE_CONVERSATION, onCmdResolveConversation);
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="relative flex items-center justify-end resolve-actions">
|
<div class="relative flex items-center justify-end resolve-actions">
|
||||||
<div
|
<ButtonGroup
|
||||||
class="rounded-lg shadow outline-1 outline flex-shrink-0"
|
class="rounded-lg shadow outline-1 outline flex-shrink-0"
|
||||||
:class="!showOpenButton ? 'outline-n-container' : 'outline-transparent'"
|
:class="!showOpenButton ? 'outline-n-container' : 'outline-transparent'"
|
||||||
>
|
>
|
||||||
@@ -142,6 +143,7 @@ useEmitter(CMD_RESOLVE_CONVERSATION, onCmdResolveConversation);
|
|||||||
:label="t('CONVERSATION.HEADER.RESOLVE_ACTION')"
|
:label="t('CONVERSATION.HEADER.RESOLVE_ACTION')"
|
||||||
size="sm"
|
size="sm"
|
||||||
color="slate"
|
color="slate"
|
||||||
|
no-animation
|
||||||
class="ltr:rounded-r-none rtl:rounded-l-none !outline-0"
|
class="ltr:rounded-r-none rtl:rounded-l-none !outline-0"
|
||||||
:is-loading="isLoading"
|
:is-loading="isLoading"
|
||||||
@click="onCmdResolveConversation"
|
@click="onCmdResolveConversation"
|
||||||
@@ -151,6 +153,7 @@ useEmitter(CMD_RESOLVE_CONVERSATION, onCmdResolveConversation);
|
|||||||
:label="t('CONVERSATION.HEADER.REOPEN_ACTION')"
|
:label="t('CONVERSATION.HEADER.REOPEN_ACTION')"
|
||||||
size="sm"
|
size="sm"
|
||||||
color="slate"
|
color="slate"
|
||||||
|
no-animation
|
||||||
class="ltr:rounded-r-none rtl:rounded-l-none !outline-0"
|
class="ltr:rounded-r-none rtl:rounded-l-none !outline-0"
|
||||||
:is-loading="isLoading"
|
:is-loading="isLoading"
|
||||||
@click="onCmdOpenConversation"
|
@click="onCmdOpenConversation"
|
||||||
@@ -160,6 +163,7 @@ useEmitter(CMD_RESOLVE_CONVERSATION, onCmdResolveConversation);
|
|||||||
:label="t('CONVERSATION.HEADER.OPEN_ACTION')"
|
:label="t('CONVERSATION.HEADER.OPEN_ACTION')"
|
||||||
size="sm"
|
size="sm"
|
||||||
color="slate"
|
color="slate"
|
||||||
|
no-animation
|
||||||
:is-loading="isLoading"
|
:is-loading="isLoading"
|
||||||
@click="onCmdOpenConversation"
|
@click="onCmdOpenConversation"
|
||||||
/>
|
/>
|
||||||
@@ -169,12 +173,13 @@ useEmitter(CMD_RESOLVE_CONVERSATION, onCmdResolveConversation);
|
|||||||
icon="i-lucide-chevron-down"
|
icon="i-lucide-chevron-down"
|
||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
no-animation
|
||||||
class="ltr:rounded-l-none rtl:rounded-r-none !outline-0"
|
class="ltr:rounded-l-none rtl:rounded-r-none !outline-0"
|
||||||
color="slate"
|
color="slate"
|
||||||
trailing-icon
|
trailing-icon
|
||||||
@click="openDropdown"
|
@click="openDropdown"
|
||||||
/>
|
/>
|
||||||
</div>
|
</ButtonGroup>
|
||||||
<div
|
<div
|
||||||
v-if="showActionsDropdown"
|
v-if="showActionsDropdown"
|
||||||
v-on-clickaway="closeDropdown"
|
v-on-clickaway="closeDropdown"
|
||||||
|
|||||||
@@ -302,7 +302,16 @@ function isBodyEmpty(content) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleEmptyBodyWithSignature() {
|
function handleEmptyBodyWithSignature() {
|
||||||
const { schema, tr } = state;
|
const { schema, tr, doc } = state;
|
||||||
|
|
||||||
|
const isEmptyParagraph = node =>
|
||||||
|
node && node.type === schema.nodes.paragraph && node.content.size === 0;
|
||||||
|
|
||||||
|
// Check if empty paragraph already exists to prevent duplicates when toggling signatures
|
||||||
|
if (isEmptyParagraph(doc.firstChild)) {
|
||||||
|
focusEditorInputField('start');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// create a paragraph node and
|
// create a paragraph node and
|
||||||
// start a transaction to append it at the end
|
// start a transaction to append it at the end
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ const translateValue = computed(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
class="flex items-center w-auto h-8 p-1 transition-all border rounded-full bg-n-alpha-2 group relative duration-300 ease-in-out z-0"
|
class="flex items-center w-auto h-8 p-1 transition-all border rounded-full bg-n-alpha-2 group relative duration-300 ease-in-out z-0 active:scale-[0.995] active:duration-75"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:class="{
|
:class="{
|
||||||
'cursor-not-allowed': disabled,
|
'cursor-not-allowed': disabled,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
} from 'dashboard/constants/automation';
|
} from 'dashboard/constants/automation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a shared composables that holds utilites used to build dropdown and file options
|
* This is a shared composables that holds utilities used to build dropdown and file options
|
||||||
* @returns {Object} An object containing various automation-related functions and computed properties.
|
* @returns {Object} An object containing various automation-related functions and computed properties.
|
||||||
*/
|
*/
|
||||||
export default function useAutomationValues() {
|
export default function useAutomationValues() {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const initializeAudioAlerts = user => {
|
|||||||
enable_audio_alerts: audioAlertType,
|
enable_audio_alerts: audioAlertType,
|
||||||
alert_if_unread_assigned_conversation_exist: alertIfUnreadConversationExist,
|
alert_if_unread_assigned_conversation_exist: alertIfUnreadConversationExist,
|
||||||
notification_tone: audioAlertTone,
|
notification_tone: audioAlertTone,
|
||||||
// UI Settings can be undefined initally as we don't send the
|
// UI Settings can be undefined initially as we don't send the
|
||||||
// entire payload for the user during the signup process.
|
// entire payload for the user during the signup process.
|
||||||
} = uiSettings || {};
|
} = uiSettings || {};
|
||||||
|
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "حذف",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "حذف جهة الاتصال"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Изтрий",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Изтриване на контакта"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Esborrar",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Contacte esborrat"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Vymazat",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Slet",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Slet kontakt"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Löschen",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Kontakt löschen"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Διαγραφή",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Διαγραφή Επαφής"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -341,6 +341,11 @@
|
|||||||
"CAPTAIN": {
|
"CAPTAIN": {
|
||||||
"NAME": "Captain",
|
"NAME": "Captain",
|
||||||
"HEADER_KNOW_MORE": "Know more",
|
"HEADER_KNOW_MORE": "Know more",
|
||||||
|
"ASSISTANT_SWITCHER": {
|
||||||
|
"ASSISTANTS": "Assistants",
|
||||||
|
"SWITCH_ASSISTANT": "Switch between assistants",
|
||||||
|
"NEW_ASSISTANT": "Create Assistant"
|
||||||
|
},
|
||||||
"COPILOT": {
|
"COPILOT": {
|
||||||
"TITLE": "Copilot",
|
"TITLE": "Copilot",
|
||||||
"TRY_THESE_PROMPTS": "Try these prompts",
|
"TRY_THESE_PROMPTS": "Try these prompts",
|
||||||
@@ -480,9 +485,7 @@
|
|||||||
"NOT_FOUND": "Could not find the assistant. Please try again."
|
"NOT_FOUND": "Could not find the assistant. Please try again."
|
||||||
},
|
},
|
||||||
"SETTINGS": {
|
"SETTINGS": {
|
||||||
"BREADCRUMB": {
|
"HEADER": "Settings",
|
||||||
"ASSISTANT": "Assistant"
|
|
||||||
},
|
|
||||||
"BASIC_SETTINGS": {
|
"BASIC_SETTINGS": {
|
||||||
"TITLE": "Basic settings",
|
"TITLE": "Basic settings",
|
||||||
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
|
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
|
||||||
@@ -499,15 +502,16 @@
|
|||||||
"TITLE": "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."
|
"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": {
|
"RESPONSE_GUIDELINES": {
|
||||||
"TITLE": "Response guidelines",
|
"TITLE": "Response guidelines",
|
||||||
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
|
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"DELETE": {
|
||||||
|
"TITLE": "Delete Assistant",
|
||||||
|
"DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
|
||||||
|
"BUTTON_TEXT": "Delete {assistantName}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"OPTIONS": {
|
"OPTIONS": {
|
||||||
@@ -526,9 +530,6 @@
|
|||||||
"GUARDRAILS": {
|
"GUARDRAILS": {
|
||||||
"TITLE": "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.",
|
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
|
||||||
"BREADCRUMB": {
|
|
||||||
"TITLE": "Guardrails"
|
|
||||||
},
|
|
||||||
"BULK_ACTION": {
|
"BULK_ACTION": {
|
||||||
"SELECTED": "{count} item selected | {count} items selected",
|
"SELECTED": "{count} item selected | {count} items selected",
|
||||||
"SELECT_ALL": "Select all ({count})",
|
"SELECT_ALL": "Select all ({count})",
|
||||||
@@ -574,9 +575,6 @@
|
|||||||
"RESPONSE_GUIDELINES": {
|
"RESPONSE_GUIDELINES": {
|
||||||
"TITLE": "Response Guidelines",
|
"TITLE": "Response Guidelines",
|
||||||
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
|
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
|
||||||
"BREADCRUMB": {
|
|
||||||
"TITLE": "Response Guidelines"
|
|
||||||
},
|
|
||||||
"BULK_ACTION": {
|
"BULK_ACTION": {
|
||||||
"SELECTED": "{count} item selected | {count} items selected",
|
"SELECTED": "{count} item selected | {count} items selected",
|
||||||
"SELECT_ALL": "Select all ({count})",
|
"SELECT_ALL": "Select all ({count})",
|
||||||
@@ -622,9 +620,6 @@
|
|||||||
"SCENARIOS": {
|
"SCENARIOS": {
|
||||||
"TITLE": "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.”",
|
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
|
||||||
"BREADCRUMB": {
|
|
||||||
"TITLE": "Scenarios"
|
|
||||||
},
|
|
||||||
"BULK_ACTION": {
|
"BULK_ACTION": {
|
||||||
"SELECTED": "{count} item selected | {count} items selected",
|
"SELECTED": "{count} item selected | {count} items selected",
|
||||||
"SELECT_ALL": "Select all ({count})",
|
"SELECT_ALL": "Select all ({count})",
|
||||||
@@ -722,11 +717,6 @@
|
|||||||
"NAME": {
|
"NAME": {
|
||||||
"LABEL": "Document Name (Optional)",
|
"LABEL": "Document Name (Optional)",
|
||||||
"PLACEHOLDER": "Enter a name for the document"
|
"PLACEHOLDER": "Enter a name for the document"
|
||||||
},
|
|
||||||
"ASSISTANT": {
|
|
||||||
"LABEL": "Assistant",
|
|
||||||
"PLACEHOLDER": "Select the assistant",
|
|
||||||
"ERROR": "The assistant field is required"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"DELETE": {
|
"DELETE": {
|
||||||
@@ -921,12 +911,6 @@
|
|||||||
"LABEL": "Answer",
|
"LABEL": "Answer",
|
||||||
"PLACEHOLDER": "Enter the answer here",
|
"PLACEHOLDER": "Enter the answer here",
|
||||||
"ERROR": "Please provide a valid answer."
|
"ERROR": "Please provide a valid answer."
|
||||||
},
|
|
||||||
|
|
||||||
"ASSISTANT": {
|
|
||||||
"LABEL": "Assistant",
|
|
||||||
"PLACEHOLDER": "Select an assistant",
|
|
||||||
"ERROR": "Please select an assistant."
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"EDIT": {
|
"EDIT": {
|
||||||
|
|||||||
@@ -251,6 +251,12 @@
|
|||||||
"ACCOUNT_SUSPENDED": {
|
"ACCOUNT_SUSPENDED": {
|
||||||
"TITLE": "Account Suspended",
|
"TITLE": "Account Suspended",
|
||||||
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
|
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
|
||||||
|
},
|
||||||
|
"NO_ACCOUNTS": {
|
||||||
|
"TITLE": "No account found",
|
||||||
|
"MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
|
||||||
|
"MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
|
||||||
|
"LOGOUT": "Log out"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"COMPONENTS": {
|
"COMPONENTS": {
|
||||||
@@ -305,6 +311,10 @@
|
|||||||
"CAPTAIN_DOCUMENTS": "Documents",
|
"CAPTAIN_DOCUMENTS": "Documents",
|
||||||
"CAPTAIN_RESPONSES": "FAQs",
|
"CAPTAIN_RESPONSES": "FAQs",
|
||||||
"CAPTAIN_TOOLS": "Tools",
|
"CAPTAIN_TOOLS": "Tools",
|
||||||
|
"CAPTAIN_SCENARIOS": "Scenarios",
|
||||||
|
"CAPTAIN_PLAYGROUND": "Playground",
|
||||||
|
"CAPTAIN_INBOXES": "Inboxes",
|
||||||
|
"CAPTAIN_SETTINGS": "Settings",
|
||||||
"HOME": "Home",
|
"HOME": "Home",
|
||||||
"AGENTS": "Agents",
|
"AGENTS": "Agents",
|
||||||
"AGENT_BOTS": "Bots",
|
"AGENT_BOTS": "Bots",
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Eliminar",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Eliminar contacto"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "حذف",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "حذف مخاطب"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Poista",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Poista yhteystieto"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Supprimer",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Supprimer le contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "מחק",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "מחק איש קשר"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Izbriši",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Törlés",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Kontakt törlése"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Hapus",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Hapus kontak"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Eyða",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Eyða tengilið"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"BROWSER": "Browser",
|
"BROWSER": "Browser",
|
||||||
"OS": "Sistema Operativo",
|
"OS": "Sistema Operativo",
|
||||||
"INITIATED_FROM": "Iniziato da",
|
"INITIATED_FROM": "Iniziato da",
|
||||||
"INITIATED_AT": "Iniziato alle",
|
"INITIATED_AT": "Avviata alle",
|
||||||
"IP_ADDRESS": "Indirizzo IP",
|
"IP_ADDRESS": "Indirizzo IP",
|
||||||
"CREATED_AT_LABEL": "Creato il",
|
"CREATED_AT_LABEL": "Creato il",
|
||||||
"NEW_MESSAGE": "Nuovo messaggio",
|
"NEW_MESSAGE": "Nuovo messaggio",
|
||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "Nessuna etichetta disponibile.",
|
"NO_LABELS_FOUND": "Nessuna etichetta disponibile.",
|
||||||
"SELECTED_COUNT": "{count} selezionate",
|
"SELECTED_COUNT": "{count} selezionate",
|
||||||
"CLEAR_SELECTION": "Annulla selezione",
|
"CLEAR_SELECTION": "Annulla selezione",
|
||||||
"SELECT_ALL": "Seleziona tutto ({count})"
|
"SELECT_ALL": "Seleziona tutto ({count})",
|
||||||
|
"DELETE_CONTACTS": "Elimina",
|
||||||
|
"DELETE_SUCCESS": "Contatti eliminati con successo.",
|
||||||
|
"DELETE_FAILED": "Impossibile eliminare i contatti.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Elimina i contatti selezionati",
|
||||||
|
"SINGULAR_TITLE": "Elimina il contatto selezionato",
|
||||||
|
"DESCRIPTION": "Questo eliminerà definitivamente i {count} contatti selezionati. Questa azione non può essere annullata.",
|
||||||
|
"SINGULAR_DESCRIPTION": "Questo eliminerà definitivamente il contatto selezionato. Questa azione non può essere annullata.",
|
||||||
|
"CONFIRM_MULTIPLE": "Elimina contatti",
|
||||||
|
"CONFIRM_SINGLE": "Elimina contatto"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"CONVERSATION": {
|
"CONVERSATION": {
|
||||||
"SELECT_A_CONVERSATION": "Si prega di selezionare una conversazione dal pannello a sinistra",
|
"SELECT_A_CONVERSATION": "Seleziona una conversazione dal pannello a sinistra",
|
||||||
"CSAT_REPLY_MESSAGE": "Valuta la conversazione",
|
"CSAT_REPLY_MESSAGE": "Valuta la conversazione",
|
||||||
"404": "Siamo spiacenti, non siamo riusciti a trovare la conversazione. Riprova",
|
"404": "Siamo spiacenti, non siamo riusciti a trovare la conversazione. Riprova",
|
||||||
"SWITCH_VIEW_LAYOUT": "Cambia layout",
|
"SWITCH_VIEW_LAYOUT": "Cambia layout",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"LOADING": "Caricamento notifiche",
|
"LOADING": "Caricamento notifiche",
|
||||||
"404": "Non ci sono notifiche attive in questo gruppo.",
|
"404": "Non ci sono notifiche attive in questo gruppo.",
|
||||||
"NO_NOTIFICATIONS": "Nessuna notifica",
|
"NO_NOTIFICATIONS": "Nessuna notifica",
|
||||||
"NOTE": "Notifiche da tutte le inbox sottoscritte",
|
"NOTE": "Notifiche da tutte le Inbox",
|
||||||
"NO_MESSAGES_AVAILABLE": "Oops! Impossibile recuperare i messaggi",
|
"NO_MESSAGES_AVAILABLE": "Oops! Impossibile recuperare i messaggi",
|
||||||
"SNOOZED_UNTIL": "Posticipata fino a",
|
"SNOOZED_UNTIL": "Posticipata fino a",
|
||||||
"SNOOZED_UNTIL_TOMORROW": "Posticipata fino a domani",
|
"SNOOZED_UNTIL_TOMORROW": "Posticipata fino a domani",
|
||||||
@@ -45,8 +45,8 @@
|
|||||||
"MARK_AS_UNREAD": "Segna come da leggere",
|
"MARK_AS_UNREAD": "Segna come da leggere",
|
||||||
"SNOOZE": "Posticipa",
|
"SNOOZE": "Posticipa",
|
||||||
"DELETE": "Elimina",
|
"DELETE": "Elimina",
|
||||||
"MARK_ALL_READ": "Segna tutto come letto",
|
"MARK_ALL_READ": "Segna tutte come lette",
|
||||||
"DELETE_ALL": "Elimina tutto",
|
"DELETE_ALL": "Elimina tutte",
|
||||||
"DELETE_ALL_READ": "Elimina tutte le lette"
|
"DELETE_ALL_READ": "Elimina tutte le lette"
|
||||||
},
|
},
|
||||||
"DISPLAY_MENU": {
|
"DISPLAY_MENU": {
|
||||||
|
|||||||
@@ -252,7 +252,7 @@
|
|||||||
},
|
},
|
||||||
"BUSINESS_ACCOUNT_ID": {
|
"BUSINESS_ACCOUNT_ID": {
|
||||||
"LABEL": "ID Account Business",
|
"LABEL": "ID Account Business",
|
||||||
"PLACEHOLDER": "Si prega di inserire l'ID dell'account business ottenuto dalla dashboard sviluppatore di Facebook.",
|
"PLACEHOLDER": "Inserisci l'ID dell'Account Business ottenuto dalla dashboard sviluppatore di Facebook.",
|
||||||
"ERROR": "Inserisci un valore valido."
|
"ERROR": "Inserisci un valore valido."
|
||||||
},
|
},
|
||||||
"WEBHOOK_VERIFY_TOKEN": {
|
"WEBHOOK_VERIFY_TOKEN": {
|
||||||
|
|||||||
@@ -107,7 +107,7 @@
|
|||||||
},
|
},
|
||||||
"HELP_TEXT": {
|
"HELP_TEXT": {
|
||||||
"TITLE": "Stai utilizzando l'integrazione Slack",
|
"TITLE": "Stai utilizzando l'integrazione Slack",
|
||||||
"BODY": "Con questa integrazione, tutte le conversazioni in arrivo verranno sincronizzate nel canale ***{selectedChannelName}*** del tuo workspace Slack. Potrai gestire tutte le conversazioni con i clienti direttamente dal canale e non perderai mai un messaggio.\n\nEcco le principali funzionalità dell’integrazione:\n\n**Rispondi alle conversazioni direttamente da Slack:** Per rispondere a una conversazione nel canale Slack ***{selectedChannelName}***, ti basta scrivere il tuo messaggio e inviarlo come thread. Questo genererà automaticamente una risposta al cliente tramite Chatwoot. Semplice, no?\n\n**Crea note private:** Se vuoi aggiungere note private invece di risposte, inizia il messaggio con ***`note:`***. In questo modo il messaggio resterà privato e non sarà visibile al cliente.\n\n**Associa un profilo operatore:** Se la persona che risponde su Slack ha un profilo operatore in Chatwoot con lo stesso indirizzo email, le risposte verranno associate automaticamente a quel profilo. In questo modo potrai sapere facilmente chi ha risposto e quando. Se invece chi risponde non ha un profilo operatore associato, le risposte verranno inviate al cliente dal profilo del bot.",
|
"BODY": "Con questa integrazione, tutte le conversazioni in arrivo verranno sincronizzate nel canale ***{selectedChannelName}*** del tuo workspace Slack. Potrai gestire tutte le conversazioni con i clienti direttamente dal canale e non perderai mai un messaggio.\n\nEcco le principali funzionalità dell’integrazione:\n\n**Rispondi alle conversazioni direttamente da Slack:** Per rispondere a una conversazione nel canale Slack ***{selectedChannelName}***, ti basta scrivere il tuo messaggio e inviarlo come thread. Questo genererà automaticamente una risposta al cliente tramite Chatwoot. Semplice, no?\n\n**Crea note private:** Se vuoi aggiungere note private invece di risposte, inizia il messaggio con ***`note:`***. In questo modo il messaggio resterà privato e non sarà visibile al cliente.\n\n**Associa un profilo operatore:** Se la persona che risponde su Slack ha un profilo operatore in app con lo stesso indirizzo email, le risposte verranno associate automaticamente a quel profilo. In questo modo potrai sapere facilmente chi ha risposto e quando. Se invece chi risponde non ha un profilo operatore associato, le risposte verranno inviate al cliente dal profilo del bot.",
|
||||||
"SELECTED": "selezionato"
|
"SELECTED": "selezionato"
|
||||||
},
|
},
|
||||||
"SELECT_CHANNEL": {
|
"SELECT_CHANNEL": {
|
||||||
@@ -472,7 +472,7 @@
|
|||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"TITLE": "Funzionalità",
|
"TITLE": "Funzionalità",
|
||||||
"ALLOW_CONVERSATION_FAQS": "Genera FAQ dalle conversazioni risolte",
|
"ALLOW_CONVERSATION_FAQS": "Genera FAQ dalle conversazioni risolte",
|
||||||
"ALLOW_MEMORIES": "Cattura i dettagli chiave come memorie dalle interazioni con i clienti.",
|
"ALLOW_MEMORIES": "Salva memorie e dettagli chiave dalle interazioni con i clienti.",
|
||||||
"ALLOW_CITATIONS": "Includi citazioni alle fonti nelle risposte"
|
"ALLOW_CITATIONS": "Includi citazioni alle fonti nelle risposte"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -694,8 +694,8 @@
|
|||||||
"HEADER": "Documents",
|
"HEADER": "Documents",
|
||||||
"ADD_NEW": "Create a new document",
|
"ADD_NEW": "Create a new document",
|
||||||
"RELATED_RESPONSES": {
|
"RELATED_RESPONSES": {
|
||||||
"TITLE": "Related FAQs",
|
"TITLE": "FAQ Correlate",
|
||||||
"DESCRIPTION": "These FAQs are generated directly from the document."
|
"DESCRIPTION": "Queste FAQ vengono generate direttamente dai Documenti."
|
||||||
},
|
},
|
||||||
"FORM_DESCRIPTION": "Enter the URL of the document to add it as a knowledge source and choose the assistant to associate it with.",
|
"FORM_DESCRIPTION": "Enter the URL of the document to add it as a knowledge source and choose the assistant to associate it with.",
|
||||||
"CREATE": {
|
"CREATE": {
|
||||||
@@ -740,7 +740,7 @@
|
|||||||
"ERROR_MESSAGE": "Si è verificato un errore durante l'eliminazione del documento, riprova."
|
"ERROR_MESSAGE": "Si è verificato un errore durante l'eliminazione del documento, riprova."
|
||||||
},
|
},
|
||||||
"OPTIONS": {
|
"OPTIONS": {
|
||||||
"VIEW_RELATED_RESPONSES": "Visualizza Risposte Correlate",
|
"VIEW_RELATED_RESPONSES": "Visualizza FAQ Correlate",
|
||||||
"DELETE_DOCUMENT": "Elimina Documento"
|
"DELETE_DOCUMENT": "Elimina Documento"
|
||||||
},
|
},
|
||||||
"EMPTY_STATE": {
|
"EMPTY_STATE": {
|
||||||
@@ -895,7 +895,7 @@
|
|||||||
"FILTER": {
|
"FILTER": {
|
||||||
"ASSISTANT": "Assistente: {selected}",
|
"ASSISTANT": "Assistente: {selected}",
|
||||||
"STATUS": "Stato: {selected}",
|
"STATUS": "Stato: {selected}",
|
||||||
"ALL_ASSISTANTS": "Tutte"
|
"ALL_ASSISTANTS": "Tutti"
|
||||||
},
|
},
|
||||||
"STATUS": {
|
"STATUS": {
|
||||||
"TITLE": "Stato",
|
"TITLE": "Stato",
|
||||||
|
|||||||
@@ -193,7 +193,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"LABEL_REPORTS": {
|
"LABEL_REPORTS": {
|
||||||
"HEADER": "Panoramica etichette",
|
"HEADER": "Panoramica Etichette",
|
||||||
"DESCRIPTION": "Monitora la performance delle etichette con metriche chiave, tra cui conversazioni, tempi di risposta, tempi di risoluzione e casi risolti. Fai clic sul nome di un'etichetta per approfondimenti dettagliati.",
|
"DESCRIPTION": "Monitora la performance delle etichette con metriche chiave, tra cui conversazioni, tempi di risposta, tempi di risoluzione e casi risolti. Fai clic sul nome di un'etichetta per approfondimenti dettagliati.",
|
||||||
"LOADING_CHART": "Caricamento dati grafici...",
|
"LOADING_CHART": "Caricamento dati grafici...",
|
||||||
"NO_ENOUGH_DATA": "Non ci sono abbastanza dati per generare il report, riprova più tardi.",
|
"NO_ENOUGH_DATA": "Non ci sono abbastanza dati per generare il report, riprova più tardi.",
|
||||||
@@ -331,7 +331,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"TEAM_REPORTS": {
|
"TEAM_REPORTS": {
|
||||||
"HEADER": "Panoramica team",
|
"HEADER": "Panoramica Team",
|
||||||
"DESCRIPTION": "Ottieni un'istantanea delle prestazioni del tuo team con metriche essenziali, tra cui conversazioni, tempi di risposta, tempi di risoluzione e casi risolti. Fare clic su un nome del team per maggiori dettagli.",
|
"DESCRIPTION": "Ottieni un'istantanea delle prestazioni del tuo team con metriche essenziali, tra cui conversazioni, tempi di risposta, tempi di risoluzione e casi risolti. Fare clic su un nome del team per maggiori dettagli.",
|
||||||
"LOADING_CHART": "Caricamento dati grafici...",
|
"LOADING_CHART": "Caricamento dati grafici...",
|
||||||
"NO_ENOUGH_DATA": "Non ci sono abbastanza dati per generare il report, riprova più tardi.",
|
"NO_ENOUGH_DATA": "Non ci sono abbastanza dati per generare il report, riprova più tardi.",
|
||||||
@@ -399,7 +399,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CSAT_REPORTS": {
|
"CSAT_REPORTS": {
|
||||||
"HEADER": "Rapporti CSAT",
|
"HEADER": "Report CSAT",
|
||||||
"NO_RECORDS": "Non ci sono risposte ai sondaggi CSAT disponibili.",
|
"NO_RECORDS": "Non ci sono risposte ai sondaggi CSAT disponibili.",
|
||||||
"DOWNLOAD": "Scarica report CSAT",
|
"DOWNLOAD": "Scarica report CSAT",
|
||||||
"DOWNLOAD_FAILED": "Download dei report CSAT non riuscito",
|
"DOWNLOAD_FAILED": "Download dei report CSAT non riuscito",
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "削除",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "連絡先を削除"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "삭제",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "연락처 지우기"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Ištrinti",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Trinti kontaktą"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "Atlasīti {count}",
|
"SELECTED_COUNT": "Atlasīti {count}",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Dzēst",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Dzēst kontaktpersonu"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "ഇല്ലാതാക്കുക",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "കോൺടാക്റ്റ് ഇല്ലാതാക്കുക"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Padamkan",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Verwijderen",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Contactpersoon verwijderen"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Slett",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Usuń",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Usuń kontakt"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Selecionar todas ({count})"
|
"SELECT_ALL": "Selecionar todas ({count})",
|
||||||
|
"DELETE_CONTACTS": "Excluir",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Excluir contacto"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selecionado",
|
"SELECTED_COUNT": "{count} selecionado",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Selecionar todos ({count})"
|
"SELECT_ALL": "Selecionar todos ({count})",
|
||||||
|
"DELETE_CONTACTS": "Excluir",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Excluir contato"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Şterge",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Șterge contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "Выбрано {count}",
|
"SELECTED_COUNT": "Выбрано {count}",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Выбрать все ({count})"
|
"SELECT_ALL": "Выбрать все ({count})",
|
||||||
|
"DELETE_CONTACTS": "Удалить",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Удалить контакт"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Vymazať",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Vymazať kontakt"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Izbriši",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Obriši kontakt"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Radera",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Ta bort kontakt"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "ลบ",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "ลบผู้ติดต่อ"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -578,8 +578,19 @@
|
|||||||
"DESCRIPTION": "Select the labels you want to add to the selected contacts.",
|
"DESCRIPTION": "Select the labels you want to add to the selected contacts.",
|
||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Seçimi temizle",
|
||||||
"SELECT_ALL": "Tümünü seç ({count})"
|
"SELECT_ALL": "Tümünü seç ({count})",
|
||||||
|
"DELETE_CONTACTS": "Sil",
|
||||||
|
"DELETE_SUCCESS": "Kişiler başarıyla silindi.",
|
||||||
|
"DELETE_FAILED": "Kişiler silinemedi.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Seçilen kişileri sil",
|
||||||
|
"SINGULAR_TITLE": "Seçilen kişiyi sil",
|
||||||
|
"DESCRIPTION": "Bu işlem, seçilen {count} kişileri kalıcı olarak silecektir. Bu eylem geri alınamaz.",
|
||||||
|
"SINGULAR_DESCRIPTION": "Bu işlem, seçilen kişiyi kalıcı olarak silecektir. Bu eylem geri alınamaz.",
|
||||||
|
"CONFIRM_MULTIPLE": "Kişileri sil",
|
||||||
|
"CONFIRM_SINGLE": "Kişiyi Sil"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
"LOADING_CONVERSATIONS": "Sohbetler Yükleniyor\n",
|
"LOADING_CONVERSATIONS": "Sohbetler Yükleniyor\n",
|
||||||
"CANNOT_REPLY": "Nedeniyle cevap veremezsiniz",
|
"CANNOT_REPLY": "Nedeniyle cevap veremezsiniz",
|
||||||
"24_HOURS_WINDOW": "24 saat mesaj penceresi kısıtlaması",
|
"24_HOURS_WINDOW": "24 saat mesaj penceresi kısıtlaması",
|
||||||
"API_HOURS_WINDOW": "Bu sohbete yalnızca {hours} saat içinde yanıt verebilirsiniz",
|
"API_HOURS_WINDOW": "Bu konuşmaya yalnızca {hours} saat içinde cevap verebilirsiniz",
|
||||||
"NOT_ASSIGNED_TO_YOU": "Bu görüşme size atanmamış. Bu konuşmayı kendinize atamak ister misiniz?",
|
"NOT_ASSIGNED_TO_YOU": "Bu görüşme size atanmamış. Bu konuşmayı kendinize atamak ister misiniz?",
|
||||||
"ASSIGN_TO_ME": "Bana ata",
|
"ASSIGN_TO_ME": "Bana ata",
|
||||||
"BOT_HANDOFF_MESSAGE": "Şu anda bir asistan veya bot tarafından yürütülen bir konuşmaya yanıt veriyorsunuz.",
|
"BOT_HANDOFF_MESSAGE": "Şu anda bir asistan veya bot tarafından yürütülen bir konuşmaya yanıt veriyorsunuz.",
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
"BOT_HANDOFF_ERROR": "Konuşma devralınamadı. Lütfen tekrar deneyin.",
|
"BOT_HANDOFF_ERROR": "Konuşma devralınamadı. Lütfen tekrar deneyin.",
|
||||||
"TWILIO_WHATSAPP_CAN_REPLY": "Bu konuşmaya yalnızca şablon mesaj kullanarak yanıt verebilirsiniz, çünkü",
|
"TWILIO_WHATSAPP_CAN_REPLY": "Bu konuşmaya yalnızca şablon mesaj kullanarak yanıt verebilirsiniz, çünkü",
|
||||||
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 saat mesaj penceresi kısıtlaması",
|
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 saat mesaj penceresi kısıtlaması",
|
||||||
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "Bu Instagram hesabı yeni Instagram kanal gelen kutusuna taşındı. Tüm yeni mesajlar orada görünecek. Bu sohbetten artık mesaj gönderemezsiniz.",
|
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "Bu Instagram hesabı, yeni Instagram kanal gelen kutusuna taşındı. Tüm yeni mesajlar orada görünecektir. Artık bu konuşmadan mesaj gönderemeyeceksiniz.",
|
||||||
"REPLYING_TO": "Cevap veriyorsun:",
|
"REPLYING_TO": "Cevap veriyorsun:",
|
||||||
"REMOVE_SELECTION": "Seçimi Kaldır",
|
"REMOVE_SELECTION": "Seçimi Kaldır",
|
||||||
"DOWNLOAD": "İndir",
|
"DOWNLOAD": "İndir",
|
||||||
@@ -139,8 +139,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"DELETE_CONVERSATION": {
|
"DELETE_CONVERSATION": {
|
||||||
"TITLE": "#{conversationId} numaralı sohbeti sil",
|
"TITLE": "#{conversationId} numaralı konuşmayı sil",
|
||||||
"DESCRIPTION": "Bu sohbeti silmek istediğinizden emin misiniz?",
|
"DESCRIPTION": "Bu konuşmayı silmek istediğinizden emin misiniz?",
|
||||||
"CONFIRM": "Sil"
|
"CONFIRM": "Sil"
|
||||||
},
|
},
|
||||||
"CARD_CONTEXT_MENU": {
|
"CARD_CONTEXT_MENU": {
|
||||||
@@ -159,7 +159,7 @@
|
|||||||
"ASSIGN_LABEL": "Etiket ata",
|
"ASSIGN_LABEL": "Etiket ata",
|
||||||
"AGENTS_LOADING": "Temsilciler Yükleniyor...",
|
"AGENTS_LOADING": "Temsilciler Yükleniyor...",
|
||||||
"ASSIGN_TEAM": "Takım ata",
|
"ASSIGN_TEAM": "Takım ata",
|
||||||
"DELETE": "Sohbeti sil",
|
"DELETE": "Konuşmayı sil",
|
||||||
"OPEN_IN_NEW_TAB": "Yeni sekmede aç",
|
"OPEN_IN_NEW_TAB": "Yeni sekmede aç",
|
||||||
"COPY_LINK": "Konuşma bağlantısını kopyala",
|
"COPY_LINK": "Konuşma bağlantısını kopyala",
|
||||||
"COPY_LINK_SUCCESS": "Konuşma bağlantısı panoya kopyalandı",
|
"COPY_LINK_SUCCESS": "Konuşma bağlantısı panoya kopyalandı",
|
||||||
@@ -244,8 +244,8 @@
|
|||||||
"ASSIGN_LABEL_SUCCESFUL": "Etiket başarıyla atandı",
|
"ASSIGN_LABEL_SUCCESFUL": "Etiket başarıyla atandı",
|
||||||
"ASSIGN_LABEL_FAILED": "Etiket ataması yapılamadı",
|
"ASSIGN_LABEL_FAILED": "Etiket ataması yapılamadı",
|
||||||
"CHANGE_TEAM": "Takım değişti",
|
"CHANGE_TEAM": "Takım değişti",
|
||||||
"SUCCESS_DELETE_CONVERSATION": "Sohbet başarıyla silindi",
|
"SUCCESS_DELETE_CONVERSATION": "Konuşma başarıyla silindi",
|
||||||
"FAIL_DELETE_CONVERSATION": "Sohbet silinemedi! Tekrar deneyin",
|
"FAIL_DELETE_CONVERSATION": "Konuşma silinemedi! Tekrar deneyin",
|
||||||
"FILE_SIZE_LIMIT": "Dosya, {MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE} MB ek dosya sınırını aşıyor",
|
"FILE_SIZE_LIMIT": "Dosya, {MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE} MB ek dosya sınırını aşıyor",
|
||||||
"MESSAGE_ERROR": "Bu mesaj gönderilemiyor, lütfen daha sonra tekrar deneyin",
|
"MESSAGE_ERROR": "Bu mesaj gönderilemiyor, lütfen daha sonra tekrar deneyin",
|
||||||
"SENT_BY": "Tarafından gönderildi:",
|
"SENT_BY": "Tarafından gönderildi:",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"GENERAL_SETTINGS": {
|
"GENERAL_SETTINGS": {
|
||||||
"LIMIT_MESSAGES": {
|
"LIMIT_MESSAGES": {
|
||||||
"CONVERSATION": "Sohbet sınırını aştınız. Hacker planı yalnızca 500 sohbete izin verir.",
|
"CONVERSATION": "Konuşma limitini aştınız. Hacker planı yalnızca 500 konuşmaya izin vermektedir.",
|
||||||
"INBOXES": "Gelen kutusu sınırını aştınız. Hacker planı yalnızca web sitesi canlı sohbetini destekler. E-posta, WhatsApp gibi ek gelen kutuları ücretli plan gerektirir.",
|
"INBOXES": "Gelen kutusu limitini aştınız. Hacker planı yalnızca web sitesi canlı sohbetini desteklemektedir. E-posta, WhatsApp gibi ek gelen kutuları ücretli bir plan gerektirir.",
|
||||||
"AGENTS": "Temsilci sınırını aştınız. Planınız yalnızca {allowedAgents} temsilciye izin veriyor.",
|
"AGENTS": "Temsilci sınırını aştınız. Planınız yalnızca {allowedAgents} temsilciye izin veriyor.",
|
||||||
"NON_ADMIN": "Tüm özellikleri kullanmaya devam etmek için lütfen yöneticinizle iletişime geçin ve planı yükseltin."
|
"NON_ADMIN": "Tüm özellikleri kullanmaya devam etmek için lütfen yöneticinizle iletişime geçin ve planı yükseltin."
|
||||||
},
|
},
|
||||||
@@ -20,10 +20,10 @@
|
|||||||
"BUTTON_TEXT": "Hesabınızı Silin",
|
"BUTTON_TEXT": "Hesabınızı Silin",
|
||||||
"CONFIRM": {
|
"CONFIRM": {
|
||||||
"TITLE": "Hesabı Sil",
|
"TITLE": "Hesabı Sil",
|
||||||
"MESSAGE": "Hesabınızı silmek geri alınamaz. Kalıcı olarak silmek istediğinizi onaylamak için aşağıya hesap adınızı girin.",
|
"MESSAGE": "Hesabınızı silmek geri alınamaz bir işlemdir. Kalıcı olarak silmek istediğinizi onaylamak için aşağıya hesap adınızı girin.",
|
||||||
"BUTTON_TEXT": "Sil",
|
"BUTTON_TEXT": "Sil",
|
||||||
"DISMISS": "İptal Et",
|
"DISMISS": "İptal Et",
|
||||||
"PLACE_HOLDER": "{accountName} yazarak onaylayın"
|
"PLACE_HOLDER": "Onaylamak için lütfen {accountName} yazın"
|
||||||
},
|
},
|
||||||
"SUCCESS": "Hesap silinmek üzere işaretlendi",
|
"SUCCESS": "Hesap silinmek üzere işaretlendi",
|
||||||
"FAILURE": "Hesap silinemedi, tekrar deneyin!",
|
"FAILURE": "Hesap silinemedi, tekrar deneyin!",
|
||||||
@@ -45,11 +45,11 @@
|
|||||||
"NOTE": "API tabanlı bir entegrasyon oluşturuyorsanız bu kimlik gereklidir"
|
"NOTE": "API tabanlı bir entegrasyon oluşturuyorsanız bu kimlik gereklidir"
|
||||||
},
|
},
|
||||||
"AUTO_RESOLVE": {
|
"AUTO_RESOLVE": {
|
||||||
"TITLE": "Sohbetleri otomatik çöz",
|
"TITLE": "Konuşmaları Otomatik Çöz",
|
||||||
"NOTE": "Bu yapılandırma, belirli bir süre etkinlik olmadığında sohbeti otomatik olarak çözmenizi sağlar.",
|
"NOTE": "Bu yapılandırma, belirli bir hareketsizlik süresinden sonra konuşmayı otomatik olarak çözümlemenize olanak tanır.",
|
||||||
"DURATION": {
|
"DURATION": {
|
||||||
"LABEL": "Etkinliksizlik süresi",
|
"LABEL": "Hareketsizlik süresi",
|
||||||
"HELP": "Sohbetin otomatik olarak çözüleceği etkinliksizlik süresi",
|
"HELP": "Konuşmanın otomatik olarak çözümlenmesinden önceki hareketsizlik süresi",
|
||||||
"PLACEHOLDER": "30",
|
"PLACEHOLDER": "30",
|
||||||
"ERROR": "Otomatik çözme süresi 10 dakika ile 999 gün arasında olmalıdır",
|
"ERROR": "Otomatik çözme süresi 10 dakika ile 999 gün arasında olmalıdır",
|
||||||
"API": {
|
"API": {
|
||||||
@@ -59,8 +59,8 @@
|
|||||||
},
|
},
|
||||||
"MESSAGE": {
|
"MESSAGE": {
|
||||||
"LABEL": "Özel otomatik çözüm mesajı",
|
"LABEL": "Özel otomatik çözüm mesajı",
|
||||||
"PLACEHOLDER": "Sohbet, 15 gün etkinlik olmadığı için sistem tarafından çözüldü olarak işaretlendi",
|
"PLACEHOLDER": "Konuşma, 15 günlük hareketsizlik nedeniyle sistem tarafından çözümlendi olarak işaretlendi",
|
||||||
"HELP": "Sohbet otomatik olarak çözüldükten sonra müşteriye gönderilen mesaj"
|
"HELP": "Konuşma otomatik olarak çözüldükten sonra müşteriye gönderilen mesaj"
|
||||||
},
|
},
|
||||||
"PREFERENCES": "Tercihler",
|
"PREFERENCES": "Tercihler",
|
||||||
"LABEL": {
|
"LABEL": {
|
||||||
@@ -94,19 +94,19 @@
|
|||||||
},
|
},
|
||||||
"AUTO_RESOLVE_IGNORE_WAITING": {
|
"AUTO_RESOLVE_IGNORE_WAITING": {
|
||||||
"LABEL": "Yanıtsız sohbetleri hariç tut",
|
"LABEL": "Yanıtsız sohbetleri hariç tut",
|
||||||
"HELP": "Etkinleştirildiğinde, sistem hâlâ temsilci yanıtı bekleyen sohbetleri çözmeyi atlayacaktır."
|
"HELP": "Etkinleştirildiğinde, sistem hâlâ bir temsilcinin yanıtını bekleyen konuşmaları çözümlemeyi atlayacaktır."
|
||||||
},
|
},
|
||||||
"AUDIO_TRANSCRIPTION": {
|
"AUDIO_TRANSCRIPTION": {
|
||||||
"TITLE": "Sesli Mesajları Yazıya Döktür",
|
"TITLE": "Sesli Mesajları Metne Çevir",
|
||||||
"NOTE": "Sohbetlerdeki sesli mesajları otomatik olarak yazıya dökün. Bir sesli mesaj gönderildiğinde veya alındığında bir metin dökümü oluşturun ve mesajın yanında gösterin.",
|
"NOTE": "Konuşmalardaki sesli mesajları otomatik olarak metne çevirin. Bir sesli mesaj gönderildiğinde veya alındığında bir metin dökümü (transkript) oluşturun ve mesajın yanında görüntüleyin.",
|
||||||
"API": {
|
"API": {
|
||||||
"SUCCESS": "Sesli mesaj transkripsiyon ayarı başarıyla güncellendi",
|
"SUCCESS": "Sesli mesaj transkripsiyon ayarı başarıyla güncellendi",
|
||||||
"ERROR": "Sesli yazıya dökme ayarı güncellenemedi"
|
"ERROR": "Ses transkripsiyon ayarı güncellenirken hata oluştu"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AUTO_RESOLVE_DURATION": {
|
"AUTO_RESOLVE_DURATION": {
|
||||||
"LABEL": "Çözüm için etkinliksizlik süresi",
|
"LABEL": "Çözümleme için hareketsizlik süresi",
|
||||||
"HELP": "Bir sohbette etkinlik yoksa otomatik çözüm için süre",
|
"HELP": "Bir konuşmanın, hiçbir etkinlik olmazsa otomatik olarak çözümlenmesi gereken süre",
|
||||||
"PLACEHOLDER": "30",
|
"PLACEHOLDER": "30",
|
||||||
"ERROR": "Otomatik çözme süresi 10 dakika ile 999 gün arasında olmalıdır",
|
"ERROR": "Otomatik çözme süresi 10 dakika ile 999 gün arasında olmalıdır",
|
||||||
"API": {
|
"API": {
|
||||||
@@ -115,8 +115,8 @@
|
|||||||
},
|
},
|
||||||
"UPDATE_BUTTON": "Güncelleme",
|
"UPDATE_BUTTON": "Güncelleme",
|
||||||
"MESSAGE_LABEL": "Özel çözüm mesajı",
|
"MESSAGE_LABEL": "Özel çözüm mesajı",
|
||||||
"MESSAGE_PLACEHOLDER": "Sohbet, 15 gün etkinlik olmadığı için sistem tarafından çözüldü olarak işaretlendi",
|
"MESSAGE_PLACEHOLDER": "Konuşma, 15 günlük hareketsizlik nedeniyle sistem tarafından çözümlendi olarak işaretlendi",
|
||||||
"MESSAGE_HELP": "Bu mesaj, bir sohbet sistem tarafından etkinliksizlik nedeniyle otomatik olarak çözüldüğünde müşteriye gönderilir."
|
"MESSAGE_HELP": "Bu mesaj, bir konuşma hareketsizlik nedeniyle sistem tarafından otomatik olarak çözümlendiğinde müşteriye gönderilir."
|
||||||
},
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Hesabınız için e-posta ile iletişim devre dışı bırakıldı.",
|
"INBOUND_EMAIL_ENABLED": "Hesabınız için e-posta ile iletişim devre dışı bırakıldı.",
|
||||||
|
|||||||
@@ -51,10 +51,10 @@
|
|||||||
"INSTAGRAM": {
|
"INSTAGRAM": {
|
||||||
"CONTINUE_WITH_INSTAGRAM": "Instagram ile devam et",
|
"CONTINUE_WITH_INSTAGRAM": "Instagram ile devam et",
|
||||||
"CONNECT_YOUR_INSTAGRAM_PROFILE": "Instagram profilinizi bağlayın",
|
"CONNECT_YOUR_INSTAGRAM_PROFILE": "Instagram profilinizi bağlayın",
|
||||||
"HELP": "Bu Instagram hesabı yeni Instagram kanal gelen kutusuna taşındı. Artık bu gelen kutusundan Instagram mesajı gönderip alamayacaksınız ",
|
"HELP": "Instagram profilinizi kanal olarak eklemek için, 'Instagram ile Devam Et' seçeneğine tıklayarak Instagram Profilinizin kimliğini doğrulamanız gerekmektedir. ",
|
||||||
"ERROR_MESSAGE": "Instagram'a bağlanırken bir hata oluştu, lütfen tekrar deneyin",
|
"ERROR_MESSAGE": "Instagram'a bağlanırken bir hata oluştu, lütfen tekrar deneyin",
|
||||||
"ERROR_AUTH": "Instagram'a bağlanırken bir hata oluştu, lütfen tekrar deneyin",
|
"ERROR_AUTH": "Instagram'a bağlanırken bir hata oluştu, lütfen tekrar deneyin",
|
||||||
"NEW_INBOX_SUGGESTION": "Bu Instagram hesabı daha önce farklı bir gelen kutusuna bağlıydı ve şimdi buraya taşındı. Tüm yeni mesajlar burada görünecek. Eski gelen kutusu artık bu hesap için mesaj gönderip alamayacak.",
|
"NEW_INBOX_SUGGESTION": "Bu Instagram hesabı daha önce farklı bir gelen kutusuna bağlıydı ve şimdi buraya taşındı. Tüm yeni mesajlar burada görünecektir. Eski gelen kutusu, bu hesap için artık mesaj gönderemeyecek veya alamayacaktır.",
|
||||||
"DUPLICATE_INBOX_BANNER": "Bu Instagram hesabı yeni Instagram kanal gelen kutusuna taşındı. Artık bu gelen kutusundan Instagram mesajı gönderip alamayacaksınız."
|
"DUPLICATE_INBOX_BANNER": "Bu Instagram hesabı yeni Instagram kanal gelen kutusuna taşındı. Artık bu gelen kutusundan Instagram mesajı gönderip alamayacaksınız."
|
||||||
},
|
},
|
||||||
"TWITTER": {
|
"TWITTER": {
|
||||||
@@ -341,9 +341,9 @@
|
|||||||
"TWILIO_STATUS_URL_TITLE": "Twilio Status Callback URL",
|
"TWILIO_STATUS_URL_TITLE": "Twilio Status Callback URL",
|
||||||
"TWILIO_STATUS_URL_SUBTITLE": "Configure this URL as the Status Callback URL on your Twilio phone number."
|
"TWILIO_STATUS_URL_SUBTITLE": "Configure this URL as the Status Callback URL on your Twilio phone number."
|
||||||
},
|
},
|
||||||
"SUBMIT_BUTTON": "Create Voice Channel",
|
"SUBMIT_BUTTON": "Ses Kanalı Oluştur",
|
||||||
"API": {
|
"API": {
|
||||||
"ERROR_MESSAGE": "We were not able to create the voice channel"
|
"ERROR_MESSAGE": "Ses kanalı oluşturulamadı"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"API_CHANNEL": {
|
"API_CHANNEL": {
|
||||||
@@ -437,7 +437,7 @@
|
|||||||
},
|
},
|
||||||
"FACEBOOK": {
|
"FACEBOOK": {
|
||||||
"TITLE": "Facebook\n",
|
"TITLE": "Facebook\n",
|
||||||
"DESCRIPTION": "Connect your Facebook page"
|
"DESCRIPTION": "Facebook sayfanızı bağlayın"
|
||||||
},
|
},
|
||||||
"WHATSAPP": {
|
"WHATSAPP": {
|
||||||
"TITLE": "WhatsApp",
|
"TITLE": "WhatsApp",
|
||||||
@@ -445,31 +445,31 @@
|
|||||||
},
|
},
|
||||||
"EMAIL": {
|
"EMAIL": {
|
||||||
"TITLE": "E-Posta",
|
"TITLE": "E-Posta",
|
||||||
"DESCRIPTION": "Connect with Gmail, Outlook, or other providers"
|
"DESCRIPTION": "Gmail, Outlook veya diğer sağlayıcılarla bağlantı kurun"
|
||||||
},
|
},
|
||||||
"SMS": {
|
"SMS": {
|
||||||
"TITLE": "SMS",
|
"TITLE": "SMS",
|
||||||
"DESCRIPTION": "Integrate SMS channel with Twilio or bandwidth"
|
"DESCRIPTION": "SMS kanalını Twilio veya Bandwidth ile entegre edin"
|
||||||
},
|
},
|
||||||
"API": {
|
"API": {
|
||||||
"TITLE": "API",
|
"TITLE": "API",
|
||||||
"DESCRIPTION": "Make a custom channel using our API"
|
"DESCRIPTION": "API'mizi kullanarak özel bir kanal oluşturun"
|
||||||
},
|
},
|
||||||
"TELEGRAM": {
|
"TELEGRAM": {
|
||||||
"TITLE": "Telegram",
|
"TITLE": "Telegram",
|
||||||
"DESCRIPTION": "Configure Telegram channel using Bot token"
|
"DESCRIPTION": "Bot token kullanarak Telegram kanalını yapılandırın"
|
||||||
},
|
},
|
||||||
"LINE": {
|
"LINE": {
|
||||||
"TITLE": "Line",
|
"TITLE": "Line",
|
||||||
"DESCRIPTION": "Integrate your Line channel"
|
"DESCRIPTION": "Line kanalınızı entegre edin"
|
||||||
},
|
},
|
||||||
"INSTAGRAM": {
|
"INSTAGRAM": {
|
||||||
"TITLE": "Instagram",
|
"TITLE": "Instagram",
|
||||||
"DESCRIPTION": "Connect your instagram account"
|
"DESCRIPTION": "Instagram hesabınızı bağlayın"
|
||||||
},
|
},
|
||||||
"VOICE": {
|
"VOICE": {
|
||||||
"TITLE": "Ses",
|
"TITLE": "Ses",
|
||||||
"DESCRIPTION": "Integrate with Twilio Voice"
|
"DESCRIPTION": "Twilio Voice ile entegre edin"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -526,9 +526,9 @@
|
|||||||
"BUTTON_TEXT": "Beni oraya götür",
|
"BUTTON_TEXT": "Beni oraya götür",
|
||||||
"MORE_SETTINGS": "Daha fazla ayar",
|
"MORE_SETTINGS": "Daha fazla ayar",
|
||||||
"WEBSITE_SUCCESS": "Bir web sitesi kanalı oluşturmayı başarıyla tamamladınız. Aşağıda gösterilen kodu kopyalayın ve web sitenize yapıştırın. Bir müşteri canlı sohbeti bir dahaki sefere kullandığında, konuşma otomatik olarak gelen kutunuzda görünecektir.",
|
"WEBSITE_SUCCESS": "Bir web sitesi kanalı oluşturmayı başarıyla tamamladınız. Aşağıda gösterilen kodu kopyalayın ve web sitenize yapıştırın. Bir müşteri canlı sohbeti bir dahaki sefere kullandığında, konuşma otomatik olarak gelen kutunuzda görünecektir.",
|
||||||
"WHATSAPP_QR_INSTRUCTION": "Scan the QR code above to quickly test your WhatsApp inbox",
|
"WHATSAPP_QR_INSTRUCTION": "WhatsApp gelen kutunuzu hızlıca test etmek için yukarıdaki QR kodu tarayın",
|
||||||
"MESSENGER_QR_INSTRUCTION": "Scan the QR code above to quickly test your Facebook Messenger inbox",
|
"MESSENGER_QR_INSTRUCTION": "Facebook Messenger gelen kutunuzu hızlıca test etmek için yukarıdaki QR kodu tarayın",
|
||||||
"TELEGRAM_QR_INSTRUCTION": "Scan the QR code above to quickly test your Telegram inbox"
|
"TELEGRAM_QR_INSTRUCTION": "Telegram gelen kutunuzu hızlıca test etmek için yukarıdaki QR kodu tarayın"
|
||||||
},
|
},
|
||||||
"REAUTH": "Yeniden yetkilendir",
|
"REAUTH": "Yeniden yetkilendir",
|
||||||
"VIEW": "Görünüm",
|
"VIEW": "Görünüm",
|
||||||
@@ -607,37 +607,37 @@
|
|||||||
"BUSINESS_HOURS": "İş Saatleri",
|
"BUSINESS_HOURS": "İş Saatleri",
|
||||||
"WIDGET_BUILDER": "Widget Oluşturucu",
|
"WIDGET_BUILDER": "Widget Oluşturucu",
|
||||||
"BOT_CONFIGURATION": "Bot Yapılandırma",
|
"BOT_CONFIGURATION": "Bot Yapılandırma",
|
||||||
"ACCOUNT_HEALTH": "Account Health",
|
"ACCOUNT_HEALTH": "Hesap Sağlığı",
|
||||||
"CSAT": "CSAT"
|
"CSAT": "CSAT"
|
||||||
},
|
},
|
||||||
"ACCOUNT_HEALTH": {
|
"ACCOUNT_HEALTH": {
|
||||||
"TITLE": "Manage your WhatsApp account",
|
"TITLE": "WhatsApp hesabınızı yönetin",
|
||||||
"DESCRIPTION": "Review your WhatsApp account status, messaging limits, and quality. Update settings or resolve issues if needed",
|
"DESCRIPTION": "WhatsApp hesap durumunuzu, mesajlaşma limitlerinizi ve kalitesini inceleyin. Gerekirse ayarları güncelleyin veya sorunları çözün",
|
||||||
"GO_TO_SETTINGS": "Go to Meta Business Manager",
|
"GO_TO_SETTINGS": "Meta Business Manager'a gidin",
|
||||||
"NO_DATA": "Health data is not available",
|
"NO_DATA": "Sağlık verisi mevcut değil",
|
||||||
"FIELDS": {
|
"FIELDS": {
|
||||||
"DISPLAY_PHONE_NUMBER": {
|
"DISPLAY_PHONE_NUMBER": {
|
||||||
"LABEL": "Display phone number",
|
"LABEL": "Telefon numarasını göster",
|
||||||
"TOOLTIP": "Phone number displayed to customers"
|
"TOOLTIP": "Müşterilere gösterilen telefon numarası"
|
||||||
},
|
},
|
||||||
"VERIFIED_NAME": {
|
"VERIFIED_NAME": {
|
||||||
"LABEL": "Business name",
|
"LABEL": "İşletme adı",
|
||||||
"TOOLTIP": "Business name verified by WhatsApp"
|
"TOOLTIP": "WhatsApp tarafından onaylanmış işletme adı"
|
||||||
},
|
},
|
||||||
"DISPLAY_NAME_STATUS": {
|
"DISPLAY_NAME_STATUS": {
|
||||||
"LABEL": "Display name status",
|
"LABEL": "Görünen adın durumu",
|
||||||
"TOOLTIP": "Status of your business name verification"
|
"TOOLTIP": "İşletme adı doğrulamanızın durumu"
|
||||||
},
|
},
|
||||||
"QUALITY_RATING": {
|
"QUALITY_RATING": {
|
||||||
"LABEL": "Quality rating",
|
"LABEL": "Kalite puanı",
|
||||||
"TOOLTIP": "WhatsApp quality rating for your account"
|
"TOOLTIP": "Hesabınız için WhatsApp kalite puanı"
|
||||||
},
|
},
|
||||||
"MESSAGING_LIMIT_TIER": {
|
"MESSAGING_LIMIT_TIER": {
|
||||||
"LABEL": "Messaging limit tier",
|
"LABEL": "Mesajlaşma limiti seviyesi",
|
||||||
"TOOLTIP": "Daily messaging limit for your account"
|
"TOOLTIP": "Hesabınız için günlük mesajlaşma limiti"
|
||||||
},
|
},
|
||||||
"ACCOUNT_MODE": {
|
"ACCOUNT_MODE": {
|
||||||
"LABEL": "Account mode",
|
"LABEL": "Hesap modu",
|
||||||
"TOOLTIP": "Current operating mode of your WhatsApp account"
|
"TOOLTIP": "Current operating mode of your WhatsApp account"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -784,7 +784,7 @@
|
|||||||
},
|
},
|
||||||
"CSAT": {
|
"CSAT": {
|
||||||
"TITLE": "CSAT'yi etkinleştir",
|
"TITLE": "CSAT'yi etkinleştir",
|
||||||
"SUBTITLE": "Müşterilerin destek deneyimleri hakkında ne hissettiklerini anlamak için sohbetlerin sonunda otomatik olarak CSAT anketleri başlatın. Memnuniyet eğilimlerini takip edin ve zaman içinde iyileştirme alanlarını belirleyin.",
|
"SUBTITLE": "Müşterilerin destek deneyimleri hakkındaki düşüncelerini anlamak için konuşma sonunda CSAT anketlerini (Müşteri Memnuniyeti Anketleri) otomatik olarak tetikleyin. Memnuniyet eğilimlerini takip edin ve zaman içinde iyileştirme alanlarını belirleyin.",
|
||||||
"DISPLAY_TYPE": {
|
"DISPLAY_TYPE": {
|
||||||
"LABEL": "Görüntüleme türü"
|
"LABEL": "Görüntüleme türü"
|
||||||
},
|
},
|
||||||
@@ -802,7 +802,7 @@
|
|||||||
},
|
},
|
||||||
"SELECT_PLACEHOLDER": "etiketleri seç"
|
"SELECT_PLACEHOLDER": "etiketleri seç"
|
||||||
},
|
},
|
||||||
"NOTE": "Not: CSAT anketleri her sohbet için yalnızca bir kez gönderilir",
|
"NOTE": "Not: CSAT anketleri, konuşma başına yalnızca bir kez gönderilir",
|
||||||
"API": {
|
"API": {
|
||||||
"SUCCESS_MESSAGE": "CSAT ayarları başarıyla güncellendi",
|
"SUCCESS_MESSAGE": "CSAT ayarları başarıyla güncellendi",
|
||||||
"ERROR_MESSAGE": "CSAT ayarları güncellenemedi. Lütfen daha sonra tekrar deneyin."
|
"ERROR_MESSAGE": "CSAT ayarları güncellenemedi. Lütfen daha sonra tekrar deneyin."
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
"SUBSCRIPTIONS": {
|
"SUBSCRIPTIONS": {
|
||||||
"LABEL": "Olaylar",
|
"LABEL": "Olaylar",
|
||||||
"EVENTS": {
|
"EVENTS": {
|
||||||
"CONVERSATION_CREATED": "Görüşme Oluşturuldu",
|
"CONVERSATION_CREATED": "Konuşma Oluşturuldu",
|
||||||
"CONVERSATION_STATUS_CHANGED": "Görüşme Durumu Değişti",
|
"CONVERSATION_STATUS_CHANGED": "Görüşme Durumu Değişti",
|
||||||
"CONVERSATION_UPDATED": "Görüşme Güncellendi",
|
"CONVERSATION_UPDATED": "Görüşme Güncellendi",
|
||||||
"MESSAGE_CREATED": "Mesaj Oluşturuldu",
|
"MESSAGE_CREATED": "Mesaj Oluşturuldu",
|
||||||
@@ -42,8 +42,8 @@
|
|||||||
"WEBWIDGET_TRIGGERED": "Kullanıcı tarafından canlı sohbet widget'ı açıldı",
|
"WEBWIDGET_TRIGGERED": "Kullanıcı tarafından canlı sohbet widget'ı açıldı",
|
||||||
"CONTACT_CREATED": "Kişi Oluşturuldu",
|
"CONTACT_CREATED": "Kişi Oluşturuldu",
|
||||||
"CONTACT_UPDATED": "Kişi Güncellendi",
|
"CONTACT_UPDATED": "Kişi Güncellendi",
|
||||||
"CONVERSATION_TYPING_ON": "Sohbet Yazıyor Açık",
|
"CONVERSATION_TYPING_ON": "Konuşmada Yazıyor Açık",
|
||||||
"CONVERSATION_TYPING_OFF": "Sohbet Yazıyor Kapalı"
|
"CONVERSATION_TYPING_OFF": "Konuşmada Yazıyor Kapalı"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
@@ -327,7 +327,7 @@
|
|||||||
},
|
},
|
||||||
"CTA": {
|
"CTA": {
|
||||||
"TITLE": "Linear'a bağlan",
|
"TITLE": "Linear'a bağlan",
|
||||||
"AGENT_DESCRIPTION": "Doğrusal çalışma alanı bağlı değil. Bu entegrasyonu kullanmak için yöneticinizden bir çalışma alanı bağlamasını isteyin.",
|
"AGENT_DESCRIPTION": "Linear çalışma alanı bağlı değil. Bu entegrasyonu kullanmak için yöneticinizden bir çalışma alanı bağlamasını isteyin.",
|
||||||
"DESCRIPTION": "Linear çalışma alanı bağlı değil. Bu entegrasyonu kullanmak için çalışma alanınızı bağlamak üzere aşağıdaki düğmeye tıklayın.",
|
"DESCRIPTION": "Linear çalışma alanı bağlı değil. Bu entegrasyonu kullanmak için çalışma alanınızı bağlamak üzere aşağıdaki düğmeye tıklayın.",
|
||||||
"BUTTON_TEXT": "Linear çalışma alanını bağlayın"
|
"BUTTON_TEXT": "Linear çalışma alanını bağlayın"
|
||||||
}
|
}
|
||||||
@@ -348,7 +348,7 @@
|
|||||||
"TITLE": "Copilot",
|
"TITLE": "Copilot",
|
||||||
"TRY_THESE_PROMPTS": "Try these prompts",
|
"TRY_THESE_PROMPTS": "Try these prompts",
|
||||||
"PANEL_TITLE": "Copilot ile başlayın",
|
"PANEL_TITLE": "Copilot ile başlayın",
|
||||||
"KICK_OFF_MESSAGE": "Hızlı bir özet mi lazım, geçmiş sohbetleri mi kontrol etmek istiyorsunuz ya da daha iyi bir yanıt mı yazmak istiyorsunuz? Copilot işleri hızlandırmak için burada.",
|
"KICK_OFF_MESSAGE": "Hızlı bir özet mi gerekiyor, geçmiş konuşmaları mı kontrol etmek istiyorsunuz, yoksa daha iyi bir yanıt mı tasarlamak istiyorsunuz? Copilot işleri hızlandırmak için burada.",
|
||||||
"SEND_MESSAGE": "Mesajı Gönder...",
|
"SEND_MESSAGE": "Mesajı Gönder...",
|
||||||
"EMPTY_MESSAGE": "Yanıt oluşturulurken bir hata oluştu. Lütfen tekrar deneyin.",
|
"EMPTY_MESSAGE": "Yanıt oluşturulurken bir hata oluştu. Lütfen tekrar deneyin.",
|
||||||
"LOADER": "Captain is thinking",
|
"LOADER": "Captain is thinking",
|
||||||
@@ -371,8 +371,8 @@
|
|||||||
"CONTENT": "Sohbetin müşterinin ihtiyaçlarını ne kadar karşıladığını gözden geçirin. Ton, açıklık ve etkililik açısından 5 üzerinden bir puan verin."
|
"CONTENT": "Sohbetin müşterinin ihtiyaçlarını ne kadar karşıladığını gözden geçirin. Ton, açıklık ve etkililik açısından 5 üzerinden bir puan verin."
|
||||||
},
|
},
|
||||||
"HIGH_PRIORITY": {
|
"HIGH_PRIORITY": {
|
||||||
"LABEL": "Yüksek öncelikli sohbetler",
|
"LABEL": "Yüksek öncelikli konuşmalar",
|
||||||
"CONTENT": "Tüm yüksek öncelikli açık sohbetlerin bir özetini verin. Sohbet kimliği, müşteri adı (varsa), son mesaj içeriği ve atanan temsilciyi ekleyin. Gerekirse duruma göre gruplayın."
|
"CONTENT": "Tüm yüksek öncelikli açık konuşmaların bir özetini verin. Konuşma kimliği, müşteri adı (varsa), son mesaj içeriği ve atanan temsilciyi ekleyin. Gerekirse duruma göre gruplayın."
|
||||||
},
|
},
|
||||||
"LIST_CONTACTS": {
|
"LIST_CONTACTS": {
|
||||||
"LABEL": "Kişileri listele",
|
"LABEL": "Kişileri listele",
|
||||||
@@ -383,7 +383,7 @@
|
|||||||
"PLAYGROUND": {
|
"PLAYGROUND": {
|
||||||
"USER": "Sen",
|
"USER": "Sen",
|
||||||
"ASSISTANT": "Assistant",
|
"ASSISTANT": "Assistant",
|
||||||
"MESSAGE_PLACEHOLDER": "Mesajınız...",
|
"MESSAGE_PLACEHOLDER": "Mesajınızı yazın...",
|
||||||
"HEADER": "Oyun Alanı",
|
"HEADER": "Oyun Alanı",
|
||||||
"DESCRIPTION": "Bu oyun alanını asistanınıza mesaj göndermek ve yanıtlarının doğru, hızlı ve beklediğiniz tonda olup olmadığını kontrol etmek için kullanın.",
|
"DESCRIPTION": "Bu oyun alanını asistanınıza mesaj göndermek ve yanıtlarının doğru, hızlı ve beklediğiniz tonda olup olmadığını kontrol etmek için kullanın.",
|
||||||
"CREDIT_NOTE": "Buradan gönderilen mesajlar Captain kredilerinize sayılacaktır."
|
"CREDIT_NOTE": "Buradan gönderilen mesajlar Captain kredilerinize sayılacaktır."
|
||||||
|
|||||||
@@ -194,7 +194,7 @@
|
|||||||
},
|
},
|
||||||
"LABEL_REPORTS": {
|
"LABEL_REPORTS": {
|
||||||
"HEADER": "Etiketler Genel Bakış",
|
"HEADER": "Etiketler Genel Bakış",
|
||||||
"DESCRIPTION": "Konuşmalar, yanıt süreleri, çözüm süreleri ve çözülmüş vakalar gibi temel ölçümlerle etiket performansını takip edin. Ayrıntılı içgörüler için bir etiket adına tıklayın.",
|
"DESCRIPTION": "Etiket performansını; konuşmalar, yanıt süreleri, çözüm süreleri ve çözümlenen vakalar dahil olmak üzere temel metriklerle takip edin. Ayrıntılı analizler için bir etiket adına tıklayın.",
|
||||||
"LOADING_CHART": "Grafik verileri yükleniyor...",
|
"LOADING_CHART": "Grafik verileri yükleniyor...",
|
||||||
"NO_ENOUGH_DATA": "Rapor oluşturmak için yeterli veri yok, Lütfen daha sonra tekrar deneyin.",
|
"NO_ENOUGH_DATA": "Rapor oluşturmak için yeterli veri yok, Lütfen daha sonra tekrar deneyin.",
|
||||||
"DOWNLOAD_LABEL_REPORTS": "Etiket raporlarını indir",
|
"DOWNLOAD_LABEL_REPORTS": "Etiket raporlarını indir",
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Видалити",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Видалити контакт"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "حذف کریں۔",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "کانٹیکٹ حذف کریں۔"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -579,7 +579,18 @@
|
|||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "No labels available yet.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Clear selection",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Select all ({count})",
|
||||||
|
"DELETE_CONTACTS": "Delete",
|
||||||
|
"DELETE_SUCCESS": "Contacts deleted successfully.",
|
||||||
|
"DELETE_FAILED": "Failed to delete contacts.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Delete selected contacts",
|
||||||
|
"SINGULAR_TITLE": "Delete selected contact",
|
||||||
|
"DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
|
||||||
|
"SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
|
||||||
|
"CONFIRM_MULTIPLE": "Delete contacts",
|
||||||
|
"CONFIRM_SINGLE": "Delete contact"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user