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

QuickEdit: Add slug field control #65196

Merged
merged 21 commits into from
Oct 23, 2024
Merged

Conversation

gigitux
Copy link
Contributor

@gigitux gigitux commented Sep 10, 2024

What?

Part of #64519

Screen.Capture.on.2024-09-10.at.12-42-17.mp4

This PR adds the slug field control to the Page view. Most of the logic is copied from:

Currently, these two functions are public selectors and rely on the editor state, so we can't refactor those. I think that for now, we can keep this duplicate code and when the post editor sidebar will be powered by the dataview, we can think to refactor those, but I'm open to feedback on this.

Similar to #64496, this code could be moved to the @wordpress/core-fields-control package if we agree to create it.

Validation

There is an edge-case that I think that we should take care, but I will wait for your feedback before to proceed. When the input is empty, the save button is clickable:

image

This isn’t ideal because a page/post should always have a slug set. Currently, if the input is empty, the original slug is restored on the onBlur event, which is not the best UX.

How?

Testing Instructions

Ensure that Quick Edit in DataViews and Quick Edit in DataViews are enabled.

  1. Visit the Site Editor.
  2. Click on pages.
  3. Toggle to the table view.
  4. Click on the settings.
  5. Click on details panel icon.
  6. Ensure that the link field is visible
  7. Click on it.
  8. Update the slug.
  9. Save.
  10. Ensure that the page is visible to the new link.
  11. Visit /wp-admin/options-permalink.php.
  12. Select plain setting.
  13. Save it.
  14. Repeat 1-7 steps.
  15. Ensure that you can't update the slug.

@gigitux gigitux changed the title Page view: Add slug field control Dataview - Page view: Add slug field control Sep 10, 2024
@gigitux gigitux changed the title Dataview - Page view: Add slug field control Data View - Page view: Add slug field control Sep 10, 2024
@jameskoster
Copy link
Contributor

There is an edge-case that I think that we should take care, but I will wait for your feedback before to proceed. When the input is empty, the save button is clickable:

This is a tricky one, and technically an existing issue (see video below) so perhaps not one we have to fix here?

slug.mp4

Some validation might help; maybe the field should error when empty, and revert to the current value on blur? The Save button would be disabled when the field is empty. Some validation to avoid duplicate slugs might be handy as well.


We also need to think about the conditions in which the Link field is shown in the quick-edit panel. In the vast majority of cases it's not possible to apply the same slug to multiple items, so maybe we just hide it for now?

@gigitux
Copy link
Contributor Author

gigitux commented Sep 10, 2024

This is a tricky one, and technically an existing issue (see video below) so perhaps not one we have to fix here?

Yeah, this is something that I noticed too.

Some validation might help; maybe the field should error when empty, and revert to the current value on blur? The Save button would be disabled when the field is empty.

I'm fine following this approach. I'm going to try to implement it!

Some validation to avoid duplicate slugs might be handy as well.

Yeah good point. I would see this kind of validation on the backend side when the user clicks save. For now, I would skip this point because it impacts some work not specifically related to the scope of this project.

We also need to think about the conditions in which the Link field is shown in the quick-edit panel. In the vast majority of cases it's not possible to apply the same slug to multiple items, so maybe we just hide it for now?

True! Let's hide it!

Thanks for your precious feedback, @jameskoster! 🙇

@@ -369,6 +370,13 @@ function usePostFields( viewType ) {
return <time>{ getFormattedDate( item.date ) }</time>;
},
},
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works because our APIs are already extensible. However, there's an alternative that @joshuatf mentioned somewhere. Instead of doing:

{
  id: 'slug',
  Edit: /* custom slug Edit */,
  render: /* custom slug render */,
  isValid: /* custom slug isValid */,
  // etc.
}

we can do something along these lines:

registerFieldType( 'core/slug', FieldSlug );

const fields = [
  {
    id: 'slug',
    type: 'core/slug',
  }
];

