Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion resources/js/components/actions/ItemActions.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup>
import { ref, computed, useTemplateRef, watch } from 'vue';
import { ref, computed, useTemplateRef, watch, useSlots } from 'vue';
import useActions from './Actions.js';
import ConfirmableAction from './ConfirmableAction.vue';
import axios from 'axios';
Expand Down Expand Up @@ -30,6 +30,10 @@ let preparedActions = computed(() => {
return prepareActions(actions.value, confirmableActions.value);
});

let preparedPinnedActions = computed(() => {
return prepareActions(actions.value?.filter(action => action.pinned), confirmableActions.value);
});

let errors = ref({});

function runAction(action, values, onSuccess, onError) {
Expand Down Expand Up @@ -68,6 +72,9 @@ function loadActions() {
actionsLoaded.value = true;
}

const slots = useSlots();
const showPinnedActions = computed(() => preparedPinnedActions.value && !!slots.pinned);

defineExpose({
preparedActions,
});
Expand All @@ -85,4 +92,5 @@ defineExpose({
@confirmed="runAction"
/>
<slot :actions="preparedActions" :load-actions="loadActions" />
<slot v-if="showPinnedActions" name="pinned" :actions="preparedPinnedActions" />
</template>
17 changes: 16 additions & 1 deletion resources/js/components/assets/Editor/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@
<ui-button inset size="sm" @click="download" icon="download" variant="ghost" class="[&_svg]:!opacity-45" :text="__('Download')" />
<ui-button inset size="sm" v-if="allowDeleting && canRunAction('delete')" @click="runAction(actions, 'delete')" icon="trash" variant="ghost" class="[&_svg]:!opacity-45" :text="__('Delete')" />

<ui-button
v-for="action in pinnedActions(actions)"
inset
size="sm"
@click="action.run"
:icon="action.icon"
variant="ghost"
class="[&_svg]:!opacity-45"
:text="__(action.title)"
/>

<Dropdown class="me-4">
<DropdownMenu>
<DropdownItem
Expand Down Expand Up @@ -494,7 +505,11 @@ export default {
];

return actions.filter((action) => !buttonActions.includes(action.handle));
}
},

pinnedActions(actions) {
return actions.filter((action) => action.pinned);
},
},
};
</script>
48 changes: 30 additions & 18 deletions resources/js/components/entries/PublishForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,37 @@
:is-dirty="isDirty"
@started="actionStarted"
@completed="actionCompleted"
v-slot="{ actions: itemActions }"
>
<Dropdown v-if="canEditBlueprint || hasItemActions">
<template #trigger>
<Button icon="dots" variant="ghost" :aria-label="__('Open dropdown menu')" />
</template>
<DropdownMenu>
<DropdownItem :text="__('Edit Blueprint')" icon="blueprint-edit" v-if="canEditBlueprint" :href="actions.editBlueprint" />
<DropdownSeparator v-if="canEditBlueprint && itemActions.length" />
<DropdownItem
v-for="action in itemActions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'destructive' : 'default'"
@click="action.run"
/>
</DropdownMenu>
</Dropdown>
<template #default="{ actions: itemActions }">
<Dropdown v-if="canEditBlueprint || hasItemActions">
<template #trigger>
<Button icon="dots" variant="ghost" :aria-label="__('Open dropdown menu')" />
</template>
<DropdownMenu>
<DropdownItem :text="__('Edit Blueprint')" icon="blueprint-edit" v-if="canEditBlueprint" :href="actions.editBlueprint" />
<DropdownSeparator v-if="canEditBlueprint && itemActions.length" />
<DropdownItem
v-for="action in itemActions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'destructive' : 'default'"
@click="action.run"
/>
</DropdownMenu>
</Dropdown>
</template>

<template #pinned="{ actions }">
<Button
v-for="action in actions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'danger' : 'default'"
@click="action.run"
/>
</template>
</ItemActions>

