Some checks are pending
E2E / Playwright e2e (push) Waiting to run
- Replaced hardcoded "Agenda" labels with dynamic ULTICAL_APP_NAME in various components for consistency. - Introduced new AiUsageSection and CompteAiUsageSection components to track AI usage and costs. - Updated settings and metadata to reflect changes in AI cost policies and usage limits. - Enhanced user interface elements for better accessibility and user experience across admin settings.
257 lines
9.8 KiB
TypeScript
257 lines
9.8 KiB
TypeScript
import type {
|
|
ActionType,
|
|
AutomationTrigger,
|
|
ConditionField,
|
|
TriggerOrGroup,
|
|
TriggerType,
|
|
} from './types'
|
|
import { ULTICAL_APP_NAME } from '@/lib/suite/page-metadata'
|
|
|
|
export type AutomationDomain = 'mail' | 'drive' | 'contacts' | 'agenda'
|
|
|
|
export const AUTOMATION_DOMAIN_LABELS: Record<AutomationDomain, string> = {
|
|
mail: 'Mail',
|
|
drive: 'Drive',
|
|
contacts: 'Contacts',
|
|
agenda: ULTICAL_APP_NAME,
|
|
}
|
|
|
|
export const DOMAIN_TRIGGER_TYPES: Record<AutomationDomain, TriggerType[]> = {
|
|
mail: ['message_received', 'label_added', 'label_removed'],
|
|
drive: [
|
|
'drive_file_created',
|
|
'drive_file_updated',
|
|
'drive_file_deleted',
|
|
'drive_file_moved',
|
|
'drive_share_updated',
|
|
],
|
|
contacts: ['contact_created', 'contact_updated', 'contact_deleted'],
|
|
agenda: [
|
|
'calendar_event_created',
|
|
'calendar_event_updated',
|
|
'calendar_event_deleted',
|
|
'calendar_event_response',
|
|
],
|
|
}
|
|
|
|
export const TRIGGER_LABELS: Record<TriggerType, string> = {
|
|
message_received: 'Mail reçu',
|
|
label_added: 'Libellé ajouté',
|
|
label_removed: 'Libellé retiré',
|
|
drive_file_created: 'Fichier ajouté',
|
|
drive_file_updated: 'Fichier modifié',
|
|
drive_file_deleted: 'Fichier supprimé',
|
|
drive_file_moved: 'Fichier déplacé',
|
|
drive_share_updated: 'Partage modifié',
|
|
contact_created: 'Contact créé',
|
|
contact_updated: 'Contact modifié',
|
|
contact_deleted: 'Contact supprimé',
|
|
calendar_event_created: 'Événement créé',
|
|
calendar_event_updated: 'Événement modifié',
|
|
calendar_event_deleted: 'Événement supprimé',
|
|
calendar_event_response: 'Réponse invitation',
|
|
}
|
|
|
|
export const DOMAIN_CONDITION_FIELDS: Record<AutomationDomain, ConditionField[]> = {
|
|
mail: ['from', 'to', 'subject', 'body', 'has_attachment', 'label'],
|
|
drive: ['drive_file_name', 'drive_file_path', 'drive_mime_type', 'drive_file_size', 'drive_is_folder'],
|
|
contacts: ['contact_name', 'contact_email', 'contact_phone', 'contact_org', 'contact_label'],
|
|
agenda: [
|
|
'calendar_event_title',
|
|
'calendar_event_location',
|
|
'calendar_event_organizer',
|
|
'calendar_event_attendee',
|
|
'calendar_event_all_day',
|
|
'calendar_event_has_video',
|
|
],
|
|
}
|
|
|
|
export const CONDITION_FIELD_LABELS: Record<ConditionField, string> = {
|
|
from: 'Expéditeur',
|
|
to: 'Destinataire',
|
|
subject: 'Sujet',
|
|
body: 'Corps',
|
|
has_attachment: 'Pièce jointe',
|
|
label: 'Libellé du message',
|
|
drive_file_name: 'Nom du fichier',
|
|
drive_file_path: 'Chemin',
|
|
drive_mime_type: 'Type MIME',
|
|
drive_file_size: 'Taille (octets)',
|
|
drive_is_folder: 'Dossier',
|
|
contact_name: 'Nom du contact',
|
|
contact_email: 'E-mail du contact',
|
|
contact_phone: 'Téléphone',
|
|
contact_org: 'Organisation',
|
|
contact_label: 'Libellé du contact',
|
|
calendar_event_title: 'Titre de l\'événement',
|
|
calendar_event_location: 'Lieu',
|
|
calendar_event_organizer: 'Organisateur',
|
|
calendar_event_attendee: 'Participant',
|
|
calendar_event_all_day: 'Journée entière',
|
|
calendar_event_has_video: 'Visioconférence',
|
|
}
|
|
|
|
export const UNIVERSAL_ACTION_TYPES: ActionType[] = ['webhook', 'notify']
|
|
|
|
export const DOMAIN_ACTION_TYPES: Record<AutomationDomain, ActionType[]> = {
|
|
mail: [
|
|
'label',
|
|
'remove_label',
|
|
'move',
|
|
'archive',
|
|
'delete',
|
|
'mark_read',
|
|
'mark_important',
|
|
'mark_spam',
|
|
'star',
|
|
'reply',
|
|
'send_mail',
|
|
'forward',
|
|
],
|
|
drive: ['drive_move', 'drive_rename', 'drive_delete', 'drive_share', 'drive_copy'],
|
|
contacts: ['contact_add_label', 'contact_remove_label', 'contact_delete'],
|
|
agenda: ['calendar_add_attendee', 'calendar_update_title', 'calendar_cancel_event', 'calendar_notify_attendees'],
|
|
}
|
|
|
|
export const ACTION_TYPE_META: Record<
|
|
ActionType,
|
|
{ label: string; needsValue: boolean; placeholder?: string; domain?: AutomationDomain | 'universal' }
|
|
> = {
|
|
label: { label: 'Ajouter libellé', needsValue: true, placeholder: 'Nom du libellé', domain: 'mail' },
|
|
remove_label: { label: 'Retirer libellé', needsValue: true, placeholder: 'Nom du libellé', domain: 'mail' },
|
|
move: { label: 'Déplacer vers dossier', needsValue: true, placeholder: 'Nom du dossier', domain: 'mail' },
|
|
archive: { label: 'Archiver', needsValue: false, domain: 'mail' },
|
|
delete: { label: 'Supprimer', needsValue: false, domain: 'mail' },
|
|
mark_read: { label: 'Marquer lu', needsValue: false, domain: 'mail' },
|
|
mark_important: { label: 'Marquer important', needsValue: false, domain: 'mail' },
|
|
mark_spam: { label: 'Marquer spam', needsValue: false, domain: 'mail' },
|
|
star: { label: 'Suivi / étoile', needsValue: false, domain: 'mail' },
|
|
reply: { label: 'Répondre', needsValue: true, placeholder: 'Corps de la réponse', domain: 'mail' },
|
|
send_mail: { label: 'Envoyer un mail', needsValue: true, placeholder: 'dest@example.com', domain: 'mail' },
|
|
forward: { label: 'Transférer', needsValue: true, placeholder: 'dest@example.com', domain: 'mail' },
|
|
drive_move: { label: 'Déplacer le fichier', needsValue: true, placeholder: '/Dossier cible', domain: 'drive' },
|
|
drive_rename: { label: 'Renommer le fichier', needsValue: true, placeholder: 'nouveau-nom.pdf', domain: 'drive' },
|
|
drive_delete: { label: 'Supprimer le fichier', needsValue: false, domain: 'drive' },
|
|
drive_share: { label: 'Partager', needsValue: true, placeholder: 'email@example.com', domain: 'drive' },
|
|
drive_copy: { label: 'Copier vers', needsValue: true, placeholder: '/Dossier cible', domain: 'drive' },
|
|
contact_add_label: { label: 'Ajouter libellé contact', needsValue: true, placeholder: 'Libellé', domain: 'contacts' },
|
|
contact_remove_label: { label: 'Retirer libellé contact', needsValue: true, placeholder: 'Libellé', domain: 'contacts' },
|
|
contact_delete: { label: 'Supprimer le contact', needsValue: false, domain: 'contacts' },
|
|
calendar_add_attendee: { label: 'Ajouter un participant', needsValue: true, placeholder: 'email@example.com', domain: 'agenda' },
|
|
calendar_update_title: { label: 'Modifier le titre', needsValue: true, placeholder: 'Nouveau titre', domain: 'agenda' },
|
|
calendar_cancel_event: { label: 'Annuler l\'événement', needsValue: false, domain: 'agenda' },
|
|
calendar_notify_attendees: { label: 'Notifier les participants', needsValue: true, placeholder: 'Message', domain: 'agenda' },
|
|
webhook: { label: 'Webhook', needsValue: true, placeholder: 'ID du template webhook', domain: 'universal' },
|
|
notify: { label: 'Notification', needsValue: true, placeholder: 'Message notification', domain: 'universal' },
|
|
}
|
|
|
|
export function triggerDomain(type: TriggerType): AutomationDomain {
|
|
if (type.startsWith('drive_')) return 'drive'
|
|
if (type.startsWith('contact_')) return 'contacts'
|
|
if (type.startsWith('calendar_')) return 'agenda'
|
|
return 'mail'
|
|
}
|
|
|
|
export function inferDomainsFromTriggers(triggers: TriggerOrGroup): AutomationDomain[] {
|
|
const domains = new Set<AutomationDomain>()
|
|
for (const group of triggers.groups) {
|
|
for (const item of group.items) {
|
|
domains.add(triggerDomain(item.type))
|
|
}
|
|
}
|
|
if (domains.size === 0) domains.add('mail')
|
|
return [...domains]
|
|
}
|
|
|
|
export function primaryDomainFromTriggers(triggers: TriggerOrGroup): AutomationDomain {
|
|
const domains = inferDomainsFromTriggers(triggers)
|
|
return domains[0] ?? 'mail'
|
|
}
|
|
|
|
export function conditionFieldsForDomains(domains: AutomationDomain[]): { value: ConditionField; label: string; domain: AutomationDomain }[] {
|
|
const out: { value: ConditionField; label: string; domain: AutomationDomain }[] = []
|
|
for (const domain of domains) {
|
|
for (const field of DOMAIN_CONDITION_FIELDS[domain]) {
|
|
out.push({ value: field, label: CONDITION_FIELD_LABELS[field], domain })
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
export function actionTypesForDomains(domains: AutomationDomain[]): {
|
|
value: ActionType
|
|
label: string
|
|
needsValue: boolean
|
|
placeholder?: string
|
|
domain: AutomationDomain | 'universal'
|
|
}[] {
|
|
const seen = new Set<ActionType>()
|
|
const out: ReturnType<typeof actionTypesForDomains> = []
|
|
|
|
function push(type: ActionType) {
|
|
if (seen.has(type)) return
|
|
seen.add(type)
|
|
const meta = ACTION_TYPE_META[type]
|
|
out.push({
|
|
value: type,
|
|
label: meta.label,
|
|
needsValue: meta.needsValue,
|
|
placeholder: meta.placeholder,
|
|
domain: meta.domain ?? 'universal',
|
|
})
|
|
}
|
|
|
|
for (const type of UNIVERSAL_ACTION_TYPES) push(type)
|
|
for (const domain of domains) {
|
|
for (const type of DOMAIN_ACTION_TYPES[domain]) push(type)
|
|
}
|
|
return out
|
|
}
|
|
|
|
export function defaultConditionFieldForDomain(domain: AutomationDomain): ConditionField {
|
|
return DOMAIN_CONDITION_FIELDS[domain][0]
|
|
}
|
|
|
|
export function defaultActionForDomain(domain: AutomationDomain): ActionType {
|
|
if (domain === 'drive') return 'drive_move'
|
|
if (domain === 'contacts') return 'contact_add_label'
|
|
if (domain === 'agenda') return 'calendar_add_attendee'
|
|
return 'label'
|
|
}
|
|
|
|
export function defaultTriggerForDomain(domain: AutomationDomain): AutomationTrigger {
|
|
const type = DOMAIN_TRIGGER_TYPES[domain][0]
|
|
if (domain === 'mail') return { type }
|
|
if (domain === 'drive') return { type, folder_path: undefined }
|
|
if (domain === 'agenda') return { type, calendar_id: undefined }
|
|
return { type, contact_label: undefined }
|
|
}
|
|
|
|
export function triggerUsesFolderPath(type: TriggerType): boolean {
|
|
return type.startsWith('drive_')
|
|
}
|
|
|
|
export function triggerUsesMailFolder(type: TriggerType): boolean {
|
|
return type === 'message_received'
|
|
}
|
|
|
|
export function triggerUsesMailLabel(type: TriggerType): boolean {
|
|
return type === 'label_added' || type === 'label_removed'
|
|
}
|
|
|
|
export function triggerUsesContactLabel(type: TriggerType): boolean {
|
|
return type.startsWith('contact_')
|
|
}
|
|
|
|
export function triggerUsesCalendarId(type: TriggerType): boolean {
|
|
return type.startsWith('calendar_')
|
|
}
|
|
|
|
export function conditionFieldLabel(field: string): string {
|
|
return CONDITION_FIELD_LABELS[field as ConditionField] ?? field
|
|
}
|
|
|
|
export function actionTypeLabel(type: string): string {
|
|
return ACTION_TYPE_META[type as ActionType]?.label ?? type
|
|
}
|