This has a few advantages:

  • It gets us a bit closer to making the type field required. We're not there there yet because there are a couple of missing types we need (image, for example), but we should aim to do it.

  • We offer higher semantics and gets us a bit closer to having no-code JSON-oriented fields. This may sound a bit abstract, but imagine the following scenario: in the future, there's a mechanism for users to create screens based on declaring which fields they want from a dataset. All via UI. In that scenario, that UI needs to be no-code, and users shouldn't have to provide a "custom render", "custom edit", "custom validation", etc. if they just want a field to be a "slug". Instead, they should work with types: the basic ones provided by DataViews (string, integer, date, etc.) but also any other one that is domain-specific (slug, cart-status, etc.).

Another aspect of this PR is what should be the API offered by the wordpress/field package?

This suggest it should export individual field properties (render, edit, isValid, etc.). There are a few. What if it exported the whole field instead? An advantage of exporting the whole Field is that the wordpress/field package can implement new APIs as they come without having to modify the consumers:

// The consumer doesn't have to modify any code when
// a new Field property is introduced, renamed it, etc.
// It's the FieldSlug responsibility to implement it.

const fields = [
  {
    id: 'slug',
    type: 'core/slug'
  }
];

@gigitux
Copy link
Contributor Author

gigitux commented Sep 18, 2024

We also need to think about the conditions in which the Link field is shown in the quick-edit panel. In the vast majority of cases it's not possible to apply the same slug to multiple items, so maybe we just hide it for now?

With dc2e1b8, the slug field is hidden in bulk edit mode.


After a chat with @louwie17 and @joshuatf we are inclined to merge this PR without the validation (given that currently there isn't in the post editor). I'm going to mark this PR as ready to be reviewed!

This is a tricky one, and technically an existing issue (see video below) so perhaps not one we have to fix here?

Regarding the validation, we are planning to use this field as playground to think/implement how the validation should look. We are planning to create a dedicated PR (or multiples) for the validation!

This has a few advantages:

It gets us a bit closer to making the type field required. We're not there there yet because there are a couple of missing types we need (image, for example), but we should aim to do it.

We offer higher semantics and gets us a bit closer to having no-code JSON-oriented fields. This may sound a bit abstract, but imagine the following scenario: in the future, there's a mechanism for users to create screens based on declaring which fields they want from a dataset. All via UI. In that scenario, that UI needs to be no-code, and users shouldn't have to provide a "custom render", "custom edit", "custom validation", etc. if they just want a field to be a "slug". Instead, they should work with types: the basic ones provided by DataViews (string, integer, date, etc.) but also any other one that is domain-specific (slug, cart-status, etc.)

Thanks for your comment! We are planning to work on this new API in the upcoming weeks!

@@ -0,0 +1,18 @@
.fields-controls__slug {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense this classname? Or should we think a better one?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps I'd go with .field-slug as a prefix.

@gigitux gigitux marked this pull request as ready for review September 18, 2024 09:50
@oandregal oandregal changed the title Data View - Page view: Add slug field control QuickEdit: Add slug field control Sep 26, 2024
@@ -9,7 +9,6 @@
"gutenberg",
"dataviews"
],
"private": true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I presume this needs to be rebased from trunk, correct? This package was made public already.

import SlugView from './slug-view';

const slugField: Field< BasePost > = {
id: 'slug',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What type would this field be? I feel we need to make progress on making type obligatory and every new field we introduce should have a type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say slug, what do you think? Mostly, because this field contains specific logic to preview the final link based on the slug setting:

const permalinkPrefix = prefix;
const permalinkSuffix = suffix;
const isEditable = PERMALINK_POSTNAME_REGEX.test( permalinkTemplate );
const originalSlug = useRef( slug );
const slugToDisplay = slug || originalSlug.current;
const permalink = isEditable
? `${ permalinkPrefix }${ slugToDisplay }${ permalinkSuffix }`
: safeDecodeURIComponent( data.link || '' );

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After further consideration, the type should always represent a generic type, not strictly tied to WordPress. In this case, it should be link. In the future, we might have:

  • A generic field for the link type.
  • Other fields that work with the link type but have additional functionalities that depend on specific settings like this one.

Would it make sense for each field to have a name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on this discussion, I updated the type with 4efda74

@@ -369,6 +370,7 @@ function usePostFields( viewType ) {
return <time>{ getFormattedDate( item.date ) }</time>;
},
},
slugField,
Copy link
Member

@oandregal oandregal Sep 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok for this PR going this way. I'd like to offer some thoughts about next steps.

Initially, the wordpress/fields package exported every specific part of a field (edit, label, etc.) and we changed it to the whole field. Now that I see this, I think we have to offer an even higher-level API:

const postFields = usePostFields();
const pageFields = usePageFields();
// etc.

Essentially, the same we do for actions. In the future, we'll want 3rd parties to be able to register/unregister fields, so we can't use individual fields in every screen — otherwise, every screen will have to provide a filter/registry for that. Instead, we should offer an API that gives all the fields that are registered for a given post type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially, the wordpress/fields package exported every specific part of a field (edit, label, etc.) and we changed it to the whole field. Now that I see this, I think we have to offer an even higher-level API:

I see what you mean. I think that we will start to work on similar API when we will create a fields store in the @wordpress/fields package.

In the future, we'll want 3rd parties to be able to register/unregister fields, so we can't use individual fields in every screen — otherwise, every screen will have to provide a filter/registry for that

On this, we are full aligned! We will plan to work on this API.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gigitux gigitux requested a review from oandregal October 22, 2024 15:12
@oandregal oandregal added [Type] Experimental Experimental feature or API. [Package] DataViews /packages/dataviews labels Oct 23, 2024
@@ -66,6 +66,10 @@ Undocumented declaration.

Undocumented declaration.

### slugField
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we start adding some JSDoc comments to the exported entities so this is filled up with actual info? It's enough to add a JSDoc to this statement.

@oandregal
Copy link
Member

There is an edge-case that I think that we should take care, but I will wait for your feedback before to proceed. When the input is empty, the save button is clickable:

It's ok to address this in a follow-up, but wanted to share some thoughts:

  • we already validation in fields (isValid)
  • it's already built-in in the types (if your field declares a type it doesn't have to have its own isValid)
  • there's an utility to validate all fields based on their isValid callback: isItemValid that we are already using in some scenarios (reorder page modal)