<ui-badge icon="padlock-locked" :text="__('Read Only')" v-if="readOnly" />
Expand Down
49 changes: 30 additions & 19 deletions resources/js/components/globals/PublishForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,37 @@
:item="initialHandle"
@started="actionStarted"
@completed="actionCompleted"
v-slot="{ actions: preparedActions }"
>
<Dropdown v-if="canConfigure || canEditBlueprint || hasItemActions">
<template #trigger>
<Button icon="dots" variant="ghost" :aria-label="__('Open dropdown menu')" />
</template>
<DropdownMenu>
<DropdownItem :text="__('Configure')" icon="cog" v-if="canConfigure" :href="configureUrl" />
<DropdownItem :text="__('Edit Blueprint')" icon="blueprint-edit" v-if="canEditBlueprint" :href="actions.editBlueprint" />
<DropdownSeparator v-if="hasItemActions && (canConfigure || canEditBlueprint)" />
<DropdownItem
v-for="action in preparedActions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'destructive' : 'default'"
@click="action.run"
/>
</DropdownMenu>
</Dropdown>
<template #default="{ actions: preparedActions }">
<Dropdown v-if="canConfigure || canEditBlueprint || hasItemActions">
<template #trigger>
<Button icon="dots" variant="ghost" :aria-label="__('Open dropdown menu')" />
</template>
<DropdownMenu>
<DropdownItem :text="__('Configure')" icon="cog" v-if="canConfigure" :href="configureUrl" />
<DropdownItem :text="__('Edit Blueprint')" icon="blueprint-edit" v-if="canEditBlueprint" :href="actions.editBlueprint" />
<DropdownSeparator v-if="hasItemActions && (canConfigure || canEditBlueprint)" />
<DropdownItem
v-for="action in preparedActions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'destructive' : 'default'"
@click="action.run"
/>
</DropdownMenu>
</Dropdown>
</template>
<template #pinned="{ actions }">
<Button
v-for="action in actions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'danger' : 'default'"
@click="action.run"
/>
</template>
</ItemActions>
<Dropdown v-else-if="canConfigure || canEditBlueprint">
<template #trigger>
Expand Down
50 changes: 31 additions & 19 deletions resources/js/components/users/PublishForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,38 @@
:is-dirty="isDirty"
@started="actionStarted"
@completed="actionCompleted"
v-slot="{ actions: itemActions }"
>
<Dropdown>
<template #trigger>
<Button icon="dots" variant="ghost" :aria-label="__('Open dropdown menu')" />
</template>
<DropdownMenu>
<DropdownItem :text="__('Edit Blueprint')" icon="blueprint-edit" v-if="canEditBlueprint" :href="actions.editBlueprint" />
<DropdownItem :text="__('Passkeys')" icon="key" :href="cp_url('passkeys')" />
<DropdownSeparator v-if="canEditBlueprint && itemActions.length" />
<DropdownItem
v-for="action in itemActions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'destructive' : 'default'"
@click="action.run"
/>
</DropdownMenu>
</Dropdown>
<template #default="{ actions: itemActions }">
<Dropdown>
<template #trigger>
<Button icon="dots" variant="ghost" :aria-label="__('Open dropdown menu')" />
</template>
<DropdownMenu>
<DropdownItem :text="__('Edit Blueprint')" icon="blueprint-edit" v-if="canEditBlueprint" :href="actions.editBlueprint" />
<DropdownItem :text="__('Passkeys')" icon="key" :href="cp_url('passkeys')" />
<DropdownSeparator v-if="canEditBlueprint && itemActions.length" />
<DropdownItem
v-for="action in itemActions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'destructive' : 'default'"
@click="action.run"
/>
</DropdownMenu>
</Dropdown>
</template>

<template #pinned="{ actions }">
<Button
v-for="action in actions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'danger' : 'default'"
@click="action.run"
/>
</template>
</ItemActions>

