From 6828ae739c548b7bb3f347143c10b0594bb5326f Mon Sep 17 00:00:00 2001 From: Andi1986 Date: Tue, 29 Sep 2020 18:45:35 +0200 Subject: [PATCH] implement overflow menu (#11) By: Andreas Hofmann --- README.md | 6 +- src/Blocks/Actions.php | 8 +++ src/Blocks/Section.php | 8 +++ src/Inputs/OverflowMenu.php | 51 +++++++++++++++++ src/Type.php | 10 ++-- tests/Inputs/OverflowMenuTest.php | 93 +++++++++++++++++++++++++++++++ tests/Inputs/RadioButtonsTest.php | 9 +++ tests/manual/menus.php | 9 ++- 8 files changed, 185 insertions(+), 9 deletions(-) create mode 100644 src/Inputs/OverflowMenu.php create mode 100644 tests/Inputs/OverflowMenuTest.php diff --git a/README.md b/README.md index e2b03fe..34177cb 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ The following are supported elements from the Block Kit documentation: | Surface | Message | ✅ | | Surface | Model | ✅ | | Block | Actions | ✅ | -| Block | Checkboxes | ❌ | +| Block | Checkboxes | ✅ | | Block | Context | ✅ | | Block | Divider | ✅ | | Block | File | ❌ | @@ -201,9 +201,9 @@ The following are supported elements from the Block Kit documentation: | Input | Button | ✅️ | | Input | Date Picker | ✅ | | Input | Multi-select Menus | ✅✅✅✅✅ | -| Input | Overflow Menu | ❌ | +| Input | Overflow Menu | ✅ | | Input | Plain Text Input | ✅ | -| Input | Radio Buttons | ❌ | +| Input | Radio Buttons | ✅ | | Input | Select Menus | ✅✅✅✅✅ | | Partial | Confirm Dialog | ✅ | | Partial | Mrkdwn Text | ✅ | diff --git a/src/Blocks/Actions.php b/src/Blocks/Actions.php index 218c448..1d2ade9 100644 --- a/src/Blocks/Actions.php +++ b/src/Blocks/Actions.php @@ -94,6 +94,14 @@ public function newCheckboxes(?string $actionId = null): Inputs\Checkboxes return $action; } + public function newOverflowMenu(?string $actionId = null): Inputs\OverflowMenu + { + $action = new Inputs\OverflowMenu($actionId); + $this->add($action); + + return $action; + } + public function validate(): void { if (empty($this->elements)) { diff --git a/src/Blocks/Section.php b/src/Blocks/Section.php index 3f88470..901da7f 100644 --- a/src/Blocks/Section.php +++ b/src/Blocks/Section.php @@ -186,6 +186,14 @@ public function newCheckboxesAccessory(?string $actionId = null): Inputs\Checkbo return $action; } + public function newOverflowMenuAccessory(?string $actionId = null): Inputs\OverflowMenu + { + $action = new Inputs\OverflowMenu($actionId); + $this->setAccessory($action); + + return $action; + } + public function validate(): void { if (empty($this->text) && empty($this->fields)) { diff --git a/src/Inputs/OverflowMenu.php b/src/Inputs/OverflowMenu.php new file mode 100644 index 0000000..6d42512 --- /dev/null +++ b/src/Inputs/OverflowMenu.php @@ -0,0 +1,51 @@ +validateOptions(); + + if (!empty($this->confirm)) { + $this->confirm->validate(); + } + + if (count($this->options) > self::MAX_OPTIONS) { + throw new Exception('Option Size cannot exceed %d', [self::MAX_OPTIONS]); + } + + if (count($this->options) < self::MIN_OPTIONS) { + throw new Exception('Option Size must be at least %d', [self::MIN_OPTIONS]); + } + } + + /** + * @return array + */ + public function toArray(): array + { + + $data = parent::toArray(); + $data += $this->getOptionsAsArray(); + + if (!empty($this->confirm)) { + $data['confirm'] = $this->confirm->toArray(); + } + + return $data; + } +} diff --git a/src/Type.php b/src/Type.php index c218712..788b785 100644 --- a/src/Type.php +++ b/src/Type.php @@ -27,7 +27,7 @@ abstract class Type public const CHECKBOXES = 'checkboxes'; public const DATEPICKER = 'datepicker'; public const TEXT_INPUT = 'plain_text_input'; - // public const OVERFLOW_MENU = 'overflow'; // Not yet supported. + public const OVERFLOW_MENU = 'overflow'; public const RADIO_BUTTONS = 'radio_buttons'; // Select Menus @@ -86,7 +86,7 @@ abstract class Type self::MULTI_SELECT_MENU_EXTERNAL, self::MULTI_SELECT_MENU_STATIC, self::MULTI_SELECT_MENU_USERS, - // self::OVERFLOW_MENU, // Not yet supported. + self::OVERFLOW_MENU, self::RADIO_BUTTONS, self::SELECT_MENU_CHANNELS, self::SELECT_MENU_CONVERSATIONS, @@ -100,7 +100,7 @@ abstract class Type self::BUTTON, self::CHECKBOXES, self::DATEPICKER, - // self::OVERFLOW_MENU, // Not yet supported. + self::OVERFLOW_MENU, self::RADIO_BUTTONS, self::SELECT_MENU_CHANNELS, self::SELECT_MENU_CONVERSATIONS, @@ -151,9 +151,9 @@ abstract class Type // Inputs Inputs\Button::class => self::BUTTON, - Inputs\Checkboxes::class => self::CHECKBOXES, // Not yet supported. + Inputs\Checkboxes::class => self::CHECKBOXES, Inputs\DatePicker::class => self::DATEPICKER, - // Inputs\OverflowMenu::class => self::OVERFLOW_MENU, // Not yet supported. + Inputs\OverflowMenu::class => self::OVERFLOW_MENU, Inputs\RadioButtons::class => self::RADIO_BUTTONS, Inputs\TextInput::class => self::TEXT_INPUT, diff --git a/tests/Inputs/OverflowMenuTest.php b/tests/Inputs/OverflowMenuTest.php new file mode 100644 index 0000000..f170a91 --- /dev/null +++ b/tests/Inputs/OverflowMenuTest.php @@ -0,0 +1,93 @@ +option('foo', 'foo') + ->option('bar', 'bar') + ->option('foobar', 'foobar') + ->setConfirm(new Confirm('Choose', 'Do you really want to choose this?', 'Yes choose')); + + $this->assertJsonData([ + 'type' => Type::OVERFLOW_MENU, + 'action_id' => 'overflow-identifier', + 'options' => [ + [ + 'text' => [ + 'type' => 'plain_text', + 'text' => 'foo', + ], + 'value' => 'foo', + ], + [ + 'text' => [ + 'type' => 'plain_text', + 'text' => 'bar', + ], + 'value' => 'bar', + ], + [ + 'text' => [ + 'type' => 'plain_text', + 'text' => 'foobar', + ], + 'value' => 'foobar', + ], + ], + 'confirm' => [ + 'title' => [ + 'type' => 'plain_text', + 'text' => 'Choose', + ], + 'text' => [ + 'type' => 'mrkdwn', + 'text' => 'Do you really want to choose this?', + ], + 'confirm' => [ + 'type' => 'plain_text', + 'text' => 'Yes choose', + ], + 'deny' => [ + 'type' => 'plain_text', + 'text' => 'Cancel', + ], + ] + ], $input); + } + + public function testTooManyOptions() + { + $this->expectException(Exception::class); + $input = (new OverflowMenu()) + ->option('foo', 'foo') + ->option('foo', 'foo') + ->option('foo', 'foo') + ->option('foo', 'foo') + ->option('foo', 'foo') + ->option('foo', 'foo'); + $input->validate(); + } + + public function testTooFewOptions() + { + $this->expectException(Exception::class); + $input = (new OverflowMenu()) + ->option('foo', 'foo'); + $input->validate(); + } +} diff --git a/tests/Inputs/RadioButtonsTest.php b/tests/Inputs/RadioButtonsTest.php index 3077534..4f80a15 100644 --- a/tests/Inputs/RadioButtonsTest.php +++ b/tests/Inputs/RadioButtonsTest.php @@ -103,4 +103,13 @@ public function testNoOptions() $input = new RadioButtons(); $input->validate(); } + + public function testTooManyInitialOptions() + { + $this->expectException(Exception::class); + $input = (new RadioButtons()) + ->option('foo', 'foo', true) + ->option('foo', 'foo', true); + $input->validate(); + } } diff --git a/tests/manual/menus.php b/tests/manual/menus.php index 5f0bcad..28630c6 100644 --- a/tests/manual/menus.php +++ b/tests/manual/menus.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use Jeremeamia\Slack\BlockKit\Partials\Confirm; use Jeremeamia\Slack\BlockKit\Slack; require __DIR__ . '/../../vendor/autoload.php'; @@ -63,7 +64,13 @@ ] ]) ->initialOptions(['b' => 'l2', 'c' => 'l3']); - +$msg->newSection('b5') + ->mrkdwnText('Select from Overflow Menu') + ->newOverflowMenuAccessory('m6') + ->option('foo', 'foo') + ->option('bar', 'bar') + ->option('foobar', 'foobar') + ->setConfirm(new Confirm('Choose', 'Do you really want to choose this?', 'Yes choose')); //echo Slack::newRenderer()->forJson()->render($msg) . "\n"; echo Slack::newRenderer()->forKitBuilder()->render($msg) . "\n"; // echo Slack::newRenderer()->forCli()->render($msg) . "\n";