mirror of
https://github.com/abhinavxd/libredesk.git
synced 2025-11-15 11:21:53 +00:00
feat: translate automations
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
46
i18n/en.json
46
i18n/en.json
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user