Documentation
  • 👋Welcome to Cerberus
  • Overview
    • 💡What we do
    • ✨Our Features
  • Product Guides
    • 💡Core concepts
    • 🍎Creating an App
    • 📎Modeling your domain
    • 📄Creating policies
  • Tutorial
    • 🛠️Getting set up
      • 🌠Cloning project
      • 👷Setting up workspace
      • 🏃‍♂️Build and run app
    • 📏Creating static rules
      • Create an account
      • Add migrations
    • ✍️Implementation
      • Backend
        • Migrate existing data
        • Routes
        • Services
          • User
          • Project
          • Sprint
          • Story
      • Frontend
        • Settings
        • Projects
        • Sprints
        • Stories
  • APIs
    • 🎨REST API
    • 🖥️Websocket API
  • Migrations
    • 🐧Scripting language
    • 🏃‍♂️Running migrations
Powered by GitBook
On this page
  1. Tutorial
  2. Implementation
  3. Frontend

Stories

Let's navigate to the 'stories' folder.

In the 'Story.js' file, add a new tab for Story permissions on line 15 like this:

<Tabs defaultActiveKey="details">
    <Tab eventKey="details" title="Details"><Dashboard story={story} setSelectedStory={setSelectedStory} setStories={setStories}/></Tab>
    <Tab eventKey="permissions" title="Permissions"><StoryPermissions story={story}/></Tab>
</Tabs>

In the Dashboard component, add new state variables and make use of the useAccess hook to see which permissions the user has for changing story elements:

.
.
.
const [estimateAccess, setEstimateAccess] = useState(false)
const [statusAccess, setStatusAccess] = useState(false)
const [assigneeAccess, setAssigneeAccess] = useState(false)
const {story, setSelectedStory, setStories} = props

useAccess(story.id, "EstimateStory", setEstimateAccess)
useAccess(story.id, "ChangeStoryStatus", setStatusAccess)
useAccess(story.id, "ChangeStoryAssignee", setAssigneeAccess)
.
.
.

Now, disable form controls if the user doesn't have the required permissions:

.
.
.
<Form.Group className="mb-3">
    <Form.Label>Estimate</Form.Label>
    <Form.Control disabled={!estimateAccess} type="number" value={estimate} onChange={handleEstimateChange} onBlur={handleEstimateBlur}/>
</Form.Group>
<Form.Group className="mb-3">
    <Form.Label>Status</Form.Label>
    <Form.Select disabled={!statusAccess} value={status} onChange={handleStatusChange}>
        <option value="todo">todo</option>
        <option value="busy">busy</option>
        <option value="done">done</option>
    </Form.Select>
</Form.Group>
<Form.Group className="mb-3">
    <Form.Label>Assignee</Form.Label>
    <Form.Select disabled={!assigneeAccess} value={assignee} onChange={handleAssigneeChange}>
    .
    .
    .

And add the StoryPermissions component to the same file:

function StoryPermissions(props) {
    const {story} = props

    return <>
        <AccessGuard resourceId={story.id} action="ReadStoryPermissions">
            <Permissions resourceId={story.id} changeAction="ChangeStoryPermissions"/>
        </AccessGuard>
    </>
}

In the 'Stories.js' file, wrap the CreateStory button on line 70 in an AccessGuard like this:

selectedStory
? <Story story={selectedStory} setSelectedStory={setSelectedStory} setStories={setStories}/>
: <AccessGuard resourceId={sprintCtx.sprint.id} action="CreateStory">
        <CreateStory setStories={setStories}/>
  </AccessGuard>

And disable the StoryButton element if the user doesn't have 'ReadStory' permission on the story:

function StoryButton(props) {
    const [readAccess, setReadAccess] = useState(false)
    useAccess(props.story.id, "ReadStory", setReadAccess)

    return <>
        <ListGroupItem
            disabled={!readAccess}
            .
            .
            .

That's it! You now have a fully permissioned app, congratulations!

PreviousSprintsNextREST API

Last updated 2 years ago

✍️