Skip to content

Commit cd491ea

Browse files
authored
Merge pull request #656 from code16/handle-targetBlank-on-command-link-return
Handle target=blank in link command return
2 parents 99f71ef + f725a9e commit cd491ea

File tree

8 files changed

+92
-27
lines changed

8 files changed

+92
-27
lines changed

demo/app/Sharp/Authors/Commands/VisitFacebookProfileCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public function buildCommandConfig(): void
2020

2121
public function execute(mixed $instanceId, array $data = []): array
2222
{
23-
return $this->link('https://facebook.com');
23+
return $this->link('https://facebook.com', openInNewTab: true);
2424
}
2525

2626
public function authorizeFor(mixed $instanceId): bool

docs/guide/commands.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -169,18 +169,18 @@ Here is the full list of available methods:
169169

170170
### Command return types
171171

172-
Finally, let's review the return possibilities: after a Command has been executed, the code must return something to tell to the front what to do next. There are height of them:
172+
Finally, let's review the return possibilities: after a Command has been executed, the code must return something to tell to the front what to do next. There are eight of them:
173173

174-
- `return $this->info('some text', reload: true)`: displays the entered text in a modal. The second argument, optional (default is `false`), is a boolean to also mark Sharp to reload the page.
174+
- `return $this->info(string $message, bool $reload = false)`: displays the entered text in a modal. The second argument allows reloading the page first.
175175
- `return $this->reload()`: reload the current page (with context).
176-
- `return $this->refresh(1)`*: refresh only the instance with an id on `1`. We can pass an id array also to refresh more than one instance.
177-
- `return $this->view('view.name', ['some'=>'params'])`: display a view right in Sharp; useful for page previews.
178-
- `return $this->html('...')`: display an HTML content.
179-
- `return $this->link('/path/to/redirect')`: redirect to the given path.
180-
- `return $this->download('path', 'diskName')`: the browser will download the specified file.
181-
- `return $this->streamDownload('path', 'name')`: the browser will stream the specified file.
182-
183-
\* `refresh()` is only useful in an Entity List case (in a Dashboard or a Show Page, it will be treated as a `reload()`). In order to make it work properly, you have to slightly adapt the `getListData()` of your Entity List implementation, making use of `$this->queryParams->specificIds()`:
176+
- `return $this->refresh(mixed $ids)`*: refresh only instance(s) with an id in `$ids`, which can be either a single id or an array.
177+
- `return $this->view(string $bladeView, array $params = [])`: display a view right in Sharp; useful for page previews.
178+
- `return $this->html(string $htmlContent)`: display an HTML content.
179+
- `return $this->link(string $link, bool $openInNewTab = false)`: redirect to the given path. The second argument, optional (default is `false`), is a boolean to open the link in a new tab.
180+
- `return $this->download(string $filePath, ?string $fileName = null, ?string $diskName = null)`: the browser will download the specified file.
181+
- `return $this->streamDownload(string $fileContent, string $fileName)`: the browser will stream the specified file.
182+
183+
\* `refresh()` is only useful in an Entity List case (in a Dashboard or a Show Page, it will be treated as a `reload()`). To make it work properly, you have to slightly adapt the `getListData()` of your Entity List implementation, making use of `$this->queryParams->specificIds()`:
184184

