Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.x] Run actions from publish forms #6375

Merged
merged 72 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
1c644d8
Run actions from the edit entry view
jacksleight Jul 25, 2022
de72777
WIP
jacksleight Nov 18, 2022
8611bf8
WIP
jacksleight Nov 19, 2022
7b93bfb
Merge branch 'statamic:3.3' into actions-detail
jacksleight Dec 1, 2022
e496f8e
Implement redirect on entry duplication
jacksleight Dec 1, 2022
d2f11f1
Merge branch '3.4' into actions-detail
jacksleight Feb 1, 2023
1139a41
Merge branch '4.x' into actions-detail
jacksleight May 10, 2023
0729391
Run tests again
jacksleight May 12, 2023
10a8179
Merge branch '4.x' into actions-detail
jasonvarga Sep 5, 2023
eb9332c
move actions after edit blueprint
jasonvarga Sep 5, 2023
17aaed9
Merge branch '4.x' into actions-detail
jacksleight Dec 15, 2023
c74662f
Update duplicate entry action
jacksleight Dec 15, 2023
d007a02
Update duplicate entry action
jacksleight Dec 15, 2023
1c7940f
Rename mixin to HasActions
jacksleight Dec 15, 2023
2a62a98
Reanme listActions to itemActions
jacksleight Dec 15, 2023
6a782e1
Rename publish_form context key to view
jacksleight Dec 15, 2023
3b1b1e7
Rename publish_form context key to view
jacksleight Dec 15, 2023
42f80b7
Add view key to all list contexts
jacksleight Dec 15, 2023
099e34e
Rename listActionUrl
jacksleight Dec 15, 2023
6136d19
Add blank callback method
jacksleight Dec 15, 2023
3094e39
Move method
jacksleight Dec 15, 2023
74f640c
Terms support (and some other tweaks)
jacksleight Dec 15, 2023
bd93be4
Support users
jacksleight Dec 15, 2023
a641a44
Rename callback method
jacksleight Dec 18, 2023
8233b74
Refactor a bunch of thingd
jacksleight Dec 18, 2023
f7f74a7
Assets support
jacksleight Dec 18, 2023
25ea12e
Rename filtered actions list
jacksleight Dec 18, 2023
d73aa2a
Ensure view context is always set
jacksleight Dec 19, 2023
a02baff
User delete redirect
jacksleight Dec 19, 2023
d4351d8
Fix error creating new entries and terms
jacksleight Dec 19, 2023
090ef40
Reanme initialReferenceId to just id
jacksleight Dec 19, 2023
fc11080
Remove duplicate callback call
jacksleight Dec 19, 2023
42ccbdb
Refactor user extractFromFields
jacksleight Dec 19, 2023
bc76eaf
Fix whitespace
jacksleight Dec 19, 2023
42287d1
Fix test
jacksleight Dec 19, 2023
8bd45b9
Ensure actions always have view context param
jacksleight Dec 19, 2023
eb0fc4e
Rename menuActions to actionsMenu
jacksleight Dec 19, 2023
9f8091b
Fix whitespace
jacksleight Dec 19, 2023
1c89ed0
Also hide dividers if they're last
jacksleight Dec 19, 2023
de03616
Also hide dividers if they're last
jacksleight Dec 19, 2023
e380cd1
That shouldn't be there
jacksleight Jan 12, 2024
46a5927
Merge branch '5.x' into actions-detail
jacksleight May 10, 2024
dee630f
Merge branch '5.x' into actions-detail
jacksleight May 14, 2024
7b88dd3
Update title watcher
jacksleight May 14, 2024
931456f
Remove copy asset URL action from menu
jacksleight May 16, 2024
2327363
Merge branch '5.x' into actions-detail
jasonvarga May 16, 2024
c5fa2af
use trait
jasonvarga May 16, 2024
3fc43bd
unreachable
jasonvarga May 16, 2024
84d5b2e
visibility
jasonvarga May 16, 2024
617cb14
Providing view of list is unnecessary since its the default in the Ac…
jasonvarga May 16, 2024
67396e1
nitpick
jasonvarga May 16, 2024
9f2d5be
abstract
jasonvarga May 16, 2024
fea9ceb
Revert and use arr::get instead
jasonvarga May 16, 2024
1a877af
Exclude entry actions in the actions rather than in vue.
jasonvarga May 17, 2024
36e6234
Send back data in a consistent way to saving
jasonvarga May 17, 2024
5b56433
The actions werent being updated ...
jasonvarga May 17, 2024
735322b
Even though we aren't showing the publish actions, update it anyway t…
jasonvarga May 17, 2024
3cb96cc
use id from values
jasonvarga May 17, 2024
20310b3
extract trait
jasonvarga May 17, 2024
19f2816
use term resourse for consistency
jasonvarga May 17, 2024
2330504
extract trait
jasonvarga May 17, 2024
16d582d
send ids consistent with the other forms
jasonvarga May 17, 2024
ce01561
exclude user actions in php
jasonvarga May 17, 2024
cc59cea
grab id from values
jasonvarga May 17, 2024
c329959
missed from 617cb14a
jasonvarga May 17, 2024
625050e
nitpick
jasonvarga May 17, 2024
b74ce3c
context
jasonvarga May 17, 2024
82e68f4
This must have accidentally been re-added in a merge. It was removed …
jasonvarga May 17, 2024
5eed6b4
Actions will show a dirty state warning ...
jasonvarga May 17, 2024
5e8bf68
Ability to disable the dirty warning text when it doesn't matter, lik…
jasonvarga May 17, 2024
eda9a0f
Make impersonate confirmable with appropriate messaging which makes m…
jasonvarga May 17, 2024
4305646
Make it work on terms and users
jasonvarga May 17, 2024
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
6 changes: 6 additions & 0 deletions resources/css/elements/dropdowns.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@
.divider {
@apply h-px bg-gray-400 overflow-hidden;
margin: 6px -8px;
/* Hide dividers that come first, last or immediately after another (due to v-if) */
& + &,
&:first-child,
&:last-child {
display: none;
}
}

