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

Add permissions API and actionBar override #461

Open
chrisvxd opened this issue Apr 23, 2024 · 6 comments · May be fixed by #558
Open

Add permissions API and actionBar override #461

chrisvxd opened this issue Apr 23, 2024 · 6 comments · May be fixed by #558

Comments

@chrisvxd
Copy link
Member

chrisvxd commented Apr 23, 2024

This ticket covers two features:

  1. Adding an API to override the action bar and inject new items
  2. Adding a new permissions API to control key parts of functionality for:
  • drag: whether the component can be dragged
  • edit: whether or not fields are editable (read-only if not)
  • delete: whether the component can be deleted
  • duplicate: whether the component can be duplicated
  • insert: whether the component can be inserted
  • ... TBD

Proposal

Injecting new items via actionBar override

import { ActionBar, Puck } from "@measured/puck";

const data = {};

export function Editor() {
  return (
    <Puck
      data={data}
      overrides={{
        // Enable override of entire action bar, not just internal actions
        actionBar: ({ children, item, itemSelector }) => {
          return (
            // <ActionBar> is the default UI
            <ActionBar>
              <div
                style={{
                  display: "flex",
                }}
              >
                <ActionBar.Item>My custom item</ActionBar.Item>
                {children}
            </ActionBar>
          );
        },
      }}
    />
  );
}

Adding permissions and resolvePermissions APIs

import { usePuck } from "@measured/puck";

const data = {};

export function Editor() {
  const permissions = {
    duplicate: false,
    edit: true,
    // A custom permission for the user
    party: false,
  };
  
  return (
    <Puck
      // Specify global permissions
      permissions={permissions}

      config={{
        components: {
          MyComponent: {
            // Basic usage
            permissions: { edit: false },

            // Advanced usage
            resolvePermissions: async ({
              props,
              lastPermissions,
              initialPermissions,
            }) => {
              // Do some async task
              const isAdmin = await getAdmin();
              
              return {
                party: isAdmin
               };
            },
          },
        },
      }}
      data={data}
    />
  );
}
@chrisvxd chrisvxd changed the title Add API to restrict Puck behaviour component Add API to restrict draggable component behaviour Apr 23, 2024
@sagarchoudhary96
Copy link
Contributor

sagarchoudhary96 commented Jul 3, 2024

@chrisvxd do we have any updates on this one ?

Also is there any way to capture the duplicateEvent? The issue i'm facing is while duplicating the component it creating copy with same id value for it and hence when trying to update my db, it throws error as there is primary key constraint on the id column. I need some way to control this duplicate action.

Screenshot 2024-07-04 at 1 01 27 AM

@chrisvxd
Copy link
Member Author

This one is on our radar to implement relatively soon.

Regarding duplications - Puck should update the ID for any components caught in duplications. Is that the issue you're facing? Or is it a separate ID that you're tracking that needs updating??

@sagarchoudhary96
Copy link
Contributor

my issue is not to be able to control the state when duplicate action is clicked and be able to edit the props which gets updated to editor state .

@BR1G00
Copy link

BR1G00 commented Aug 9, 2024

Hi @chrisvxd, i need to disable dragging in the preview, i would like to know if there are any update on this feat? or there is a workaround i can use?

@xaviemirmon
Copy link
Contributor

xaviemirmon commented Aug 12, 2024

These APIs need a good amount of thought and understanding of the different scenarios where someone might want to use them.

The overlay actions seem to be very similar to something like headerActions. For consistency, I propose a similar API e.g.

<Puck<Config>
  config={config}
  data={data}
  onPublish={async () => {}}
  plugins={[...]}
  headerPath={path}
  overrides={{
    headerActions: ({ children }) => (...),
    overlayActions: ({ children }) => (
      <>
        <div>
          <Button onClick={()=> {}} variant="secondary">
            Lock
          </Button>
        </div>

        {children}
      </>
    ),
  }}
/>

A downside to the propsal above is that unlike AppState the dropZoneContext isn't exposed so you'd have to hack the children to alter how a pre-existing button displays/behaves or build a new button but the actions aren't publicly available are they? (For example, if you wanted to adjust the icons). Is that a problem?

I agree with @sagarchoudhary96's point that altering the data would be beneficial. However, this seems like a separate functionality, so I will create a different issue. I ran into problems similar to those in my implementation, which is leveraging additional metadata behind the scenes. Rather than exposing the entire Dropzone context and dispatch function, perhaps we can update the duplicate action to add a flag to the duplicated and change the ID such as isDuplicate={true}? Then, when using the onPublish, we could alter the data/behaviour before sending the payload to the server.

The other parts of this issue are related to me, such as boolean toggles. It boils down to whether or not a user can perform the following actions on an instance of a component:

  • Edit
  • Duplicate
  • Delete
  • Drag

Conceptually, I see these toggles as having a data configuration similar to fields and component types.

export const ExampleComponent: ComponentConfig<ComponentProps> = {
  fields: { },
  actions: {
    isEditable,
    isDuplicatable,
    isDeleteable,
    isDraggable,
  }
  defaultProps: {
  },
  render: ({}) => (),
};

You could then add the object of an optional action to the data/initialData. For a Hero, I could see this being useful.

{
  type: "ExampleComponent",
  props: {
    ...
  },
  actions: {
    isEditable: true,
    isDuplicatable: false,
    isDeleteable: false,
    isDraggable: false,
  }
},

From my perspective, having worked on integrating Puck with a CMS, there is also a need to interpret rules beyond those provided by the data payload.

The main question I have is should these API's exist as global configuration or an individual (or a mixture of the two)? I see this being used to change the edit state of all components on a page where a user doesn't have the correct permissions but can limit some of the components' rules individually.

Globally:

<Puck<Config>
  config={config}
  data={data}
  onPublish={async () => {}}
  plugins={[...]}
  headerPath={path}
  overrides={{
    componentActions:({ config, data }) => {
      // pseudo code
      if(data.user.role == "limited") {
        config.components.Text.actions.isEditable = false
      }
    }
  }}
/>

Individually:

export const ExampleComponent: ComponentConfig<ComponentProps> = {
  ...
  resolveActions: (data) => {
    // pseudo code
    if(data.props.size = "8px") {
      return {
        isDraggable: false
      }
    }
  }
};

Are there any preferences, thoughts, comments, alternative ideas or concerns towards the approaches above?

@chrisvxd
Copy link
Member Author

After much conversation with @xaviemirmon, we're going with the proposal now outlined in the ticket description

@chrisvxd chrisvxd changed the title Add API to restrict draggable component behaviour Add permissions API and actionBar override Aug 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants