Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions resources/js/components/blueprints/ImportField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<a class="cursor-pointer overflow-hidden text-ellipsis text-sm text-ui-accent-text hover:text-ui-accent-text/80" :href="fieldsetEditUrl" v-text="fieldsetTitle" v-tooltip="__('Edit fieldset')" />
<ui-icon name="link" class="text-gray-400" />
<span class="text-gray-500 font-mono text-2xs" v-text="__('Fieldset')" />
<ui-badge v-if="sectionBadgeText" size="sm" color="gray" :text="sectionBadgeText" />
<ui-badge
v-if="field.prefix"
size="sm"
Expand Down Expand Up @@ -62,10 +63,38 @@ export default {
return title ? __(title) : this.field.fieldset;
},

fieldsetHasSections() {
return this.$page?.props?.fieldsets?.[this.field.fieldset]?.has_sections === true;
},

fieldsetSectionsCount() {
return this.$page?.props?.fieldsets?.[this.field.fieldset]?.sections_count ?? 0;
},

fieldsetEditUrl() {
return cp_url(`fields/fieldsets/${this.field.fieldset}/edit`);
},

sectionBehavior() {
return this.field.section_behavior ?? 'preserve';
},

sectionBadgeText() {
if (!this.fieldsetHasSections) {
return null;
}

if (this.sectionBehavior === 'flatten') {
return this.fieldsetSectionsCount === 1
? __('Ignoring Section')
: __('Ignoring Sections');
}

return this.fieldsetSectionsCount === 1
? __('Has Section')
: __('Has Sections');
},

