Replace magic strings across the automation domain with backed PHP enums
(HttpMethod, AuthType, DelayUnit, ScheduleField) and mirrored TS consts
(http-method, auth-type, delay-unit, schedule-field, condition-operator,
publish-mode), plus the existing Condition\Handle / Operator / Publish\Mode.
Also:
- require scheduled_offset via concrete-index required_if instead of
defaulting to 60 when the publish mode is scheduled
- fail the webhook node explicitly when the resolved url is empty
- localize node failure messages (fetch_rss/http/webhook)
- cast resolver/strtoupper inputs to string so a present-null config value
degrades gracefully instead of crashing
- list automations with config('app.pagination.default'), drop the perPage param
393 lines
16 KiB
PHP
393 lines
16 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
return [
|
||
'title' => 'Automations',
|
||
'default_name' => 'New automation',
|
||
|
||
'actions' => [
|
||
'new' => 'New automation',
|
||
'edit' => 'Edit',
|
||
'save' => 'Save',
|
||
'activate' => 'Activate',
|
||
'pause' => 'Pause',
|
||
'delete' => 'Delete',
|
||
'retry' => 'Retry',
|
||
'guide' => 'Learn how it works',
|
||
],
|
||
|
||
'tabs' => [
|
||
'build' => 'Build',
|
||
'variables' => 'Variables',
|
||
'test' => 'Test',
|
||
],
|
||
|
||
'nav' => [
|
||
'workflow' => 'Workflow',
|
||
'invocations' => 'Invocations',
|
||
'metrics' => 'Metrics',
|
||
'settings' => 'Settings',
|
||
],
|
||
|
||
'settings' => [
|
||
'general' => 'General',
|
||
'general_description' => 'Rename this automation.',
|
||
'name_label' => 'Name',
|
||
'name_saved' => 'Automation renamed.',
|
||
'status_title' => 'Status',
|
||
'status_description' => 'Activate to start running it, or pause to stop.',
|
||
'activated_at' => 'Activated :date',
|
||
'paused_at' => 'Paused :date',
|
||
'created_at' => 'Created :date',
|
||
'danger_title' => 'Danger zone',
|
||
'danger_description' => 'Irreversible actions.',
|
||
'delete_title' => 'Delete this automation',
|
||
'delete_description' => 'Permanently removes the automation and its run history.',
|
||
],
|
||
|
||
'status_run' => [
|
||
'pending' => 'Pending',
|
||
'running' => 'Running',
|
||
'waiting' => 'Waiting',
|
||
'completed' => 'Completed',
|
||
'failed' => 'Failed',
|
||
'cancelled' => 'Cancelled',
|
||
],
|
||
|
||
'node_type' => [
|
||
'trigger' => 'Trigger',
|
||
'generate' => 'Generate content',
|
||
'delay' => 'Delay',
|
||
'condition' => 'Condition',
|
||
'publish' => 'Publish',
|
||
'webhook' => 'Webhook',
|
||
'end' => 'End',
|
||
'fetch_rss' => 'Fetch RSS',
|
||
'http_request' => 'HTTP request',
|
||
],
|
||
|
||
'invocations' => [
|
||
'empty' => 'No invocations yet.',
|
||
'refresh' => 'Refresh',
|
||
'search_placeholder' => 'Search by run ID…',
|
||
'copied' => 'Run ID copied.',
|
||
'loading' => 'Loading steps…',
|
||
'no_steps' => 'No steps recorded.',
|
||
'load_error' => 'Could not load steps.',
|
||
'steps' => '{0}No steps|{1}:count step|[2,*]:count steps',
|
||
'filter' => [
|
||
'all' => 'All statuses',
|
||
],
|
||
'columns' => [
|
||
'timestamp' => 'Timestamp',
|
||
'run' => 'Run',
|
||
'status' => 'Status',
|
||
'message' => 'Last message',
|
||
'duration' => 'Duration',
|
||
],
|
||
'summary' => [
|
||
'completed' => 'Workflow completed',
|
||
'failed' => 'Workflow failed',
|
||
'running' => 'Workflow running',
|
||
'cancelled' => 'Workflow cancelled',
|
||
'pending' => 'Workflow pending',
|
||
],
|
||
],
|
||
|
||
'metrics' => [
|
||
'overview' => 'Overview',
|
||
'runs_over_time' => 'Runs over time',
|
||
'posts_by_platform' => 'Posts by platform',
|
||
'no_posts' => 'No posts published in this period.',
|
||
'cards' => [
|
||
'runs' => 'Total runs',
|
||
'completed' => 'Completed',
|
||
'failed' => 'Failed',
|
||
'in_progress' => 'In progress',
|
||
'success_rate' => 'Success rate',
|
||
'avg_duration' => 'Avg duration',
|
||
'posts_created' => 'Posts created',
|
||
],
|
||
'legend' => [
|
||
'started' => 'Started',
|
||
'completed' => 'Completed',
|
||
'failed' => 'Failed',
|
||
],
|
||
],
|
||
|
||
'categories' => [
|
||
'sources' => 'Sources',
|
||
'content' => 'Content',
|
||
'flow' => 'Flow',
|
||
'output' => 'Output',
|
||
],
|
||
|
||
'variables' => [
|
||
'title' => 'Workflow variables',
|
||
'hint' => 'Reusable values referenced anywhere with {{ variables.KEY }}. Stored encrypted.',
|
||
'empty' => 'No variables yet.',
|
||
'key' => 'Key',
|
||
'value' => 'Value',
|
||
'key_placeholder' => 'API_KEY',
|
||
'value_placeholder' => 'Value',
|
||
'add' => 'New variable',
|
||
],
|
||
|
||
'expr' => [
|
||
'trigger_event' => 'Trigger event name',
|
||
'trigger_fired_at' => 'When the trigger fired',
|
||
'trigger_post_id' => 'Triggering post ID',
|
||
'trigger_post_content' => 'Triggering post content',
|
||
'trigger_post_status' => 'Triggering post status',
|
||
'trigger_post_scheduled_at' => 'When the post is scheduled',
|
||
'trigger_post_published_at' => 'When the post was published',
|
||
'fetched_title' => 'Fetched item title',
|
||
'fetched_link' => 'Fetched item link',
|
||
'fetched_description' => 'Fetched item description',
|
||
'fetched_pubdate' => 'Fetched item publish date',
|
||
'fetched_http' => 'Fetched HTTP item (append a field)',
|
||
'generated_content' => 'AI-generated post content',
|
||
'generated_post_url' => 'AI-generated post URL',
|
||
'variable' => 'Workflow variable',
|
||
'now' => 'Current date & time',
|
||
],
|
||
|
||
'test' => [
|
||
'description' => 'Runs the automation end-to-end using a synthesized trigger payload. Useful for validating each node without waiting for the real schedule or feed.',
|
||
'starting' => 'Starting test run…',
|
||
'in_progress' => 'In progress',
|
||
'completed' => 'Completed',
|
||
'failed' => 'Failed',
|
||
'waiting' => 'Waiting',
|
||
'close' => 'Close',
|
||
'no_node_runs' => 'Waiting for the first node to start…',
|
||
'node_input' => 'Input',
|
||
'node_output' => 'Output',
|
||
'node_error' => 'Error',
|
||
'no_new_items' => 'No new items — nothing downstream ran.',
|
||
'error_starting' => 'Could not start the test run.',
|
||
'with_real_data' => 'With real data',
|
||
'run' => 'Run test',
|
||
'idle_hint' => 'Hit Run test to execute the automation end-to-end.',
|
||
'real_data_hint' => 'This test will publish posts, advance polling watermarks, and trigger external side effects.',
|
||
'dry_badge' => 'Dry run',
|
||
],
|
||
|
||
'status' => [
|
||
'draft' => 'Draft',
|
||
'active' => 'Active',
|
||
'paused' => 'Paused',
|
||
],
|
||
|
||
'index' => [
|
||
'empty_title' => 'No automations yet',
|
||
'empty_description' => 'Create your first automation to start publishing on autopilot.',
|
||
'columns' => [
|
||
'name' => 'Name',
|
||
'status' => 'Status',
|
||
'created' => 'Created',
|
||
],
|
||
],
|
||
|
||
'form' => [
|
||
'activate_error_fallback' => 'Could not activate automation.',
|
||
'pause_error_fallback' => 'Could not pause automation.',
|
||
'save_error_fallback' => 'Could not save automation.',
|
||
'save_success' => 'Automation saved.',
|
||
'empty_canvas_title' => 'Start building your automation',
|
||
'empty_canvas_description' => 'Drag a node from the left panel to get started.',
|
||
'name_placeholder' => 'Untitled automation',
|
||
],
|
||
|
||
'nodes' => [
|
||
'trigger' => 'Trigger',
|
||
'generate' => 'Generate',
|
||
'delay' => 'Delay',
|
||
'condition' => 'Condition',
|
||
'publish' => 'Publish',
|
||
'webhook' => 'Webhook',
|
||
'end' => 'End',
|
||
'end_summary' => 'Stops the automation here',
|
||
'fetch_rss' => 'Fetch RSS',
|
||
'http_request' => 'HTTP Request',
|
||
'handles' => [
|
||
'items' => 'has items',
|
||
'no_items' => 'no items',
|
||
],
|
||
],
|
||
|
||
'config' => [
|
||
'select_placeholder' => 'Select…',
|
||
'invalid_json' => 'This isn’t valid JSON yet.',
|
||
'expand_editor' => 'Expand editor',
|
||
'minimize_editor' => 'Minimize',
|
||
|
||
'trigger' => [
|
||
'type' => 'Trigger type',
|
||
'types' => [
|
||
'schedule' => 'Schedule',
|
||
'post_published' => 'When a post is published',
|
||
'post_scheduled' => 'When a post is scheduled',
|
||
],
|
||
'post_published_hint' => 'Runs whenever any post in this workspace is published. The published post becomes available at {{ trigger.post }} for downstream nodes.',
|
||
'post_scheduled_hint' => 'Runs whenever any post in this workspace is scheduled. The scheduled post is available at {{ trigger.post }}.',
|
||
|
||
'schedule' => [
|
||
'field' => 'Trigger interval',
|
||
'fields' => [
|
||
'minutes' => 'Minutes',
|
||
'hours' => 'Hours',
|
||
'days' => 'Days',
|
||
'weeks' => 'Weeks',
|
||
'months' => 'Months',
|
||
],
|
||
'minutes_interval' => 'Minutes between triggers',
|
||
'hours_interval' => 'Hours between triggers',
|
||
'days_interval' => 'Days between triggers',
|
||
'hour' => 'Trigger at hour',
|
||
'minute' => 'Trigger at minute',
|
||
'weekdays' => 'Trigger on weekdays',
|
||
'day_of_month' => 'Day of month',
|
||
'timezone_hint' => 'All times in :tz',
|
||
'weekday_names' => [
|
||
'sun' => 'Sun',
|
||
'mon' => 'Mon',
|
||
'tue' => 'Tue',
|
||
'wed' => 'Wed',
|
||
'thu' => 'Thu',
|
||
'fri' => 'Fri',
|
||
'sat' => 'Sat',
|
||
],
|
||
'summary' => [
|
||
'every_n_minutes' => 'Runs every minute|Runs every :count minutes',
|
||
'every_n_hours' => 'Runs every hour at minute :minute|Runs every :count hours at minute :minute',
|
||
'every_n_days' => 'Runs every day at :time|Runs every :count days at :time',
|
||
'weekly' => 'Runs every :days at :time',
|
||
'monthly' => 'Runs on day :day of every month at :time',
|
||
],
|
||
],
|
||
],
|
||
'generate' => [
|
||
'social_accounts' => 'Social accounts',
|
||
'social_accounts_empty' => 'No connected social accounts. Connect one first.',
|
||
'target_slide_count' => 'Slides to generate',
|
||
'prompt_template' => 'Prompt template',
|
||
'prompt_template_hint' => 'Type {{ to insert data from earlier steps.',
|
||
'image_count' => 'Images to generate',
|
||
'image_count_hint' => '0 = text-only post (no image). 1 = single image. 2+ = carousel.',
|
||
'use_brand_voice' => 'Use brand voice',
|
||
'use_brand_voice_hint' => 'Apply your brand description and voice. Turn off for faithful curation of third-party sources (news, RSS).',
|
||
'use_brand_visuals' => 'Use brand visuals',
|
||
'use_brand_visuals_hint' => 'Steer AI images with your brand colors and identity. Turn off for neutral imagery driven only by the post topic.',
|
||
],
|
||
'delay' => [
|
||
'duration' => 'Duration',
|
||
'unit' => 'Unit',
|
||
'units' => [
|
||
'minutes' => 'Minutes',
|
||
'hours' => 'Hours',
|
||
'days' => 'Days',
|
||
],
|
||
],
|
||
'condition' => [
|
||
'field' => 'Field',
|
||
'operator' => 'Operator',
|
||
'operators' => [
|
||
'contains' => 'contains',
|
||
'not_contains' => 'not contains',
|
||
'equals' => 'equals',
|
||
'not_equals' => 'not equals',
|
||
'matches' => 'matches (regex)',
|
||
'greater_than' => 'greater than',
|
||
'less_than' => 'less than',
|
||
],
|
||
'value' => 'Value',
|
||
],
|
||
'publish' => [
|
||
'mode' => 'Mode',
|
||
'modes' => [
|
||
'now' => 'Publish now',
|
||
'scheduled' => 'Schedule',
|
||
'draft' => 'Save as draft',
|
||
],
|
||
'scheduled_offset' => 'Offset from trigger (minutes)',
|
||
],
|
||
'webhook' => [
|
||
'url' => 'URL',
|
||
'method' => 'Method',
|
||
'payload_template' => 'Payload template (JSON)',
|
||
],
|
||
'end' => [
|
||
'reason' => 'Reason (optional)',
|
||
'reason_placeholder' => 'e.g. Filtered out by condition',
|
||
],
|
||
'fetch_rss' => [
|
||
'feed_url' => 'Feed URL',
|
||
'feed_url_hint' => 'On first run, the watermark is set to "now" so historical items don\'t flood downstream nodes. Subsequent runs only see items newer than the previous poll.',
|
||
],
|
||
'http_request' => [
|
||
'url' => 'URL',
|
||
'method' => 'Method',
|
||
'auth_type' => 'Authentication',
|
||
'auth' => [
|
||
'none' => 'None (public)',
|
||
'bearer' => 'Bearer token',
|
||
'basic' => 'Basic auth',
|
||
'api_key' => 'API key header',
|
||
],
|
||
'bearer_token' => 'Bearer token',
|
||
'basic_username' => 'Username',
|
||
'basic_password' => 'Password',
|
||
'api_key_header' => 'Header name',
|
||
'api_key_value' => 'API key',
|
||
'body_template' => 'Body template (JSON)',
|
||
'headers' => 'Headers',
|
||
'header_name' => 'Header name',
|
||
'header_value' => 'Value',
|
||
'add_header' => 'Add header',
|
||
'polling_section' => 'List & deduplication (optional)',
|
||
'polling_hint' => 'When the response is a list, each item runs the workflow separately. A single object runs once.',
|
||
'items_path' => 'Items path',
|
||
'items_path_hint' => 'Leave blank if the response is already an array. Use a dotted path (e.g. data.items) for a nested array, or * for an object keyed by id.',
|
||
'item_key_path' => 'Item key path',
|
||
'item_key_path_hint' => 'JSON path to a unique id (e.g. id). Items already seen are skipped, so a feed without dates still only forwards new entries.',
|
||
'item_date_path' => 'Item date path',
|
||
'item_date_path_hint' => 'JSON path to the item timestamp (e.g. published_at). Preferred over the key path when available. The first poll records the baseline and forwards nothing, so an existing feed never floods on day one.',
|
||
],
|
||
],
|
||
|
||
'delete' => [
|
||
'title' => 'Delete automation',
|
||
'description' => 'Are you sure you want to delete this automation? All runs and trigger items will also be removed. This action cannot be undone.',
|
||
'confirm' => 'Delete',
|
||
'cancel' => 'Cancel',
|
||
],
|
||
|
||
'flash' => [
|
||
'deleted' => 'Automation deleted successfully!',
|
||
],
|
||
|
||
'errors' => [
|
||
'no_active_social_accounts' => 'No active social accounts configured for this automation.',
|
||
'must_have_one_trigger' => 'Automation must have exactly one trigger node.',
|
||
'trigger_must_be_connected' => 'Trigger node must be connected to at least one node.',
|
||
'graph_contains_cycle' => 'Automation graph contains a cycle.',
|
||
'only_failed_can_retry' => 'Only failed runs can be retried.',
|
||
'no_generated_post' => 'No generated post found on run.',
|
||
'webhook_server_error' => 'Webhook server error.',
|
||
'webhook_request_failed' => 'The webhook request could not be completed.',
|
||
'webhook_missing_url' => 'The webhook node is missing a URL.',
|
||
'webhook_invalid_payload_json' => 'The payload template is not valid JSON.',
|
||
'url_not_allowed' => 'The request URL points to a private or unreachable address and was blocked.',
|
||
'node_no_longer_exists' => 'Node :node_id no longer exists in the automation.',
|
||
'no_trigger_connection' => 'No node connected to the Trigger node.',
|
||
'fetch_rss_missing_url' => 'The Fetch RSS node is missing a feed URL.',
|
||
'fetch_rss_request_failed' => 'The RSS feed request failed.',
|
||
'fetch_rss_malformed' => 'The RSS feed is malformed.',
|
||
'http_missing_url' => 'The HTTP request node is missing a URL.',
|
||
'http_request_exception' => 'The HTTP request threw an exception.',
|
||
'http_request_failed' => 'The HTTP request failed.',
|
||
'http_items_path_not_array' => 'The items path did not resolve to a list.',
|
||
],
|
||
];
|