<TwoFactor v-if="twoFactor" v-bind="twoFactor" />
Expand Down
46 changes: 29 additions & 17 deletions resources/js/pages/collections/Show.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,36 @@
:url="actionUrl"
:actions="actions"
:item="handle"
v-slot="{ actions }"
>
<Dropdown placement="left-start">
<DropdownMenu>
<DropdownItem v-if="canEdit" :text="__('Configure Collection')" icon="cog" :href="editUrl" />
<DropdownItem v-if="canEditBlueprints" :text="__('Edit Blueprints')" icon="blueprint-edit" :href="blueprintsUrl" />
<DropdownItem v-if="canEdit" :text="__('Scaffold Views')" icon="scaffold" :href="scaffoldUrl" />
<DropdownSeparator v-if="canEdit || canEditBlueprints || actions.length" />
<DropdownItem
v-for="action in actions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'destructive' : 'default'"
@click="action.run"
/>
</DropdownMenu>
</Dropdown>
<template #default="{ actions }">
<Dropdown placement="left-start">
<DropdownMenu>
<DropdownItem v-if="canEdit" :text="__('Configure Collection')" icon="cog" :href="editUrl" />
<DropdownItem v-if="canEditBlueprints" :text="__('Edit Blueprints')" icon="blueprint-edit" :href="blueprintsUrl" />
<DropdownItem v-if="canEdit" :text="__('Scaffold Views')" icon="scaffold" :href="scaffoldUrl" />
<DropdownSeparator v-if="canEdit || canEditBlueprints || actions.length" />
<DropdownItem
v-for="action in actions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'destructive' : 'default'"
@click="action.run"
/>
</DropdownMenu>
</Dropdown>
</template>

<template #pinned="{ actions }">
<Button
v-for="action in actions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'danger' : 'default'"
@click="action.run"
/>
</template>
</ItemActions>

<template v-if="view === 'tree'">
Expand Down
43 changes: 27 additions & 16 deletions resources/js/pages/navigation/Show.vue
Original file line number Diff line number Diff line change
Expand Up @@ -369,23 +369,34 @@ export default {
:item="handle"
@started="actionStarted"
@completed="actionCompleted"
v-slot="{ actions: preparedActions }"
>
<Dropdown placement="left-start" v-if="canEdit || canEditBlueprint || hasItemActions">
<DropdownMenu>
<DropdownItem v-if="canEdit" :text="__('Configure Navigation')" icon="cog" :href="editUrl" />
<DropdownItem v-if="canEditBlueprint" :text="__('Edit Blueprints')" icon="blueprint-edit" :href="blueprintUrl" />
<DropdownSeparator v-if="hasItemActions && (canEdit || canEditBlueprint)" />
<DropdownItem
v-for="action in preparedActions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'destructive' : 'default'"
@click="action.run"
/>
</DropdownMenu>
</Dropdown>
<template #default="{ actions: preparedActions }">
<Dropdown placement="left-start" v-if="canEdit || canEditBlueprint || hasItemActions">
<DropdownMenu>
<DropdownItem v-if="canEdit" :text="__('Configure Navigation')" icon="cog" :href="editUrl" />
<DropdownItem v-if="canEditBlueprint" :text="__('Edit Blueprints')" icon="blueprint-edit" :href="blueprintUrl" />
<DropdownSeparator v-if="hasItemActions && (canEdit || canEditBlueprint)" />
<DropdownItem
v-for="action in preparedActions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'destructive' : 'default'"
@click="action.run"
/>
</DropdownMenu>
</Dropdown>
</template>
<template #pinned="{ actions }">
<Button
v-for="action in actions"
:key="action.handle"
:text="__(action.title)"
:icon="action.icon"
:variant="action.dangerous ? 'danger' : 'default'"
@click="action.run"
/>
</template>
</ItemActions>
<Dropdown v-else-if="canEdit || canEditBlueprint" placement="left-start">
<DropdownMenu>
Expand Down
2 changes: 2 additions & 0 deletions src/Actions/Action.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ abstract class Action implements Arrayable
protected $items;
protected $confirm = true;
protected $dangerous = false;
protected $pinned = false;
protected $fields = [];
protected $context = [];
protected $runnable = true;
Expand Down Expand Up @@ -162,6 +163,7 @@ public function toArray()
'bypassesDirtyWarning' => $this->bypassesDirtyWarning(),
'requiresElevatedSession' => $this->requiresElevatedSession(),
'dangerous' => $this->dangerous,
'pinned' => $this->pinned,
'fields' => $this->fields()->toPublishArray(),
'values' => $this->fields()->preProcess()->values(),
'meta' => $this->fields()->meta(),
Expand Down