Compare commits
56
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a7769ab6e | ||
|
|
c9823d9409 | ||
|
|
2c4e65d68e | ||
|
|
6ae5e67b52 | ||
|
|
32da4eec27 | ||
|
|
e3c82a322a | ||
|
|
945a08eadb | ||
|
|
216430ac05 | ||
|
|
559d1b6576 | ||
|
|
eed1825d5a | ||
|
|
651645fbd2 | ||
|
|
29fe982d39 | ||
|
|
b4a252a459 | ||
|
|
608da1614e | ||
|
|
bdcb1934c0 | ||
|
|
4f09c2203c | ||
|
|
f455e7994e | ||
|
|
52b4dbc8c6 | ||
|
|
28e16f7ee0 | ||
|
|
fb0be60ae2 | ||
|
|
3c9c0298ba | ||
|
|
d6af182f82 | ||
|
|
421be5cad8 | ||
|
|
c07d03e4e5 | ||
|
|
1e621be90c | ||
|
|
e81152608d | ||
|
|
615e81731c | ||
|
|
79d9cb3cea | ||
|
|
0862692b0e | ||
|
|
97dabbf7f6 | ||
|
|
fb1aa085cf | ||
|
|
1ee5b4f9d6 | ||
|
|
514e95969a | ||
|
|
80f4ed45a3 | ||
|
|
875d36488e | ||
|
|
f2fe66263f | ||
|
|
86cbe7f0d6 | ||
|
|
5365304c6f | ||
|
|
8b05825681 | ||
|
|
1f60548020 | ||
|
|
1522e14ffb | ||
|
|
8e6210dc2c | ||
|
|
831d3a16c6 | ||
|
|
829c07efbb | ||
|
|
4e74f7920f | ||
|
|
44579bdcad | ||
|
|
e8a01ace41 | ||
|
|
01363042ce | ||
|
|
068bd8f083 | ||
|
|
9c4c9635a0 | ||
|
|
5bf39d20e5 | ||
|
|
90352b3a20 | ||
|
|
ba8df900e3 | ||
|
|
9b75d9bd1b | ||
|
|
ec6c3b3571 | ||
|
|
48ba273730 |
@@ -36,5 +36,5 @@ jobs:
|
|||||||
platforms: ${{ matrix.platform }}
|
platforms: ${{ matrix.platform }}
|
||||||
push: false
|
push: false
|
||||||
load: false
|
load: false
|
||||||
cache-from: type=gha
|
cache-from: type=gha,scope=${{ matrix.platform }}
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max,scope=${{ matrix.platform }}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
class Messages::MessageBuilder
|
class Messages::MessageBuilder
|
||||||
include ::FileTypeHelper
|
include ::FileTypeHelper
|
||||||
|
include ::EmailHelper
|
||||||
|
include ::DataHelper
|
||||||
|
|
||||||
attr_reader :message
|
attr_reader :message
|
||||||
|
|
||||||
def initialize(user, conversation, params)
|
def initialize(user, conversation, params)
|
||||||
@@ -38,30 +41,12 @@ class Messages::MessageBuilder
|
|||||||
params = convert_to_hash(@params)
|
params = convert_to_hash(@params)
|
||||||
content_attributes = params.fetch(:content_attributes, {})
|
content_attributes = params.fetch(:content_attributes, {})
|
||||||
|
|
||||||
return parse_json(content_attributes) if content_attributes.is_a?(String)
|
return safe_parse_json(content_attributes) if content_attributes.is_a?(String)
|
||||||
return content_attributes if content_attributes.is_a?(Hash)
|
return content_attributes if content_attributes.is_a?(Hash)
|
||||||
|
|
||||||
{}
|
{}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Converts the given object to a hash.
|
|
||||||
# If it's an instance of ActionController::Parameters, converts it to an unsafe hash.
|
|
||||||
# Otherwise, returns the object as-is.
|
|
||||||
def convert_to_hash(obj)
|
|
||||||
return obj.to_unsafe_h if obj.instance_of?(ActionController::Parameters)
|
|
||||||
|
|
||||||
obj
|
|
||||||
end
|
|
||||||
|
|
||||||
# Attempts to parse a string as JSON.
|
|
||||||
# If successful, returns the parsed hash with symbolized names.
|
|
||||||
# If unsuccessful, returns nil.
|
|
||||||
def parse_json(content)
|
|
||||||
JSON.parse(content, symbolize_names: true)
|
|
||||||
rescue JSON::ParserError
|
|
||||||
{}
|
|
||||||
end
|
|
||||||
|
|
||||||
def process_attachments
|
def process_attachments
|
||||||
return if @attachments.blank?
|
return if @attachments.blank?
|
||||||
|
|
||||||
@@ -110,12 +95,6 @@ class Messages::MessageBuilder
|
|||||||
email_string.gsub(/\s+/, '').split(',')
|
email_string.gsub(/\s+/, '').split(',')
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_email_addresses(all_emails)
|
|
||||||
all_emails&.each do |email|
|
|
||||||
raise StandardError, 'Invalid email address' unless email.match?(URI::MailTo::EMAIL_REGEXP)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def message_type
|
def message_type
|
||||||
if @conversation.inbox.channel_type != 'Channel::Api' && @message_type == 'incoming'
|
if @conversation.inbox.channel_type != 'Channel::Api' && @message_type == 'incoming'
|
||||||
raise StandardError, 'Incoming messages are only allowed in Api inboxes'
|
raise StandardError, 'Incoming messages are only allowed in Api inboxes'
|
||||||
@@ -178,14 +157,17 @@ class Messages::MessageBuilder
|
|||||||
email_attributes = ensure_indifferent_access(@message.content_attributes[:email] || {})
|
email_attributes = ensure_indifferent_access(@message.content_attributes[:email] || {})
|
||||||
normalized_content = normalize_email_body(@message.content)
|
normalized_content = normalize_email_body(@message.content)
|
||||||
|
|
||||||
|
# Process liquid templates in normalized content with code block protection
|
||||||
|
processed_content = process_liquid_in_email_body(normalized_content)
|
||||||
|
|
||||||
# Use custom HTML content if provided, otherwise generate from message content
|
# Use custom HTML content if provided, otherwise generate from message content
|
||||||
email_attributes[:html_content] = if custom_email_content_provided?
|
email_attributes[:html_content] = if custom_email_content_provided?
|
||||||
build_custom_html_content
|
build_custom_html_content
|
||||||
else
|
else
|
||||||
build_html_content(normalized_content)
|
build_html_content(processed_content)
|
||||||
end
|
end
|
||||||
|
|
||||||
email_attributes[:text_content] = build_text_content(normalized_content)
|
email_attributes[:text_content] = build_text_content(processed_content)
|
||||||
email_attributes
|
email_attributes
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -204,22 +186,6 @@ class Messages::MessageBuilder
|
|||||||
text_content
|
text_content
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_indifferent_access(hash)
|
|
||||||
return {} if hash.blank?
|
|
||||||
|
|
||||||
hash.respond_to?(:with_indifferent_access) ? hash.with_indifferent_access : hash
|
|
||||||
end
|
|
||||||
|
|
||||||
def normalize_email_body(content)
|
|
||||||
content.to_s.gsub("\r\n", "\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_email_html(content)
|
|
||||||
return '' if content.blank?
|
|
||||||
|
|
||||||
ChatwootMarkdownRenderer.new(content).render_message.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def custom_email_content_provided?
|
def custom_email_content_provided?
|
||||||
@params[:email_html_content].present?
|
@params[:email_html_content].present?
|
||||||
end
|
end
|
||||||
@@ -232,4 +198,27 @@ class Messages::MessageBuilder
|
|||||||
|
|
||||||
html_content
|
html_content
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Liquid processing methods for email content
|
||||||
|
def process_liquid_in_email_body(content)
|
||||||
|
return content if content.blank?
|
||||||
|
return content unless should_process_liquid?
|
||||||
|
|
||||||
|
# Protect code blocks from liquid processing
|
||||||
|
modified_content = modified_liquid_content(content)
|
||||||
|
template = Liquid::Template.parse(modified_content)
|
||||||
|
template.render(drops_with_sender)
|
||||||
|
rescue Liquid::Error
|
||||||
|
content
|
||||||
|
end
|
||||||
|
|
||||||
|
def should_process_liquid?
|
||||||
|
@message_type == 'outgoing' || @message_type == 'template'
|
||||||
|
end
|
||||||
|
|
||||||
|
def drops_with_sender
|
||||||
|
message_drops(@conversation).merge({
|
||||||
|
'agent' => UserDrop.new(sender)
|
||||||
|
})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -22,9 +22,10 @@ class Api::V1::Accounts::ArticlesController < Api::V1::Accounts::BaseController
|
|||||||
def edit; end
|
def edit; end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@article = @portal.articles.create!(article_params)
|
params_with_defaults = article_params
|
||||||
|
params_with_defaults[:status] ||= :draft
|
||||||
|
@article = @portal.articles.create!(params_with_defaults)
|
||||||
@article.associate_root_article(article_params[:associated_article_id])
|
@article.associate_root_article(article_params[:associated_article_id])
|
||||||
@article.draft!
|
|
||||||
render json: { error: @article.errors.messages }, status: :unprocessable_entity and return unless @article.valid?
|
render json: { error: @article.errors.messages }, status: :unprocessable_entity and return unless @article.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class Api::V1::Accounts::WebhooksController < Api::V1::Accounts::BaseController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def webhook_params
|
def webhook_params
|
||||||
params.require(:webhook).permit(:inbox_id, :url, subscriptions: [])
|
params.require(:webhook).permit(:inbox_id, :name, :url, subscriptions: [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_webhook
|
def fetch_webhook
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Provides utility methods for data transformation, hash manipulation, and JSON parsing.
|
||||||
|
# This module contains helper methods for converting between different data types,
|
||||||
|
# normalizing hashes, and safely handling JSON operations.
|
||||||
|
module DataHelper
|
||||||
|
# Ensures a hash supports indifferent access (string or symbol keys).
|
||||||
|
# Returns an empty hash if the input is blank.
|
||||||
|
def ensure_indifferent_access(hash)
|
||||||
|
return {} if hash.blank?
|
||||||
|
|
||||||
|
hash.respond_to?(:with_indifferent_access) ? hash.with_indifferent_access : hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def convert_to_hash(obj)
|
||||||
|
return obj.to_unsafe_h if obj.instance_of?(ActionController::Parameters)
|
||||||
|
|
||||||
|
obj
|
||||||
|
end
|
||||||
|
|
||||||
|
def safe_parse_json(content)
|
||||||
|
JSON.parse(content, symbolize_names: true)
|
||||||
|
rescue JSON::ParserError
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -4,6 +4,19 @@ module EmailHelper
|
|||||||
domain.split('.').first
|
domain.split('.').first
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render_email_html(content)
|
||||||
|
return '' if content.blank?
|
||||||
|
|
||||||
|
ChatwootMarkdownRenderer.new(content).render_message.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
# Raise a standard error if any email address is invalid
|
||||||
|
def validate_email_addresses(emails_to_test)
|
||||||
|
emails_to_test&.each do |email|
|
||||||
|
raise StandardError, 'Invalid email address' unless email.match?(URI::MailTo::EMAIL_REGEXP)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# ref: https://www.rfc-editor.org/rfc/rfc5233.html
|
# ref: https://www.rfc-editor.org/rfc/rfc5233.html
|
||||||
# This is not a mandatory requirement for email addresses, but it is a common practice.
|
# This is not a mandatory requirement for email addresses, but it is a common practice.
|
||||||
# john+test@xyc.com is the same as john@xyc.com
|
# john+test@xyc.com is the same as john@xyc.com
|
||||||
@@ -21,6 +34,10 @@ module EmailHelper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def normalize_email_body(content)
|
||||||
|
content.to_s.gsub("\r\n", "\n")
|
||||||
|
end
|
||||||
|
|
||||||
def modified_liquid_content(email)
|
def modified_liquid_content(email)
|
||||||
# This regex is used to match the code blocks in the content
|
# This regex is used to match the code blocks in the content
|
||||||
# We don't want to process liquid in code blocks
|
# We don't want to process liquid in code blocks
|
||||||
@@ -29,7 +46,10 @@ module EmailHelper
|
|||||||
|
|
||||||
def message_drops(conversation)
|
def message_drops(conversation)
|
||||||
{
|
{
|
||||||
'contact' => ContactDrop.new(conversation.contact)
|
'contact' => ContactDrop.new(conversation.contact),
|
||||||
|
'conversation' => ConversationDrop.new(conversation),
|
||||||
|
'inbox' => InboxDrop.new(conversation.inbox),
|
||||||
|
'account' => AccountDrop.new(conversation.account)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
+1
-1
@@ -202,7 +202,7 @@ defineExpose({ state, isSubmitDisabled });
|
|||||||
size="sm"
|
size="sm"
|
||||||
type="button"
|
type="button"
|
||||||
:icon="!state.icon ? 'i-lucide-smile-plus' : ''"
|
:icon="!state.icon ? 'i-lucide-smile-plus' : ''"
|
||||||
class="!h-[2.4rem] !w-[2.375rem] absolute top-[1.94rem] !outline-none !rounded-[0.438rem] border-0 ltr:left-px rtl:right-px ltr:!rounded-r-none rtl:!rounded-l-none"
|
class="!h-[2.39rem] !w-[2.375rem] absolute top-px !outline-none !rounded-[0.438rem] border-0 ltr:left-px rtl:right-px ltr:!rounded-r-none rtl:!rounded-l-none"
|
||||||
@click="isEmojiPickerOpen = !isEmojiPickerOpen"
|
@click="isEmojiPickerOpen = !isEmojiPickerOpen"
|
||||||
/>
|
/>
|
||||||
<EmojiInput
|
<EmojiInput
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -82,12 +82,12 @@ const handleSendMessage = template => {
|
|||||||
:placeholder="
|
:placeholder="
|
||||||
t('COMPOSE_NEW_CONVERSATION.FORM.TWILIO_OPTIONS.SEARCH_PLACEHOLDER')
|
t('COMPOSE_NEW_CONVERSATION.FORM.TWILIO_OPTIONS.SEARCH_PLACEHOLDER')
|
||||||
"
|
"
|
||||||
custom-input-class="ltr:pl-10 rtl:pr-10"
|
class="ltr:!pl-8 rtl:!pr-8"
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<Icon
|
<Icon
|
||||||
icon="i-lucide-search"
|
icon="i-lucide-search"
|
||||||
class="absolute top-2 size-3.5 ltr:left-3 rtl:right-3"
|
class="absolute top-3 size-3.5 ltr:left-3 rtl:right-3"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</Input>
|
</Input>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
+11
-7
@@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
|
|||||||
import { useMapGetter } from 'dashboard/composables/store';
|
import { useMapGetter } from 'dashboard/composables/store';
|
||||||
|
|
||||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||||
|
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 WhatsappTemplate from './WhatsappTemplate.vue';
|
import WhatsappTemplate from './WhatsappTemplate.vue';
|
||||||
|
|
||||||
@@ -77,11 +78,7 @@ const handleSendMessage = template => {
|
|||||||
class="absolute top-full mt-1.5 max-h-96 overflow-y-auto ltr:left-0 rtl:right-0 flex flex-col gap-2 p-4 items-center w-[21.875rem] h-auto bg-n-solid-2 border border-n-strong shadow-sm rounded-lg"
|
class="absolute top-full mt-1.5 max-h-96 overflow-y-auto ltr:left-0 rtl:right-0 flex flex-col gap-2 p-4 items-center w-[21.875rem] h-auto bg-n-solid-2 border border-n-strong shadow-sm rounded-lg"
|
||||||
>
|
>
|
||||||
<div class="relative w-full">
|
<div class="relative w-full">
|
||||||
<Icon
|
<Input
|
||||||
icon="i-lucide-search"
|
|
||||||
class="absolute size-3.5 top-2 ltr:left-3 rtl:right-3"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
v-model="searchQuery"
|
v-model="searchQuery"
|
||||||
type="search"
|
type="search"
|
||||||
:placeholder="
|
:placeholder="
|
||||||
@@ -89,8 +86,15 @@ const handleSendMessage = template => {
|
|||||||
'COMPOSE_NEW_CONVERSATION.FORM.WHATSAPP_OPTIONS.SEARCH_PLACEHOLDER'
|
'COMPOSE_NEW_CONVERSATION.FORM.WHATSAPP_OPTIONS.SEARCH_PLACEHOLDER'
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
class="w-full h-8 py-2 ltr:pl-10 rtl:pr-10 ltr:pr-2 rtl:pl-2 text-sm reset-base outline-none border-none rounded-lg bg-n-alpha-black2 dark:bg-n-solid-1 text-n-slate-12"
|
class="ltr:!pl-8 rtl:!pr-8"
|
||||||
/>
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<Icon
|
||||||
|
icon="i-lucide-search"
|
||||||
|
class="absolute top-3 size-3.5 ltr:left-3 rtl:right-3"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Input>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-for="template in filteredTemplates"
|
v-for="template in filteredTemplates"
|
||||||
|
|||||||
@@ -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 { useI18n } from 'vue-i18n';
|
||||||
|
import { useMapGetter } from 'dashboard/composables/store.js';
|
||||||
import { usePolicy } from 'dashboard/composables/usePolicy';
|
import { usePolicy } from 'dashboard/composables/usePolicy';
|
||||||
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,36 @@ 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 { t } = useI18n();
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
const { shouldShowPaywall } = usePolicy();
|
const { shouldShowPaywall } = usePolicy();
|
||||||
|
|
||||||
|
const showAssistantSwitcherDropdown = ref(false);
|
||||||
|
const createAssistantDialogRef = ref(null);
|
||||||
|
|
||||||
|
const assistants = useMapGetter('captainAssistants/getRecords');
|
||||||
|
const uiFlags = useMapGetter('captainAssistants/getUIFlags');
|
||||||
|
|
||||||
|
const currentAssistantId = computed(() => route.params.assistantId);
|
||||||
|
const isFetchingAssistants = computed(() => uiFlags.value?.fetchingList);
|
||||||
|
|
||||||
|
const activeAssistantName = computed(() => {
|
||||||
|
return (
|
||||||
|
assistants.value?.find(
|
||||||
|
assistant => assistant.id === Number(currentAssistantId.value)
|
||||||
|
)?.name || t('CAPTAIN.ASSISTANT_SWITCHER.NEW_ASSISTANT')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const showPaywall = computed(() => {
|
const showPaywall = computed(() => {
|
||||||
return shouldShowPaywall(props.featureFlag);
|
return shouldShowPaywall(props.featureFlag);
|
||||||
});
|
});
|
||||||
@@ -72,6 +103,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>
|
||||||
@@ -81,37 +121,83 @@ const handlePageChange = event => {
|
|||||||
<div
|
<div
|
||||||
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-3 items-center">
|
||||||
<BackButton v-if="backUrl" :to="backUrl" />
|
<BackButton v-if="backUrl" :back-url="backUrl" />
|
||||||
<slot name="headerTitle">
|
|
||||||
<span class="text-xl font-medium text-n-slate-12">
|
|
||||||
{{ headerTitle }}
|
|
||||||
</span>
|
|
||||||
</slot>
|
|
||||||
<div
|
<div
|
||||||
v-if="!isEmpty && showKnowMore"
|
v-if="showAssistantSwitcher && !showPaywall"
|
||||||
class="flex items-center gap-2"
|
class="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<div class="w-0.5 h-4 rounded-2xl bg-n-weak" />
|
<div class="flex items-center gap-2">
|
||||||
<slot name="knowMore" />
|
<span
|
||||||
|
v-if="!isFetchingAssistants"
|
||||||
|
class="text-xl font-medium truncate text-n-slate-12"
|
||||||
|
>
|
||||||
|
{{ activeAssistantName }}
|
||||||
|
</span>
|
||||||
|
<div class="relative group">
|
||||||
|
<OnClickOutside
|
||||||
|
@trigger="showAssistantSwitcherDropdown = false"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
icon="i-lucide-chevron-down"
|
||||||
|
variant="ghost"
|
||||||
|
color="slate"
|
||||||
|
size="xs"
|
||||||
|
:disabled="isFetchingAssistants"
|
||||||
|
:is-loading="isFetchingAssistants"
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div
|
||||||
|
v-if="showAssistantSwitcher && !showPaywall && headerTitle"
|
||||||
|
class="w-0.5 h-4 rounded-2xl bg-n-weak"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-if="headerTitle"
|
||||||
|
class="text-xl font-medium text-n-slate-12"
|
||||||
|
>
|
||||||
|
{{ headerTitle }}
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
v-if="!isEmpty && showKnowMore"
|
||||||
|
class="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<div class="w-0.5 h-4 rounded-2xl bg-n-weak" />
|
||||||
|
<slot name="knowMore" />
|
||||||
|
</div>
|
||||||
</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 +230,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;
|
||||||
|
|
||||||
@@ -65,16 +75,17 @@ const sendMessage = async () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col h-full rounded-lg p-4 border border-n-slate-4 text-n-slate-11"
|
class="flex flex-col h-full rounded-xl border py-6 border-n-weak text-n-slate-11"
|
||||||
>
|
>
|
||||||
<div class="mb-4">
|
<div class="mb-8 px-6">
|
||||||
<div class="flex justify-between items-center mb-1">
|
<div class="flex justify-between items-center mb-1">
|
||||||
<h3 class="text-lg font-medium">
|
<h3 class="text-lg font-medium">
|
||||||
{{ t('CAPTAIN.PLAYGROUND.HEADER') }}
|
{{ t('CAPTAIN.PLAYGROUND.HEADER') }}
|
||||||
</h3>
|
</h3>
|
||||||
<NextButton
|
<NextButton
|
||||||
ghost
|
ghost
|
||||||
size="small"
|
sm
|
||||||
|
slate
|
||||||
icon="i-lucide-rotate-ccw"
|
icon="i-lucide-rotate-ccw"
|
||||||
@click="resetConversation"
|
@click="resetConversation"
|
||||||
/>
|
/>
|
||||||
@@ -87,17 +98,17 @@ const sendMessage = async () => {
|
|||||||
<MessageList :messages="messages" :is-loading="isLoading" />
|
<MessageList :messages="messages" :is-loading="isLoading" />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex items-center bg-n-solid-1 outline outline-n-container rounded-lg p-3"
|
class="flex items-center mx-6 bg-n-background outline outline-1 outline-n-weak rounded-xl p-3"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-model="newMessage"
|
v-model="newMessage"
|
||||||
class="flex-1 bg-transparent border-none focus:outline-none text-sm mb-0"
|
class="flex-1 bg-transparent border-none focus:outline-none text-sm mb-0 text-n-slate-12 placeholder:text-n-slate-10"
|
||||||
:placeholder="t('CAPTAIN.PLAYGROUND.MESSAGE_PLACEHOLDER')"
|
:placeholder="t('CAPTAIN.PLAYGROUND.MESSAGE_PLACEHOLDER')"
|
||||||
@keyup.enter="sendMessage"
|
@keyup.enter="sendMessage"
|
||||||
/>
|
/>
|
||||||
<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"
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ const getAvatarName = sender =>
|
|||||||
|
|
||||||
const getMessageStyle = sender =>
|
const getMessageStyle = sender =>
|
||||||
isUserMessage(sender)
|
isUserMessage(sender)
|
||||||
? 'bg-n-strong text-n-white'
|
? 'bg-n-solid-blue text-n-slate-12 rounded-br-sm rounded-bl-xl rounded-t-xl'
|
||||||
: 'bg-n-solid-iris text-n-slate-12';
|
: 'bg-n-solid-iris text-n-slate-12 rounded-bl-sm rounded-br-xl rounded-t-xl';
|
||||||
|
|
||||||
const scrollToBottom = async () => {
|
const scrollToBottom = async () => {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
@@ -49,7 +49,10 @@ watch(() => props.messages.length, scrollToBottom);
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div ref="messageContainer" class="flex-1 overflow-y-auto mb-4 space-y-2">
|
<div
|
||||||
|
ref="messageContainer"
|
||||||
|
class="flex-1 overflow-y-auto mb-4 px-6 space-y-6"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(message, index) in messages"
|
v-for="(message, index) in messages"
|
||||||
:key="index"
|
:key="index"
|
||||||
@@ -57,15 +60,20 @@ watch(() => props.messages.length, scrollToBottom);
|
|||||||
:class="getMessageAlignment(message.sender)"
|
:class="getMessageAlignment(message.sender)"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex items-start gap-1.5"
|
class="flex items-end gap-1.5 max-w-[90%] md:max-w-[60%]"
|
||||||
:class="getMessageDirection(message.sender)"
|
:class="getMessageDirection(message.sender)"
|
||||||
>
|
>
|
||||||
<Avatar :name="getAvatarName(message.sender)" rounded-full :size="24" />
|
<Avatar
|
||||||
|
:name="getAvatarName(message.sender)"
|
||||||
|
rounded-full
|
||||||
|
:size="24"
|
||||||
|
class="shrink-0"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
class="max-w-[80%] rounded-lg p-3 text-sm"
|
class="px-4 py-3 text-sm [overflow-wrap:break-word]"
|
||||||
:class="getMessageStyle(message.sender)"
|
:class="getMessageStyle(message.sender)"
|
||||||
>
|
>
|
||||||
<div class="break-words" v-html="formatMessage(message.content)" />
|
<div v-html="formatMessage(message.content)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
+148
@@ -0,0 +1,148 @@
|
|||||||
|
<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 v-else class="flex flex-col items-center gap-2 px-4 py-3">
|
||||||
|
<p class="text-sm text-n-slate-11">
|
||||||
|
{{ t('CAPTAIN.ASSISTANT_SWITCHER.EMPTY_LIST') }}
|
||||||
|
</p>
|
||||||
|
</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>
|
||||||
|
|||||||
@@ -8,11 +8,15 @@ import Avatar from 'dashboard/components-next/avatar/Avatar.vue';
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
menuItems: {
|
menuItems: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true,
|
default: () => [],
|
||||||
validator: value => {
|
validator: value => {
|
||||||
return value.every(item => item.action && item.value && item.label);
|
return value.every(item => item.action && item.value && item.label);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
menuSections: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
thumbnailSize: {
|
thumbnailSize: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 20,
|
default: 20,
|
||||||
@@ -42,19 +46,62 @@ const { t } = useI18n();
|
|||||||
const searchInput = ref(null);
|
const searchInput = ref(null);
|
||||||
const searchQuery = ref('');
|
const searchQuery = ref('');
|
||||||
|
|
||||||
const filteredMenuItems = computed(() => {
|
const hasSections = computed(() => props.menuSections.length > 0);
|
||||||
if (!searchQuery.value) return props.menuItems;
|
|
||||||
|
|
||||||
return props.menuItems.filter(item =>
|
const flattenedMenuItems = computed(() => {
|
||||||
|
if (!hasSections.value) {
|
||||||
|
return props.menuItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
return props.menuSections.flatMap(section => section.items || []);
|
||||||
|
});
|
||||||
|
|
||||||
|
const filteredMenuItems = computed(() => {
|
||||||
|
if (!searchQuery.value) return flattenedMenuItems.value;
|
||||||
|
|
||||||
|
return flattenedMenuItems.value.filter(item =>
|
||||||
item.label.toLowerCase().includes(searchQuery.value.toLowerCase())
|
item.label.toLowerCase().includes(searchQuery.value.toLowerCase())
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const filteredMenuSections = computed(() => {
|
||||||
|
if (!hasSections.value) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!searchQuery.value) {
|
||||||
|
return props.menuSections;
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = searchQuery.value.toLowerCase();
|
||||||
|
|
||||||
|
return props.menuSections
|
||||||
|
.map(section => {
|
||||||
|
const filteredItems = (section.items || []).filter(item =>
|
||||||
|
item.label.toLowerCase().includes(query)
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...section,
|
||||||
|
items: filteredItems,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(section => section.items.length > 0);
|
||||||
|
});
|
||||||
|
|
||||||
const handleAction = item => {
|
const handleAction = item => {
|
||||||
const { action, value, ...rest } = item;
|
const { action, value, ...rest } = item;
|
||||||
emit('action', { action, value, ...rest });
|
emit('action', { action, value, ...rest });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const shouldShowEmptyState = computed(() => {
|
||||||
|
if (hasSections.value) {
|
||||||
|
return filteredMenuSections.value.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredMenuItems.value.length === 0;
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (searchInput.value && props.showSearch) {
|
if (searchInput.value && props.showSearch) {
|
||||||
searchInput.value.focus();
|
searchInput.value.focus();
|
||||||
@@ -64,54 +111,122 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="bg-n-alpha-3 backdrop-blur-[100px] border-0 outline outline-1 outline-n-container absolute rounded-xl z-50 py-2 px-2 gap-2 flex flex-col min-w-[136px] shadow-lg"
|
class="bg-n-alpha-3 backdrop-blur-[100px] border-0 outline outline-1 outline-n-container absolute rounded-xl z-50 gap-2 flex flex-col min-w-[136px] shadow-lg pb-2 px-2"
|
||||||
|
:class="{
|
||||||
|
'pt-2': !showSearch,
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<div v-if="showSearch" class="relative">
|
|
||||||
<span class="absolute i-lucide-search size-3.5 top-2 left-3" />
|
|
||||||
<input
|
|
||||||
ref="searchInput"
|
|
||||||
v-model="searchQuery"
|
|
||||||
type="search"
|
|
||||||
:placeholder="
|
|
||||||
searchPlaceholder || t('DROPDOWN_MENU.SEARCH_PLACEHOLDER')
|
|
||||||
"
|
|
||||||
class="reset-base w-full h-8 py-2 pl-10 pr-2 text-sm focus:outline-none border-none rounded-lg bg-n-alpha-black2 dark:bg-n-solid-1 text-n-slate-12"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
v-for="(item, index) in filteredMenuItems"
|
|
||||||
:key="index"
|
|
||||||
type="button"
|
|
||||||
class="inline-flex items-center justify-start w-full h-8 min-w-0 gap-2 px-2 py-1.5 transition-all duration-200 ease-in-out border-0 rounded-lg z-60 hover:bg-n-alpha-1 dark:hover:bg-n-alpha-2 disabled:cursor-not-allowed disabled:pointer-events-none disabled:opacity-50"
|
|
||||||
:class="{
|
|
||||||
'bg-n-alpha-1 dark:bg-n-solid-active': item.isSelected,
|
|
||||||
'text-n-ruby-11': item.action === 'delete',
|
|
||||||
'text-n-slate-12': item.action !== 'delete',
|
|
||||||
}"
|
|
||||||
:disabled="item.disabled"
|
|
||||||
@click="handleAction(item)"
|
|
||||||
>
|
|
||||||
<slot name="thumbnail" :item="item">
|
|
||||||
<Avatar
|
|
||||||
v-if="item.thumbnail"
|
|
||||||
:name="item.thumbnail.name"
|
|
||||||
:src="item.thumbnail.src"
|
|
||||||
:size="thumbnailSize"
|
|
||||||
rounded-full
|
|
||||||
/>
|
|
||||||
</slot>
|
|
||||||
<Icon v-if="item.icon" :icon="item.icon" class="flex-shrink-0 size-3.5" />
|
|
||||||
<span v-if="item.emoji" class="flex-shrink-0">{{ item.emoji }}</span>
|
|
||||||
<span
|
|
||||||
v-if="item.label"
|
|
||||||
class="min-w-0 text-sm truncate"
|
|
||||||
:class="labelClass"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<div
|
<div
|
||||||
v-if="filteredMenuItems.length === 0"
|
v-if="showSearch"
|
||||||
|
class="sticky top-0 bg-n-alpha-3 backdrop-blur-sm pt-2"
|
||||||
|
>
|
||||||
|
<div class="relative">
|
||||||
|
<span class="absolute i-lucide-search size-3.5 top-2 left-3" />
|
||||||
|
<input
|
||||||
|
ref="searchInput"
|
||||||
|
v-model="searchQuery"
|
||||||
|
type="search"
|
||||||
|
:placeholder="
|
||||||
|
searchPlaceholder || t('DROPDOWN_MENU.SEARCH_PLACEHOLDER')
|
||||||
|
"
|
||||||
|
class="reset-base w-full h-8 py-2 pl-10 pr-2 text-sm focus:outline-none border-none rounded-lg bg-n-alpha-black2 dark:bg-n-solid-1 text-n-slate-12"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template v-if="hasSections">
|
||||||
|
<div
|
||||||
|
v-for="(section, sectionIndex) in filteredMenuSections"
|
||||||
|
:key="section.title || sectionIndex"
|
||||||
|
class="flex flex-col gap-1"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
v-if="section.title"
|
||||||
|
class="px-2 pt-2 text-xs font-medium text-n-slate-11 uppercase tracking-wide"
|
||||||
|
>
|
||||||
|
{{ section.title }}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
v-for="(item, itemIndex) in section.items"
|
||||||
|
:key="item.value || itemIndex"
|
||||||
|
type="button"
|
||||||
|
class="inline-flex items-center justify-start w-full h-8 min-w-0 gap-2 px-2 py-1.5 transition-all duration-200 ease-in-out border-0 rounded-lg z-60 hover:bg-n-alpha-1 dark:hover:bg-n-alpha-2 disabled:cursor-not-allowed disabled:pointer-events-none disabled:opacity-50"
|
||||||
|
:class="{
|
||||||
|
'bg-n-alpha-1 dark:bg-n-solid-active': item.isSelected,
|
||||||
|
'text-n-ruby-11': item.action === 'delete',
|
||||||
|
'text-n-slate-12': item.action !== 'delete',
|
||||||
|
}"
|
||||||
|
:disabled="item.disabled"
|
||||||
|
@click="handleAction(item)"
|
||||||
|
>
|
||||||
|
<slot name="thumbnail" :item="item">
|
||||||
|
<Avatar
|
||||||
|
v-if="item.thumbnail"
|
||||||
|
:name="item.thumbnail.name"
|
||||||
|
:src="item.thumbnail.src"
|
||||||
|
:size="thumbnailSize"
|
||||||
|
rounded-full
|
||||||
|
/>
|
||||||
|
</slot>
|
||||||
|
<Icon
|
||||||
|
v-if="item.icon"
|
||||||
|
:icon="item.icon"
|
||||||
|
class="flex-shrink-0 size-3.5"
|
||||||
|
/>
|
||||||
|
<span v-if="item.emoji" class="flex-shrink-0">{{ item.emoji }}</span>
|
||||||
|
<span
|
||||||
|
v-if="item.label"
|
||||||
|
class="min-w-0 text-sm truncate"
|
||||||
|
:class="labelClass"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
v-if="sectionIndex < filteredMenuSections.length - 1"
|
||||||
|
class="h-px bg-n-alpha-2 mx-2 my-1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<button
|
||||||
|
v-for="(item, index) in filteredMenuItems"
|
||||||
|
:key="index"
|
||||||
|
type="button"
|
||||||
|
class="inline-flex items-center justify-start w-full h-8 min-w-0 gap-2 px-2 py-1.5 transition-all duration-200 ease-in-out border-0 rounded-lg z-60 hover:bg-n-alpha-1 dark:hover:bg-n-alpha-2 disabled:cursor-not-allowed disabled:pointer-events-none disabled:opacity-50"
|
||||||
|
:class="{
|
||||||
|
'bg-n-alpha-1 dark:bg-n-solid-active': item.isSelected,
|
||||||
|
'text-n-ruby-11': item.action === 'delete',
|
||||||
|
'text-n-slate-12': item.action !== 'delete',
|
||||||
|
}"
|
||||||
|
:disabled="item.disabled"
|
||||||
|
@click="handleAction(item)"
|
||||||
|
>
|
||||||
|
<slot name="thumbnail" :item="item">
|
||||||
|
<Avatar
|
||||||
|
v-if="item.thumbnail"
|
||||||
|
:name="item.thumbnail.name"
|
||||||
|
:src="item.thumbnail.src"
|
||||||
|
:size="thumbnailSize"
|
||||||
|
rounded-full
|
||||||
|
/>
|
||||||
|
</slot>
|
||||||
|
<Icon
|
||||||
|
v-if="item.icon"
|
||||||
|
:icon="item.icon"
|
||||||
|
class="flex-shrink-0 size-3.5"
|
||||||
|
/>
|
||||||
|
<span v-if="item.emoji" class="flex-shrink-0">{{ item.emoji }}</span>
|
||||||
|
<span
|
||||||
|
v-if="item.label"
|
||||||
|
class="min-w-0 text-sm truncate"
|
||||||
|
:class="labelClass"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
v-if="shouldShowEmptyState"
|
||||||
class="text-sm text-n-slate-11 px-2 py-1.5"
|
class="text-sm text-n-slate-11 px-2 py-1.5"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, onMounted, nextTick, getCurrentInstance } from 'vue';
|
import { computed, ref, onMounted, nextTick, getCurrentInstance } from 'vue';
|
||||||
|
import { useToggle } from '@vueuse/core';
|
||||||
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: { type: [String, Number], default: '' },
|
modelValue: { type: [String, Number], default: '' },
|
||||||
type: { type: String, default: 'text' },
|
type: { type: String, default: 'text' },
|
||||||
@@ -17,10 +20,10 @@ const props = defineProps({
|
|||||||
messageType: {
|
messageType: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'info',
|
default: 'info',
|
||||||
validator: value => ['info', 'error', 'success'].includes(value),
|
validator: value => !value || ['info', 'error', 'success'].includes(value),
|
||||||
},
|
},
|
||||||
min: { type: String, default: '' },
|
min: { type: [String, Number], default: '' },
|
||||||
max: { type: String, default: '' },
|
max: { type: [String, Number], default: '' },
|
||||||
autofocus: { type: Boolean, default: false },
|
autofocus: { type: Boolean, default: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -32,6 +35,10 @@ const emit = defineEmits([
|
|||||||
'enter',
|
'enter',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
inheritAttrs: false,
|
||||||
|
});
|
||||||
|
|
||||||
// Generate a unique ID per component instance when `id` prop is not provided.
|
// Generate a unique ID per component instance when `id` prop is not provided.
|
||||||
const { uid } = getCurrentInstance();
|
const { uid } = getCurrentInstance();
|
||||||
const uniqueId = computed(() => props.id || `input-${uid}`);
|
const uniqueId = computed(() => props.id || `input-${uid}`);
|
||||||
@@ -39,25 +46,42 @@ const uniqueId = computed(() => props.id || `input-${uid}`);
|
|||||||
const isFocused = ref(false);
|
const isFocused = ref(false);
|
||||||
const inputRef = ref(null);
|
const inputRef = ref(null);
|
||||||
|
|
||||||
const messageClass = computed(() => {
|
const FIELDS = {
|
||||||
switch (props.messageType) {
|
TEXT: 'text',
|
||||||
case 'error':
|
PASSWORD: 'password',
|
||||||
return 'text-n-ruby-9 dark:text-n-ruby-9';
|
};
|
||||||
case 'success':
|
|
||||||
return 'text-n-teal-10 dark:text-n-teal-10';
|
const [isPasswordVisible, togglePasswordVisibility] = useToggle();
|
||||||
default:
|
|
||||||
return 'text-n-slate-11 dark:text-n-slate-11';
|
const isPasswordField = computed(() => props.type === FIELDS.PASSWORD);
|
||||||
|
|
||||||
|
const currentInputType = computed(() => {
|
||||||
|
if (isPasswordField.value) {
|
||||||
|
return isPasswordVisible.value ? FIELDS.TEXT : FIELDS.PASSWORD;
|
||||||
}
|
}
|
||||||
|
return props.type;
|
||||||
});
|
});
|
||||||
|
|
||||||
const inputOutlineClass = computed(() => {
|
const MESSAGE_STYLES = {
|
||||||
switch (props.messageType) {
|
error: 'text-n-ruby-9 dark:text-n-ruby-9',
|
||||||
case 'error':
|
success: 'text-n-teal-10 dark:text-n-teal-10',
|
||||||
return 'outline-n-ruby-8 dark:outline-n-ruby-8 hover:outline-n-ruby-9 dark:hover:outline-n-ruby-9 disabled:outline-n-ruby-8 dark:disabled:outline-n-ruby-8';
|
info: 'text-n-slate-11 dark:text-n-slate-11',
|
||||||
default:
|
};
|
||||||
return 'outline-n-weak dark:outline-n-weak hover:outline-n-slate-6 dark:hover:outline-n-slate-6 disabled:outline-n-weak dark:disabled:outline-n-weak focus:outline-n-brand dark:focus:outline-n-brand';
|
|
||||||
}
|
const OUTLINE_STYLES = {
|
||||||
});
|
error:
|
||||||
|
'outline-n-ruby-8 dark:outline-n-ruby-8 hover:outline-n-ruby-9 dark:hover:outline-n-ruby-9 disabled:outline-n-ruby-8 dark:disabled:outline-n-ruby-8',
|
||||||
|
default:
|
||||||
|
'outline-n-weak dark:outline-n-weak hover:outline-n-slate-6 dark:hover:outline-n-slate-6 disabled:outline-n-weak dark:disabled:outline-n-weak focus:outline-n-brand dark:focus:outline-n-brand',
|
||||||
|
};
|
||||||
|
|
||||||
|
const messageClass = computed(
|
||||||
|
() => MESSAGE_STYLES[props.messageType || 'info'] || MESSAGE_STYLES.info
|
||||||
|
);
|
||||||
|
|
||||||
|
const inputOutlineClass = computed(
|
||||||
|
() => OUTLINE_STYLES[props.messageType || 'info'] || OUTLINE_STYLES.default
|
||||||
|
);
|
||||||
|
|
||||||
const handleInput = event => {
|
const handleInput = event => {
|
||||||
let value = event.target.value;
|
let value = event.target.value;
|
||||||
@@ -104,7 +128,7 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="relative flex flex-col min-w-0 gap-1">
|
<div class="relative flex flex-col min-w-0 gap-1 w-full">
|
||||||
<label
|
<label
|
||||||
v-if="label"
|
v-if="label"
|
||||||
:for="uniqueId"
|
:for="uniqueId"
|
||||||
@@ -112,40 +136,57 @@ onMounted(() => {
|
|||||||
>
|
>
|
||||||
{{ label }}
|
{{ label }}
|
||||||
</label>
|
</label>
|
||||||
<!-- Added prefix slot to allow adding icons to the input -->
|
<div class="relative flex min-w-0 items-center">
|
||||||
<slot name="prefix" />
|
<!-- Added prefix slot to allow adding icons to the input -->
|
||||||
<input
|
<slot name="prefix" />
|
||||||
:id="uniqueId"
|
<input
|
||||||
v-bind="$attrs"
|
:id="uniqueId"
|
||||||
ref="inputRef"
|
ref="inputRef"
|
||||||
:value="modelValue"
|
v-bind="$attrs"
|
||||||
:class="[
|
:value="modelValue"
|
||||||
customInputClass,
|
:class="[
|
||||||
inputOutlineClass,
|
customInputClass,
|
||||||
sizeClass,
|
inputOutlineClass,
|
||||||
{
|
sizeClass,
|
||||||
error: messageType === 'error',
|
{
|
||||||
focus: isFocused,
|
error: messageType === 'error',
|
||||||
},
|
focus: isFocused,
|
||||||
]"
|
'ltr:!pr-10 rtl:!pl-10': isPasswordField,
|
||||||
:type="type"
|
},
|
||||||
:placeholder="placeholder"
|
]"
|
||||||
:disabled="disabled"
|
:type="currentInputType"
|
||||||
:min="['date', 'datetime-local', 'time'].includes(type) ? min : undefined"
|
:placeholder="placeholder"
|
||||||
:max="
|
:disabled="disabled"
|
||||||
['date', 'datetime-local', 'time', 'number'].includes(type)
|
:min="
|
||||||
? max
|
['date', 'datetime-local', 'time'].includes(type) ? min : undefined
|
||||||
: undefined
|
"
|
||||||
"
|
:max="
|
||||||
class="block w-full reset-base text-sm !mb-0 outline outline-1 border-none border-0 outline-offset-[-1px] rounded-lg bg-n-alpha-black2 file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-n-slate-10 dark:placeholder:text-n-slate-10 disabled:cursor-not-allowed disabled:opacity-50 text-n-slate-12 transition-all duration-500 ease-in-out [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
['date', 'datetime-local', 'time', 'number'].includes(type)
|
||||||
@input="handleInput"
|
? max
|
||||||
@focus="handleFocus"
|
: undefined
|
||||||
@blur="handleBlur"
|
"
|
||||||
@keyup.enter="handleEnter"
|
class="block w-full reset-base text-sm !mb-0 outline outline-1 border-none border-0 outline-offset-[-1px] rounded-lg bg-n-alpha-black2 file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-n-slate-10 dark:placeholder:text-n-slate-10 disabled:cursor-not-allowed disabled:opacity-50 text-n-slate-12 transition-all duration-500 ease-in-out [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
||||||
/>
|
@input="handleInput"
|
||||||
|
@focus="handleFocus"
|
||||||
|
@blur="handleBlur"
|
||||||
|
@keyup.enter="handleEnter"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
v-if="isPasswordField"
|
||||||
|
type="button"
|
||||||
|
slate
|
||||||
|
sm
|
||||||
|
link
|
||||||
|
class="absolute inset-y-0 ltr:right-3.5 rtl:left-3.5"
|
||||||
|
:icon="isPasswordVisible ? 'i-lucide-eye-off' : 'i-lucide-eye'"
|
||||||
|
:aria-label="isPasswordVisible ? 'Hide password' : 'Show password'"
|
||||||
|
:aria-pressed="isPasswordVisible"
|
||||||
|
@click="togglePasswordVisibility()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<p
|
<p
|
||||||
v-if="message"
|
v-if="message"
|
||||||
class="min-w-0 mt-1 mb-0 text-xs truncate transition-all duration-500 ease-in-out"
|
class="min-w-0 mt-0.5 mb-0 text-xs truncate transition-all duration-500 ease-in-out"
|
||||||
:class="messageClass"
|
:class="messageClass"
|
||||||
>
|
>
|
||||||
{{ message }}
|
{{ message }}
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ watch(
|
|||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
v-on-clickaway="() => closeCountryDropdown()"
|
v-on-clickaway="() => closeCountryDropdown()"
|
||||||
class="relative flex items-center h-8 transition-all duration-500 ease-in-out outline outline-1 outline-offset-[-1px] rounded-lg bg-n-alpha-black2"
|
class="relative flex items-center h-8 transition-all duration-500 ease-in-out outline outline-1 outline-offset-[-1px] w-full rounded-lg bg-n-alpha-black2"
|
||||||
:class="[inputBorderClass, { 'cursor-not-allowed opacity-50': disabled }]"
|
:class="[inputBorderClass, { 'cursor-not-allowed opacity-50': disabled }]"
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
@@ -171,8 +171,7 @@ watch(
|
|||||||
type="tel"
|
type="tel"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
custom-input-class="!border-0 !outline-none h-8 !py-0.5 !bg-transparent ltr:!pl-1 rtl:!pr-1"
|
class="!border-0 !outline-none h-8 !py-0.5 !bg-transparent ltr:!pl-1 rtl:!pr-1"
|
||||||
class="w-full !flex-row"
|
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<div class="flex items-center flex-shrink-0">
|
<div class="flex items-center flex-shrink-0">
|
||||||
@@ -186,7 +185,7 @@ watch(
|
|||||||
trailing-icon
|
trailing-icon
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
type="button"
|
type="button"
|
||||||
class="!h-[1.875rem] top-1 ltr:ml-px rtl:mr-px !px-2 outline-0 !outline-none !rounded-lg border-0 ltr:!rounded-r-none rtl:!rounded-l-none"
|
class="!h-[1.875rem] top-1 ltr:ml-px rtl:mr-px !px-2 outline-0 !outline-none !rounded-[7px] border-0 ltr:!rounded-r-none rtl:!rounded-l-none"
|
||||||
@click="toggleCountryDropdown"
|
@click="toggleCountryDropdown"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { parseAPIErrorResponse } from 'dashboard/store/utils/api';
|
|||||||
import { useAccount } from 'dashboard/composables/useAccount';
|
import { useAccount } from 'dashboard/composables/useAccount';
|
||||||
|
|
||||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||||
import FormInput from 'v3/components/Form/Input.vue';
|
import FormInput from 'dashboard/components-next/input/Input.vue';
|
||||||
import NextButton from 'dashboard/components-next/button/Button.vue';
|
import NextButton from 'dashboard/components-next/button/Button.vue';
|
||||||
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
|
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ const handleTryAnotherMethod = () => {
|
|||||||
<form class="space-y-4" @submit.prevent="handleVerification">
|
<form class="space-y-4" @submit.prevent="handleVerification">
|
||||||
<!-- OTP Code Input -->
|
<!-- OTP Code Input -->
|
||||||
<div v-if="verificationMethod === OTP">
|
<div v-if="verificationMethod === OTP">
|
||||||
<label class="block text-sm font-medium text-n-slate-12 mb-2">
|
<label class="block text-sm font-medium text-n-slate-12 mb-1.5">
|
||||||
{{ $t('MFA_VERIFICATION.ENTER_OTP_CODE') }}
|
{{ $t('MFA_VERIFICATION.ENTER_OTP_CODE') }}
|
||||||
</label>
|
</label>
|
||||||
<div class="flex justify-between gap-2">
|
<div class="flex justify-between gap-2">
|
||||||
@@ -213,7 +213,7 @@ const handleTryAnotherMethod = () => {
|
|||||||
maxlength="1"
|
maxlength="1"
|
||||||
pattern="[0-9]"
|
pattern="[0-9]"
|
||||||
inputmode="numeric"
|
inputmode="numeric"
|
||||||
class="w-12 h-12 text-center text-lg font-semibold border-2 border-n-weak hover:border-n-strong rounded-lg focus:border-n-brand bg-n-alpha-black2 text-n-slate-12 placeholder:text-n-slate-10"
|
class="w-12 h-10 text-center text-lg font-semibold outline outline-1 outline-n-weak hover:outline-n-slate-6 rounded-lg focus:outline-n-brand bg-n-alpha-black2 text-n-slate-12 placeholder:text-n-slate-10"
|
||||||
@input="handleOtpInput(i)"
|
@input="handleOtpInput(i)"
|
||||||
@keydown.left.prevent="focusInput(i - 1)"
|
@keydown.left.prevent="focusInput(i - 1)"
|
||||||
@keydown.right.prevent="focusInput(i + 1)"
|
@keydown.right.prevent="focusInput(i + 1)"
|
||||||
@@ -229,6 +229,7 @@ const handleTryAnotherMethod = () => {
|
|||||||
v-model="backupCode"
|
v-model="backupCode"
|
||||||
name="backup_code"
|
name="backup_code"
|
||||||
type="text"
|
type="text"
|
||||||
|
autocomplete="one-time-code"
|
||||||
data-testid="backup_code_input"
|
data-testid="backup_code_input"
|
||||||
:tabindex="1"
|
:tabindex="1"
|
||||||
required
|
required
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ defineProps({
|
|||||||
slate
|
slate
|
||||||
sm
|
sm
|
||||||
class="relative"
|
class="relative"
|
||||||
|
no-animation
|
||||||
:icon="icon"
|
:icon="icon"
|
||||||
:trailing-icon="trailingIcon"
|
:trailing-icon="trailingIcon"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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": {
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "Webhook URL",
|
"LABEL": "Webhook URL",
|
||||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||||
@@ -344,6 +348,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",
|
||||||
@@ -483,9 +492,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."
|
||||||
@@ -502,15 +509,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": {
|
||||||
@@ -529,9 +537,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})",
|
||||||
@@ -577,9 +582,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})",
|
||||||
@@ -625,9 +627,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})",
|
||||||
@@ -725,11 +724,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": {
|
||||||
@@ -923,11 +917,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "Last 7 days",
|
"LAST_7_DAYS": "Last 7 days",
|
||||||
"LAST_14_DAYS": "Last 14 days",
|
"LAST_14_DAYS": "Last 14 days",
|
||||||
"LAST_30_DAYS": "Last 30 days",
|
"LAST_30_DAYS": "Last 30 days",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "Last 3 months",
|
"LAST_3_MONTHS": "Last 3 months",
|
||||||
"LAST_6_MONTHS": "Last 6 months",
|
"LAST_6_MONTHS": "Last 6 months",
|
||||||
"LAST_YEAR": "Last year",
|
"LAST_YEAR": "Last year",
|
||||||
|
|||||||
@@ -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": "حذف",
|
||||||
|
"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": {
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "رابط Webhook",
|
"LABEL": "رابط Webhook",
|
||||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||||
@@ -344,6 +348,11 @@
|
|||||||
"CAPTAIN": {
|
"CAPTAIN": {
|
||||||
"NAME": "قائد",
|
"NAME": "قائد",
|
||||||
"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",
|
||||||
@@ -483,9 +492,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": "الإعدادات",
|
||||||
"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."
|
||||||
@@ -502,15 +509,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": {
|
||||||
@@ -529,9 +537,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})",
|
||||||
@@ -577,9 +582,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})",
|
||||||
@@ -625,9 +627,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})",
|
||||||
@@ -725,11 +724,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": {
|
||||||
@@ -923,11 +917,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "آخر 7 أيام",
|
"LAST_7_DAYS": "آخر 7 أيام",
|
||||||
"LAST_14_DAYS": "آخر 14 يوماً",
|
"LAST_14_DAYS": "آخر 14 يوماً",
|
||||||
"LAST_30_DAYS": "آخر 30 يوماً",
|
"LAST_30_DAYS": "آخر 30 يوماً",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "آخر 3 أشهر",
|
"LAST_3_MONTHS": "آخر 3 أشهر",
|
||||||
"LAST_6_MONTHS": "آخر 6 أشهر",
|
"LAST_6_MONTHS": "آخر 6 أشهر",
|
||||||
"LAST_YEAR": "العام الماضي",
|
"LAST_YEAR": "العام الماضي",
|
||||||
|
|||||||
@@ -251,6 +251,12 @@
|
|||||||
"ACCOUNT_SUSPENDED": {
|
"ACCOUNT_SUSPENDED": {
|
||||||
"TITLE": "تم تعليق الحساب",
|
"TITLE": "تم تعليق الحساب",
|
||||||
"MESSAGE": "تم تعليق حسابك. يرجى الاتصال بفريق الدعم للمزيد من المعلومات."
|
"MESSAGE": "تم تعليق حسابك. يرجى الاتصال بفريق الدعم للمزيد من المعلومات."
|
||||||
|
},
|
||||||
|
"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": "قنوات التواصل",
|
||||||
|
"CAPTAIN_SETTINGS": "الإعدادات",
|
||||||
"HOME": "الرئيسية",
|
"HOME": "الرئيسية",
|
||||||
"AGENTS": "وكيل الدعم",
|
"AGENTS": "وكيل الدعم",
|
||||||
"AGENT_BOTS": "الروبوتات",
|
"AGENT_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": "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": {
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "Webhook URL",
|
"LABEL": "Webhook URL",
|
||||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||||
@@ -344,6 +348,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",
|
||||||
@@ -483,9 +492,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."
|
||||||
@@ -502,15 +509,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": {
|
||||||
@@ -529,9 +537,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})",
|
||||||
@@ -577,9 +582,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})",
|
||||||
@@ -625,9 +627,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})",
|
||||||
@@ -725,11 +724,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": {
|
||||||
@@ -923,11 +917,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "Last 7 days",
|
"LAST_7_DAYS": "Last 7 days",
|
||||||
"LAST_14_DAYS": "Last 14 days",
|
"LAST_14_DAYS": "Last 14 days",
|
||||||
"LAST_30_DAYS": "Last 30 days",
|
"LAST_30_DAYS": "Last 30 days",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "Last 3 months",
|
"LAST_3_MONTHS": "Last 3 months",
|
||||||
"LAST_6_MONTHS": "Last 6 months",
|
"LAST_6_MONTHS": "Last 6 months",
|
||||||
"LAST_YEAR": "Last year",
|
"LAST_YEAR": "Last year",
|
||||||
|
|||||||
@@ -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": "Изтрий",
|
||||||
|
"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": {
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "Webhook URL",
|
"LABEL": "Webhook URL",
|
||||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||||
@@ -344,6 +348,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",
|
||||||
@@ -483,9 +492,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."
|
||||||
@@ -502,15 +509,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": {
|
||||||
@@ -529,9 +537,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})",
|
||||||
@@ -577,9 +582,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})",
|
||||||
@@ -625,9 +627,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})",
|
||||||
@@ -725,11 +724,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": {
|
||||||
@@ -923,11 +917,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "Last 7 days",
|
"LAST_7_DAYS": "Last 7 days",
|
||||||
"LAST_14_DAYS": "Last 14 days",
|
"LAST_14_DAYS": "Last 14 days",
|
||||||
"LAST_30_DAYS": "Last 30 days",
|
"LAST_30_DAYS": "Last 30 days",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "Last 3 months",
|
"LAST_3_MONTHS": "Last 3 months",
|
||||||
"LAST_6_MONTHS": "Last 6 months",
|
"LAST_6_MONTHS": "Last 6 months",
|
||||||
"LAST_YEAR": "Last year",
|
"LAST_YEAR": "Last year",
|
||||||
|
|||||||
@@ -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": "Агенти",
|
||||||
"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": "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": {
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "Webhook URL",
|
"LABEL": "Webhook URL",
|
||||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||||
@@ -344,6 +348,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",
|
||||||
@@ -483,9 +492,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."
|
||||||
@@ -502,15 +509,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": {
|
||||||
@@ -529,9 +537,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})",
|
||||||
@@ -577,9 +582,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})",
|
||||||
@@ -625,9 +627,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})",
|
||||||
@@ -725,11 +724,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": {
|
||||||
@@ -923,11 +917,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "Last 7 days",
|
"LAST_7_DAYS": "Last 7 days",
|
||||||
"LAST_14_DAYS": "Last 14 days",
|
"LAST_14_DAYS": "Last 14 days",
|
||||||
"LAST_30_DAYS": "Last 30 days",
|
"LAST_30_DAYS": "Last 30 days",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "Last 3 months",
|
"LAST_3_MONTHS": "Last 3 months",
|
||||||
"LAST_6_MONTHS": "Last 6 months",
|
"LAST_6_MONTHS": "Last 6 months",
|
||||||
"LAST_YEAR": "Last year",
|
"LAST_YEAR": "Last year",
|
||||||
|
|||||||
@@ -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": "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": {
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "URL del webhook",
|
"LABEL": "URL del webhook",
|
||||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||||
@@ -344,6 +348,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",
|
||||||
@@ -483,9 +492,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": "Configuracions",
|
||||||
"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."
|
||||||
@@ -502,15 +509,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": {
|
||||||
@@ -529,9 +537,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})",
|
||||||
@@ -577,9 +582,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})",
|
||||||
@@ -625,9 +627,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})",
|
||||||
@@ -725,11 +724,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": {
|
||||||
@@ -923,11 +917,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "Últims 7 dies",
|
"LAST_7_DAYS": "Últims 7 dies",
|
||||||
"LAST_14_DAYS": "Últims 14 dies",
|
"LAST_14_DAYS": "Últims 14 dies",
|
||||||
"LAST_30_DAYS": "Últims 30 dies",
|
"LAST_30_DAYS": "Últims 30 dies",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "Últims tres mesos",
|
"LAST_3_MONTHS": "Últims tres mesos",
|
||||||
"LAST_6_MONTHS": "Últims sis mesos",
|
"LAST_6_MONTHS": "Últims sis mesos",
|
||||||
"LAST_YEAR": "Darrer any",
|
"LAST_YEAR": "Darrer any",
|
||||||
|
|||||||
@@ -251,6 +251,12 @@
|
|||||||
"ACCOUNT_SUSPENDED": {
|
"ACCOUNT_SUSPENDED": {
|
||||||
"TITLE": "Compte suspès",
|
"TITLE": "Compte suspès",
|
||||||
"MESSAGE": "El teu compte està suspès. Posa't en contacte amb l'equip d'assistència per obtenir més informació."
|
"MESSAGE": "El teu compte està suspès. Posa't en contacte amb l'equip d'assistència per obtenir més informació."
|
||||||
|
},
|
||||||
|
"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": "Safates d'entrada",
|
||||||
|
"CAPTAIN_SETTINGS": "Configuracions",
|
||||||
"HOME": "Inici",
|
"HOME": "Inici",
|
||||||
"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": "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": {
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "URL webového háčku",
|
"LABEL": "URL webového háčku",
|
||||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||||
@@ -344,6 +348,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",
|
||||||
@@ -483,9 +492,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": "Nastavení",
|
||||||
"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."
|
||||||
@@ -502,15 +509,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": {
|
||||||
@@ -529,9 +537,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})",
|
||||||
@@ -577,9 +582,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})",
|
||||||
@@ -625,9 +627,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})",
|
||||||
@@ -725,11 +724,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": {
|
||||||
@@ -923,11 +917,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "Posledních 7 dní",
|
"LAST_7_DAYS": "Posledních 7 dní",
|
||||||
"LAST_14_DAYS": "Posledních 14 dní",
|
"LAST_14_DAYS": "Posledních 14 dní",
|
||||||
"LAST_30_DAYS": "Posledních 30 dní",
|
"LAST_30_DAYS": "Posledních 30 dní",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "Poslední 3 měsíce",
|
"LAST_3_MONTHS": "Poslední 3 měsíce",
|
||||||
"LAST_6_MONTHS": "Posledních 6 měsíců",
|
"LAST_6_MONTHS": "Posledních 6 měsíců",
|
||||||
"LAST_YEAR": "Poslední rok",
|
"LAST_YEAR": "Poslední rok",
|
||||||
|
|||||||
@@ -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": "Schránky",
|
||||||
|
"CAPTAIN_SETTINGS": "Nastavení",
|
||||||
"HOME": "Domů",
|
"HOME": "Domů",
|
||||||
"AGENTS": "Agenti",
|
"AGENTS": "Agenti",
|
||||||
"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": "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": {
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "Webhook URL",
|
"LABEL": "Webhook URL",
|
||||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||||
@@ -344,6 +348,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",
|
||||||
@@ -483,9 +492,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": "Indstillinger",
|
||||||
"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."
|
||||||
@@ -502,15 +509,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": {
|
||||||
@@ -529,9 +537,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})",
|
||||||
@@ -577,9 +582,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})",
|
||||||
@@ -625,9 +627,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})",
|
||||||
@@ -725,11 +724,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": {
|
||||||
@@ -923,11 +917,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "Seneste 7 dage",
|
"LAST_7_DAYS": "Seneste 7 dage",
|
||||||
"LAST_14_DAYS": "Seneste 14 dage",
|
"LAST_14_DAYS": "Seneste 14 dage",
|
||||||
"LAST_30_DAYS": "Seneste 30 dage",
|
"LAST_30_DAYS": "Seneste 30 dage",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "Seneste 3 måneder",
|
"LAST_3_MONTHS": "Seneste 3 måneder",
|
||||||
"LAST_6_MONTHS": "Seneste 6 måneder",
|
"LAST_6_MONTHS": "Seneste 6 måneder",
|
||||||
"LAST_YEAR": "Sidste år",
|
"LAST_YEAR": "Sidste år",
|
||||||
|
|||||||
@@ -251,6 +251,12 @@
|
|||||||
"ACCOUNT_SUSPENDED": {
|
"ACCOUNT_SUSPENDED": {
|
||||||
"TITLE": "Konto Suspenderet",
|
"TITLE": "Konto Suspenderet",
|
||||||
"MESSAGE": "Din konto er suspenderet. Gå ud til supportteamet for mere information."
|
"MESSAGE": "Din konto er suspenderet. Gå ud til supportteamet for mere 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": "Indbakker",
|
||||||
|
"CAPTAIN_SETTINGS": "Indstillinger",
|
||||||
"HOME": "Hjem",
|
"HOME": "Hjem",
|
||||||
"AGENTS": "Agenter",
|
"AGENTS": "Agenter",
|
||||||
"AGENT_BOTS": "Bots",
|
"AGENT_BOTS": "Bots",
|
||||||
|
|||||||
@@ -18,9 +18,9 @@
|
|||||||
"CREATED_AT_LABEL": "Erstellt",
|
"CREATED_AT_LABEL": "Erstellt",
|
||||||
"NEW_MESSAGE": "Neue Nachricht",
|
"NEW_MESSAGE": "Neue Nachricht",
|
||||||
"CALL": "Anruf",
|
"CALL": "Anruf",
|
||||||
"CALL_UNDER_DEVELOPMENT": "Calling is under development",
|
"CALL_UNDER_DEVELOPMENT": "Anrufe sind in der Entwicklung",
|
||||||
"VOICE_INBOX_PICKER": {
|
"VOICE_INBOX_PICKER": {
|
||||||
"TITLE": "Choose a voice inbox"
|
"TITLE": "Spracheingang wählen"
|
||||||
},
|
},
|
||||||
"CONVERSATIONS": {
|
"CONVERSATIONS": {
|
||||||
"NO_RECORDS_FOUND": "Es sind keine vorherigen Gespräche mit diesem Kontakt verbunden.",
|
"NO_RECORDS_FOUND": "Es sind keine vorherigen Gespräche mit diesem Kontakt verbunden.",
|
||||||
@@ -554,12 +554,12 @@
|
|||||||
"WROTE": "schrieb",
|
"WROTE": "schrieb",
|
||||||
"YOU": "Sie",
|
"YOU": "Sie",
|
||||||
"SAVE": "Notiz speichern",
|
"SAVE": "Notiz speichern",
|
||||||
"ADD_NOTE": "Add contact note",
|
"ADD_NOTE": "Füge eine Kontakt-Notiz hinzu",
|
||||||
"EXPAND": "Erweitern",
|
"EXPAND": "Erweitern",
|
||||||
"COLLAPSE": "Einklappen",
|
"COLLAPSE": "Einklappen",
|
||||||
"NO_NOTES": "Keine Notizen, Sie können Notizen auf der Kontakt-Detailseite hinzufügen.",
|
"NO_NOTES": "Keine Notizen, Sie können Notizen auf der Kontakt-Detailseite hinzufügen.",
|
||||||
"EMPTY_STATE": "Es gibt keine Notizen zu diesem Kontakt. Sie können eine Notiz hinzufügen, indem Sie diese in das obige Feld eingeben.",
|
"EMPTY_STATE": "Es gibt keine Notizen zu diesem Kontakt. Sie können eine Notiz hinzufügen, indem Sie diese in das obige Feld eingeben.",
|
||||||
"CONVERSATION_EMPTY_STATE": "There are no notes yet. Use the Add note button to create one."
|
"CONVERSATION_EMPTY_STATE": "Es sind noch keine Notizen vorhanden. Benutzen Sie die Schaltfläche \"Notiz hinzufügen\" um eine zu erstellen."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"EMPTY_STATE": {
|
"EMPTY_STATE": {
|
||||||
@@ -574,12 +574,23 @@
|
|||||||
"CONTACTS_BULK_ACTIONS": {
|
"CONTACTS_BULK_ACTIONS": {
|
||||||
"ASSIGN_LABELS": "Labels zuweisen",
|
"ASSIGN_LABELS": "Labels zuweisen",
|
||||||
"ASSIGN_LABELS_SUCCESS": "Labels erfolgreich zugewiesen.",
|
"ASSIGN_LABELS_SUCCESS": "Labels erfolgreich zugewiesen.",
|
||||||
"ASSIGN_LABELS_FAILED": "Failed to assign labels",
|
"ASSIGN_LABELS_FAILED": "Fehler beim Zuweisen der Labels",
|
||||||
"DESCRIPTION": "Select the labels you want to add to the selected contacts.",
|
"DESCRIPTION": "Wählen Sie die Labels aus, die zu den ausgewählten Kontakten hinzugefügt werden sollen.",
|
||||||
"NO_LABELS_FOUND": "No labels available yet.",
|
"NO_LABELS_FOUND": "Noch keine Labels vorhanden.",
|
||||||
"SELECTED_COUNT": "{count} selected",
|
"SELECTED_COUNT": "{count} selected",
|
||||||
"CLEAR_SELECTION": "Clear selection",
|
"CLEAR_SELECTION": "Auswahl löschen",
|
||||||
"SELECT_ALL": "Select all ({count})"
|
"SELECT_ALL": "Alle auswählen ({count})",
|
||||||
|
"DELETE_CONTACTS": "Löschen",
|
||||||
|
"DELETE_SUCCESS": "Kontakte erfolgreich gelöscht.",
|
||||||
|
"DELETE_FAILED": "Kontakte konnten nicht gelöscht werden.",
|
||||||
|
"DELETE_DIALOG": {
|
||||||
|
"TITLE": "Ausgewählte Kontakte löschen",
|
||||||
|
"SINGULAR_TITLE": "Ausgewählten Kontakt löschen",
|
||||||
|
"DESCRIPTION": "Dies wird {count} ausgewählte Kontakte dauerhaft löschen. Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||||
|
"SINGULAR_DESCRIPTION": "Der ausgewählte Kontakt wird dauerhaft gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||||
|
"CONFIRM_MULTIPLE": "Kontakte löschen",
|
||||||
|
"CONFIRM_SINGLE": "Kontakt löschen"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"COMPOSE_NEW_CONVERSATION": {
|
"COMPOSE_NEW_CONVERSATION": {
|
||||||
"CONTACT_SEARCH": {
|
"CONTACT_SEARCH": {
|
||||||
|
|||||||
@@ -36,10 +36,10 @@
|
|||||||
"NOT_ASSIGNED_TO_YOU": "Diese Konversation ist Ihnen nicht zugeordnet. Möchten Sie dieses Gespräch sich selbst zuordnen?",
|
"NOT_ASSIGNED_TO_YOU": "Diese Konversation ist Ihnen nicht zugeordnet. Möchten Sie dieses Gespräch sich selbst zuordnen?",
|
||||||
"ASSIGN_TO_ME": "Mir zuweisen",
|
"ASSIGN_TO_ME": "Mir zuweisen",
|
||||||
"BOT_HANDOFF_MESSAGE": "Sie antworten auf eine Unterhaltung, die derzeit von einem Assistenten oder einem Bot bearbeitet wird.",
|
"BOT_HANDOFF_MESSAGE": "Sie antworten auf eine Unterhaltung, die derzeit von einem Assistenten oder einem Bot bearbeitet wird.",
|
||||||
"BOT_HANDOFF_ACTION": "Mark open and assign to you",
|
"BOT_HANDOFF_ACTION": "Als geöffnet markieren und Ihnen zuweisen",
|
||||||
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
|
"BOT_HANDOFF_REOPEN_ACTION": "Gespräch als geöffnet markieren",
|
||||||
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
|
"BOT_HANDOFF_SUCCESS": "Die Unterhaltung wurde dir übergeben",
|
||||||
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
|
"BOT_HANDOFF_ERROR": "Die Unterhaltung konnte nicht übernommen werden. Bitte versuche es erneut.",
|
||||||
"TWILIO_WHATSAPP_CAN_REPLY": "Sie können auf diese Konversation nur mit einer Nachrichtenvorlage antworten wegen",
|
"TWILIO_WHATSAPP_CAN_REPLY": "Sie können auf diese Konversation nur mit einer Nachrichtenvorlage antworten wegen",
|
||||||
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24-Stunden-Nachrichtenfenster-Beschränkung",
|
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24-Stunden-Nachrichtenfenster-Beschränkung",
|
||||||
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "Dieser Instagram-Account wurde in den neuen Instagram-Kanal übertragen. Alle neuen Nachrichten werden dort erscheinen. Sie werden keine Nachrichten mehr von dieser Unterhaltung senden können.",
|
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "Dieser Instagram-Account wurde in den neuen Instagram-Kanal übertragen. Alle neuen Nachrichten werden dort erscheinen. Sie werden keine Nachrichten mehr von dieser Unterhaltung senden können.",
|
||||||
@@ -72,15 +72,15 @@
|
|||||||
"HIDE_LABELS": "Labels ausblenden"
|
"HIDE_LABELS": "Labels ausblenden"
|
||||||
},
|
},
|
||||||
"VOICE_CALL": {
|
"VOICE_CALL": {
|
||||||
"INCOMING_CALL": "Incoming call",
|
"INCOMING_CALL": "Eingehender Anruf",
|
||||||
"OUTGOING_CALL": "Outgoing call",
|
"OUTGOING_CALL": "Ausgehender Anruf",
|
||||||
"CALL_IN_PROGRESS": "Call in progress",
|
"CALL_IN_PROGRESS": "Anruf läuft",
|
||||||
"NO_ANSWER": "No answer",
|
"NO_ANSWER": "Keine Antwort",
|
||||||
"MISSED_CALL": "Missed call",
|
"MISSED_CALL": "Entgangener Anruf",
|
||||||
"CALL_ENDED": "Call ended",
|
"CALL_ENDED": "Anruf beendet",
|
||||||
"NOT_ANSWERED_YET": "Not answered yet",
|
"NOT_ANSWERED_YET": "Noch nicht beantwortet",
|
||||||
"THEY_ANSWERED": "They answered",
|
"THEY_ANSWERED": "Sie antworteten",
|
||||||
"YOU_ANSWERED": "You answered"
|
"YOU_ANSWERED": "Sie haben beantwortet"
|
||||||
},
|
},
|
||||||
"HEADER": {
|
"HEADER": {
|
||||||
"RESOLVE_ACTION": "Fall schließen",
|
"RESOLVE_ACTION": "Fall schließen",
|
||||||
@@ -160,9 +160,9 @@
|
|||||||
"AGENTS_LOADING": "Agenten werden geladen...",
|
"AGENTS_LOADING": "Agenten werden geladen...",
|
||||||
"ASSIGN_TEAM": "Team zuweisen",
|
"ASSIGN_TEAM": "Team zuweisen",
|
||||||
"DELETE": "Unterhaltung löschen",
|
"DELETE": "Unterhaltung löschen",
|
||||||
"OPEN_IN_NEW_TAB": "Open in new tab",
|
"OPEN_IN_NEW_TAB": "In neuem Tab öffnen",
|
||||||
"COPY_LINK": "Copy conversation link",
|
"COPY_LINK": "Konversationslink kopieren",
|
||||||
"COPY_LINK_SUCCESS": "Conversation link copied to clipboard",
|
"COPY_LINK_SUCCESS": "Konversationslink in Zwischenablage kopiert",
|
||||||
"API": {
|
"API": {
|
||||||
"AGENT_ASSIGNMENT": {
|
"AGENT_ASSIGNMENT": {
|
||||||
"SUCCESFUL": "Konversations-ID {conversationId} zugewiesen zu \"{agentName}\"",
|
"SUCCESFUL": "Konversations-ID {conversationId} zugewiesen zu \"{agentName}\"",
|
||||||
@@ -229,11 +229,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"QUOTED_REPLY": {
|
"QUOTED_REPLY": {
|
||||||
"ENABLE_TOOLTIP": "Include quoted email thread",
|
"ENABLE_TOOLTIP": "Zitierten E-Mail-Thread einbeziehen",
|
||||||
"DISABLE_TOOLTIP": "Don't include quoted email thread",
|
"DISABLE_TOOLTIP": "Zitierten E-Mail-Thread nicht einbeziehen",
|
||||||
"REMOVE_PREVIEW": "Remove quoted email thread",
|
"REMOVE_PREVIEW": "Zitierte E-Mail-Themen entfernen",
|
||||||
"COLLAPSE": "Collapse preview",
|
"COLLAPSE": "Vorschau ausblenden",
|
||||||
"EXPAND": "Expand preview"
|
"EXPAND": "Vorschau erweitern"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"VISIBLE_TO_AGENTS": "Privater Hinweis: Nur für Sie und Ihr Team sichtbar",
|
"VISIBLE_TO_AGENTS": "Privater Hinweis: Nur für Sie und Ihr Team sichtbar",
|
||||||
@@ -338,7 +338,7 @@
|
|||||||
"CONTACT_ATTRIBUTES": "Kontakt-Attribute",
|
"CONTACT_ATTRIBUTES": "Kontakt-Attribute",
|
||||||
"PREVIOUS_CONVERSATION": "Vorherige Konversationen",
|
"PREVIOUS_CONVERSATION": "Vorherige Konversationen",
|
||||||
"MACROS": "Makros",
|
"MACROS": "Makros",
|
||||||
"LINEAR_ISSUES": "Linked Linear Issues",
|
"LINEAR_ISSUES": "Verknüpfte lineare Probleme",
|
||||||
"SHOPIFY_ORDERS": "Shopify Orders"
|
"SHOPIFY_ORDERS": "Shopify Orders"
|
||||||
},
|
},
|
||||||
"SHOPIFY": {
|
"SHOPIFY": {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"LIMIT_MESSAGES": {
|
"LIMIT_MESSAGES": {
|
||||||
"CONVERSATION": "Sie haben das Konversationslimit überschritten. Der Hacker Plan erlaubt nur 500 Unterhaltungen.",
|
"CONVERSATION": "Sie haben das Konversationslimit überschritten. Der Hacker Plan erlaubt nur 500 Unterhaltungen.",
|
||||||
"INBOXES": "Sie haben das Posteingang-Limit überschritten. Der Hacker-Plan unterstützt nur Live-Chat der Webseite. Zusätzliche Posteingänge wie E-Mail, WhatsApp usw. erfordern einen kostenpflichtigen Tarif.",
|
"INBOXES": "Sie haben das Posteingang-Limit überschritten. Der Hacker-Plan unterstützt nur Live-Chat der Webseite. Zusätzliche Posteingänge wie E-Mail, WhatsApp usw. erfordern einen kostenpflichtigen Tarif.",
|
||||||
"AGENTS": "You have exceeded the agent limit. Your plan only allows {allowedAgents} agents.",
|
"AGENTS": "Sie haben das Agenten-Limit überschritten. Ihr Plan erlaubt nur {allowedAgents} Agenten.",
|
||||||
"NON_ADMIN": "Bitte kontaktieren Sie Ihren Administrator, um den Plan zu upgraden und alle Funktionen weiterzunutzen."
|
"NON_ADMIN": "Bitte kontaktieren Sie Ihren Administrator, um den Plan zu upgraden und alle Funktionen weiterzunutzen."
|
||||||
},
|
},
|
||||||
"TITLE": "Kontoeinstellungen",
|
"TITLE": "Kontoeinstellungen",
|
||||||
@@ -25,13 +25,13 @@
|
|||||||
"DISMISS": "Stornieren",
|
"DISMISS": "Stornieren",
|
||||||
"PLACE_HOLDER": "Bitte {accountName} zur Bestätigung eingeben"
|
"PLACE_HOLDER": "Bitte {accountName} zur Bestätigung eingeben"
|
||||||
},
|
},
|
||||||
"SUCCESS": "Account marked for deletion",
|
"SUCCESS": "Konto zur Löschung markiert",
|
||||||
"FAILURE": "Could not delete account, try again!",
|
"FAILURE": "Konto konnte nicht gelöscht werden, versuche es erneut!",
|
||||||
"SCHEDULED_DELETION": {
|
"SCHEDULED_DELETION": {
|
||||||
"TITLE": "Account Scheduled for Deletion",
|
"TITLE": "Konto für Löschung geplant",
|
||||||
"MESSAGE_MANUAL": "This account is scheduled for deletion on {deletionDate}. This was requested by an administrator. You can cancel the deletion before this date.",
|
"MESSAGE_MANUAL": "Dieses Konto ist für das Löschen auf {deletionDate} geplant. Dies wurde von einem Administrator angefordert. Sie können das Löschen vor diesem Datum abbrechen.",
|
||||||
"MESSAGE_INACTIVITY": "This account is scheduled for deletion on {deletionDate} due to account inactivity. You can cancel the deletion before this date.",
|
"MESSAGE_INACTIVITY": "Dieses Konto ist für die Löschung auf {deletionDate} aufgrund von Kontoinaktivität vorgesehen. Sie können die Löschung vor diesem Datum abbrechen.",
|
||||||
"CLEAR_BUTTON": "Cancel Scheduled Deletion"
|
"CLEAR_BUTTON": "Geplante Löschung abbrechen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"FORM": {
|
"FORM": {
|
||||||
@@ -45,13 +45,13 @@
|
|||||||
"NOTE": "Diese ID ist erforderlich, wenn Sie eine API-basierte Integration erstellen"
|
"NOTE": "Diese ID ist erforderlich, wenn Sie eine API-basierte Integration erstellen"
|
||||||
},
|
},
|
||||||
"AUTO_RESOLVE": {
|
"AUTO_RESOLVE": {
|
||||||
"TITLE": "Auto-resolve conversations",
|
"TITLE": "Unterhaltungen automatisch auflösen",
|
||||||
"NOTE": "This configuration would allow you to automatically resolve the conversation after a certain period of inactivity.",
|
"NOTE": "Diese Konfiguration würde es Ihnen ermöglichen, die Unterhaltung nach einer gewissen Zeit der Inaktivität automatisch zu beenden.",
|
||||||
"DURATION": {
|
"DURATION": {
|
||||||
"LABEL": "Inactivity duration",
|
"LABEL": "Dauer der Inaktivität",
|
||||||
"HELP": "Time period of inactivity after which conversation is auto-resolved",
|
"HELP": "Zeit der Inaktivität, nach der die Unterhaltung automatisch gelöst wird",
|
||||||
"PLACEHOLDER": "30",
|
"PLACEHOLDER": "30",
|
||||||
"ERROR": "Auto resolve duration should be between 10 minutes and 999 days",
|
"ERROR": "Automatische Auflösungsdauer sollte zwischen 10 Minuten und 999 Tagen liegen",
|
||||||
"API": {
|
"API": {
|
||||||
"SUCCESS": "Auto resolve settings updated successfully",
|
"SUCCESS": "Auto resolve settings updated successfully",
|
||||||
"ERROR": "Failed to update auto resolve settings"
|
"ERROR": "Failed to update auto resolve settings"
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
"LABEL": "Inactivity duration for resolution",
|
"LABEL": "Inactivity duration for resolution",
|
||||||
"HELP": "Duration after a conversation should auto resolve if there is no activity",
|
"HELP": "Duration after a conversation should auto resolve if there is no activity",
|
||||||
"PLACEHOLDER": "30",
|
"PLACEHOLDER": "30",
|
||||||
"ERROR": "Auto resolve duration should be between 10 minutes and 999 days",
|
"ERROR": "Automatische Auflösungsdauer sollte zwischen 10 Minuten und 999 Tagen liegen",
|
||||||
"API": {
|
"API": {
|
||||||
"SUCCESS": "Auto resolve settings updated successfully",
|
"SUCCESS": "Auto resolve settings updated successfully",
|
||||||
"ERROR": "Failed to update auto resolve settings"
|
"ERROR": "Failed to update auto resolve settings"
|
||||||
|
|||||||
@@ -296,17 +296,17 @@
|
|||||||
"WAITING_FOR_AUTH": "Waiting for authentication...",
|
"WAITING_FOR_AUTH": "Waiting for authentication...",
|
||||||
"INVALID_BUSINESS_DATA": "Invalid business data received from Facebook. Please try again.",
|
"INVALID_BUSINESS_DATA": "Invalid business data received from Facebook. Please try again.",
|
||||||
"SIGNUP_ERROR": "Signup error occurred",
|
"SIGNUP_ERROR": "Signup error occurred",
|
||||||
"AUTH_NOT_COMPLETED": "Authentication not completed. Please restart the process.",
|
"AUTH_NOT_COMPLETED": "Authentifizierung nicht abgeschlossen. Bitte starte den Prozess neu.",
|
||||||
"SUCCESS_FALLBACK": "WhatsApp Business Account has been successfully configured",
|
"SUCCESS_FALLBACK": "WhatsApp Business Account wurde erfolgreich konfiguriert",
|
||||||
"MANUAL_FALLBACK": "If your number is already connected to the WhatsApp Business Platform (API), or if you’re a tech provider onboarding your own number, please use the {link} flow",
|
"MANUAL_FALLBACK": "Wenn Ihre Nummer bereits mit der WhatsApp Business Plattform (API) verbunden ist, oder wenn Sie als Technologieanbieter Ihre eigene Nummer an Bord haben, verwenden Sie bitte den {link} Flow",
|
||||||
"MANUAL_LINK_TEXT": "manual setup flow"
|
"MANUAL_LINK_TEXT": "Manueller Einrichtungsablauf"
|
||||||
},
|
},
|
||||||
"API": {
|
"API": {
|
||||||
"ERROR_MESSAGE": "Wir konnten den WhatsApp-Kanal nicht speichern"
|
"ERROR_MESSAGE": "Wir konnten den WhatsApp-Kanal nicht speichern"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"VOICE": {
|
"VOICE": {
|
||||||
"TITLE": "Voice Channel",
|
"TITLE": "Sprachkanal",
|
||||||
"DESC": "Integrate Twilio Voice and start supporting your customers via phone calls.",
|
"DESC": "Integrate Twilio Voice and start supporting your customers via phone calls.",
|
||||||
"PHONE_NUMBER": {
|
"PHONE_NUMBER": {
|
||||||
"LABEL": "Telefonnummer",
|
"LABEL": "Telefonnummer",
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "Webhook-URL",
|
"LABEL": "Webhook-URL",
|
||||||
"PLACEHOLDER": "Beispiel: {webhookExampleURL}",
|
"PLACEHOLDER": "Beispiel: {webhookExampleURL}",
|
||||||
@@ -344,6 +348,11 @@
|
|||||||
"CAPTAIN": {
|
"CAPTAIN": {
|
||||||
"NAME": "Kapitän",
|
"NAME": "Kapitän",
|
||||||
"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": "Probiere diese Prompts",
|
"TRY_THESE_PROMPTS": "Probiere diese Prompts",
|
||||||
@@ -483,9 +492,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": "Einstellungen",
|
||||||
"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."
|
||||||
@@ -502,15 +509,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": {
|
||||||
@@ -529,9 +537,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})",
|
||||||
@@ -577,9 +582,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})",
|
||||||
@@ -625,9 +627,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})",
|
||||||
@@ -725,11 +724,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": {
|
||||||
@@ -923,11 +917,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "Letzten 7 Tage",
|
"LAST_7_DAYS": "Letzten 7 Tage",
|
||||||
"LAST_14_DAYS": "Letzten 14 Tage",
|
"LAST_14_DAYS": "Letzten 14 Tage",
|
||||||
"LAST_30_DAYS": "Letzte 30 Tage",
|
"LAST_30_DAYS": "Letzte 30 Tage",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "Die letzten 3 Monate",
|
"LAST_3_MONTHS": "Die letzten 3 Monate",
|
||||||
"LAST_6_MONTHS": "Die letzten 6 Monate",
|
"LAST_6_MONTHS": "Die letzten 6 Monate",
|
||||||
"LAST_YEAR": "Letztes Jahr",
|
"LAST_YEAR": "Letztes Jahr",
|
||||||
|
|||||||
@@ -251,6 +251,12 @@
|
|||||||
"ACCOUNT_SUSPENDED": {
|
"ACCOUNT_SUSPENDED": {
|
||||||
"TITLE": "Konto gesperrt",
|
"TITLE": "Konto gesperrt",
|
||||||
"MESSAGE": "Ihr Account wurde gesperrt. Wenden Sie sich für weitere Informationen bitte an das Support-Team."
|
"MESSAGE": "Ihr Account wurde gesperrt. Wenden Sie sich für weitere Informationen bitte an das Support-Team."
|
||||||
|
},
|
||||||
|
"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": "Posteingänge",
|
||||||
|
"CAPTAIN_SETTINGS": "Einstellungen",
|
||||||
"HOME": "Hauptseite",
|
"HOME": "Hauptseite",
|
||||||
"AGENTS": "Agenten",
|
"AGENTS": "Agenten",
|
||||||
"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": "Διαγραφή",
|
||||||
|
"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": {
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "Σύνδεσμος Webhook",
|
"LABEL": "Σύνδεσμος Webhook",
|
||||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||||
@@ -344,6 +348,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",
|
||||||
@@ -483,9 +492,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": "Ρυθμίσεις",
|
||||||
"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."
|
||||||
@@ -502,15 +509,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": {
|
||||||
@@ -529,9 +537,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})",
|
||||||
@@ -577,9 +582,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})",
|
||||||
@@ -625,9 +627,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})",
|
||||||
@@ -725,11 +724,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": {
|
||||||
@@ -923,11 +917,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "Τελευταίες 7 ημέρες",
|
"LAST_7_DAYS": "Τελευταίες 7 ημέρες",
|
||||||
"LAST_14_DAYS": "Τελευταίες 14 ημέρες",
|
"LAST_14_DAYS": "Τελευταίες 14 ημέρες",
|
||||||
"LAST_30_DAYS": "Τελευταίες 30 ημέρες",
|
"LAST_30_DAYS": "Τελευταίες 30 ημέρες",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "Τελευταίοι 3 μήνες",
|
"LAST_3_MONTHS": "Τελευταίοι 3 μήνες",
|
||||||
"LAST_6_MONTHS": "Τελευταίοι 6 μήνες",
|
"LAST_6_MONTHS": "Τελευταίοι 6 μήνες",
|
||||||
"LAST_YEAR": "Τελευταίο έτος",
|
"LAST_YEAR": "Τελευταίο έτος",
|
||||||
|
|||||||
@@ -251,6 +251,12 @@
|
|||||||
"ACCOUNT_SUSPENDED": {
|
"ACCOUNT_SUSPENDED": {
|
||||||
"TITLE": "Αναστολή Λογαριασμού",
|
"TITLE": "Αναστολή Λογαριασμού",
|
||||||
"MESSAGE": "Ο λογαριασμός σας έχει ανασταλεί. Επικοινωνήστε με την ομάδα υποστήριξης για περισσότερες πληροφορίες."
|
"MESSAGE": "Ο λογαριασμός σας έχει ανασταλεί. Επικοινωνήστε με την ομάδα υποστήριξης για περισσότερες πληροφορίες."
|
||||||
|
},
|
||||||
|
"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": "Κιβώτια Εισερχομένων",
|
||||||
|
"CAPTAIN_SETTINGS": "Ρυθμίσεις",
|
||||||
"HOME": "Αρχική",
|
"HOME": "Αρχική",
|
||||||
"AGENTS": "Πράκτορες",
|
"AGENTS": "Πράκτορες",
|
||||||
"AGENT_BOTS": "Bots",
|
"AGENT_BOTS": "Bots",
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "Webhook URL",
|
"LABEL": "Webhook URL",
|
||||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||||
@@ -341,6 +345,12 @@
|
|||||||
"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",
|
||||||
|
"EMPTY_LIST": "No assistants found, please create one to get started"
|
||||||
|
},
|
||||||
"COPILOT": {
|
"COPILOT": {
|
||||||
"TITLE": "Copilot",
|
"TITLE": "Copilot",
|
||||||
"TRY_THESE_PROMPTS": "Try these prompts",
|
"TRY_THESE_PROMPTS": "Try these prompts",
|
||||||
@@ -480,9 +490,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 +507,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 +535,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 +580,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 +625,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 +722,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 +916,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "Last 7 days",
|
"LAST_7_DAYS": "Last 7 days",
|
||||||
"LAST_14_DAYS": "Last 14 days",
|
"LAST_14_DAYS": "Last 14 days",
|
||||||
"LAST_30_DAYS": "Last 30 days",
|
"LAST_30_DAYS": "Last 30 days",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "Last 3 months",
|
"LAST_3_MONTHS": "Last 3 months",
|
||||||
"LAST_6_MONTHS": "Last 6 months",
|
"LAST_6_MONTHS": "Last 6 months",
|
||||||
"LAST_YEAR": "Last year",
|
"LAST_YEAR": "Last year",
|
||||||
|
|||||||
@@ -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": {
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Webhook Name",
|
||||||
|
"PLACEHOLDER": "Enter the name of the webhook"
|
||||||
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "URL de Webhook",
|
"LABEL": "URL de Webhook",
|
||||||
"PLACEHOLDER": "Ejemplo: {webhookExampleURL}",
|
"PLACEHOLDER": "Ejemplo: {webhookExampleURL}",
|
||||||
@@ -344,6 +348,11 @@
|
|||||||
"CAPTAIN": {
|
"CAPTAIN": {
|
||||||
"NAME": "Capitán",
|
"NAME": "Capitán",
|
||||||
"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": "Prueba estas sugerencias",
|
"TRY_THESE_PROMPTS": "Prueba estas sugerencias",
|
||||||
@@ -483,9 +492,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": "Ajustes",
|
||||||
"ASSISTANT": "Assistant"
|
|
||||||
},
|
|
||||||
"BASIC_SETTINGS": {
|
"BASIC_SETTINGS": {
|
||||||
"TITLE": "Configuraciones básicas",
|
"TITLE": "Configuraciones básicas",
|
||||||
"DESCRIPTION": ""
|
"DESCRIPTION": ""
|
||||||
@@ -502,15 +509,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": {
|
||||||
@@ -529,9 +537,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})",
|
||||||
@@ -577,9 +582,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})",
|
||||||
@@ -625,9 +627,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})",
|
||||||
@@ -725,11 +724,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": {
|
||||||
@@ -923,11 +917,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": {
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
"LAST_7_DAYS": "Últimos 7 días",
|
"LAST_7_DAYS": "Últimos 7 días",
|
||||||
"LAST_14_DAYS": "Últimos 14 días",
|
"LAST_14_DAYS": "Últimos 14 días",
|
||||||
"LAST_30_DAYS": "Últimos 30 días",
|
"LAST_30_DAYS": "Últimos 30 días",
|
||||||
|
"THIS_MONTH": "This month",
|
||||||
|
"LAST_MONTH": "Last month",
|
||||||
"LAST_3_MONTHS": "Últimos 3 meses",
|
"LAST_3_MONTHS": "Últimos 3 meses",
|
||||||
"LAST_6_MONTHS": "Últimos 6 meses",
|
"LAST_6_MONTHS": "Últimos 6 meses",
|
||||||
"LAST_YEAR": "Último año",
|
"LAST_YEAR": "Último año",
|
||||||
|
|||||||
@@ -251,6 +251,12 @@
|
|||||||
"ACCOUNT_SUSPENDED": {
|
"ACCOUNT_SUSPENDED": {
|
||||||
"TITLE": "Cuenta suspendida",
|
"TITLE": "Cuenta suspendida",
|
||||||
"MESSAGE": "Tu cuenta está suspendida. Comuníquese con el equipo de soporte para obtener más información."
|
"MESSAGE": "Tu cuenta está suspendida. Comuníquese con el equipo de soporte para obtener más información."
|
||||||
|
},
|
||||||
|
"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": "Cerrar sesión"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"COMPONENTS": {
|
"COMPONENTS": {
|
||||||
@@ -305,6 +311,10 @@
|
|||||||
"CAPTAIN_DOCUMENTS": "Documentos",
|
"CAPTAIN_DOCUMENTS": "Documentos",
|
||||||
"CAPTAIN_RESPONSES": "Preguntas frecuentes",
|
"CAPTAIN_RESPONSES": "Preguntas frecuentes",
|
||||||
"CAPTAIN_TOOLS": "Tools",
|
"CAPTAIN_TOOLS": "Tools",
|
||||||
|
"CAPTAIN_SCENARIOS": "Scenarios",
|
||||||
|
"CAPTAIN_PLAYGROUND": "Playground",
|
||||||
|
"CAPTAIN_INBOXES": "Entradas",
|
||||||
|
"CAPTAIN_SETTINGS": "Ajustes",
|
||||||
"HOME": "Inicio",
|
"HOME": "Inicio",
|
||||||
"AGENTS": "Agentes",
|
"AGENTS": "Agentes",
|
||||||
"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": "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