Update automation guides and UI components

- Updated the 'guide' label in English, Spanish, and Portuguese translations to provide clearer context: changed from 'Guide' to 'Learn how it works' and its translations.
- Removed the EditorGuide component from the automation form, replacing it with a tooltip that links to the documentation.
- Adjusted the icon used for the help button from IconHelp to IconLifebuoy for better visual representation.
- Enhanced the tooltip functionality to provide guidance on automation actions directly within the UI.
This commit is contained in:
Paulo Castellano 2026-06-12 19:41:25 -03:00
parent 3e43da29e0
commit cda197adf8
5 changed files with 26 additions and 211 deletions

View file

@ -14,7 +14,7 @@
'pause' => 'Pause',
'delete' => 'Delete',
'retry' => 'Retry',
'guide' => 'Guide',
'guide' => 'Learn how it works',
],
'tabs' => [
@ -134,32 +134,6 @@
'add' => 'New variable',
],
'guide' => [
'title' => 'How automations work',
'subtitle' => 'Build a flow, then wire data between nodes.',
'tabs' => [
'overview' => 'Overview',
'expressions' => 'Expressions',
],
'flow_title' => 'The flow',
'flow_text' => 'A trigger (a schedule, or a published/scheduled post) starts the flow. Actions in between fetch data, generate content, or branch on conditions. Output nodes publish posts or call webhooks.',
'scope_title' => 'What data is in scope',
'scope_text' => 'A node can only use data from nodes connected before it (upstream). In any text field, type {{ to autocomplete what is available — unknown references are flagged.',
'data_text' => 'Wrap a path in double braces. Which paths exist depends on the nodes running upstream:',
'groups' => [
'trigger_schedule' => 'Schedule trigger',
'trigger_post' => 'Post trigger',
'fetch_rss' => 'Fetch RSS',
'http' => 'HTTP request',
'generate' => 'Generate content',
'always' => 'Always available',
],
'http_note' => 'Append any field from the JSON response, e.g. {{ fetched.data.0.title }}.',
'vars_title' => 'Variables',
'vars_text' => 'Define reusable values (API keys, base URLs) in the Variables tab, then reference them by key. Secrets are stored encrypted.',
'tip_text' => 'Run a Test to see exactly what data each node outputs.',
],
'expr' => [
'trigger_event' => 'Trigger event name',
'trigger_fired_at' => 'When the trigger fired',

View file

@ -14,7 +14,7 @@
'pause' => 'Pausar',
'delete' => 'Eliminar',
'retry' => 'Reintentar',
'guide' => 'Guía',
'guide' => 'Aprende cómo funciona',
],
'tabs' => [
@ -134,32 +134,6 @@
'add' => 'Nueva variable',
],
'guide' => [
'title' => 'Cómo funcionan las automatizaciones',
'subtitle' => 'Construye un flujo y conecta los datos entre nodos.',
'tabs' => [
'overview' => 'Resumen',
'expressions' => 'Expresiones',
],
'flow_title' => 'El flujo',
'flow_text' => 'Un disparador (una programación, o un post publicado/programado) inicia el flujo. Las acciones intermedias obtienen datos, generan contenido o se ramifican por condiciones. Los nodos de salida publican posts o llaman webhooks.',
'scope_title' => 'Qué datos están disponibles',
'scope_text' => 'Un nodo solo puede usar datos de nodos conectados antes de él (upstream). En cualquier campo de texto, escribe {{ para autocompletar lo disponible — las referencias desconocidas se señalan.',
'data_text' => 'Envuelve la ruta en llaves dobles. Qué rutas existen depende de los nodos que se ejecutan antes:',
'groups' => [
'trigger_schedule' => 'Disparador programado',
'trigger_post' => 'Disparador de post',
'fetch_rss' => 'Obtener RSS',
'http' => 'Petición HTTP',
'generate' => 'Generar contenido',
'always' => 'Siempre disponible',
],
'http_note' => 'Añade cualquier campo de la respuesta JSON, ej: {{ fetched.data.0.title }}.',
'vars_title' => 'Variables',
'vars_text' => 'Define valores reutilizables (API keys, URLs base) en la pestaña Variables y referéncialos por clave. Los secretos se almacenan cifrados.',
'tip_text' => 'Ejecuta una Prueba para ver exactamente qué produce cada nodo.',
],
'expr' => [
'trigger_event' => 'Nombre del evento del disparador',
'trigger_fired_at' => 'Cuándo se disparó',

View file

@ -14,7 +14,7 @@
'pause' => 'Pausar',
'delete' => 'Excluir',
'retry' => 'Tentar novamente',
'guide' => 'Guia',
'guide' => 'Aprenda como funciona',
],
'tabs' => [
@ -134,32 +134,6 @@
'add' => 'Nova variável',
],
'guide' => [
'title' => 'Como as automações funcionam',
'subtitle' => 'Monte um fluxo e conecte os dados entre os nós.',
'tabs' => [
'overview' => 'Visão geral',
'expressions' => 'Expressões',
],
'flow_title' => 'O fluxo',
'flow_text' => 'Um trigger (um agendamento, ou um post publicado/agendado) inicia o fluxo. As ações no meio buscam dados, geram conteúdo ou ramificam por condições. Os nós de saída publicam posts ou chamam webhooks.',
'scope_title' => 'Quais dados estão disponíveis',
'scope_text' => 'Um nó só pode usar dados de nós conectados antes dele (upstream). Em qualquer campo de texto, digite {{ pra autocompletar o que está disponível — referências desconhecidas são sinalizadas.',
'data_text' => 'Envolva o caminho em chaves duplas. Quais caminhos existem depende dos nós que rodam antes:',
'groups' => [
'trigger_schedule' => 'Trigger agendado',
'trigger_post' => 'Trigger de post',
'fetch_rss' => 'Buscar RSS',
'http' => 'Requisição HTTP',
'generate' => 'Gerar conteúdo',
'always' => 'Sempre disponível',
],
'http_note' => 'Adicione qualquer campo da resposta JSON, ex: {{ fetched.data.0.title }}.',
'vars_title' => 'Variáveis',
'vars_text' => 'Defina valores reutilizáveis (API keys, base URLs) na aba Variáveis e referencie pela chave. Segredos são armazenados encriptados.',
'tip_text' => 'Rode um Teste pra ver exatamente o que cada nó produz.',
],
'expr' => [
'trigger_event' => 'Nome do evento do gatilho',
'trigger_fired_at' => 'Quando o gatilho disparou',

View file

@ -1,119 +0,0 @@
<script setup lang="ts">
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/components/ui/sheet';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
const open = defineModel<boolean>('open', { default: false });
// The `{{ ... }}` snippets stay literal (they're code). Descriptions reuse the
// same `automations.expr.*` keys the `{{` autocomplete shows, so the guide and
// the editor hints never drift apart.
const expressionGroups = [
{
titleKey: 'automations.guide.groups.trigger_schedule',
items: [
{ code: '{{ trigger.event }}', descKey: 'automations.expr.trigger_event' },
{ code: '{{ trigger.fired_at }}', descKey: 'automations.expr.trigger_fired_at' },
],
},
{
titleKey: 'automations.guide.groups.trigger_post',
items: [
{ code: '{{ trigger.post.id }}', descKey: 'automations.expr.trigger_post_id' },
{ code: '{{ trigger.post.content }}', descKey: 'automations.expr.trigger_post_content' },
{ code: '{{ trigger.post.status }}', descKey: 'automations.expr.trigger_post_status' },
{ code: '{{ trigger.post.scheduled_at }}', descKey: 'automations.expr.trigger_post_scheduled_at' },
{ code: '{{ trigger.post.published_at }}', descKey: 'automations.expr.trigger_post_published_at' },
],
},
{
titleKey: 'automations.guide.groups.fetch_rss',
items: [
{ code: '{{ fetched.title }}', descKey: 'automations.expr.fetched_title' },
{ code: '{{ fetched.link }}', descKey: 'automations.expr.fetched_link' },
{ code: '{{ fetched.description }}', descKey: 'automations.expr.fetched_description' },
{ code: '{{ fetched.pubDate }}', descKey: 'automations.expr.fetched_pubdate' },
],
},
{
titleKey: 'automations.guide.groups.http',
items: [{ code: '{{ fetched.<field> }}', descKey: 'automations.expr.fetched_http' }],
noteKey: 'automations.guide.http_note',
},
{
titleKey: 'automations.guide.groups.generate',
items: [
{ code: '{{ generated.content }}', descKey: 'automations.expr.generated_content' },
{ code: '{{ generated.post_url }}', descKey: 'automations.expr.generated_post_url' },
],
},
{
titleKey: 'automations.guide.groups.always',
items: [
{ code: '{{ variables.API_KEY }}', descKey: 'automations.expr.variable' },
{ code: '{{ now }}', descKey: 'automations.expr.now' },
],
},
];
</script>
<template>
<Sheet v-model:open="open">
<SheetContent side="right" class="flex w-full flex-col overflow-hidden sm:max-w-md">
<SheetHeader>
<SheetTitle>{{ $t('automations.guide.title') }}</SheetTitle>
<SheetDescription>{{ $t('automations.guide.subtitle') }}</SheetDescription>
</SheetHeader>
<Tabs default-value="overview" class="flex min-h-0 flex-1 flex-col px-4 pb-6">
<TabsList class="grid w-full grid-cols-2">
<TabsTrigger value="overview">{{ $t('automations.guide.tabs.overview') }}</TabsTrigger>
<TabsTrigger value="expressions">{{ $t('automations.guide.tabs.expressions') }}</TabsTrigger>
</TabsList>
<TabsContent value="overview" class="mt-4 min-h-0 flex-1 space-y-6 overflow-y-auto">
<section class="space-y-1.5">
<h3 class="text-[11px] font-black uppercase tracking-widest text-foreground/50">
{{ $t('automations.guide.flow_title') }}
</h3>
<p class="text-sm text-foreground/70">{{ $t('automations.guide.flow_text') }}</p>
</section>
<section class="space-y-1.5">
<h3 class="text-[11px] font-black uppercase tracking-widest text-foreground/50">
{{ $t('automations.guide.scope_title') }}
</h3>
<p class="text-sm text-foreground/70">{{ $t('automations.guide.scope_text') }}</p>
</section>
<section class="space-y-2">
<h3 class="text-[11px] font-black uppercase tracking-widest text-foreground/50">
{{ $t('automations.guide.vars_title') }}
</h3>
<p class="text-sm text-foreground/70">{{ $t('automations.guide.vars_text') }}</p>
</section>
<section class="rounded-xl border-2 border-foreground bg-amber-50 p-3 shadow-[3px_3px_0_var(--foreground)]">
<p class="text-sm font-medium text-foreground">💡 {{ $t('automations.guide.tip_text') }}</p>
</section>
</TabsContent>
<TabsContent value="expressions" class="mt-4 min-h-0 flex-1 space-y-3 overflow-y-auto">
<p class="text-sm text-foreground/70">{{ $t('automations.guide.data_text') }}</p>
<div v-for="group in expressionGroups" :key="group.titleKey" class="space-y-1.5">
<h4 class="text-xs font-bold text-foreground/70">{{ $t(group.titleKey) }}</h4>
<div
v-for="item in group.items"
:key="item.code"
class="flex flex-col gap-0.5 rounded-lg border-2 border-foreground/15 bg-card/50 p-2.5"
>
<code class="font-mono text-xs font-bold text-foreground">{{ item.code }}</code>
<span class="text-xs text-foreground/55">{{ $t(item.descKey) }}</span>
</div>
<p v-if="group.noteKey" class="text-xs text-foreground/55">{{ $t(group.noteKey) }}</p>
</div>
</TabsContent>
</Tabs>
</SheetContent>
</Sheet>
</template>

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { Head, router } from '@inertiajs/vue3';
import { IconBolt, IconHelp } from '@tabler/icons-vue';
import { IconBolt, IconLifebuoy } from '@tabler/icons-vue';
import { Background } from '@vue-flow/background';
import { Controls } from '@vue-flow/controls';
import {
@ -33,7 +33,6 @@ import HttpRequestNodeConfig from '@/components/automations/config/HttpRequestNo
import PublishNodeConfig from '@/components/automations/config/PublishNodeConfig.vue';
import TriggerNodeConfig from '@/components/automations/config/TriggerNodeConfig.vue';
import WebhookNodeConfig from '@/components/automations/config/WebhookNodeConfig.vue';
import EditorGuide from '@/components/automations/EditorGuide.vue';
import EditorSidebar from '@/components/automations/EditorSidebar.vue';
import ConditionNode from '@/components/automations/nodes/ConditionNode.vue';
import DelayNode from '@/components/automations/nodes/DelayNode.vue';
@ -45,6 +44,7 @@ import PublishNode from '@/components/automations/nodes/PublishNode.vue';
import TriggerNode from '@/components/automations/nodes/TriggerNode.vue';
import WebhookNode from '@/components/automations/nodes/WebhookNode.vue';
import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { AddEdgeCommand } from '@/composables/history/commands/AddEdgeCommand';
import { AddNodeCommand } from '@/composables/history/commands/AddNodeCommand';
import { MoveNodeCommand } from '@/composables/history/commands/MoveNodeCommand';
@ -337,7 +337,6 @@ const deleteSelectedEdge = () => {
const isSaving = ref(false);
const activeTab = ref('build');
const isGuideOpen = ref(false);
const sanitizeNodes = (list: Node[]) =>
list.map((n) => ({
@ -439,10 +438,25 @@ const defaultEdgeOptions = {
<div class="flex min-h-0 flex-1 flex-col bg-background">
<AutomationHeader :automation="automation" current="workflow">
<template #actions>
<Button variant="outline" size="sm" @click="isGuideOpen = true">
<IconHelp class="size-4" />
{{ $t('automations.actions.guide') }}
</Button>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<Button
as="a"
href="https://docs.trypost.it/knowledge-base/automations/introduction"
target="_blank"
rel="noopener noreferrer"
variant="outline"
size="icon-sm"
class="group"
:aria-label="$t('automations.actions.guide')"
>
<IconLifebuoy class="size-4 transition-transform duration-500 group-hover:rotate-180" />
</Button>
</TooltipTrigger>
<TooltipContent>{{ $t('automations.actions.guide') }}</TooltipContent>
</Tooltip>
</TooltipProvider>
<Button size="sm" @click="save" :disabled="isSaving">{{ $t('automations.actions.save') }}</Button>
</template>
</AutomationHeader>
@ -466,9 +480,9 @@ const defaultEdgeOptions = {
class="automations-canvas"
>
<Background
pattern-color="#9ca3af"
pattern-color="#8b919c"
:gap="16"
:size="1"
:size="1.4"
/>
<Controls position="bottom-left" />
<template #connection-line="props">
@ -518,8 +532,6 @@ const defaultEdgeOptions = {
</aside>
</div>
</div>
<EditorGuide v-model:open="isGuideOpen" />
</AppLayout>
</template>