Skip to content

Commit c91c70d

Browse files
authored
Merge pull request #691 from code16/allow-show-primary-commands
Allow show primary commands
2 parents a555e59 + 0875d9c commit c91c70d

12 files changed

Lines changed: 164 additions & 58 deletions

File tree

demo/app/Sharp/Posts/PostShow.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,10 @@ public function buildShowConfig(): void
109109
->configureEntityState('state', PostStateHandler::class)
110110
->configureBreadcrumbCustomLabelAttribute('breadcrumb')
111111
->configurePageTitleAttribute('title', localized: true)
112-
->configureDeleteConfirmationText('Are you sure you want to delete this post (this will permanently delete its data)?');
112+
->configureDeleteConfirmationText('Are you sure you want to delete this post (this will permanently delete its data)?')
113+
->configurePrimaryInstanceCommands([
114+
PreviewPostCommand::class,
115+
]);
113116
}
114117

115118
protected function buildPageAlert(PageAlert $pageAlert): void
@@ -132,7 +135,6 @@ public function getInstanceCommands(): ?array
132135
PreviewPostCommand::class,
133136
],
134137
EvaluateDraftPostWizardCommand::class,
135-
PreviewPostCommand::class,
136138
];
137139
}
138140

resources/js/Pages/Show/Show.vue

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
show.sectionHasField(show.layout.sections[0], 'entityList')
6767
|| show.sectionHasField(show.layout.sections[0], 'dashboard')
6868
|| show.layout.sections[0].title
69-
|| show.sectionCommands(show.layout.sections[0])?.flat().length
69+
|| show.sectionAllowedCommands(show.layout.sections[0])?.flat().length
7070
)
7171
|| !show.layout.sections.length) {
7272
return [
@@ -208,7 +208,7 @@
208208
</template>
209209
<template v-else>
210210
<RootCard>
211-
<template v-if="section.title || i == 0 || section.collapsable || show.sectionCommands(section)?.flat().length">
211+
<template v-if="section.title || i == 0 || section.collapsable || show.sectionAllowedCommands(section)?.flat().length">
212212
<RootCardHeader class="data-overflowing-viewport:sticky" :collapsed="collapsed">
213213
<div class="flex flex-wrap gap-4">
214214
<div class="flex gap-4">
@@ -226,27 +226,6 @@
226226
</Button>
227227
</template>
228228
</div>
229-
<template v-if="show.sectionCommands(section)?.flat().length">
230-
<div class="ml-auto flex -my-1 justify-end" :class="{ 'invisible': collapsed }"
231-
role="group"
232-
:aria-label="__('sharp::show.section_menu.aria_label', { title: section.title })"
233-
>
234-
<DropdownMenu>
235-
<DropdownMenuTrigger as-child>
236-
<Button class="h-8" size="sm" variant="outline">
237-
{{ __('sharp::entity_list.commands.instance.label') }}
238-
<DropdownChevronDown />
239-
</Button>
240-
</DropdownMenuTrigger>
241-
<DropdownMenuContent>
242-
<CommandDropdownItems
243-
:commands="show.sectionCommands(section)"
244-
@select="onCommand"
245-
/>
246-
</DropdownMenuContent>
247-
</DropdownMenu>
248-
</div>
249-
</template>
250229
<template v-if="i == 0">
251230
<div class="ml-auto flex flex-wrap -my-1 justify-end gap-2"
252231
:class="{ 'invisible': collapsed }"
@@ -325,11 +304,12 @@
325304
</template>
326305

327306
<CommandDropdownItems
328-
:commands="show.allowedInstanceCommands"
307+
:commands="show.dropdownInstanceCommands"
329308
@select="onCommand"
330309
/>
310+
331311
<template v-if="show.authorizations.delete">
332-
<template v-if="show.allowedInstanceCommands?.flat().length">
312+
<template v-if="show.dropdownInstanceCommands?.flat().length">
333313
<DropdownMenuSeparator />
334314
</template>
335315
<DropdownMenuItem class="text-destructive" @click="onDelete">
@@ -339,6 +319,11 @@
339319
</DropdownMenuContent>
340320
</DropdownMenu>
341321
</template>
322+
<template v-for="command in show.primaryInstanceCommands">
323+
<Button class="h-8" size="sm" @click="onCommand(command)">
324+
{{ command.label }}
325+
</Button>
326+
</template>
342327
<template v-if="show.authorizations.update">
343328
<Button class="h-8 pointer-events-auto" size="sm" :disabled="isReordering" as-child>
344329
<Link :as="isReordering ? 'button' : 'a'" :href="show.config.formEditUrl">
@@ -350,6 +335,36 @@
350335
</template>
351336
</div>
352337
</template>
338+
<template v-else>
339+
<template v-if="show.sectionAllowedCommands(section)?.flat().length">
340+
<div class="ml-auto flex -my-1 justify-end gap-2" :class="{ 'invisible': collapsed }"
341+
role="group"
342+
:aria-label="__('sharp::show.section_menu.aria_label', { title: section.title })"
343+
>
344+
<template v-if="show.sectionDropdownCommands(section)?.flat().length">
345+
<DropdownMenu>
346+
<DropdownMenuTrigger as-child>
347+
<Button class="h-8" size="sm" variant="outline">
348+
{{ __('sharp::entity_list.commands.instance.label') }}
349+
<DropdownChevronDown />
350+
</Button>
351+
</DropdownMenuTrigger>
352+
<DropdownMenuContent>
353+
<CommandDropdownItems
354+
:commands="show.sectionDropdownCommands(section)"
355+
@select="onCommand"
356+
/>
357+
</DropdownMenuContent>
358+
</DropdownMenu>
359+
</template>
360+
<template v-for="command in show.sectionPrimaryCommands(section)">
361+
<Button class="h-8" size="sm" @click="onCommand(command)">
362+
{{ command.label }}
363+
</Button>
364+
</template>
365+
</div>
366+
</template>
367+
</template>
353368
</div>
354369
</RootCardHeader>
355370
</template>

resources/js/show/Show.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,44 @@ export class Show implements ShowData {
4040
return this.config.state?.values.find(item => item.value === this.instanceState);
4141
}
4242

43-
get allowedInstanceCommands(): Array<Array<CommandData>> | undefined {
43+
get allowedInstanceCommands(): CommandData[][] {
4444
return this.config.commands?.instance
4545
?.map(group => group.filter(command => command.authorization));
4646
}
4747

48+
get dropdownInstanceCommands(): CommandData[][] {
49+
return this.allowedInstanceCommands
50+
?.map(group => group.filter(command => !command.primary));
51+
}
52+
53+
get primaryInstanceCommands(): CommandData[] | undefined {
54+
return this.allowedInstanceCommands
55+
?.flat()
56+
.filter(command => command.primary);
57+
}
58+
59+
sectionAllowedCommands(section: ShowLayoutSectionData): CommandData[][] | null {
60+
if(!section.key) {
61+
return null;
62+
}
63+
return (this.config.commands?.[section.key] ?? [])
64+
.map(group => group.filter(command => command.authorization));
65+
}
66+
67+
sectionDropdownCommands(section: ShowLayoutSectionData): CommandData[][] | null {
68+
if(!section.key) {
69+
return null;
70+
}
71+
return this.sectionAllowedCommands(section).map(group => group.filter(command => !command.primary));
72+
}
73+
74+
sectionPrimaryCommands(section: ShowLayoutSectionData): CommandData[] | null {
75+
if(!section.key) {
76+
return null;
77+
}
78+
return this.sectionAllowedCommands(section).flat().filter(command => command.primary);
79+
}
80+
4881
getTitle(locale: string): string | null {
4982
if(this.title) {
5083
return typeof this.title === 'object'
@@ -65,14 +98,6 @@ export class Show implements ShowData {
6598
return this.sectionFields(section).some(field => field.type === type);
6699
}
67100

68-
sectionCommands(section: ShowLayoutSectionData): Array<Array<CommandData>> | null {
69-
if(!section.key) {
70-
return null;
71-
}
72-
return (this.config.commands[section.key] ?? [])
73-
.map(group => group.filter(command => command.authorization));
74-
}
75-
76101
sectionShouldBeVisible(section: ShowLayoutSectionData, locale: string): boolean {
77102
return section.columns
78103
.map((column) => column.fields)

src/EntityList/Traits/HandleDashboardCommands.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ protected function appendDashboardCommandsToConfig(array &$config): void
2222
$this->getDashboardCommandHandlers()
2323
->each(function ($handlers, $positionKey) use (&$config) {
2424
$this->appendCommandsToConfig(
25-
$handlers,
26-
$config,
27-
$positionKey,
25+
commandHandlers: $handlers,
26+
config: $config,
27+
positionKey: $positionKey,
28+
primaryCommands: [],
2829
);
2930
});
3031
}

src/EntityList/Traits/HandleEntityCommands.php

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,11 @@ protected function configurePrimaryEntityCommand(string $commandKeyOrClassName):
2727
protected function appendEntityCommandsToConfig(array &$config): void
2828
{
2929
$this->appendCommandsToConfig(
30-
$this->getEntityCommandsHandlers(),
31-
$config,
32-
'entity'
30+
commandHandlers: $this->getEntityCommandsHandlers(),
31+
config: $config,
32+
positionKey: 'entity',
33+
primaryCommands: $this->primaryEntityCommandKey ? [$this->primaryEntityCommandKey] : [],
3334
);
34-
35-
// If a command is defined as [primary], we have to update its config for the front:
36-
if ($this->primaryEntityCommandKey && $handler = $this->findEntityCommandHandler($this->primaryEntityCommandKey)) {
37-
foreach ($config['commands']['entity'][$handler->groupIndex()] as $index => $commandConfig) {
38-
if ($commandConfig['key'] === $this->primaryEntityCommandKey) {
39-
$config['commands']['entity'][$handler->groupIndex()][$index]['primary'] = true;
40-
break;
41-
}
42-
}
43-
}
4435
}
4536

4637
final public function getEntityCommandsHandlers(): Collection

src/EntityList/Traits/HandleInstanceCommands.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ protected function appendInstanceCommandsToConfig(array &$config, $instanceId =
2323
$this->getInstanceCommandsHandlers()
2424
->each(function ($handlers, $positionKey) use (&$config, $instanceId) {
2525
$this->appendCommandsToConfig(
26-
$handlers,
27-
$config,
28-
$positionKey,
29-
$instanceId,
26+
commandHandlers: $handlers,
27+
config: $config,
28+
positionKey: $positionKey,
29+
primaryCommands: $this->primaryInstanceCommandKeys ?? [],
30+
instanceId: $instanceId,
3031
);
3132
});
3233
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Code16\Sharp\EntityList\Traits;
4+
5+
trait HandleInstancePrimaryCommands
6+
{
7+
protected array $primaryInstanceCommandKeys = [];
8+
9+
protected function configurePrimaryInstanceCommands(array $commandKeyOrClassNames): self
10+
{
11+
$this->primaryInstanceCommandKeys = collect($commandKeyOrClassNames)
12+
->map(fn ($key) => class_exists($key) ? class_basename($key) : $key)
13+
->all();
14+
15+
return $this;
16+
}
17+
}

src/EntityList/Traits/Utils/CommonCommandUtils.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99

1010
trait CommonCommandUtils
1111
{
12-
protected function appendCommandsToConfig(Collection $commandHandlers, array &$config, string $positionKey, $instanceId = null): void
12+
protected function appendCommandsToConfig(Collection $commandHandlers, array &$config, string $positionKey, array $primaryCommands, $instanceId = null): void
1313
{
1414
$commandHandlers
15-
->each(function (Command $handler) use (&$config, $instanceId, $positionKey) {
15+
->each(function (Command $handler) use (&$config, $instanceId, $positionKey, $primaryCommands) {
1616
$handler->buildCommandConfig();
1717

1818
$config['commands'][$positionKey][$handler->groupIndex()][] = [
@@ -32,6 +32,7 @@ protected function appendCommandsToConfig(Collection $commandHandlers, array &$c
3232
? $handler->authorizeFor($instanceId)
3333
: $handler->getGlobalAuthorization(),
3434
'icon' => app(IconManager::class)->iconToArray($handler->getIcon()),
35+
'primary' => in_array($handler->getCommandKey(), $primaryCommands),
3536
...$handler instanceof EntityCommand ? [
3637
'instanceSelection' => $handler->getInstanceSelectionMode(),
3738
] : [],

src/Show/SharpShow.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Code16\Sharp\EntityList\Traits\HandleEntityState;
66
use Code16\Sharp\EntityList\Traits\HandleInstanceCommands;
7+
use Code16\Sharp\EntityList\Traits\HandleInstancePrimaryCommands;
78
use Code16\Sharp\Show\Fields\SharpShowTextField;
89
use Code16\Sharp\Show\Layout\ShowLayout;
910
use Code16\Sharp\Utils\Fields\FieldsContainer;
@@ -19,6 +20,7 @@ abstract class SharpShow
1920
use HandleEntityState;
2021
use HandleFields;
2122
use HandleInstanceCommands;
23+
use HandleInstancePrimaryCommands;
2224
use HandleLocalizedFields;
2325
use HandlePageAlertMessage;
2426
use WithCustomTransformers;

tests/Unit/Dashboard/DashboardCommandTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public function execute(array $data = []): array {}
3535
'confirmation' => null,
3636
'hasForm' => false,
3737
'icon' => null,
38+
'primary' => false,
3839
]);
3940
});
4041

@@ -115,6 +116,7 @@ public function execute(array $data = []): array {}
115116
'confirmation' => null,
116117
'description' => null,
117118
'icon' => null,
119+
'primary' => false,
118120
],
119121
],
120122
],

0 commit comments

Comments
 (0)