Node – Get Named Command Line Arguments

I am writing a small command line utility using Node and needed to get named arguments from the command line. A quick Google search led me down crazy complicated rabbit holes and (of course) a bunch of recommendations to just install npm modules.

There ain’t no way I’m installing an npm module to READ COMMAND LINE ARGUMENTS!

So I wrote a tiny function that gets command line arguments and turns them into an object. 10 lines is all you need in ES6.

function getArgs() {
  const args = process.argv.slice(2);
  let params = {};

  args.forEach(a => {
    const nameValue = a.split("=");
    params[nameValue[0]] = nameValue[1];

  return params;

Easy enough. Now if I call the script from the command line like this:

node myapp.js arg1=foo arg2=bar

I can transform the arguments to an object by calling:

const args = getArgs();

Which will give me the following object:

arg1: "foo",
arg2: "bar"

So now I can just do this:

// called using node myapp.js name=nick role="master of node"

const args = getArgs();
console.log(`${} is the ${args.role}`);

// which outputs "nick is the master of node"

I mean, that’s all there is to it. I’ll save my rant about the wasteland that is npm for another post.

Configuring Booked SSO with SAML

Booked comes with multiple Single Sign On plugins out of the box. There are many benefits to SSO over standard authentication. For administrators, having a single point of account credential and access administration is very valuable. If someone leaves the organization they don’t have to deactivate accounts in multiple systems. For your normal user, the benefit is not having to register and remember yet another set of application credentials.

In this post we’ll cover how to set up SSO with SAML.

Most SSO configurations for Booked are pretty straightforward – you just update the configuration options for the plugin. But SAML is different. SAML requires a 3rd party application called SimpleSAMLphp to be running on the same server as Booked.

Install SimpleSAMLphp

Our first step is to download the latest version of SimpleSAMLphp and install it on your web server. I recommend installing it outside of your publicly visible directories and set up a subdomain pointing to the www directory.

For example, if you install it to /home/username/simplesamlphp and you have Booked running out of /home/username/public_html/booked, then you’d create a subdomain such as pointing to /home/username/simplesamlphp/www. The reason we do this is because the only files which need to be publicly visible in SimpleSAMLphp are located in the www directory. Exposing more than that opens unnecessary security holes.

Configure SimpleSAMLphp

SimpleSAMLphp has a lot of configuration options. If you’re like me and far from an expert in SAML, it’s overwhelming. Luckily, since Booked is a Service Provider it doesn’t need anything special.

I’ll go through each of the settings that need to be updated individually. Please note that at the time of writing this post, the latest version of SimpleSAMLphp was 1.18.5. It’s possible that the names of the options will change in future versions.

Open up home/username/simplesamlphp/config/config.php with a text editor.

baseurlpath should be updated to the full path of the SimpleSAMLphp www directory. If you followed the above advice and created a subdomain, this should be something like

technicalcontact_email should be set to your email address (or anyone responsible for managing SSO integrations)

secretsalt should be set to any secure, random value.

auth.adminpassword should be set to any secure, random value. should be set to an array of domains that will participate in the SSO handshake. I use array(‘’, ‘’)

session.cookie.domain should be set to the wildcard subdomain of your primary domain. For example, I use should be set to true, assuming all traffic is sent over https.

store.type should be set to sql. This ensures that PHP sessions from Booked and sessions from SimpleSAMLphp do not conflict.

store.sql.dsn should be set to a writable location for the sqlite database. You must have SQLite support in PHP enabled for this to work. Alternatively, you can set up any PDO supported database to store session data. Since I use SQLite, I have this set to something like sqlite:/home/username/tmp/sqlitedatabase.sq3

Exchange Metadata

Now that we have the configuration set, we’ll need to exchange metadata.

The first thing to do is get the metadata XML from the Identity Provider that you’re integrating with. SimpleSAMLphp has a handy metadata XML conversion tool, which we’ll use to finish up our configuration.

Open the subdomain for SimpleSAMLphp in a browser ( was what I used). Click on the Federation tab, then the XML to SimpleSAMLphp metadata converter link. You’ll be prompted to enter the auth.adminpassword that you set in your config.php

Paste in the XML or, if you have it saved to a file, upload it. SimpleSAMLphp will output at least one PHP version of that metadata.

For each one of those, location the file with the same name in /home/username/simplesamlphp/metadata. The most common files to update will be saml20-idp-remote.php or shib13-idp-remote.php

Delete everything except the opening php tag, then paste in the output from SimpleSAMLphp.

Copy the value of the entityid (usually found on the 3rd line of that file) and open up /simplesamlphp/config/authsources.php. Find the idp setting, and paste the value of the entityid there.

Update SAML Configuration in Booked

Whew, almost done. The last few settings are in Booked.

First, open up /your-booked-directory/config/config.php, find the authentication setting in the plugins section and set the value to Saml.

$conf['settings']['plugins']['Authentication'] = 'Saml';

Open up /your-booked-directory/plugins/Authentication/Saml and copy Saml.config.dist.php to Saml.config.php. Open Saml.config.php in an editor.

simplesamlphp.lib should be updated to the root filesystem directory of SimpleSAMLphp. If you’re using the settings I described here, this would be /home/username/simplesamlphp.

simplesamlphp.config should be updated to the config filesystem directory for SimpleSAMLphp. In this case /home/username/simplesamlphp/config

Most of the remaining settings are attribute maps. SAML will send over user attributes, but often with obscure names. Booked needs to know which attribute maps to the proper user field in Booked.

There are only 2 absolutely required fields to map – username/userid and email. For example, if the username is being sent across in the SAML payload as urn:oid: you’d set simplesamlphp.username to this value like $conf[‘settings’][‘simplesamlphp.username’] = ‘urn:oid:’;

This is the same for all the other attributes. If you don’t know the attributes coming across then you can add the following line to plugins/Authentication/Saml/SamlUser.php as the first line in the constructor.

Log::Debug('Saml attributes are: %s', var_export($saml_attributes, true));

Enable Logging in Booked and try to log in. We’ll write out the attributes to the log file and you can copy the names into the Booked SAML configuration file.

Some Restrictions

A couple important notes with SAML enabled. The first is that you will no longer be able to log into Booked with any other credentials. There is no “back door” – so every authentication request will be routed through SAML.

The other restriction is that you will not be able to use any authenticated method from the API. SAML performs a series of browser redirects in order to complete the authentication process. When using the API you are not within the context of a browser, so authentication will fail.

Logging In

Once all the mapping is complete, you should be able to log into Booked via your organization’s federated log in page. Your users will no longer have to remember another set of credentials and your account management just got one step easier.

Social Distancing Features in Booked

Slowing the spread of COVID-19 is about the most important thing we can do as a society right now. I know that Booked is heavily used in laboratories and other organizations where working remotely may not be possible. I want to highlight a few features that can help reinforce social distancing in your lab or organization.


The most obvious one is capacity limits for resources. For any resource that is designed for a group of people (conference room, lab bench) you can set the maximum capacity to something small. This prevents more than a set number of people from participating in that reservation.

Buffer Times

Buffer times are perfect for enforcing time between reservations. This can assist with cleaning and disinfecting or simply help space people out and prevent unintended contact.

Maximum Reservation Duration

This is a simple rule that will prevent reservations over a certain duration. Combining this with capacity constraints can help limit people’s interactions.


Quotas are typically used to prevent over-booking by a single individual, but they can also be used to keep resources under-booked, reducing the sanitation burden.

You can also use quotas to ensure that resources are available to as many people as possible. For example, many people use Booked for appointment scheduling. If you have a COVID-19 response team or internal health team, this could be a way to make sure they’re available to as many people as possible.

Hosting and Support

Booked continues to be open source and completely free to anyone that wants it. You can download it here.

I have been offering hosting services for many years, which completely removes the burden of installation and support from your internal team. The first 30 days of hosting are free, with no absolutely no obligation or commitment of any kind.

I know that business is unpredictable right now and placing orders for new services is far down the list of priorities. I’m happy to work with your team on free trial extensions and flexible billing terms until things are back to normal.

Configuring Sonar with a Create React App in TypeScript

There are a ton of posts on StackOverflow and Medium and the rest of the internet on setting up SonarQube, but I couldn’t find a definitive guide on configuring it with a React web application (using react-scripts/create react app) written in TypeScript. Turns out that it’s not that hard once you know all the pieces that need to be pulled together.

This article was written in February, 2020. These are the versions of the different components I’m using. Your mileage may vary.

  • Yarn 1.2.1
  • Node 12.4.1
  • React 16.12.0
  • Sonar 7.9.2
  • TypeScript 3.7.5
  • Docker Desktop (Windows)
  • Docker 19.03.5
  • react-scripts 3.3.0
  • sonarqube-scanner 2.5.0
  • jest-sonar-reporter 2.0.0

First of all, I’m going to assume nothing is ejected from the CRA configuration and that you have a working application written in TypeScript. For example if you cannot successfully run npm test or yarn test then this guide will not work. I’m also assuming you’re comfortable with Docker.


Get SonarQube up. I used Docker for this because it was the quickest way.

First, set your memory allocation for Docker to at least 4GB for the Sonar container to be able to run correctly. ElasticSearch needs this, I guess.

Next, I used this docker-compose file from Just docker-compose up. This will start a SonarQube instance using Postgres on http://localhost:9000

Open that URL in a browser, log in with admin/admin, and make sure everything is looking good. There should be a wizard that guides you through creating a security token for your user. If not, you can always do so in Administration > Security and creating a Sonar user just for project analysis (this is probably a good idea anyway).

Analyzing your React application with Sonar


You’ll need a couple tools to simplify this process. Install sonarqube-scanner and jest-sonar-reporter into your React project using either yarn or npm. Save it as a development dependency.

yarn add -D sonarqube-scanner
yarn add -D jest-sonar-reporter

Sonar Configuration

I was expecting to do a bunch of configuration within Sonar itself, but it can all be contained within your React project. In the root of your project (at the same level as your package.json) create a file named sonar-project.js with the following contents. I’ll go over the details next.

const sonarqubeScanner = require("sonarqube-scanner");
    serverUrl: "http://localhost:9000",
    token: "YOUR-TOKEN-HERE",
    options: {
      "sonar.sources": "./src",
      "sonar.exclusions": "**/__tests__/**",
      "sonar.tests": "./src/__tests__",
      "sonar.test.inclusions": "./src/__tests__/**/*.test.tsx,./src/__tests__/**/*.test.ts",
      "sonar.typescript.lcov.reportPaths": "coverage/",
      "sonar.testExecutionReportPaths": "reports/test-report.xml",
  () => {},

Each of these settings is a standard Sonar configuration property, but they weren’t immediately clear to me.

  • serverUrl is the URL to your SonarQube instance
  • token is the security token assigned to your Sonar user
  • sonar.sources is the base directory for all of your code. This is where your React application lives (in my case the *.tsx files). By default, CRA puts __tests__ within the src directory. We’ll deal with that next.
  • sonar.exclusions is everything you do not want Sonar to analyze. The most important one for me is that we don’t want to be analysis on our tests. In fact, if there is overlap between sonar.sources and sonar.tests then Sonar will throw an indexing error. So I exclude anything in any __tests__ folder.
  • sonar.tests is the location of all of your tests. By default, CRA puts this in /src/__tests__
  • sonar.test.inclusions is a comma separated list of all files that should be treated as test files. I have a mix of .tsx and .ts tests, but they all follow the standard jest pattern of testname.test.ts*
  • sonar.typescript.lcov.reportPaths is the path to the test coverage output file from jest. By default this will be coverage/
  • sonar.testExecutionReportPaths is the path to the jest-sonar-reporter output file. We’ll configure this next.

Test Coverage Configuration

The first thing to note is that we use the sonar.typescript.lcov.reportPaths property in our sonar-project.js configuration, not the javascript property.

By default jest-sonar-reporter outputs a file called test-report.xml to the root directory. I don’t like littering that directory with unrelated files, so I added this to the end of my package.json file in order to put the report in a reports directory.

"jestSonar": {
  "reportPath": "reports",
  "reportFile": "test-report.xml",
  "indent": 4

The last thing you need to do is tell react-scripts to use this test report generator rather than the default. I assume you have something like this in your package.json scripts definition.

"test": "react-scripts test --silent --env=jsdom"

We need to change that so we process the results in a Sonar-friendly format

"test": "react-scripts test --silent --env=jsdom --coverage --testResultsProcessor jest-sonar-reporter"

To be honest, I do one more thing so that we’re not watching tests, so my test script is, which tells react-scripts that we’re running in a continuous integration mode and should not watch.

"test": "cross-env CI=true react-scripts test --silent --env=jsdom --coverage --testResultsProcessor jest-sonar-reporter",

Running Sonar Analysis

We’ll add another script to our package.json file to initiate the Sonar analysis.

"sonar": "node sonar-project.js"

At this point we have all of our configuration done and just need to run everything.

First run your tests

yarn test

This should run all of your tests with coverage. You’ll have files in /coverage and /reports.

Next, run your sonar analysis

yarn sonar

This will take a couple minutes, depending on the size of your project. But when it’s complete, refresh your Sonar projects and you should see your project show up. By default, it will use the name defined in your package.json file.

Continuous Integration

If you wanted to (and why wouldn’t you) integrate this into your CI environment so every push triggers a Sonar analysis, you can just add a build step that invokes yarn sonar after your test stage.

Other Projects

I’m using this base set of instructions for all of my TypeScript based projects. The only thing that really changes is the location of source, tests, and the inclusion/exclusion list. For example, in my api, where I have __tests_ at the same level as src (instead of nested within), my sonar-project.js looks like this.

const sonarqubeScanner = require("sonarqube-scanner");

    serverUrl: "http://localhost:9000",
    token: "MY-TOKEN",
    options: {
      "sonar.sources": "./src",
      "sonar.tests": "./__tests__",
      "sonar.test.inclusions": "./__tests__/**/*.test.ts",
      "sonar.typescript.lcov.reportPaths": "coverage/",
      "sonar.testExecutionReportPaths": "reports/test-report.xml",
  () => {},

Some Cleanup

This whole thing will create some cruft in your project. You want to ignore /.scannerwork, /coverage, /reports from Git.

Booked Tips: Limiting Resource Usage

Booked is configurable in so many ways. In this article we’ll review a few ways to control when, how, and by whom resources are booked.

Let’s start with some of the simple settings. In Application Management > Resources you are able to control broad settings on when resources can be reserved.

Resource Access Settings

The Access section of each resource lets you control the following: How far in advance a resource can be booked, how far in advance an existing reservation for that resource can be updated, and how far in advance an existing reservation can be deleted.

By default, this is all unrestricted. To set any of these values, uncheck and set the notification time. For example, to force a 6 hour lead time on all reservations you would use the following setting. Any attempt to book this resource within 6 hours of the start time will be denied.

To limit how far into the future a reservation can be made, you would use the something like the following setting. This would prevent any reservations more than 30 days in the future.

Resource Duration Settings

To limit (or force) how long a reservation must be, you can change the minimum and maximum duration settings. For example, the following settings would force reservations to be at least 4 hours but no more than 8 hours in duration.


Quotas are a powerful, though somewhat complex, way to control resource usage. Using Quotas you can restrict usage based on cumulative time booked or cumulative number of reservations over a given period of time. To get started, navigate to Application Management > Quotas.

So if you wanted to limit users of a specific group to only be able to book 5 hours per week for a specific resource, you can set up that quota rule.

There are few more advanced features.

By default a rule will include past reservations, but you can ignore anything in the past if you want. So let’s use that same 5 hours per week rule as above and assume today is Wednesday. If we’re including past reservations and I had an hour booked on Monday and Tuesday each, I would only be able to book 3 more hours this week. If we’re ignoring past reservations, then I can keep booking up to 5 more hours for the rest of this week.

You can also enforce quotas on only certain days or times. This is especially helpful if certain resources tend to be very popular at peak times. So if you wanted to only allow people to book 30 minute reservations between 10am and 2pm on weekdays, you would set up something like this.

Quota rules are cumulative, as well, so you can “stack” them. Meaning you can limit people to no more than 10 hours per week and no more than 2 hours per day. It’s a very powerful way to control how much time people can reserve.

Hosting and Support

Did you know that I offer professional hosting and support for Booked? You can set up a free trial in minutes and get unlimited support.

This article was written on November 20, 2019, so check your documentation for the latest options.

Booked Tips: Showing Events on Your Website

Booked includes a lot of features that you may not know about. In this article we’ll talk about a simple way to display reservations from Booked on your website.

If you just want to display reservations from Booked to your guests without needing them to navigate to the application and browse the schedule, there is a simple JavaScript snippet you can include on your website.

The first thing you’ll need to do is make schedules or resources public. Anything that has not been marked as public will not be displayed.

The next task is a little bit more technical. Servers have a security feature that prevent loading JavaScript from different domains (Cross Origin Resource Sharing). You’ll need to tell your web server that it’s OK to serve this content. In Apache you can accomplish this by adding the following line to your .htaccess file.

Header Set Access-Control-Allow-Origin "*"

Once that’s done you’re ready to add the snippet to your website. If you open Help and go to the section titled “Embedding a Calendar Externally” we give you the full snippet. It will look something like this.

<script async src="" crossorigin="anonymous"></script>

You can drop this anywhere in your HTML body content and we’ll load reservations using the default snippet settings.

The snippet displays a very simple HTML component that isn’t the prettiest thing to look at.

My feeling is that you’ll want to fit the component in with your website’s theme, so you can take advantage of the CSS classes we provide to style it however you like. All of the CSS class names start with booked-

Customizing the Contents

There are multiple options you can include on the script to customize what’s shown.

NamePossible ValuesDefaultDetails
typeagenda, week, monthagendaControls the view that is shown
formatdate, title, user, resourcedateControls the information shown in the reservation box. Multiple options can be passed. For example, to show date and title request date,title
dAny digit between 1 and 307Limits the number of days shown for the agenda view
sidAny schedule public IDAll schedulesLimits the reservations shown to a specific schedule
ridAny resource public IDAll resourcesLimits the reservations shown to a specific resource

For example, to show the month view for schedule 123 and the date and title for reservations, you would use the following.

<script async src="https://your-booked-url/Web/scripts/embed-calendar.js?type=month&sid=123&format=date,title" crossorigin="anonymous"></script>

Hosting and Support

Did you know that I offer professional hosting and support for Booked? You can set up a free trial in minutes and get unlimited support.

This article was written on November 15, 2019, so check your documentation for the latest options.

Booked Tips: Custom Attributes

Booked includes a lot of features that you may not know about. In this article we’ll talk about extending Booked to gather additional information from your users. For example, you may need to know the configuration of seating for a room, or mileage out and mileage in for fleet management.

Reservation Custom Attributes

Custom Attributes provide a powerful way to make Booked fit the way your organization works. We’ll first look at reservation attributes, which are the most common and useful type of custom attribute. Open Application Management > Custom Attributes to get started. Click Add an Attribute and you’ll get a form like this

We offer a few different options for the types of attributes to add. Single Line Textbox, Multiple Line Textbox, Select List, Checkbox, and Date Time. Just pick the type and set a Display Label. Here’s what a Select List may look like on the reservation screen.

Every time a new reservation is made or updated, the user will be prompted for these additional pieces of data.

Let’s Get Crazy

We just covered the most basic reservation custom attributes, but we can do a lot more with custom attributes.

An attribute can be required or optional. Ok, that’s not so crazy, but it’s useful.

An attribute can also be used for Admins Only, which means regular users will never see it, but admins will. This is perfect for capturing internal-only information that the user is not able to provide or should not see.

Private attributes are a lot like admin only attributes, but the reservation owner will also have access to it. Again, this is great for confidential information that the user provides.

Collect In Specific Cases is an interesting option that only adds the custom attribute in specific scenarios.

Using this option you can add custom attributes to the reservation screen only if the reservation is being made by a specific user or if the reservation includes a specific resource. You can almost think of this as a user or resource custom attribute where the values are provided as part of the reservation.

An example use case for this may be a unique characteristic of a conference room. Let’s say only rooms of type “Auditorium” have a podium and you need to know whether or not a microphone is needed. If you pick the Auditorium resource type in the Collect In Specific Cases then users will only see this if they’re booking an Auditorium room.

Other Attribute Categories

You can also add additional attributes to Users, Resources, and Resource Types.

These are pretty self explanatory. User attributes are entered on registration, user profiles, and within the admin tools. Resource attributes are entered on the resource management screen. Resource Type attributes also show up on the resource management screen, but are limited to resources of a specific type.

The options for creating custom attributes here are similar but not as extensive as Reservation custom attributes. One difference for these types of attributes is that you can choose which specific items the attributes apply to. You can have completely different attributes for different resources, for example.

But wait, there’s more…

Custom attributes automatically get included in reports, so you can easily export that information and build custom data views.

Resource custom attributes show up as filter options on the Schedule and Find a Time pages.

You can color code reservations based on custom attribute values. So if you have a select list of options, you can make all reservations with option 1 selected red and option 2 selected can be blue. Perfect for at-a-glance categorization.

You can also show reservation custom attribute values in the reservation label on the schedule page.

So instead of (or in addition to) the owner name or reservation title, you can show user-provided information. To do this, first go find the Id of the attribute you want to include.

Then go into Application Configuration and change the reservation.label setting to be {att#} where # is the Id of the attribute. Alternatively, you can include all attributes by setting this to {reservationAttributes}

Hosting and Support

Did you know that I offer professional hosting and support for Booked? You can set up a free trial in minutes and get unlimited support.

This article was written on November 6, 2019, so check your documentation for the latest options.

Booked Tips: Monitor Display

Booked includes a lot of features that you may not know about. In this article we’ll talk about the monitor display, which is perfect for showing reservation information on a big monitor for all to see. Some good uses are waiting rooms, a shared space or common area, or at reception.

This view has a few options, but by default you’ll see a grid schedule view of the default schedule. It will look something like this.

You can change this to show different schedules, different resources, or a list instead of a grid.

To get the monitor display view, first go to Application Configuration and set view.schedules to true. Then open a browser and navigate to https://your-booked-url/monitor-display.php

That’s it! This is a simple way to broadcast the real-time availability of resources to a common area.

Hosting and Support

Did you know that I offer professional hosting and support for Booked? You can set up a free trial in minutes and get unlimited support.

This article was written on November 4, 2019. Check your documentation for the latest options.

Booked Tips: Emailing Users

Booked includes a lot of features that you may not know about. In this article we’ll talk about the capability to email Booked users.

There are lots of times when you may need to send a notification to Booked users. Maybe a piece of equipment is unexpectedly unavailable or there is a change in booking policy.

Booked announcements let you post these messages in the application and also gives you the option to email the message to users. Open Application Management > Announcements to post something.

You can limit the audience of announcements with a few simple options. Click the More Options link.

Here you can slim down who an announcement will be seen by or sent to, if you’re emailing it. You can limit it to certain groups of users. You can also limit it to users who have permission to certain resources (this is especially useful when posting resource-specific announcements). You’ll also find the Send as Email option here.

You can also send (or resend) announcements that have already been posted.

Hosting and Support

Did you know that I offer professional hosting and support for Booked? You can set up a free trial in minutes and get unlimited support.

This article was written on November 4, 2019. Check your documentation for the latest options.

Booked Tips: Setting up Administrators

Booked is configurable in so many ways. In this article we’ll review how to set up multiple levels of administration.

Most of the time organizations can get away with the single administrator that is the default in Booked. The first user to register gets full administrative rights for the whole application. So they can create resources, manage reservations, control configuration settings, and so on.

This is a powerful set of permissions and it should be limited who gets them. If you do want to add users to the application administrator role, you have two options.

The first is to open Application Configuration and add the other users’ email addresses to the setting – just add a space or comma between each email address.

The second option is the same way you can add lower-privileged administrators, as well.

First, create a new group in Application Management > Groups. Then change the roles for the group to include Application Admin

Finally, add users to this group. Every user added will have full application administrator rights.

Other Types of Administrators

Booked has multiple levels of administration to allow certain people to do things like manage a set of resources or update user details for a set of users. These are Group Admins, Resource Admins, and Schedule Admins.

Group Admins

These users can update user details and manage reservations for specific users. To set them up, follow the same steps as for Application Admins, except choose Group Admin as the role.

Next we need to set the users that these admins can manage. To do this, create another group (I created one called Users), then set the Group Administrator to the admin group.

Now every user in the Users group can be managed by users in the Group Administrators group.

Resource Admins

Users in a Resource Admin group can manage resource information and reservations for a set of resources. To set them up, follow the same steps as for Application Admins, except choose Resource Admin as the role.

Next we need to set the resources that these admins can manage. Click the drop down in the Roles column, then pick the Resources option. Finally, check off all the resources that you’d like this group to be able to manage.

Schedule Admins

Users in a Schedule Admin group have all the same privileges as resource admins, but for all resources on a schedule. They also have management rights for the schedule. To set them up, follow the same steps as for Application Admins, except choose Schedule Admin as the role.

Next we need to set the resources that these admins can manage. Click the drop down in the Roles column, then pick the Schedules option. Finally, check off all the schedules that you’d like this group to be able to manage. Remember – they will be administrators for all of the resources on those schedules.

Hosting and Support

Did you know that I offer professional hosting and support for Booked? You can set up a free trial in minutes and get unlimited support.

This article was written on November 4, 2019, so check your documentation for the latest options.