diff --git a/resources/fieldsets/event.yaml b/resources/fieldsets/event.yaml index 6e89f2d..aa66414 100644 --- a/resources/fieldsets/event.yaml +++ b/resources/fieldsets/event.yaml @@ -1,47 +1,30 @@ title: Event fields: - - handle: all_day - field: - type: toggle - width: 25 - display: 'All Day?' - - - handle: multi_day - field: - type: toggle - width: 25 - display: 'Multi-Day?' - - - handle: start_date - field: - type: date - allow_blank: false - allow_time: false - require_time: false - input_format: M/D/YYYY - width: 25 - display: 'Start Date' - if: - multi_day: 'equals false' - - - handle: start_time - field: - type: time - width: 25 - display: 'Start Time' - if: - multi_day: 'equals false' - all_day: 'equals false' - - - handle: end_time + handle: recurrence field: - type: time - width: 25 - display: 'End Time' - if: - multi_day: 'equals false' - all_day: 'equals false' + type: select + options: + none: None + daily: Daily + weekly: Weekly + monthly: Monthly + every: Every + multi_day: Multi-Day + width: 33 + display: Recurrence + default: none + instructions_position: above + listable: hidden + visibility: visible + replicator_preview: true + taggable: false + push_tags: false + multiple: false + clearable: false + searchable: true + cast_booleans: false + hide_display: false - handle: timezone field: @@ -53,71 +36,30 @@ fields: cast_booleans: false display: Timezone type: timezones + icon: select listable: hidden instructions_position: above mode: typeahead - width: 50 + width: 33 - - handle: days + handle: all_day field: - type: grid - mode: table - fields: - - - handle: date - field: - type: date - allow_blank: false - allow_time: false - require_time: false - input_format: M/D/YYYY - width: 33 - display: Date - - - handle: start_time - field: - type: time - width: 33 - display: 'Start Time' - - - handle: end_time - field: - type: time - width: 33 - display: 'End Time' - display: Days - add_row: 'Add Day' + type: toggle + width: 33 + display: 'All Day?' + instructions_position: above listable: hidden - reorderable: true - if: - multi_day: 'equals true' - - - handle: recurrence_section - field: - type: section - display: Recurrence - if: - multi_day: 'equals false' - - - handle: recurrence - field: - type: select - options: - 0: None - daily: Daily - weekly: Weekly - monthly: Monthly - every: Every - width: 25 - display: 'Recurrence Type' + visibility: visible + replicator_preview: true default: false - if: - multi_day: 'equals false' + hide_display: false + unless: + recurrence: 'equals multi_day' - handle: interval field: type: integer - width: 25 + width: 50 display: Interval if: recurrence: 'equals every' @@ -130,9 +72,34 @@ fields: weeks: Weeks years: Years display: Period - width: 25 + width: 50 if: recurrence: 'equals every' + - + handle: start_date + field: + type: date + allow_blank: false + allow_time: false + require_time: false + input_format: M/D/YYYY + width: 50 + display: 'Start Date' + instructions_position: above + listable: hidden + visibility: visible + replicator_preview: true + mode: single + inline: true + full_width: true + columns: 1 + rows: 1 + time_enabled: false + time_seconds_enabled: false + hide_display: false + unless_any: + multi_day: 'equals true' + recurrence: 'equals multi_day' - handle: end_date field: @@ -142,49 +109,143 @@ fields: require_time: false input_format: M/D/YYYY display: 'End Date' - width: 25 + width: 50 listable: hidden mode: single time_enabled: false time_required: false - full_width: false - inline: false + full_width: true + inline: true columns: 1 rows: 1 + instructions_position: above + visibility: visible + replicator_preview: true + time_seconds_enabled: false + hide_display: false if: recurrence: 'contains_any daily, weekly, monthly, every' - - handle: exclude_dates + handle: start_time + field: + type: time + width: 25 + display: 'Start Time' + instructions: 'Input in [24-hour format](https://en.wikipedia.org/wiki/24-hour_clock)' + instructions_position: above + listable: hidden + visibility: visible + replicator_preview: true + seconds_enabled: false + hide_display: false + unless_any: + multi_day: 'equals true' + all_day: 'equals true' + recurrence: 'equals multi_day' + - + handle: end_time field: + type: time + width: 25 + display: 'End Time' + instructions: 'Input in [24-hour format](https://en.wikipedia.org/wiki/24-hour_clock)' + instructions_position: above + listable: hidden + visibility: visible + replicator_preview: true + seconds_enabled: false + hide_display: false + unless_any: + multi_day: 'equals true' + all_day: 'equals true' + recurrence: 'equals multi_day' + - + handle: days + field: + type: grid + mode: table fields: - handle: date field: - mode: single - inline: false - full_width: false - columns: 1 - rows: 1 - time_enabled: false - time_seconds_enabled: false type: date + allow_blank: false + allow_time: false + require_time: false + input_format: M/D/YYYY + width: 25 display: Date + - + handle: start_time + field: + type: time + width: 25 + display: 'Start Time' + instructions: 'Input in 24-hour format (ie 2:00 PM will be entered as 14:00)' + instructions_position: above listable: hidden + visibility: visible + replicator_preview: true + seconds_enabled: false + hide_display: false + unless: + all_day: 'equals true' + - + handle: end_time + field: + type: time + width: 25 + display: 'End Time' + instructions: 'Input in 24-hour format (ie 2:00 PM will be entered as 14:00)' instructions_position: above + listable: hidden visibility: visible replicator_preview: true + seconds_enabled: false hide_display: false - mode: table - reorderable: false - fullscreen: false + unless: + all_day: 'equals true' + - + handle: all_day + field: 'events::event.all_day' + config: + width: 25 + display: 'Event Days' + add_row: 'Add Day' + listable: hidden + reorderable: true + instructions_position: above + visibility: visible + replicator_preview: true + min_rows: 1 + fullscreen: true + hide_display: false + if_any: + multi_day: 'equals true' + recurrence: 'equals multi_day' + - + handle: exclude_dates + field: type: grid - display: Exclusions + mode: table + fields: + - + handle: date + field: + type: date + allow_blank: false + allow_time: false + require_time: false + input_format: M/D/YYYY + display: Date + display: 'Exclude Days' + add_row: 'Add Day' listable: hidden + reorderable: true instructions_position: above visibility: visible replicator_preview: true + fullscreen: true hide_display: false - if: - multi_day: 'equals false' - recurrence: 'contains_any daily, weekly, monthly, every' - add_row: 'Add Excluded Date' + if_any: + recurrence: 'contains_any monthly, daily, weekly, every' diff --git a/src/Day.php b/src/Day.php index fb9cf32..99a4727 100644 --- a/src/Day.php +++ b/src/Day.php @@ -23,7 +23,7 @@ public function __construct(array $data, string $timezone, bool $isAllDay = fals $this->startTime = Arr::get($data, 'start_time'); $this->endTime = Arr::get($data, 'end_time'); - if (! $isAllDay && $this->isAllDay()) { + if (! $isAllDay && (empty($this->startTime) && empty($this->endTime))) { $this->isAllDay = true; } else { $this->isAllDay = $isAllDay; @@ -37,7 +37,7 @@ public function hasEndtime(): bool public function isAllDay(): bool { - return empty($this->startTime) && empty($this->endTime); + return $this->isAllDay; } public function start(): CarbonImmutable diff --git a/src/EventFactory.php b/src/EventFactory.php index fc5cb24..e24ad98 100644 --- a/src/EventFactory.php +++ b/src/EventFactory.php @@ -12,7 +12,7 @@ class EventFactory { public static function createFromEntry(Entry $event, bool $collapseMultiDays = false): Event { - if ($event->multi_day) { + if ($event->multi_day || $event->recurrence->value() === 'multi_day') { return new MultiDayEvent($event, $collapseMultiDays); } diff --git a/src/Events.php b/src/Events.php index d6e81e0..00322ad 100644 --- a/src/Events.php +++ b/src/Events.php @@ -168,6 +168,7 @@ private function occurrences(callable $generator): EntryCollection // take each event and generate the occurences ->flatMap(callback: $generator) ->reject(fn (Entry $occurrence) => collect($occurrence->exclude_dates) + ->filter(fn (Values $dateRow) => $dateRow->date) ->contains(fn (Values $dateRow) => $dateRow->date->isSameDay($occurrence->start)) )->sortBy(callback: fn (Entry $occurrence) => $occurrence->start, descending: $this->sort === 'desc') ->values(); diff --git a/src/Types/Event.php b/src/Types/Event.php index 8f34e13..66fa61c 100644 --- a/src/Types/Event.php +++ b/src/Types/Event.php @@ -41,13 +41,16 @@ public function isAllDay(): bool public function isMultiDay(): bool { - return boolval($this->multi_day); + return boolval($this->multi_day) || $this->recurrence?->value() === 'multi_day'; } public function isRecurring(): bool { // this is a select field so you have to get its value - return boolval($this->recurrence?->value()); + return match ($this->recurrence?->value()) { + 'daily', 'weekly', 'monthly', 'yearly' => true, + default => false, + }; } public function occurrencesBetween(string|CarbonInterface $from, string|CarbonInterface $to): Collection diff --git a/src/Types/MultiDayEvent.php b/src/Types/MultiDayEvent.php index cbabcbf..25e7bf0 100644 --- a/src/Types/MultiDayEvent.php +++ b/src/Types/MultiDayEvent.php @@ -25,7 +25,7 @@ public function __construct(Entry $event, private bool $collapseMultiDays) ->map(fn (Values $day) => new Day( $day->all(), $this->timezone['timezone'], - $this->isAllDay() + $day->all_day || $this->isAllDay(), )); } @@ -115,6 +115,7 @@ protected function supplement(CarbonInterface $date): ?Entry return tap( unserialize(serialize($this->event)), fn (Entry $occurrence) => $occurrence + ->setSupplement('all_day', $day->isAllDay()) ->setSupplement('collapse_multi_days', $this->collapseMultiDays) ->setSupplement('start', $day->start()) ->setSupplement('end', $day->end()) diff --git a/tests/Feature/IcsControllerTest.php b/tests/Feature/IcsControllerTest.php index e08a615..3dcf1ec 100755 --- a/tests/Feature/IcsControllerTest.php +++ b/tests/Feature/IcsControllerTest.php @@ -16,7 +16,6 @@ public function setUp(): void parent::setUp(); Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('single-event') ->id('the-id') @@ -49,7 +48,6 @@ public function canCreateSingleDayRecurringEventIcsFile() Carbon::setTestNow(now()->addDay()->setTimeFromTimeString('10:00')); Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('recurring-event') ->id('the-recurring-id') diff --git a/tests/Feature/TagTest.php b/tests/Feature/TagTest.php index b07f5a4..141199d 100755 --- a/tests/Feature/TagTest.php +++ b/tests/Feature/TagTest.php @@ -21,7 +21,6 @@ public function setUp(): void parent::setUp(); Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('recurring-event') ->id('recurring-event') @@ -80,7 +79,6 @@ public function canGenerateCalendarOccurrences() Entry::all()->each->delete(); Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('single-event-start-of-month') ->data([ @@ -91,7 +89,6 @@ public function canGenerateCalendarOccurrences() ])->save(); Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('recurring-event-start-of-month') ->data([ @@ -142,7 +139,6 @@ public function canGenerateTodayOccurrences() Carbon::setTestNow(now()->setTimeFromTimeString('12:01')); Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('single-event') ->data([ @@ -191,7 +187,6 @@ public function canGenerateUpcomingOccurrences() public function canGenerateUpcomingLimitedOccurrences() { Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('another-recurring-event') ->id('another-recurring-event') @@ -251,7 +246,6 @@ public function canGenerateUpcomingOccurrencesWithTaxonomyTerms() Carbon::setTestNow(now()->setTimeFromTimeString('10:00')); Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('single-event') ->id('single-event') @@ -282,7 +276,6 @@ public function canGenerateUpcomingOccurrencesWithFilter() Carbon::setTestNow(now()->setTimeFromTimeString('10:00')); Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('single-event') ->id('single-event') diff --git a/tests/TestCase.php b/tests/TestCase.php index 50d989f..ac4df4b 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -5,12 +5,12 @@ use Orchestra\Testbench\TestCase as OrchestraTestCase; use Statamic\Entries\Collection; use Statamic\Extend\Manifest; -use Statamic\Facades\Blueprint as BlueprintFacade; use Statamic\Facades\Collection as CollectionFacade; +use Statamic\Facades\Fieldset; use Statamic\Facades\Taxonomy; use Statamic\Facades\Term; -use Statamic\Facades\YAML; use Statamic\Fields\Blueprint; +use Statamic\Fields\BlueprintRepository; use Statamic\Providers\StatamicServiceProvider; use Statamic\Statamic; use TransformStudios\Events\ServiceProvider; @@ -20,6 +20,7 @@ abstract class TestCase extends OrchestraTestCase use PreventSavingStacheItemsToDisk; protected Collection $collection; + protected Blueprint $blueprint; public function setup(): void @@ -81,21 +82,15 @@ protected function resolveApplicationConfiguration($app) // Assume the pro edition within tests $app['config']->set('statamic.editions.pro', true); + $app['config']->set('events.timezone', 'UTC'); Statamic::booted(function () { - $taxonomy = Taxonomy::make('categories')->save(); + Fieldset::addNamespace('events', __DIR__.'/../resources/fieldsets'); + app()->extend(BlueprintRepository::class, fn ($repo) => $repo->setDirectory(__DIR__.'/__fixtures__/blueprints')); + + Taxonomy::make('categories')->save(); Term::make('one')->taxonomy('categories')->dataForLocale('default', [])->save(); Term::make('two')->taxonomy('categories')->dataForLocale('default', [])->save(); - $blueprintContents = YAML::parse(file_get_contents(__DIR__.'/__fixtures__/blueprints/event.yaml')); - $blueprintFields = collect($blueprintContents['sections']['main']['fields']) - ->keyBy(fn ($item) => $item['handle']) - ->map(fn ($item) => $item['field']) - ->all(); - - $this->blueprint = BlueprintFacade::makeFromFields($blueprintFields) - ->setNamespace('collections.events') - ->setHandle('event') - ->save(); $this->collection = CollectionFacade::make('events') ->taxonomies(['categories']) diff --git a/tests/Unit/EventsTest.php b/tests/Unit/EventsTest.php index 266f2c8..5e75537 100755 --- a/tests/Unit/EventsTest.php +++ b/tests/Unit/EventsTest.php @@ -28,14 +28,14 @@ public function canGenerateDatesWhenNowBeforeStart() 'recurrence' => 'daily', ])->save(); - Entry::make() + $event = tap(Entry::make() ->collection('events') ->slug('single-event') ->data([ 'title' => 'Single Event', 'start_date' => Carbon::now()->toDateString(), 'start_time' => '13:00', - ])->save(); + ]))->save(); $occurrences = Events::fromCollection(handle: 'events') ->between(now(), now()->addDays(2)->endOfDay()); @@ -139,7 +139,6 @@ public function canFilterEvents() ])->save(); Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('other-event') ->data([ @@ -174,7 +173,6 @@ public function canFilterMultipleEvents() ])->save(); Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('other-event') ->data([ @@ -280,7 +278,6 @@ public function canDetermineOccursAtForSingleEvent() Carbon::setTestNow(now()->setTimeFromTimeString('10:00')); $entry = Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->slug('single-event') ->id('the-id') @@ -352,8 +349,31 @@ public function canExcludeDates() ])->save(); $occurrences = Events::fromCollection(handle: 'events') - ->between(now(), now()->addDays(9)->endOfDay()); + ->between(now(), now()->addDays(3)->endOfDay()); + + $this->assertCount(3, $occurrences); + } + + /** @test */ + public function canHandleEmptyExcludeDates() + { + Carbon::setTestNow(now()->setTimeFromTimeString('10:00')); - $this->assertCount(9, $occurrences); + Entry::make() + ->collection('events') + ->slug('recurring-event') + ->data([ + 'title' => 'Recurring Event', + 'start_date' => Carbon::now()->toDateString(), + 'start_time' => '11:00', + 'end_time' => '12:00', + 'recurrence' => 'daily', + 'exclude_dates' => [['id' => 'random-id']], + ])->save(); + + $occurrences = Events::fromCollection(handle: 'events') + ->between(now(), now()->addDays(3)->endOfDay()); + + $this->assertCount(4, $occurrences); } } diff --git a/tests/Unit/MultiDayEventsTest.php b/tests/Unit/MultiDayEventsTest.php index bbaa224..57605e2 100755 --- a/tests/Unit/MultiDayEventsTest.php +++ b/tests/Unit/MultiDayEventsTest.php @@ -3,6 +3,7 @@ namespace TransformStudios\Events\Tests\Unit; use Carbon\Carbon; +use Statamic\Facades\Blueprint; use Statamic\Facades\Entry; use TransformStudios\Events\EventFactory; use TransformStudios\Events\Tests\TestCase; @@ -25,12 +26,11 @@ public function setUp(): void Carbon::setTestNowAndTimezone(now(), 'America/Vancouver'); - $entry = Entry::make() ->slug('multi-day-event') ->collection('events') ->data([ - 'multi_day' => true, + 'recurrence' => 'multi_day', 'days' => [ [ 'date' => '2019-11-23', @@ -57,7 +57,7 @@ public function setUp(): void ->collection('events') ->slug('no-end-time') ->data([ - 'multi_day' => true, + 'recurrence' => 'multi_day', 'days' => [ [ 'date' => '2019-11-23', @@ -76,7 +76,7 @@ public function setUp(): void $allDayEntry = Entry::make() ->collection('events') ->data([ - 'multi_day' => true, + 'recurrence' => 'multi_day', 'days' => [ [ 'date' => '2019-11-20', diff --git a/tests/Unit/RecurringDailyEventsTest.php b/tests/Unit/RecurringDailyEventsTest.php index 31c179c..a6b905e 100755 --- a/tests/Unit/RecurringDailyEventsTest.php +++ b/tests/Unit/RecurringDailyEventsTest.php @@ -14,7 +14,6 @@ class RecurringDailyEventsTest extends TestCase public function nullNextDateIfNowAfterEndDate() { $recurringEntry = Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->data([ 'start_date' => Carbon::now()->toDateString(), diff --git a/tests/Unit/RecurringEventsTest.php b/tests/Unit/RecurringEventsTest.php index 46ebcba..60935ce 100755 --- a/tests/Unit/RecurringEventsTest.php +++ b/tests/Unit/RecurringEventsTest.php @@ -5,7 +5,9 @@ use Carbon\Carbon; use Statamic\Facades\Entry; use TransformStudios\Events\EventFactory; +use TransformStudios\Events\Events; use TransformStudios\Events\Tests\TestCase; +use TransformStudios\Events\Types\MultiDayEvent; use TransformStudios\Events\Types\RecurringEvent; class RecurringEventsTest extends TestCase @@ -14,7 +16,6 @@ class RecurringEventsTest extends TestCase public function canCreateRecurringEvent() { $recurringEntry = Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->data([ 'start_date' => Carbon::now()->toDateString(), @@ -29,20 +30,23 @@ public function canCreateRecurringEvent() $this->assertFalse($event->isMultiDay()); } - // public function test_get_end_date_null_if_no_end_date() - // { - // $event = [ - // 'start_date' => Carbon::now()->toDateString(), - // 'start_time' => '11:00', - // 'recurrence' => 'daily', - // 'all_day' => true, - // ]; + /** @test */ + public function wontCreateRecurringEventWhenMultiDay() + { + $recurringEntry = Entry::make() + ->collection('events') + ->data([ + 'start_date' => Carbon::now()->toDateString(), + 'start_time' => '11:00', + 'recurrence' => 'multi_day', + ]); - // $event = EventFactory::createFromArray($event); + $event = EventFactory::createFromEntry($recurringEntry); - // $this->assertNull($event->endDate()); - // $this->assertNull($event->end()); - // } + $this->assertTrue($event instanceof MultiDayEvent); + $this->assertFalse($event->isRecurring()); + $this->assertTrue($event->isMultiDay()); + } /** @test */ public function canShowLastOccurrenceWhenNoEndTime() diff --git a/tests/Unit/SingleDayEventsTest.php b/tests/Unit/SingleDayEventsTest.php index 62086c2..ebe2242 100755 --- a/tests/Unit/SingleDayEventsTest.php +++ b/tests/Unit/SingleDayEventsTest.php @@ -127,7 +127,6 @@ public function canGenerateNextOccurrenceIfNowIsDuring() ]); $singleNoEndTime = Entry::make() - ->blueprint($this->blueprint->handle()) ->collection('events') ->data([ 'start_date' => $startDate->toDateString(), diff --git a/tests/__fixtures__/blueprints/collections/events/event.yaml b/tests/__fixtures__/blueprints/collections/events/event.yaml new file mode 100644 index 0000000..edac8dc --- /dev/null +++ b/tests/__fixtures__/blueprints/collections/events/event.yaml @@ -0,0 +1,16 @@ +title: Event +sections: + main: + display: Main + fields: + - + import: events::event + - + handle: categories + field: + type: terms + taxonomies: + - categories + display: Categories + mode: tags + width: 50 diff --git a/tests/__fixtures__/blueprints/event.yaml b/tests/__fixtures__/blueprints/event.yaml deleted file mode 100644 index 325c85a..0000000 --- a/tests/__fixtures__/blueprints/event.yaml +++ /dev/null @@ -1,211 +0,0 @@ -title: Event -sections: - main: - display: Main - fields: - - - handle: multi_day - field: - type: toggle - width: 50 - display: 'Multi-Day?' - if: - all_day: 'equals false' - - - handle: all_day - field: - type: toggle - width: 50 - display: 'All Day?' - instructions_position: above - listable: hidden - default: false - if: - multi_day: 'equals false' - - - handle: start_date - field: - type: date - allow_blank: false - allow_time: false - require_time: false - input_format: M/D/YYYY - width: 25 - display: 'Start Date' - instructions_position: above - listable: hidden - mode: single - time_enabled: false - time_required: false - full_width: false - inline: false - columns: 1 - rows: 1 - if: - multi_day: 'equals false' - - - handle: start_time - field: - type: time - width: 25 - display: 'Start Time' - if: - multi_day: 'equals false' - all_day: 'equals false' - - - handle: end_time - field: - type: time - width: 25 - display: 'End Time' - if: - multi_day: 'equals false' - all_day: 'equals false' - - - handle: timezone - field: - multiple: false - max_items: 1 - clearable: false - searchable: true - taggable: false - push_tags: false - cast_booleans: false - display: Timezone - type: timezones - icon: select - listable: hidden - instructions_position: above - width: 25 - - - handle: days - field: - type: grid - mode: table - fields: - - - handle: date - field: - type: date - allow_blank: false - allow_time: false - require_time: false - input_format: M/D/YYYY - display: Date - - - handle: start_time - field: - type: time - display: 'Start Time' - - - handle: end_time - field: - type: time - display: 'End Time' - display: Days - min_rows: 2 - add_row: 'Add Day' - instructions_position: above - listable: hidden - reorderable: true - if: - multi_day: 'equals true' - - - handle: recurrence_section - field: - type: section - display: Recurrence - instructions_position: above - listable: hidden - if: - multi_day: 'equals false' - - - handle: recurrence - field: - type: select - options: - 0: None - daily: Daily - weekly: Weekly - monthly: Monthly - every: Every - width: 25 - display: 'Recurrence Type' - default: false - if: - multi_day: 'equals false' - - - handle: interval - field: - type: integer - width: 25 - display: Interval - show_when: - recurrence: every - - - handle: period - field: - type: select - options: - days: Days - weeks: Weeks - years: Years - display: Period - width: 25 - show_when: - recurrence: every - - - handle: end_date - field: - type: date - allow_blank: true - allow_time: false - require_time: false - input_format: M/D/YYYY - display: 'End Date' - width: 25 - show_when: - recurrence: 'contains_any daily, weekly, monthly, every' - - - handle: exclude_dates - field: - fields: - - - handle: date - field: - mode: single - inline: false - full_width: false - columns: 1 - rows: 1 - time_enabled: false - time_seconds_enabled: false - type: date - display: Date - listable: hidden - instructions_position: above - visibility: visible - replicator_preview: true - hide_display: false - mode: table - reorderable: false - fullscreen: false - type: grid - display: Exclusions - listable: hidden - instructions_position: above - visibility: visible - replicator_preview: true - hide_display: false - if: - multi_day: 'equals false' - add_row: 'Add Excluded Date' - - - handle: categories - field: - type: terms - taxonomies: - - categories - display: Categories - mode: tags - width: 50