.align-left & {
Expand Down
29 changes: 28 additions & 1 deletion resources/js/components/assets/Editor/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@
<svg-icon name="trash" class="h-4" />
<span class="rtl:mr-2 ltr:ml-2 hidden @3xl/toolbar:inline-block">{{ __('Delete') }}</span>
</button>

<dropdown-list class="mr-4" v-if="actionsMenu.length">
<data-list-inline-actions
:item="id"
:url="actionUrl"
:actions="actionsMenu"
@started="actionStarted"
@completed="actionCompleted"
/>
</dropdown-list>
</div>

<!-- Image Preview -->
Expand Down Expand Up @@ -271,7 +281,24 @@ export default {
isToolbarVisible()
{
return ! this.readOnly && this.showToolbar;
}
},

actionsMenu()
{
// We filter out the actions that are already in the toolbar.
// We don't want them to appear in the dropdown as well.
// If we filtered them out in PHP they wouldn't appear as buttons.
return this.actions.filter(action => ![
'rename_asset',
'move_asset',
'replace_asset',
'reupload_asset',
'download_asset',
'delete',
'copy_asset_url',
].includes(action.handle));
},

},

mounted() {
Expand Down
20 changes: 18 additions & 2 deletions resources/js/components/data-list/Action.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
@confirm="confirm"
@cancel="reset"
>
<div v-if="confirmationText" v-text="confirmationText" :class="{ 'mb-4': warningText || action.fields.length }" />
<div v-if="confirmationText" v-text="confirmationText" :class="{ 'mb-4': warningText || showDirtyWarning || action.fields.length }" />

<div v-if="warningText" v-text="warningText" class="text-red-500" :class="{ 'mb-4': action.fields.length }" />
<div v-if="warningText" v-text="warningText" class="text-red-500" :class="{ 'mb-4': showDirtyWarning || action.fields.length }" />

<div v-if="showDirtyWarning" v-text="dirtyText" class="text-red-500" :class="{ 'mb-4': action.fields.length }" />

<publish-container
v-if="action.fields.length"
Expand Down Expand Up @@ -57,6 +59,10 @@ export default {
},
errors: {
type: Object
},
isDirty: {
type: Boolean,
default: false,
}
},

Expand All @@ -82,6 +88,16 @@ export default {
return __n(this.action.warningText, this.selections);
},

dirtyText() {
if (! this.isDirty) return;

return __(this.action.dirtyWarningText);
},

showDirtyWarning() {
return this.isDirty && this.action.dirtyWarningText && ! this.action.bypassesDirtyWarning;
},

runButtonText() {
return __n(this.action.buttonText, this.selections);
}
Expand Down
5 changes: 4 additions & 1 deletion resources/js/components/data-list/Actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ export default {
handleActionSuccess(response) {
response.data.text().then(data => {
data = JSON.parse(data);
if (data.redirect) window.location = data.redirect;
if (data.redirect) {
if (data.bypassesDirtyWarning) this.$dirty.disableWarning();
window.location = data.redirect;
}
if (data.callback) Statamic.$callbacks.call(data.callback[0], ...data.callback.slice(1));
this.$emit('completed', true, data);
});
Expand Down
4 changes: 3 additions & 1 deletion resources/js/components/data-list/InlineActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
:action="action"
:selections="1"
:errors="errors"
:is-dirty="isDirty"
@selected="run"
>
<div slot-scope="{ action, select }">
Expand All @@ -30,7 +31,8 @@ export default {

props: {
actions: Array,
item: { required: true }
item: { required: true },
isDirty: { type: Boolean, default: false },
},

computed: {
Expand Down
40 changes: 34 additions & 6 deletions resources/js/components/entries/PublishForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@

<dropdown-list class="rtl:ml-4 ltr:mr-4" v-if="canEditBlueprint">
<dropdown-item :text="__('Edit Blueprint')" :redirect="actions.editBlueprint" />
<li class="divider" />
<data-list-inline-actions
v-if="!isCreating"
:item="values.id"
:url="itemActionUrl"
:actions="itemActions"
:is-dirty="isDirty"
@started="actionStarted"
@completed="actionCompleted"
/>
</dropdown-list>

<div class="pt-px text-2xs text-gray-600 flex rtl:ml-4 ltr:mr-4" v-if="readOnly">
Expand Down Expand Up @@ -297,12 +307,14 @@ import SaveButtonOptions from '../publish/SaveButtonOptions.vue';
import RevisionHistory from '../revision-history/History.vue';
import HasPreferences from '../data-list/HasPreferences';
import HasHiddenFields from '../publish/HasHiddenFields';
import HasActions from '../publish/HasActions';

export default {

mixins: [
HasPreferences,
HasHiddenFields,
HasActions,
],

components: {
Expand Down Expand Up @@ -496,7 +508,14 @@ export default {

saving(saving) {
this.$progress.loading(`${this.publishContainer}-entry-publish-form`, saving);
}
},

title(title) {
if (this.isBase) {
const arrow = this.direction === 'ltr' ? '‹' : '›';
document.title = `${title} ${arrow} ${this.breadcrumbs[1].text} ${arrow} ${this.breadcrumbs[0].text} ${arrow} ${__('Statamic')}`;
}
},

},

Expand Down Expand Up @@ -550,10 +569,6 @@ export default {
}
this.title = response.data.data.title;
this.isWorkingCopy = true;
if (this.isBase) {
const arrow = this.direction === 'ltr' ? '‹' : '›';
document.title = `${this.title} ${arrow} ${this.breadcrumbs[1].text} ${arrow} ${this.breadcrumbs[0].text} ${arrow} ${__('Statamic')}`;
}
if (!this.revisionsEnabled) this.permalink = response.data.data.permalink;
if (!this.isCreating && !this.isAutosave) this.$toast.success(__('Saved'));
this.$refs.container.saved();
Expand Down Expand Up @@ -794,7 +809,20 @@ export default {
}, this.autosaveInterval);

this.$store.commit(`publish/${this.publishContainer}/setAutosaveInterval`, interval);
}
},

afterActionSuccessfullyCompleted(response) {
if (response.data) {
this.title = response.data.title;
if (!this.revisionsEnabled) this.permalink = response.data.permalink;
this.values = this.resetValuesFromResponse(response.data.values);
this.initialPublished = response.data.published;
this.activeLocalization.published = response.data.published;
this.activeLocalization.status = response.data.status;
this.itemActions = response.data.itemActions;
}
},

},

mounted() {
Expand Down
44 changes: 44 additions & 0 deletions resources/js/components/publish/HasActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
export default {

props: {
initialItemActions: Array,
itemActionUrl: String,
},

data() {
return {
itemActions: this.initialItemActions,
}
},

methods: {

actionStarted() {
this.saving = true;
},

actionCompleted(successful=null, response) {
this.saving = false;

if (successful === false) return;

this.$events.$emit('reset-action-modals');

if (response.message !== false) {
this.$toast.success(response.message || __("Action completed"));
}

if (response.data) {
this.itemActions = response.data.itemActions;
}

this.afterActionSuccessfullyCompleted(response);
},

afterActionSuccessfullyCompleted(response) {
//
}

}

}
25 changes: 24 additions & 1 deletion resources/js/components/terms/PublishForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@

<dropdown-list class="rtl:ml-4 ltr:mr-4" v-if="canEditBlueprint">
<dropdown-item :text="__('Edit Blueprint')" :redirect="actions.editBlueprint" />
<li class="divider" />
<data-list-inline-actions
v-if="!isCreating"
:item="values.id"
:url="itemActionUrl"
:actions="itemActions"
:is-dirty="isDirty"
@started="actionStarted"
@completed="actionCompleted"
/>
</dropdown-list>

<div class="pt-px text-2xs text-gray-600 flex rtl:ml-4 ltr:mr-4" v-if="readOnly">
Expand Down Expand Up @@ -243,12 +253,14 @@ import SaveButtonOptions from '../publish/SaveButtonOptions.vue';
import RevisionHistory from '../revision-history/History.vue';
import HasPreferences from '../data-list/HasPreferences';
import HasHiddenFields from '../publish/HasHiddenFields';
import HasActions from '../publish/HasActions';

export default {

mixins: [
HasPreferences,
HasHiddenFields,
HasActions,
],

components: {
Expand Down Expand Up @@ -473,6 +485,7 @@ export default {
.then(() => {
// If revisions are enabled, just emit event.
if (this.revisionsEnabled) {
this.values = this.resetValuesFromResponse(response.data.data.values);
this.$nextTick(() => this.$emit('saved', response));
return;
}
Expand All @@ -493,6 +506,7 @@ export default {
// the hooks are resolved because if this form is being shown in a stack, we only
// want to close it once everything's done.
else {
this.values = this.resetValuesFromResponse(response.data.data.values);
this.$nextTick(() => this.$emit('saved', response));
}

Expand Down Expand Up @@ -620,7 +634,16 @@ export default {
this.localizedFields.push(handle);

this.$refs.container.dirty();
}
},

afterActionSuccessfullyCompleted(response) {
if (response.data) {
this.title = response.data.title;
this.permalink = response.data.permalink;
this.values = this.resetValuesFromResponse(response.data.values);
}
},

},

mounted() {
Expand Down
27 changes: 25 additions & 2 deletions resources/js/components/users/PublishForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
<h1 class="flex-1" v-text="title" />
<dropdown-list class="rtl:ml-4 ltr:mr-4" v-if="canEditBlueprint">
<dropdown-item :text="__('Edit Blueprint')" :redirect="actions.editBlueprint" />
<li class="divider" />
<data-list-inline-actions
:item="values.id"
:url="itemActionUrl"
:actions="itemActions"
:is-dirty="isDirty"
@started="actionStarted"
@completed="actionCompleted"
/>
</dropdown-list>

<change-password
Expand Down Expand Up @@ -55,11 +64,13 @@
<script>
import ChangePassword from './ChangePassword.vue';
import HasHiddenFields from '../publish/HasHiddenFields';
import HasActions from '../publish/HasActions';

export default {

mixins: [
HasHiddenFields,
HasActions,
],

components: {
Expand Down Expand Up @@ -95,7 +106,11 @@ export default {

hasErrors() {
return this.error || Object.keys(this.errors).length;
}
},

isDirty() {
return this.$dirty.has(this.publishContainer);
},

},

Expand All @@ -111,6 +126,7 @@ export default {

this.$axios[this.method](this.actions.save, this.visibleValues).then(response => {
this.title = response.data.title;
this.values = this.resetValuesFromResponse(response.data.data.values);
if (!response.data.saved) {
return this.$toast.error(`Couldn't save user`)
}
Expand All @@ -128,7 +144,14 @@ export default {
this.$toast.error(__('Something went wrong'));
}
});
}
},

afterActionSuccessfullyCompleted(response) {
if (response.data) {
this.title = response.data.title;
this.values = this.resetValuesFromResponse(response.data.values);
}
},

},

Expand Down
1 change: 1 addition & 0 deletions resources/lang/en/messages.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
'globals_configure_handle_instructions' => 'Used to reference this global set on the frontend. It\'s non-trivial to change later.',
'globals_configure_intro' => 'A global set is a group of variables available across all front-end pages.',
'globals_configure_title_instructions' => 'We recommend a noun representing the set\'s contents. eg. "Brand" or "Company"',
'impersonate_action_confirmation' => 'You will be logged in as this user. You can return to your account using the avatar menu.',
'licensing_config_cached_warning' => 'Any changes you make to your .env or config files will not be detected until you clear the cache. If you are seeing unexpected licensing results here, it may be because of this. You can use the <code>php artisan config:cache</code> command to regenerate the cache.',
'licensing_error_invalid_domain' => 'Invalid domain',
'licensing_error_invalid_edition' => 'License is for :edition edition',
Expand Down
Loading
Loading