fieldConfig() {
const { _id, type, ...config } = this.field;
return config;
Expand Down
4 changes: 4 additions & 0 deletions resources/js/components/blueprints/Section.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
:editing-field="editingField"
:suggestable-condition-fields="suggestableConditionFields"
:can-define-localizable="canDefineLocalizable"
:exclude-fieldset="excludeFieldset"
:with-command-palette="withCommandPalette"
@field-created="fieldCreated"
@field-updated="fieldUpdated"
@field-deleted="deleteField"
Expand Down Expand Up @@ -146,6 +148,8 @@ export default {
showCollapsibleField: { type: Boolean, default: false },
showHideField: { type: Boolean, default: false },
editText: { type: String },
excludeFieldset: { type: String, default: null },
withCommandPalette: { type: Boolean, default: false },
},

data() {
Expand Down
22 changes: 18 additions & 4 deletions resources/js/components/blueprints/Sections.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@
:show-handle-field="showSectionHandleField"
:show-collapsible-field="showSectionCollapsibleField"
:show-hide-field="showSectionHideField"
:exclude-fieldset="excludeFieldset"
:with-command-palette="withCommandPalette"
:edit-text="editSectionText"
@updated="updateSection(i, $event)"
@deleted="deleteSection(i)"
/>

<button class="w-full flex gap-2 items-center justify-center relative min-h-24 text-gray-500 hover:text-gray-700 dark:hover:text-gray-400 cursor-pointer border border-dashed border-gray-300 dark:border-gray-700 hover:border-gray-400 dark:hover:border-gray-600 rounded-xl outline-hidden" @click="addAndEditSection">
<ui-icon name="plus" class="size-4" />
<div v-text="addSectionText" />
</button>
<div class="blueprint-add-section-container w-full">
<button class="blueprint-add-section-button" @click="addAndEditSection">
<div class="flex items-center gap-2">
<ui-icon name="plus" class="size-4" />
<div v-text="addSectionText" />
</div>
</button>
</div>
</div>
</div>
</template>
Expand Down Expand Up @@ -76,6 +82,14 @@ export default {
type: Boolean,
default: false,
},
excludeFieldset: {
type: String,
default: null,
},
withCommandPalette: {
type: Boolean,
default: false,
},
},

data() {
Expand Down
63 changes: 61 additions & 2 deletions resources/js/components/fields/ImportSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,36 @@
<Field :label="__('Prefix')" :instructions="__('messages.fieldset_import_prefix_instructions')" class="form-group field-w-100">
<Input autofocus :model-value="config.prefix" @update:model-value="updateField('prefix', $event)" />
</Field>

<Field
v-if="fieldsetHasSections"
:label="__('Section Behavior')"
:instructions="sectionBehaviorInstructions"
class="form-group field-w-100"
>
<RadioGroup
:model-value="sectionBehavior"
@update:model-value="updateField('section_behavior', $event)"
>
<Radio
v-for="option in sectionBehaviorOptions"
:key="option.value"
:label="option.label"
:description="option.description"
:value="option.value"
/>
</RadioGroup>
</Field>
</div>
</CardPanel>
</StackContent>
</template>

<script>
import { Button, Heading, CardPanel, Field, Input, StackHeader, StackContent } from '@/components/ui';
import { Button, Heading, CardPanel, Field, Input, StackHeader, StackContent, RadioGroup, Radio } from '@/components/ui';

export default {
components: { StackContent, StackHeader, Heading, Button, CardPanel, Field, Input },
components: { StackContent, StackHeader, Heading, Button, CardPanel, Field, Input, RadioGroup, Radio },

props: ['config', 'isInsideSet'],

Expand All @@ -46,13 +66,52 @@ export default {
};
},

computed: {
fieldsetMeta() {
const handle = this.values.fieldset;

return this.$page?.props?.fieldsets?.[handle] ?? null;
},

fieldsetHasSections() {
return this.fieldsetMeta?.has_sections === true;
},

sectionBehavior() {
return this.values.section_behavior ?? 'preserve';
},

sectionBehaviorInstructions() {
return __('Choose whether imported fieldset sections should be preserved or flattened into this section.');
},

sectionBehaviorOptions() {
return [
{
label: __('Preserve'),
description: __('Keep imported sections as-is.'),
value: 'preserve',
},
{
label: __('Flatten'),
description: __('Merge all fields into this section.'),
value: 'flatten',
},
];
},
},

methods: {
focus() {
this.$els.display.select();
},

updateField(handle, value) {
this.values[handle] = value;

if (handle === 'fieldset' && ! this.fieldsetHasSections) {
this.values.section_behavior = 'preserve';
}
},

commit(shouldCommitParent = false) {
Expand Down
98 changes: 55 additions & 43 deletions resources/js/pages/fieldsets/Edit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,20 @@
</ui-card>
</ui-panel>

<ui-panel :heading="__('Fields')">
<fields
:fields="fields"
:editing-field="editingField"
:exclude-fieldset="fieldset.handle"
:suggestable-condition-fields="suggestableConditionFields(this)"
with-command-palette
@field-created="fieldCreated"
@field-updated="fieldUpdated"
@field-linked="fieldLinked"
@field-deleted="deleteField"
@field-editing="editingField = $event"
@editor-closed="editingField = null"
/>
</ui-panel>
<sections
class="mt-8"
tab-id="fieldset"
:initial-sections="sections"
:show-section-collapsible-field="true"
:exclude-fieldset="fieldset.handle"
with-command-palette
@updated="sections = $event"
/>
</div>
</template>

<script>
import Fields from '@/components/blueprints/Fields.vue';
import Sections from '@/components/blueprints/Sections.vue';
import { Sortable, Plugins } from '@shopify/draggable';
import SuggestsConditionalFields from '@/components/blueprints/SuggestsConditionalFields';
import { Header, Button } from '@/components/ui';
Expand All @@ -53,7 +47,7 @@ export default {

components: {
Head,
Fields,
Sections,
Header,
Button,
},
Expand All @@ -71,17 +65,17 @@ export default {
},

computed: {
fields: {
sections: {
get() {
return this.fieldset.fields;
return this.fieldset.sections;
},
set(fields) {
this.fieldset.fields = fields;
set(sections) {
this.fieldset.sections = sections;
},
},

fieldsForConditionSuggestions() {
return this.fields;
return this.sections.reduce((fields, section) => fields.concat(section.fields || []), []);
},
},

Expand All @@ -96,6 +90,12 @@ export default {
this.$dirty.add('fieldsets');
},
},
sections: {
deep: true,
handler() {
this.$nextTick(() => this.makeSortable());
},
},
},

methods: {
Expand All @@ -112,35 +112,39 @@ export default {
});
},

fieldCreated(field) {
this.fields.push(field);
},

fieldUpdated(i, field) {
this.fields.splice(i, 1, field);
},

deleteField(i) {
this.fields.splice(i, 1);
},

fieldLinked(field) {
this.fields.push(field);
this.$toast.success(__('Field added'));
makeSortable() {
if (this.sortableSections) {
this.sortableSections.destroy();
}

if (field.type === 'reference') {
this.$nextTick(() => (this.editingField = field._id));
if (this.sortableFields) {
this.sortableFields.destroy();
}
},

makeSortable() {
new Sortable(this.$el.querySelector('.blueprint-section-draggable-zone'), {
this.sortableSections = new Sortable(this.$el.querySelector('.blueprint-sections'), {
draggable: '.blueprint-section',
handle: '.blueprint-section-drag-handle',
mirror: { constrainDimensions: true, appendTo: 'body' },
plugins: [Plugins.SwapAnimation],
}).on('sortable:stop', (e) => {
this.fieldset.sections.splice(e.newIndex, 0, this.fieldset.sections.splice(e.oldIndex, 1)[0]);
});

this.sortableFields = new Sortable(this.$el.querySelectorAll('.blueprint-section-draggable-zone'), {
draggable: '.blueprint-section-field',
handle: '.blueprint-drag-handle',
mirror: { constrainDimensions: true, appendTo: 'body' },
plugins: [Plugins.SwapAnimation],
}).on('sortable:stop', (e) => {
this.fieldset.fields.splice(e.newIndex, 0, this.fieldset.fields.splice(e.oldIndex, 1)[0]);
const oldSection = this.fieldset.sections.find((section) => section._id === e.oldContainer.dataset.section);
const newSection = this.fieldset.sections.find((section) => section._id === e.newContainer.dataset.section);

if (!oldSection || !newSection) {
return;
}

const field = oldSection.fields.splice(e.oldIndex, 1)[0];
newSection.fields.splice(e.newIndex, 0, field);
});
},
},
Expand All @@ -160,6 +164,14 @@ export default {

beforeUnmount() {
this.$events.$off('root-form-save');

if (this.sortableSections) {
this.sortableSections.destroy();
}

if (this.sortableFields) {
this.sortableFields.destroy();
}
},
};
</script>
11 changes: 10 additions & 1 deletion src/Fields/FieldTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ private static function importTabField(array $submitted)
return array_filter([
'import' => $submitted['fieldset'],
'prefix' => $submitted['prefix'] ?? null,
'section_behavior' => ($submitted['section_behavior'] ?? 'preserve') === 'flatten'
? 'flatten'
: null,
]);
}

Expand Down Expand Up @@ -179,11 +182,17 @@ private static function inlineFieldToVue($field): array

private static function importFieldToVue($field): array
{
return [
$import = [
'type' => 'import',
'fieldset' => $field['import'],
'prefix' => $field['prefix'] ?? null,
];

if (isset($field['section_behavior'])) {
$import['section_behavior'] = $field['section_behavior'];
}

return $import;
}

public static function fieldsetFields()
Expand Down
Loading
Loading