Thinking about how to scope next steps, this is what I think we should do:

  • Connecting the existing isItemValid utility to the save button in the site editor.
  • Implement isValid in the slug field introduced here to check for non empty.

Note that when we introduce "slug" field type, that should be automatically created for the field — but that requires other things we don't have yet (being able to register new fields types).

@oandregal
Copy link
Member

In terms of design, I've compared this to the one we have in the editor:

QuickEdit Editor
Screenshot 2024-10-23 at 11 51 47 Screenshot 2024-10-23 at 11 51 38
Screenshot 2024-10-23 at 11 54 32 Screenshot 2024-10-23 at 11 54 43

I've noticed a couple of differences, we should probably align this PR with the editor.

  • Name: slug (quickedit) vs link (editor)
  • Missing text "Permalink:" before permalink

@oandregal
Copy link
Member

I've noticed that the permalink setting doesn't affect the slug field. We either render it disabled (plain) or render the post name (any other option).

Not something to fix in this PR because it also happens in the editor, but I suppose we'd want to better expose that setting in the slug?

Screenshot 2024-10-23 at 12 49 05

Copy link
Member

@oandregal oandregal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can merge this one and continue iterating.

@gigitux
Copy link
Contributor Author

gigitux commented Oct 23, 2024

In terms of design, I've compared this to the one we have in the editor:

Nice catch! The design has been updated in the last weeks: https://github.com/WordPress/gutenberg/pull/63669/files. I updated the design!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] DataViews /packages/dataviews [Type] Experimental Experimental feature or API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants