Skip to content

Commit 90b5670

Browse files
committed
Add support for required fields on actions
1 parent a176e5a commit 90b5670

File tree

3 files changed

+190
-1
lines changed

3 files changed

+190
-1
lines changed

src/DataView/Action.php

+49
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ final class Action {
9797
*/
9898
private array $context = [];
9999

100+
/**
101+
* Field IDs that are required to be present for the action to be eligible.
102+
*
103+
* @since $ver$
104+
*
105+
* @var string[]
106+
*/
107+
private array $required = [];
108+
100109
/**
101110
* Creates an action.
102111
*
@@ -326,6 +335,21 @@ public function single(): self {
326335
return $action;
327336
}
328337

338+
/**
339+
* Returns an action that can requires certain values to be present.
340+
*
341+
* @since $ver$
342+
*
343+
* @return self The action instance.
344+
*/
345+
public function requires( array $required_ids ): self {
346+
$action = clone $this;
347+
348+
$action->required = array_filter( $required_ids, 'is_string' );
349+
350+
return $action;
351+
}
352+
329353
/**
330354
* Returns a serialized state of the action.
331355
*
@@ -339,6 +363,7 @@ public function to_array(): array {
339363
'label' => $this->label,
340364
'isPrimary' => '' !== $this->icon,
341365
'isDestructive' => $this->is_destructive,
366+
'isEligible' => $this->js_eligible(),
342367
'icon' => $this->icon,
343368
'callback' => $this->js_callback(),
344369
'supportsBulk' => $this->is_bulk,
@@ -381,6 +406,30 @@ private function js_callback(): ?string {
381406
return '__RAW__' . $callback . '__ENDRAW__';
382407
}
383408

409+
/**
410+
* Returns the JavaScript `isEligible` callback for this action.
411+
*
412+
* @since $ver$
413+
*
414+
* @return string|null The JavaScript callback.
415+
*/
416+
private function js_eligible(): ?string {
417+
if ( [] === $this->required ) {
418+
return null;
419+
}
420+
421+
try {
422+
$callback = sprintf(
423+
'item => %s.every( (key) => null !== (item[key] || null) )',
424+
json_encode( $this->required, JSON_THROW_ON_ERROR ),
425+
);
426+
} catch ( JsonException $e ) {
427+
return '';
428+
}
429+
430+
return '__RAW__' . $callback . '__ENDRAW__';
431+
}
432+
384433
/**
385434
* Returns the actions JavaScript modal properties.
386435
*

tests/DataView/ActionTest.php

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
3+
namespace DataKit\DataViews\Tests\DataView;
4+
5+
use DataKit\DataViews\DataView\Action;
6+
use PHPUnit\Framework\TestCase;
7+
8+
/**
9+
* Unit tests for {@see Action}
10+
*
11+
* @since $ver$
12+
*/
13+
final class ActionTest extends TestCase {
14+
/**
15+
* Test case for {@see Action::url()}.
16+
*
17+
* @since $ver$
18+
*/
19+
public function test_url(): void {
20+
$action = Action::url( 'some-action', 'Action', 'url' );
21+
$array = $action->to_array();
22+
23+
self::assertStringContainsString( 'datakit_dataviews_actions.url', $array['callback'] ?? '' );
24+
self::assertStringContainsString( '"type":"url"', $array['callback'] ?? '' );
25+
self::assertSame( 'some-action', $array['id'] );
26+
self::assertSame( 'Action', $array['label'] );
27+
}
28+
29+
/**
30+
* Test case for {@see Action::modal()}.
31+
*
32+
* @since $ver$
33+
*/
34+
public function test_modal(): void {
35+
$modal = Action::modal( 'modal-action', 'Modal Action', 'some-url', true );
36+
$array = $modal->to_array();
37+
self::assertNull( $array['callback'] ?? null );
38+
self::assertSame( 'modal-action', $array['id'] );
39+
self::assertSame( 'Modal Action', $array['label'] );
40+
41+
$modal_callback = $array['RenderModal'] ?? '';
42+
self::assertStringContainsString( 'datakit_modal(', $modal_callback );
43+
self::assertStringContainsString( '{"url":"some-url","id":"modal-action","type":"modal"}', $modal_callback );
44+
}
45+
46+
/**
47+
* Test case for {@see Action::ajax()}.
48+
*
49+
* @since $ver$
50+
*/
51+
public function test_ajax(): void {
52+
$ajax = Action::ajax( 'ajax-action',
53+
'Ajax Action',
54+
'some-url',
55+
'PUT',
56+
[ 'extra' => 'param' ],
57+
true );
58+
$put = $ajax->to_array();
59+
$ajax = Action::ajax( 'ajax-action', 'Ajax Action', 'some-url', 'POST', [] );
60+
$post = $ajax->to_array();
61+
62+
self::assertStringContainsString( 'datakit_dataviews_actions.url', $put['callback'] ?? '' );
63+
self::assertStringContainsString( '"type":"ajax"', $put['callback'] ?? '' );
64+
self::assertStringContainsString( '"method":"PUT"', $put['callback'] ?? '' );
65+
self::assertStringContainsString( '"params":{"extra":"param"}', $put['callback'] ?? '' );
66+
self::assertStringContainsString( '"use_single_request":true', $put['callback'] ?? '' );
67+
self::assertSame( 'ajax-action', $put['id'] );
68+
self::assertSame( 'Ajax Action', $put['label'] );
69+
70+
self::assertStringContainsString( '"method":"POST"', $post['callback'] ?? '' );
71+
self::assertStringContainsString( '"params":[]', $post['callback'] ?? '' );
72+
self::assertStringContainsString( '"use_single_request":false', $post['callback'] ?? '' );
73+
self::assertSame( 'ajax-action', $post['id'] );
74+
self::assertSame( 'Ajax Action', $post['label'] );
75+
}
76+
77+
/**
78+
* Test case for the basic action modifiers.
79+
*
80+
* @since $ver$
81+
*/
82+
public function test_modifiers(): void {
83+
$action = Action::url( 'some-action', 'Action', 'url' );
84+
$destructive_primary_bulk = $action->destructive()->primary( 'action-icon' )->bulk();
85+
86+
self::assertFalse( $action->to_array()['isDestructive'] );
87+
self::assertFalse( $action->to_array()['isPrimary'] );
88+
self::assertFalse( $action->to_array()['supportsBulk'] );
89+
self::assertEmpty( $action->to_array()['icon'] );
90+
91+
self::assertTrue( $destructive_primary_bulk->to_array()['isDestructive'] );
92+
self::assertTrue( $destructive_primary_bulk->to_array()['isPrimary'] );
93+
self::assertTrue( $destructive_primary_bulk->to_array()['supportsBulk'] );
94+
self::assertSame( 'action-icon', $destructive_primary_bulk->to_array()['icon'] );
95+
96+
$normal_secondary_single = $destructive_primary_bulk->not_destructive()->single()->secondary();
97+
98+
self::assertFalse( $normal_secondary_single->to_array()['isDestructive'] );
99+
self::assertFalse( $normal_secondary_single->to_array()['isPrimary'] );
100+
self::assertFalse( $normal_secondary_single->to_array()['supportsBulk'] );
101+
self::assertEmpty( $normal_secondary_single->to_array()['icon'] );
102+
}
103+
104+
/**
105+
* Test case for {@see Action::requires()}.
106+
*
107+
* @since $ver$
108+
*/
109+
public function test_requires(): void {
110+
$action = Action::url( 'some-action', 'Action', 'url' )->requires( [ 'url', 'other' ] );
111+
$empty = $action->requires( [] );
112+
self::assertStringContainsString( '["url","other"].every(', $action->to_array()['isEligible'] );
113+
self::assertNull( $empty->to_array()['isEligible'] );
114+
}
115+
116+
/**
117+
* Test case for {@see Action::confirm()}.
118+
*
119+
* @since $ver$
120+
*/
121+
public function test_confirm(): void {
122+
$action = Action::url( 'some-action', 'Action', 'url' );
123+
$confirm = $action->confirm( 'sure?' );
124+
self::assertStringNotContainsString( 'confirm', $action->to_array()['callback'] );
125+
self::assertStringContainsString( '"confirm":"sure?"', $confirm->to_array()['callback'] );
126+
}
127+
128+
/**
129+
* Test case for {@see Action::allow_scripts()} and {@see Action::deny_scripts()}.
130+
*
131+
* @since $ver$
132+
*/
133+
public function test_scripts(): void {
134+
$allowed = Action::url( 'some-action', 'Action', 'url' )->allow_scripts();
135+
$denied = Action::url( 'some-action', 'Action', 'url' )->deny_scripts();
136+
self::assertStringContainsString( '"is_scripts_allowed":true', $allowed->to_array()['callback'] );
137+
self::assertStringContainsString( '"is_scripts_allowed":false', $denied->to_array()['callback'] );
138+
}
139+
}

tests/DataView/ActionsTest.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ public function testAppendPrepend(): void {
8989
*
9090
* @param bool $is_prepend Whether the method to be called is `prepend()`.
9191
*
92-
* @testWith [false, true]
92+
* @testWith [false]
93+
* [true]
9394
*/
9495
public function testAppendPrependException( bool $is_prepend ): void {
9596
$actions = Actions::of(

0 commit comments

Comments
 (0)