feat: translate automations

This commit is contained in:
Abhinav Raut
2025-03-31 16:31:17 +05:30
parent 9d18d3d08d
commit 497b54fc49
9 changed files with 193 additions and 85 deletions

View File

@@ -16,7 +16,7 @@
@update:modelValue="(value) => handleFieldChange(value, index)"
>
<SelectTrigger class="m-auto">
<SelectValue placeholder="Select action" />
<SelectValue :placeholder="t('form.field.selectAction')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
@@ -40,7 +40,7 @@
<SelectTag
v-model="action.value"
:items="tagsStore.tagNames.map((tag) => ({ label: tag, value: tag }))"
placeholder="Select tag"
:placeholder="t('form.field.selectTag')"
/>
</div>
@@ -51,7 +51,7 @@
<ComboBox
v-model="action.value[0]"
:items="conversationActions[action.type]?.options"
placeholder="Select"
:placeholder="t('form.field.select')"
@select="handleValueChange($event, index)"
>
<template #item="{ item }">
@@ -75,7 +75,7 @@
{{ selected.emoji }}
<span>{{ selected.label }}</span>
</div>
<span v-else>Select team</span>
<span v-else>{{ $t('form.field.selectTeam') }}</span>
</div>
<div v-else-if="action.type === 'assign_user'" class="flex items-center gap-2">
@@ -91,10 +91,10 @@
</Avatar>
<span>{{ selected.label }}</span>
</div>
<span v-else>Select user</span>
<span v-else>{{ $t('form.field.selectUser') }}</span>
</div>
<span v-else>
<span v-if="!selected"> Select</span>
<span v-if="!selected"> {{ $t('form.field.select') }}</span>
<span v-else>{{ selected.label }} </span>
</span>
</template>
@@ -114,14 +114,18 @@
<Editor
v-model:htmlContent="action.value[0]"
@update:htmlContent="(value) => handleEditorChange(value, index)"
:placeholder="'Shift + Enter to add new line'"
:placeholder="t('admin.macro.message_content.placeholder')"
/>
</div>
</div>
</div>
</div>
<div>
<Button variant="outline" @click.prevent="addAction">Add action</Button>
<Button variant="outline" @click.prevent="addAction">{{
$t('globals.messages.add', {
name: $t('globals.entities.action')
})
}}</Button>
</div>
</div>
</template>
@@ -144,6 +148,7 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { SelectTag } from '@/components/ui/select'
import { useConversationFilters } from '@/composables/useConversationFilters'
import { getTextFromHTML } from '@/utils/strings.js'
import { useI18n } from 'vue-i18n'
import Editor from '@/features/conversation/ConversationTextEditor.vue'
const props = defineProps({
@@ -154,6 +159,7 @@ const props = defineProps({
})
const { actions } = toRefs(props)
const { t } = useI18n()
const emit = defineEmits(['update-actions', 'add-action', 'remove-action'])
const tagsStore = useTagStore()
const { conversationActions } = useConversationFilters()

View File

@@ -1,26 +1,38 @@
<template>
<Tabs default-value="new_conversation" v-model="selectedTab">
<TabsList class="grid w-full grid-cols-3 mb-5">
<TabsTrigger value="new_conversation">New conversation</TabsTrigger>
<TabsTrigger value="conversation_update">Conversation update</TabsTrigger>
<TabsTrigger value="time_trigger">Time triggers</TabsTrigger>
<TabsTrigger value="new_conversation">{{
$t('admin.automation.newConversation')
}}</TabsTrigger>
<TabsTrigger value="conversation_update">{{
$t('admin.automation.conversationUpdate')
}}</TabsTrigger>
<TabsTrigger value="time_trigger">{{ $t('admin.automation.timeTriggers') }}</TabsTrigger>
</TabsList>
<TabsContent value="new_conversation">
<RuleTab type="new_conversation" helptext="Rules that run when a new conversation is created, drag and drop to reorder rules." />
<RuleTab
type="new_conversation"
:helptext="t('admin.automation.newConversation.description')"
/>
</TabsContent>
<TabsContent value="conversation_update">
<RuleTab type="conversation_update" helptext="Rules that run when a conversation is updated." />
<RuleTab
type="conversation_update"
:helptext="t('admin.automation.conversationUpdate.description')"
/>
</TabsContent>
<TabsContent value="time_trigger">
<RuleTab type="time_trigger" helptext="Rules that run once an hour." />
<RuleTab type="time_trigger" :helptext="t('admin.automation.timeTriggers.description')" />
</TabsContent>
</Tabs>
</template>
<script setup>
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { useI18n } from 'vue-i18n'
import RuleTab from './RuleTab.vue'
const { t } = useI18n()
const selectedTab = defineModel('automationsTab', {
default: 'new_conversation',
type: String,

View File

@@ -8,11 +8,17 @@
>
<div class="flex items-center space-x-2">
<RadioGroupItem value="OR" />
<Label>Match <b>ANY</b> of below.</Label>
<Label
>{{ $t('admin.automation.match') }} <b>{{ $t('admin.automation.any') }}</b>
{{ $t('admin.automation.below') }}.</Label
>
</div>
<div class="flex items-center space-x-2">
<RadioGroupItem value="AND" />
<Label>Match <b>ALL</b> of below.</Label>
<Label
>{{ $t('admin.automation.match') }} <b>{{ $t('admin.automation.all') }}</b>
{{ $t('admin.automation.below') }}.</Label
>
</div>
</RadioGroup>
</div>
@@ -31,11 +37,11 @@
@update:modelValue="(value) => handleFieldChange(value, index)"
>
<SelectTrigger class="w-56">
<SelectValue placeholder="Select field" />
<SelectValue :placeholder="t('form.field.selectField')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Conversation</SelectLabel>
<SelectLabel>{{ $t('globals.entities.conversation') }}</SelectLabel>
<SelectItem v-for="(field, key) in currentFilters" :key="key" :value="key">
{{ field.label }}
</SelectItem>
@@ -49,7 +55,7 @@
@update:modelValue="(value) => handleOperatorChange(value, index)"
>
<SelectTrigger class="w-56">
<SelectValue placeholder="Select operator" />
<SelectValue :placeholder="t('form.field.selectOperator')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
@@ -69,7 +75,7 @@
<!-- Plain text input -->
<Input
type="text"
placeholder="Set value"
:placeholder="t('form.fields.setValue')"
v-if="inputType(index) === 'text'"
v-model="rule.value"
@update:modelValue="(value) => handleValueChange(value, index)"
@@ -78,7 +84,7 @@
<!-- Number input -->
<Input
type="number"
placeholder="Set value"
:placeholder="t('form.fields.setValue')"
v-if="inputType(index) === 'number'"
v-model="rule.value"
@update:modelValue="(value) => handleValueChange(value, index)"
@@ -112,7 +118,7 @@
{{ selected.emoji }}
<span>{{ selected.label }}</span>
</div>
<span v-else>Select team</span>
<span v-else>{{ $t('form.field.selectTeam') }}</span>
</div>
<div
@@ -131,10 +137,10 @@
</Avatar>
<span>{{ selected.label }}</span>
</div>
<span v-else>Select user</span>
<span v-else>{{ $t('form.field.selectUser') }}</span>
</div>
<span v-else>
<span v-if="!selected"> Select</span>
<span v-if="!selected"> {{ $t('form.field.select') }}</span>
<span v-else>{{ selected.label }} </span>
</span>
</template>
@@ -155,9 +161,11 @@
<TagsInputItemText />
<TagsInputItemDelete />
</TagsInputItem>
<TagsInputInput placeholder="Select values" />
<TagsInputInput :placeholder="t('form.field.selectValue')" />
</TagsInput>
<p class="text-xs text-gray-500 mt-1">Press enter to select a value</p>
<p class="text-xs text-gray-500 mt-1">
{{ $t('globals.messages.pressEnterToSelectAValue') }}
</p>
</div>
</div>
@@ -173,12 +181,18 @@
:defaultChecked="rule.case_sensitive_match"
@update:checked="(value) => handleCaseSensitiveCheck(value, index)"
/>
<label> Case sensitive match </label>
<label> {{ $t('globals.messages.caseSensitiveMatch') }} </label>
</div>
</div>
</div>
<div>
<Button variant="outline" size="sm" @click.prevent="addCondition">Add condition</Button>
<Button variant="outline" size="sm" @click.prevent="addCondition">
{{
$t('globals.messages.add', {
name: $t('globals.entities.condition')
})
}}
</Button>
</div>
</div>
</div>
@@ -210,6 +224,7 @@ import { Label } from '@/components/ui/label'
import { Input } from '@/components/ui/input'
import ComboBox from '@/components/ui/combobox/ComboBox.vue'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { useI18n } from 'vue-i18n'
import { useConversationFilters } from '@/composables/useConversationFilters'
const props = defineProps({
@@ -230,6 +245,7 @@ const props = defineProps({
const { conversationFilters, newConversationFilters } = useConversationFilters()
const { ruleGroup } = toRefs(props)
const emit = defineEmits(['update-group', 'add-condition', 'remove-condition'])
const { t } = useI18n()
// Computed property to get the correct filters based on type
const currentFilters = computed(() => {

View File

@@ -7,8 +7,8 @@
{{ rule.name }}
</div>
<div class="mb-1">
<Badge v-if="rule.enabled" class="text-[9px]">Enabled</Badge>
<Badge v-else variant="secondary">Disabled</Badge>
<Badge v-if="rule.enabled" class="text-[9px]">{{ $t('form.field.enabled') }}</Badge>
<Badge v-else variant="secondary">{{ $t('form.field.disabled') }}</Badge>
</div>
</span>
</div>
@@ -21,16 +21,16 @@
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem @click="navigateToEditRule(rule.id)">
<span>Edit</span>
<span>{{ $t('globals.buttons.edit') }}</span>
</DropdownMenuItem>
<DropdownMenuItem @click="() => (alertOpen = true)">
<span>Delete</span>
<span>{{ $t('globals.buttons.delete') }}</span>
</DropdownMenuItem>
<DropdownMenuItem @click="$emit('toggle-rule', rule.id)" v-if="rule.enabled">
<span>Disable</span>
<span>{{ $t('globals.buttons.disable') }}</span>
</DropdownMenuItem>
<DropdownMenuItem @click="$emit('toggle-rule', rule.id)" v-else>
<span>Enable</span>
<span>{{ $t('globals.buttons.enable') }}</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
@@ -42,14 +42,16 @@
<AlertDialog :open="alertOpen" @update:open="alertOpen = $event">
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete Rule</AlertDialogTitle>
<AlertDialogTitle>{{ $t('globals.messages.areYouAbsolutelySure') }}</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete the automation rule.
{{ $t('admin.automation.deleteConfirmation') }}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction @click="handleDelete">Delete</AlertDialogAction>
<AlertDialogCancel>{{ $t('globals.buttons.cancel') }}</AlertDialogCancel>
<AlertDialogAction @click="handleDelete">{{
$t('globals.buttons.delete')
}}</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>

View File

@@ -15,8 +15,10 @@
}}</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectItem value="first_match">Execute the first matching rule</SelectItem>
<SelectItem value="all">Execute all matching rules</SelectItem>
<SelectItem value="first_match">{{
$t('admin.automation.executeFirstMatchingRule')
}}</SelectItem>
<SelectItem value="all">{{ $t('admin.automation.executeAllMatchingRules') }}</SelectItem>
</SelectContent>
</Select>
</div>

View File

@@ -1,16 +1,16 @@
import * as z from 'zod';
export const formSchema = z
export const createFormSchema = (t) => z
.object({
name: z.string({
required_error: 'Rule name is required.',
required_error: t('globals.messages.required'),
}),
description: z.string({
required_error: 'Rule description is required.',
required_error: t('globals.messages.required'),
}),
enabled: z.boolean().default(true),
type: z.string({
required_error: 'Rule type is required.',
required_error: t('globals.messages.required'),
}),
events: z.array(z.string()).optional(),
})
@@ -18,7 +18,9 @@ export const formSchema = z
if (data.type === 'conversation_update' && (!data.events || data.events.length === 0)) {
ctx.addIssue({
path: ['events'],
message: 'Please select at least one event.',
message: t('globals.messages.pleaseSelectAtLeastOne', {
name: t('globals.entities.event')
}),
code: z.ZodIssueCode.custom,
});
}

View File

@@ -4,11 +4,15 @@
<div v-if="router.currentRoute.value.name === 'automations'">
<div class="flex justify-between mb-5">
<div class="ml-auto">
<Button @click="newRule">New rule</Button>
<Button @click="newRule">{{
$t('globals.messages.new', {
name: $t('globals.entities.rule')
})
}}</Button>
</div>
</div>
<div v-if="selectedTab">
<AutomationTabs v-model="selectedTab" />
<AutomationTabs v-model:automationsTab="selectedTab" />
</div>
</div>
<router-view />

View File

@@ -20,7 +20,7 @@
<Checkbox :checked="value" @update:checked="handleChange" />
</FormControl>
<div class="space-y-1 leading-none">
<FormLabel> Enabled </FormLabel>
<FormLabel> {{ $t('form.field.enabled') }} </FormLabel>
<FormMessage />
</div>
</FormItem>
@@ -28,22 +28,24 @@
<FormField v-slot="{ field }" name="name">
<FormItem>
<FormLabel>Name</FormLabel>
<FormLabel>{{ $t('form.field.name') }}</FormLabel>
<FormControl>
<Input type="text" placeholder="My new rule" v-bind="field" />
<Input type="text" placeholder="" v-bind="field" />
</FormControl>
<FormDescription>Name for the rule.</FormDescription>
<FormDescription>{{ $t('admin.automation.name.description') }}</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<FormField v-slot="{ field }" name="description">
<FormItem>
<FormLabel>Description</FormLabel>
<FormLabel>{{ $t('form.field.description') }}</FormLabel>
<FormControl>
<Input type="text" placeholder="Description for new rule" v-bind="field" />
<Input type="text" placeholder="" v-bind="field" />
</FormControl>
<FormDescription>Description for the rule.</FormDescription>
<FormDescription>{{
$t('admin.automation.description.description')
}}</FormDescription>
<FormMessage />
</FormItem>
</FormField>
@@ -54,18 +56,28 @@
<FormControl>
<Select v-bind="componentField" @update:modelValue="handleInput">
<SelectTrigger>
<SelectValue placeholder="Select a type" />
<SelectValue :placeholder="t('form.field.selectType')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="new_conversation"> New conversation </SelectItem>
<SelectItem value="conversation_update"> Conversation update </SelectItem>
<SelectItem value="time_trigger"> Time trigger </SelectItem>
<SelectItem value="new_conversation">
{{ $t('admin.automation.newConversation') }}
</SelectItem>
<SelectItem value="conversation_update">
{{ $t('admin.automation.conversationUpdate') }}
</SelectItem>
<SelectItem value="time_trigger">
{{ $t('admin.automation.timeTriggers') }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</FormControl>
<FormDescription>Type of rule.</FormDescription>
<FormDescription>{{
$t('globals.messages.typeOf', {
name: $t('globals.entities.rule')
})
}}</FormDescription>
<FormMessage />
</FormItem>
</FormField>
@@ -73,24 +85,26 @@
<div :class="{ hidden: form.values.type !== 'conversation_update' }">
<FormField v-slot="{ componentField, handleChange }" name="events">
<FormItem>
<FormLabel>Events</FormLabel>
<FormLabel>{{ $t('globals.entities.event', 2) }}</FormLabel>
<FormControl>
<SelectTag
v-model="componentField.modelValue"
@update:modelValue="handleChange"
:items="conversationEventOptions"
placeholder="Select events"
:placeholder="t('form.fields.selectEvents')"
>
</SelectTag>
</FormControl>
<FormDescription>Evaluate rule on these events.</FormDescription>
<FormDescription>{{
$t('admin.automation.evaluateRuleOnTheseEvents')
}}</FormDescription>
<FormMessage />
</FormItem>
</FormField>
</div>
</div>
<p class="font-semibold">Match these rules</p>
<p class="font-semibold">{{ $t('admin.automation.matchTheseRules') }}</p>
<RuleBox
:ruleGroup="firstRuleGroup"
@@ -107,13 +121,13 @@
:class="[groupOperator === 'AND' ? 'bg-black' : 'bg-gray-100 text-black']"
@click.prevent="toggleGroupOperator('AND')"
>
AND
{{ $t('admin.automation.and') }}
</Button>
<Button
:class="[groupOperator === 'OR' ? 'bg-black' : 'bg-gray-100 text-black']"
@click.prevent="toggleGroupOperator('OR')"
>
OR
{{ $t('admin.automation.or') }}
</Button>
</div>
</div>
@@ -126,7 +140,7 @@
:type="form.values.type"
:groupIndex="1"
/>
<p class="font-semibold">Perform these actions</p>
<p class="font-semibold">{{ $t('admin.automation.performTheseActions') }}</p>
<ActionBox
:actions="getActions()"
@@ -134,7 +148,7 @@
@add-action="handleAddAction"
@remove-action="handleRemoveAction"
/>
<Button type="submit" :isLoading="isLoading">Save</Button>
<Button type="submit" :isLoading="isLoading">{{ $t('globals.buttons.save') }}</Button>
</div>
</form>
</div>
@@ -151,12 +165,13 @@ import api from '@/api'
import { Checkbox } from '@/components/ui/checkbox'
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import { formSchema } from '@/features/admin/automation/formSchema.js'
import { createFormSchema } from '@/features/admin/automation/formSchema.js'
import { EMITTER_EVENTS } from '@/constants/emitterEvents.js'
import { useEmitter } from '@/composables/useEmitter'
import { handleHTTPError } from '@/utils/http'
import { SelectTag } from '@/components/ui/select'
import { OPERATOR } from '@/constants/filterConfig'
import { useI18n } from 'vue-i18n'
import {
Select,
SelectContent,
@@ -179,6 +194,7 @@ import { useRoute } from 'vue-router'
import { useRouter } from 'vue-router'
const isLoading = ref(false)
const { t } = useI18n()
const route = useRoute()
const router = useRouter()
const emitter = useEmitter()
@@ -206,12 +222,12 @@ const rule = ref({
})
const conversationEventOptions = [
{ label: 'User assigned', value: 'conversation.user.assigned' },
{ label: 'Team assigned', value: 'conversation.team.assigned' },
{ label: 'Priority change', value: 'conversation.priority.change' },
{ label: 'Status change', value: 'conversation.status.change' },
{ label: 'Outgoing message', value: 'conversation.message.outgoing' },
{ label: 'Incoming message', value: 'conversation.message.incoming' }
{ label: t('admin.automation.event.user.assigned'), value: 'conversation.user.assigned' },
{ label: t('admin.automation.event.team.assigned'), value: 'conversation.team.assigned' },
{ label: t('admin.automation.event.priority.change'), value: 'conversation.priority.change' },
{ label: t('admin.automation.event.status.change'), value: 'conversation.status.change' },
{ label: t('admin.automation.event.message.outgoing'), value: 'conversation.message.outgoing' },
{ label: t('admin.automation.event.message.incoming'), value: 'conversation.message.incoming' }
]
const props = defineProps({
@@ -222,8 +238,13 @@ const props = defineProps({
})
const breadcrumbPageLabel = () => {
if (props.id > 0) return 'Edit rule'
return 'New rule'
if (props.id > 0)
return t('globals.messages.edit', {
name: t('globals.entities.rule')
})
return t('globals.messages.new', {
name: t('globals.entities.rule')
})
}
const formTitle = computed(() => {
@@ -237,7 +258,7 @@ const isNewForm = computed(() => {
})
const breadcrumbLinks = [
{ path: 'automations', label: 'Automations' },
{ path: 'automations', label: t('admin.automation') },
{ path: '', label: breadcrumbPageLabel() }
]
@@ -305,7 +326,7 @@ const handleRemoveAction = (index) => {
}
const form = useForm({
validationSchema: toTypedSchema(formSchema)
validationSchema: toTypedSchema(createFormSchema(t))
})
const onSubmit = form.handleSubmit(async (values) => {
@@ -315,10 +336,8 @@ const onSubmit = form.handleSubmit(async (values) => {
const handleSave = async (values) => {
if (!areRulesValid()) {
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
title: 'Invalid rules',
variant: 'destructive',
description:
'Make sure you have atleast one action and one rule and their values are not empty.'
description: t('admin.automation.invalid')
})
return
}
@@ -336,12 +355,12 @@ const handleSave = async (values) => {
router.push({ name: 'automations' })
}
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
title: 'Success',
description: 'Rule saved successfully'
description: t('globals.messages.savedSuccessfully', {
name: t('globals.entities.rule')
})
})
} catch (error) {
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
title: 'Could not save rule',
variant: 'destructive',
description: handleHTTPError(error).message
})
@@ -416,7 +435,6 @@ onMounted(async () => {
form.setValues(resp.data.data)
} catch (error) {
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
title: 'Could not fetch rule',
variant: 'destructive',
description: handleHTTPError(error).message
})

View File

@@ -38,6 +38,8 @@
"globals.entities.config": "Config | Configs",
"globals.entities.macro": "Macro | Macros",
"globals.entities.macroAction": "Macro Action | Macro Actions",
"globals.entities.action": "Action | Actions",
"globals.entities.event": "Event | Events",
"globals.entities.automation": "Automation | Automations",
"globals.entities.oidc": "OIDC | OIDCs",
"globals.entities.oidcProvider": "OIDC Provider | OIDC Providers",
@@ -45,6 +47,7 @@
"globals.entities.avatar": "Avatar | Avatars",
"globals.entities.view": "View | Views",
"globals.entities.email": "Email | Emails",
"globals.entities.condition": "Condition | Conditions",
"globals.messages.adjustFilters": "Try adjusting your filters",
"globals.messages.errorUploadingFile": "Error uploading file",
"globals.messages.errorUpdating": "Error updating {name}",
@@ -73,12 +76,15 @@
"globals.messages.tooLong": "{name} is too long, should be at most {max} characters",
"globals.messages.deletedSuccessfully": "{name} deleted successfully",
"globals.messages.updatedSuccessfully": "{name} updated successfully",
"globals.messages.savedSuccessfully": "{name} saved successfully",
"globals.messages.edit": "Edit {name}",
"globals.messages.delete": "Delete {name}",
"globals.messages.create": "Create {name}",
"globals.messages.new": "New {name}",
"globals.messages.add": "Add {name}",
"globals.messages.yes": "Yes",
"globals.messages.no": "No",
"globals.messages.typeOf": "Type of {name}",
"globals.messages.createdSuccessfully": "{name} created successfully",
"globals.messages.invalidEmailAddress": "Invalid email address",
"globals.messages.pleaseSelectAtLeastOne": "Please select at least one {name}",
@@ -99,6 +105,8 @@
"globals.messages.somethingWentWrong": "Something went wrong",
"globals.messages.done": "Done",
"globals.messages.emptyState": "Nothing here",
"globals.messages.pressEnterToSelectAValue": "Press enter to select a value",
"globals.messages.caseSensitiveMatch": "Case sensitive match",
"auth.csrfTokenMismatch": "CSRF token mismatch",
"authz.permissionDenied": "Permission denied",
"user.userAlreadyLoggedIn": "User already logged in",
@@ -234,7 +242,17 @@
"form.field.pickDate": "Pick a date",
"form.field.selectTLS": "Select TLS",
"form.field.selectRoles": "Select roles",
"form.field.selectField": "Select field",
"form.field.selectTeam": "Select team",
"form.field.selectTag": "Select tag",
"form.field.selectAction": "Select action",
"form.field.selectUser": "Select user",
"form.field.selectValue": "Select value",
"form.field.selectTeams": "Select teams",
"form.field.selectType": "Select type",
"form.fields.setValue": "Set value",
"form.fields.selectEvents": "Select events",
"form.field.selectOperator": "Select operator",
"form.error.min": "Should be at least {min} characters",
"form.error.max": "Should be at most {max} characters",
"form.error.minmax": "Should be between {min} and {max} characters",
@@ -427,6 +445,34 @@
"admin.role.business_hours.manage": "Manage Business Hours",
"admin.role.sla.manage": "Manage SLA Policies",
"admin.role.ai.manage": "Manage AI Features",
"admin.automation": "Automations",
"admin.automation.newConversation": "New Conversation",
"admin.automation.newConversation.description": "Rules that run when a new conversation is created, drag and drop to reorder rules.",
"admin.automation.conversationUpdate": "Conversation Update",
"admin.automation.conversationUpdate.description": "Rules that run when a conversation is updated.",
"admin.automation.timeTriggers": "Time Triggers",
"admin.automation.timeTriggers.description": "Rules that once an hour",
"admin.automation.match": "Match",
"admin.automation.any": "ANY",
"admin.automation.all": "ALL",
"admin.automation.below": "below",
"admin.automation.deleteConfirmation": "This action cannot be undone. This will permanently delete this automation rule.",
"admin.automation.executeFirstMatchingRule": "Execute first matching rule",
"admin.automation.executeAllMatchingRules": "Execute all matching rules",
"admin.automation.name.description": "Name for this automation rule.",
"admin.automation.description.description": "Short description of what this rule does.",
"admin.automation.evaluateRuleOnTheseEvents": "Evaluate rule on these events.",
"admin.automation.matchTheseRules": "Match these rules",
"admin.automation.and": "AND",
"admin.automation.or": "OR",
"admin.automation.performTheseActions": "Perform these actions",
"admin.automation.event.user.assigned": "User assigned",
"admin.automation.event.team.assigned": "Team assigned",
"admin.automation.event.priority.change": "Priority change",
"admin.automation.event.status.change": "Status change",
"admin.automation.event.message.outgoing": "Outgoing message",
"admin.automation.event.message.incoming": "Incoming message",
"admin.automation.invalid": "Make sure you have atleast one action and one rule and their values are not empty.",
"globals.buttons.save": "Save",
"globals.buttons.save_changes": "Save changes",
"globals.buttons.cancel": "Cancel",