diff --git a/lang/en/messages.php b/lang/en/messages.php index 48e217f0cb0..08c6bfc349c 100644 --- a/lang/en/messages.php +++ b/lang/en/messages.php @@ -139,6 +139,7 @@ '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_unique_instances_instructions' => 'Treat each entry using this form as its own instance. Submissions will be attached to the entry they were submitted from.', 'form_configure_title_instructions' => 'Use a call to action, such as \'Contact Us\'.', 'form_configure_close_date_instructions' => 'The form will stop accepting submissions after this date. Leave blank to never close.', 'form_configure_submission_limit_instructions' => 'The maximum number of submissions to accept. Leave blank for no limit.', @@ -147,6 +148,10 @@ 'form_configure_require_login_instructions' => 'Only allow logged in users to submit this form.', 'form_configure_require_login_message_instructions' => 'Shown when a logged out visitor tries to submit the form. Leave blank to use the default message.', 'form_closed_message' => 'This form is no longer accepting submissions.', + 'form_fieldtype_configure_instructions' => 'Edit a field to override the form\'s setting for this entry. Synced fields keep following the form.', + 'form_fieldtype_sync_confirmation' => 'Are you sure? This override will be removed and the field will follow the form\'s setting again.', + 'form_connect_unique_instances_warning' => 'Unique Instances are enabled for this form. This means that the form\'s connections may be overridden on a per-entry basis.', + 'form_fieldtype_connections_instructions' => 'Override the form\'s connections for this entry.', 'form_require_login_message' => 'You must be logged in to submit this form.', 'form_create_description' => 'Get started by creating your first form.', 'form_builder' => 'Form Builder', diff --git a/resources/js/bootstrap/fieldtypes.js b/resources/js/bootstrap/fieldtypes.js index 4c639991704..6d3714a0d55 100644 --- a/resources/js/bootstrap/fieldtypes.js +++ b/resources/js/bootstrap/fieldtypes.js @@ -32,7 +32,11 @@ import Grid from '../components/fieldtypes/grid/Grid.vue'; import GridIndex from '../components/fieldtypes/grid/GridIndex.vue'; import GroupFieldtype from '../components/fieldtypes/GroupFieldtype.vue'; import FormBannerFieldtype from '../components/fieldtypes/FormBannerFieldtype.vue'; +import FormFieldtype from '../components/fieldtypes/FormFieldtype.vue'; +import FormIndexFieldtype from '../components/fieldtypes/FormIndexFieldtype.vue'; +import FormRelatedItem from '../components/fieldtypes/FormRelatedItem.vue'; import FormFieldsFieldtype from '../components/fieldtypes/FormFieldsFieldtype.vue'; +import FormConnectionsFieldtype from '../components/fieldtypes/FormConnectionsFieldtype.vue'; import FormHeadingFieldtype from '../components/fieldtypes/FormHeadingFieldtype.vue'; import FormParagraphFieldtype from '@/components/fieldtypes/FormParagraphFieldtype.vue'; import FormUploadFieldtype from '@/components/fieldtypes/FormUploadFieldtype.vue'; @@ -115,8 +119,12 @@ export default function registerFieldtypes(app) { app.component('grid-fieldtype', Grid); app.component('grid-fieldtype-index', GridIndex); app.component('group-fieldtype', GroupFieldtype); + app.component('form-fieldtype', FormFieldtype); + app.component('form-fieldtype-index', FormIndexFieldtype); + app.component('form-related-item', FormRelatedItem); app.component('form_banner-fieldtype', FormBannerFieldtype); app.component('form_fields-fieldtype', FormFieldsFieldtype); + app.component('form_connections-fieldtype', FormConnectionsFieldtype); 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/FormConnectionsFieldtype.vue b/resources/js/components/fieldtypes/FormConnectionsFieldtype.vue new file mode 100644 index 00000000000..56b322dd04e --- /dev/null +++ b/resources/js/components/fieldtypes/FormConnectionsFieldtype.vue @@ -0,0 +1,123 @@ + + + diff --git a/resources/js/components/fieldtypes/FormFieldtype.vue b/resources/js/components/fieldtypes/FormFieldtype.vue new file mode 100644 index 00000000000..aec081c43ed --- /dev/null +++ b/resources/js/components/fieldtypes/FormFieldtype.vue @@ -0,0 +1,188 @@ + + + diff --git a/resources/js/components/fieldtypes/FormIndexFieldtype.vue b/resources/js/components/fieldtypes/FormIndexFieldtype.vue new file mode 100644 index 00000000000..d2a27930234 --- /dev/null +++ b/resources/js/components/fieldtypes/FormIndexFieldtype.vue @@ -0,0 +1,22 @@ + + + diff --git a/resources/js/components/fieldtypes/FormRelatedItem.vue b/resources/js/components/fieldtypes/FormRelatedItem.vue new file mode 100644 index 00000000000..a7767e643e6 --- /dev/null +++ b/resources/js/components/fieldtypes/FormRelatedItem.vue @@ -0,0 +1,81 @@ + + + diff --git a/resources/js/components/forms/InlineSubmissionForm.vue b/resources/js/components/forms/InlineSubmissionForm.vue new file mode 100644 index 00000000000..a2c32ead806 --- /dev/null +++ b/resources/js/components/forms/InlineSubmissionForm.vue @@ -0,0 +1,43 @@ + + + diff --git a/resources/js/components/forms/SubmissionListing.vue b/resources/js/components/forms/SubmissionListing.vue index db3004806d5..f1423c98665 100644 --- a/resources/js/components/forms/SubmissionListing.vue +++ b/resources/js/components/forms/SubmissionListing.vue @@ -9,30 +9,41 @@ :sort-direction="sortDirection" :preferences-prefix="preferencesPrefix" :filters="filters" - push-query + :allow-presets="false" + :push-query="!viewInStack" > + + diff --git a/resources/js/components/forms/connections/ConnectionEditor.vue b/resources/js/components/forms/connections/ConnectionEditor.vue new file mode 100644 index 00000000000..95e9a5dc824 --- /dev/null +++ b/resources/js/components/forms/connections/ConnectionEditor.vue @@ -0,0 +1,21 @@ + + + diff --git a/resources/js/components/forms/connections/ConnectionsListing.vue b/resources/js/components/forms/connections/ConnectionsListing.vue new file mode 100644 index 00000000000..b1d14406aa6 --- /dev/null +++ b/resources/js/components/forms/connections/ConnectionsListing.vue @@ -0,0 +1,101 @@ + + + + + + + diff --git a/resources/js/pages/forms/connect/Edit.vue b/resources/js/pages/forms/connect/Edit.vue index 1ff015b97a4..a73e1abeb20 100644 --- a/resources/js/pages/forms/connect/Edit.vue +++ b/resources/js/pages/forms/connect/Edit.vue @@ -6,8 +6,9 @@ import Layout from '@/pages/layout/Layout.vue'; import PanelLayout from '@/pages/layout/PanelLayout.vue'; import FormsLayout from '../Layout.vue'; import Head from '@/pages/layout/Head.vue'; -import { Button, Card, Header, Heading, Icon, Panel, PanelHeader } from '@ui'; +import { Alert, Button, Card, Header, Heading, Icon, Panel, PanelHeader } from '@ui'; import FormStatusIndicator from '@/components/forms/FormStatusIndicator.vue'; +import ConnectionEditor from '@/components/forms/connections/ConnectionEditor.vue'; import { Link } from '@inertiajs/vue3'; defineOptions({ layout: [Layout, PanelLayout, FormsLayout] }); @@ -20,6 +21,7 @@ const props = defineProps({ action: String, isConfigured: Boolean, suggestableFields: Array, + uniqueInstancesEnabled: Boolean, }); const errors = ref({}); @@ -77,13 +79,20 @@ onUnmounted(() => {
-
+
+ + @@ -107,13 +116,7 @@ onUnmounted(() => { - +
diff --git a/resources/js/pages/forms/connect/Index.vue b/resources/js/pages/forms/connect/Index.vue index 404b76a482a..5bf2d77aac3 100644 --- a/resources/js/pages/forms/connect/Index.vue +++ b/resources/js/pages/forms/connect/Index.vue @@ -3,34 +3,14 @@ import Layout from '@/pages/layout/Layout.vue'; import PanelLayout from '@/pages/layout/PanelLayout.vue'; import FormsLayout from '../Layout.vue'; import Head from '@/pages/layout/Head.vue'; -import { - Badge, - Button, - Card, - DocsCallout, - Header, - Heading, - Icon, - Panel, - PanelHeader, - ToggleGroup, - ToggleItem, - Listing, - ListingTable, -} from '@ui'; +import { Alert, Button, Card, DocsCallout, Header, Heading, Icon, Panel, PanelHeader, ToggleGroup, ToggleItem } from '@ui'; import FormStatusIndicator from '@/components/forms/FormStatusIndicator.vue'; -import { Link } from '@inertiajs/vue3'; +import ConnectionsListing, { View } from '@/components/forms/connections/ConnectionsListing.vue'; import { ref, watch } from 'vue'; -import { __ } from '@/bootstrap/globals'; import { preferences } from '@api'; defineOptions({ layout: [Layout, PanelLayout, FormsLayout] }); -enum View { - Grid = 'grid', - List = 'list', -} - type Connection = { handle: string; title: string; @@ -44,24 +24,19 @@ type Connection = { defineProps<{ form: Object, connections: Connection[], + uniqueInstancesEnabled: boolean, }>(); const view = ref(preferences.get('forms.connect.view', View.Grid)); -watch(view, (view: View) => preferences.set('forms.connect.view', view)); +watch(view, (view) => preferences.set('forms.connect.view', view)); - -