:path',
'email_utility_description' => 'Check email configuration settings and send test emails.',
'entry_count' => ':count entry|:count entries',
@@ -123,22 +129,18 @@
'forgot_password_enter_email' => 'Enter your email address to receive a password reset link.',
'forgot_password_sent' => 'If an account with that email address exists, a password reset link has been sent.',
'form_configure_blueprint_instructions' => 'Choose from existing blueprints or create a new one.',
- 'form_configure_email_attachments_instructions' => 'Attach uploaded assets to this email.',
- 'form_configure_email_bcc_instructions' => 'Email address of the BCC recipient(s) - comma separated.',
- 'form_configure_email_cc_instructions' => 'Email address of the CC recipient(s) - comma separated.',
+ 'form_configure_email_attachments_instructions' => 'Attach files uploaded with the submission.',
+ 'form_configure_email_body_instructions' => 'You can include submitted values using [Antlers](https://statamic.dev/frontend/antlers). Leave blank to list all submitted fields instead.',
'form_configure_email_from_instructions' => 'Leave blank to fall back to the site default.',
- 'form_configure_email_html_instructions' => 'The view for the HTML version of this email.',
- 'form_configure_email_instructions' => 'Configure emails to be sent when new form submissions are received.',
+ 'form_configure_email_views_instructions' => 'Leave both blank to use the default layout.',
'form_configure_email_description' => 'Be sure your email settings are configured to send and receive notifications when forms are submitted.',
'form_configure_email_markdown_instructions' => 'Render the HTML version of this email using Markdown.',
- 'form_configure_email_reply_to_instructions' => 'Leave blank to fall back to sender.',
- 'form_configure_email_subject_instructions' => 'Email subject line.',
- 'form_configure_email_text_instructions' => 'The view for the text version of this email.',
- 'form_configure_email_to_instructions' => 'Email address of the recipient(s) - comma separated.',
+ 'form_configure_email_reply_to_instructions' => 'Leave blank to fall back to the sender.',
+ 'form_configure_email_to_instructions' => 'Choose a form field or enter an email address.',
'form_configure_handle_instructions' => 'Used to reference this form on the frontend. This cannot be easily changed later.',
'form_configure_honeypot_instructions' => 'Field name to use as a honeypot. Honeypots are special fields used to reduce bot spam.',
'form_configure_intro' => 'Forms collect information from visitors and can trigger events and send notifications when submissions are received.',
- 'form_configure_mailer_instructions' => 'Choose the mailer for sending this email. Leave blank to fall back to the default mailer.',
+ 'form_configure_mailer_instructions' => 'Leave blank to fall back to the default mailer.',
'form_configure_generate_fake_submissions_instructions' => 'Allow generating fake submissions and workflow testing from the submissions screen.',
'form_configure_store_instructions' => 'Disable to stop storing submissions. Events and email notifications will still be sent.',
'form_configure_title_instructions' => 'Use a call to action, such as \'Contact Us\'.',
@@ -331,5 +333,10 @@
'user_wizard_invitation_subject' => 'Activate your new Statamic account on :site',
'user_wizard_roles_groups_intro' => 'Users can be assigned to roles that customize their permissions, access, and abilities throughout the Control Panel.',
'user_wizard_super_admin_instructions' => 'Super admins have complete control and access to everything in the control panel. Grant this role wisely.',
+ 'webhook_connection_delete_confirmation' => 'Are you sure you want to delete this webhook?',
+ 'webhook_connection_instructions' => 'Each webhook is sent when this form is submitted. Notify other services or trigger automations with the submission data.',
+ 'webhook_connection_payload_instructions' => 'Each submission is sent to the webhook URL as a JSON POST request.',
+ 'webhook_connection_verify_ssl_instructions' => 'Only disable this if the receiving server uses a self-signed certificate.',
+ 'webhook_connector_description' => 'Send submissions to an external URL.',
'width_x_height' => ':width × :height',
];
diff --git a/lang/en/validation.php b/lang/en/validation.php
index be3b1bd615e..c2d7b9d5279 100644
--- a/lang/en/validation.php
+++ b/lang/en/validation.php
@@ -196,6 +196,7 @@
'elevated_session_resend_code_unavailable' => 'Resend code is only available for verification code method.',
'elevated_session_verification_code' => 'The verification code is incorrect.',
'email_available' => 'A user with this email already exists.',
+ 'email_field_reference' => "References a field that doesn't exist on this form.",
'fieldset_imported_recursively' => 'Fieldset :handle is being imported recursively.',
'form_chart_hidden_field' => 'Field :field is hidden and cannot be charted.',
'form_chart_not_applicable' => 'Chart :chart cannot be used for field :field.',
@@ -218,6 +219,7 @@
'unique_user_value' => 'This value has already been taken.',
'unique_uri' => 'This URI has already been taken.',
'time' => 'Not a valid time.',
+ 'webhook_url_not_public' => 'Webhooks must use a public address.',
'asset_current_filename' => 'This is the current filename.',
'asset_file_exists' => 'A file already exists with this name.',
'asset_file_exists_same_content' => 'A file already exists with this name and has the same content. You may want to delete this rather than rename it.',
diff --git a/packages/cms/src/index.js b/packages/cms/src/index.js
index 8b30e9f288b..cbee0e5568c 100644
--- a/packages/cms/src/index.js
+++ b/packages/cms/src/index.js
@@ -16,6 +16,10 @@ export const {
RevisionPreview,
SaveButtonOptions,
SortableList,
+ ConnectionFields,
+ ConnectionList,
+ ConnectionRules,
+ ConnectionSummary,
requireElevatedSession,
requireElevatedSessionIf,
clone,
diff --git a/resources/css/dark.css b/resources/css/dark.css
index 64ee69737ff..ef9a2844b2d 100644
--- a/resources/css/dark.css
+++ b/resources/css/dark.css
@@ -1,6 +1,8 @@
.dark {
+ color-scheme: dark;
+
input:-webkit-autofill {
-webkit-box-shadow: inset 0 0 0 50px var(--color-gray-500);
-webkit-text-fill-color: var(--color-gray-300);
diff --git a/resources/css/elements/base.css b/resources/css/elements/base.css
index 236115cc450..3b219d3e6b7 100644
--- a/resources/css/elements/base.css
+++ b/resources/css/elements/base.css
@@ -1,6 +1,8 @@
/* VARIABLES
=================================================== */
:root {
+ color-scheme: light;
+
/* For animating height */
interpolate-size: allow-keywords;
diff --git a/resources/js/bootstrap/cms/core.js b/resources/js/bootstrap/cms/core.js
index 05070c7d6c8..505283c7260 100644
--- a/resources/js/bootstrap/cms/core.js
+++ b/resources/js/bootstrap/cms/core.js
@@ -19,3 +19,7 @@ export { default as resetValuesFromResponse } from '../../util/resetValuesFromRe
export { requireElevatedSession, requireElevatedSessionIf } from '../../components/elevated-sessions';
export { default as clone, deepClone } from '../../util/clone.js';
export { default as debounce } from '../../util/debounce.js';
+export { default as ConnectionFields } from '../../components/forms/connections/ConnectionFields.vue';
+export { default as ConnectionList } from '../../components/forms/connections/ConnectionList.vue';
+export { default as ConnectionRules } from '../../components/forms/connections/ConnectionRules.vue';
+export { default as ConnectionSummary } from '../../components/forms/connections/ConnectionSummary.vue';
diff --git a/resources/js/bootstrap/components.js b/resources/js/bootstrap/components.js
index fb7fdabc901..4e715e66b49 100644
--- a/resources/js/bootstrap/components.js
+++ b/resources/js/bootstrap/components.js
@@ -70,6 +70,10 @@ export default function registerGlobalComponents(app) {
app.component('min-max-insight', MinMaxInsight);
app.component('star-rating-insight', StarRatingInsight);
+ // Form Connections
+ app.component('email-connector', defineAsyncComponent(() => import('../components/forms/connections/EmailConnector.vue')));
+ app.component('webhook-connector', defineAsyncComponent(() => import('../components/forms/connections/WebhookConnector.vue')));
+
// Reusable
app.component('file-icon', FileIcon);
diff --git a/resources/js/bootstrap/fieldtypes.js b/resources/js/bootstrap/fieldtypes.js
index 1b9b078f200..6f34b4f4691 100644
--- a/resources/js/bootstrap/fieldtypes.js
+++ b/resources/js/bootstrap/fieldtypes.js
@@ -31,6 +31,7 @@ import Sites from '../components/globals/Sites.vue';
import Grid from '../components/fieldtypes/grid/Grid.vue';
import GridIndex from '../components/fieldtypes/grid/GridIndex.vue';
import GroupFieldtype from '../components/fieldtypes/GroupFieldtype.vue';
+import FormFieldsFieldtype from '../components/fieldtypes/FormFieldsFieldtype.vue';
import FormHeadingFieldtype from '../components/fieldtypes/FormHeadingFieldtype.vue';
import FormParagraphFieldtype from '@/components/fieldtypes/FormParagraphFieldtype.vue';
import FormUploadFieldtype from '@/components/fieldtypes/FormUploadFieldtype.vue';
@@ -114,6 +115,7 @@ export default function registerFieldtypes(app) {
app.component('grid-fieldtype', Grid);
app.component('grid-fieldtype-index', GridIndex);
app.component('group-fieldtype', GroupFieldtype);
+ app.component('form_fields-fieldtype', FormFieldsFieldtype);
app.component('form_heading-fieldtype', FormHeadingFieldtype);
app.component('form_paragraph-fieldtype', FormParagraphFieldtype);
app.component('form_upload-fieldtype', FormUploadFieldtype);
diff --git a/resources/js/components/fieldtypes/FormFieldsFieldtype.vue b/resources/js/components/fieldtypes/FormFieldsFieldtype.vue
new file mode 100644
index 00000000000..83a3a970d68
--- /dev/null
+++ b/resources/js/components/fieldtypes/FormFieldsFieldtype.vue
@@ -0,0 +1,51 @@
+
+
+
+ {{ preview.body }}
+ {{ examplePayload }}
+