185185
```php
186186
class OrderList extends SharpEntityList

resources/js/commands/CommandManager.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,27 @@ export class CommandManager {
4141

4242
get defaultCommandResponseHandlers(): CommandResponseHandlers {
4343
return {
44-
info: async ({ message, reload }, { formModal }) => {
45-
await showAlert(message, {
44+
info: async (data, { formModal }) => {
45+
await showAlert(data.message, {
4646
title: __('sharp::modals.command.info.title'),
4747
});
4848
if(formModal.shouldReopen) {
4949
formModal.reloadAndReopen();
50-
} else if(reload) {
50+
} else if(data.reload) {
5151
await this.handleCommandResponse({ action: 'reload' });
5252
}
5353
},
54-
link: ({ link }, { formModal }) => {
54+
link: (data, { formModal }) => {
5555
if(formModal.shouldReopen) {
5656
formModal.reloadAndReopen();
5757
return;
5858
}
59-
if(isSharpLink(link)) {
60-
router.visit(link);
59+
if(data.openInNewTab) {
60+
window.open(data.link, '_blank');
61+
} else if(isSharpLink(data.link)) {
62+
router.visit(data.link);
6163
} else {
62-
location.href = link;
64+
location.href = data.link;
6365
}
6466
},
6567
reload: (data, { formModal }) => {

resources/js/types/generated.d.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export type CommandFormData = {
6565
pageAlert: PageAlertData | null;
6666
};
6767
export type CommandResponseData =
68-
| { action: "link"; link: string }
68+
| { action: "link"; link: string; openInNewTab: boolean }
6969
| { action: "info"; message: string; reload: boolean }
7070
| { action: "refresh"; items?: Array<{ [key: string]: any }> }
7171
| { action: "reload" }
@@ -140,9 +140,6 @@ export type EmbedFormData = {
140140
fields: { [key: string]: FormFieldData };
141141
layout: FormLayoutData | null;
142142
};
143-
export type EmbeddedFieldAuthorizationsData = {
144-
view: boolean;
145-
};
146143
export type EntityListAuthorizationsData = {
147144
create: boolean;
148145
reorder: boolean;
@@ -811,7 +808,7 @@ export type ShowDashboardFieldData = {
811808
dashboardKey: string;
812809
hiddenCommands: Array<string>;
813810
endpointUrl: string;
814-
authorizations: EmbeddedFieldAuthorizationsData;
811+
authorizations: ShowFieldAuthorizationsData;
815812
label: string | null;
816813
hiddenFilters: { [key: string]: any } | null;
817814
};
@@ -838,10 +835,13 @@ export type ShowEntityListFieldData = {
838835
showSearchField: boolean;
839836
showCount: boolean;
840837
endpointUrl: string;
841-
authorizations: EmbeddedFieldAuthorizationsData;
838+
authorizations: ShowFieldAuthorizationsData;
842839
label: string | null;
843840
hiddenFilters: { [key: string]: any } | null;
844841
};
842+
export type ShowFieldAuthorizationsData = {
843+
view: boolean;
844+
};
845845
export type ShowFieldData =
846846
| ShowDashboardFieldData
847847
| ShowEntityListFieldData

src/Data/Commands/CommandResponseData.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
// download & streamDownload actions returns the file directly in the response
1010
#[LiteralTypeScriptType(
11-
'{ action: "'.CommandAction::Link->value.'", link: string } | '.
11+
'{ action: "'.CommandAction::Link->value.'", link: string, openInNewTab: boolean } | '.
1212
'{ action: "'.CommandAction::Info->value.'", message: string, reload: boolean } | '.
1313
'{ action: "'.CommandAction::Refresh->value.'", items?: Array<{ [key: string]: any }> } | '.
1414
'{ action: "'.CommandAction::Reload->value.'" } | '.

src/EntityList/Commands/Command.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,12 @@ protected function info(string $message, bool $reload = false): array
4444
];
4545
}
4646

47-
protected function link(string $link): array
47+
protected function link(string $link, bool $openInNewTab = false): array
4848
{
4949
return [
5050
'action' => CommandAction::Link->value,
5151
'link' => $link,
52+
'openInNewTab' => $openInNewTab,
5253
];
5354
}
5455

src/EntityList/Commands/EntityState.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ protected function streamDownload(string $fileContent, string $fileName): array
4646
throw new SharpInvalidConfigException('StreamDownload return type is not supported for a state.');
4747
}
4848

49-
protected function link(string $link): array
49+
protected function link(string $link, bool $openInNewTab = false): array
5050
{
5151
throw new SharpInvalidConfigException('Link return type is not supported for a state.');
5252
}

tests/Http/Api/Commands/ApiEntityListEntityCommandControllerTest.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,68 @@ public function getListData(): array|\Illuminate\Contracts\Support\Arrayable
211211
]);
212212
});
213213

214+
it('allows to call an link entity command', function () {
215+
fakeListFor('person', new class() extends PersonList
216+
{
217+
protected function getEntityCommands(): ?array
218+
{
219+
return [
220+
'cmd' => new class() extends EntityCommand
221+
{
222+
public function label(): ?string
223+
{
224+
return 'entity';
225+
}
226+
227+
public function execute(array $data = []): array
228+
{
229+
return $this->link('https://sharp.code16.fr');
230+
}
231+
},
232+
];
233+
}
234+
});
235+
236+
$this->postJson(route('code16.sharp.api.list.command.entity', ['person', 'cmd']))
237+
->assertOk()
238+
->assertJson([
239+
'action' => 'link',
240+
'link' => 'https://sharp.code16.fr',
241+
'openInNewTab' => false,
242+
]);
243+
});
244+
245+
it('allows to call an link + openInNewTab entity command', function () {
246+
fakeListFor('person', new class() extends PersonList
247+
{
248+
protected function getEntityCommands(): ?array
249+
{
250+
return [
251+
'cmd' => new class() extends EntityCommand
252+
{
253+
public function label(): ?string
254+
{
255+
return 'entity';
256+
}
257+
258+
public function execute(array $data = []): array
259+
{
260+
return $this->link('https://sharp.code16.fr', openInNewTab: true);
261+
}
262+
},
263+
];
264+
}
265+
});
266+
267+
$this->postJson(route('code16.sharp.api.list.command.entity', ['person', 'cmd']))
268+
->assertOk()
269+
->assertJson([
270+
'action' => 'link',
271+
'link' => 'https://sharp.code16.fr',
272+
'openInNewTab' => true,
273+
]);
274+
});
275+
214276
it('allows to call a form entity command and it handles 422', function () {
215277
fakeListFor('person', new class() extends PersonList
216278
{

0 commit comments

Comments
 (0)