
DayBack can help you filter your events by grouping Resources into Resource Folders. By creating folders and using them as a filter, you can view the availability of specific lists of resources at a glance. Using filters gives you a lot of flexibility, but what if you manage multiple calendars and need a quicker way to switch your filters to a different set of folders? One popular way would be to create bookmarks for specific views of your organization. DayBack can also be set up to automatically select specific resources when you click on a particular calendar.
This method is great if your workflow requires you to manage calendars for multiple teams. By creating a Custom App Action, you can automatically select only the specific resource folders that are relevant to a particular calendar you are viewing.
Example Organization
Suppose your organization has a Sales Support Team calendar and a Management Team calendar. You’ve organized your resources into 3 folders for your Sales Support Team, and 2 folders for your Management Team. You also have an additional folder for team members who work on both teams. You’d like each of your calendars to automatically select the resources in the relevant folders when you switch between calendars.

Since the Admin Staff folder is set up to be shared by both teams, clicking either the Sales Support Team calendar or the Management Team calendar should also load Admin Staff availability regardless of which calendar you have open.
See It In Action
This video shows how clicking on a calendar automatically selects the appropriate folder as an active filter.
Configuring SetSourceFilters.js Custom Action
By default, DayBack doesn’t change your filters when you select a calendar, but this is very easy to set up with a custom app action. To have DayBack filter events by resource folder when a user selects a particular calendar, you can install the SetSourceFilter.js custom app action. The action will run automatically after the user clicks on a calendar.
Configuring your Custom App Action:
Setting up the configuration for your organization is easy. You will need to change the following section of the JavaScript code. Here is the configuration we created for our example organization:
inputs.calendars = { 'Sales Support Team' : [ 'Service Techs', 'Jr Service Techs', 'Service Managers', 'Admin Staff' ], 'Management Team' : [ 'Sales Team', 'Campaign Managers', 'Admin Staff' ] };
It doesn’t matter which order you list your calendars and folders, so long as the folders are listed under the correct calendar. In the above example, note how the list of folders is unique to each calendar, but the Admin Staff folder appears twice, once for each calendar.
How to install the Custom App Action:
- Follow the Custom App Action installation instructions
- Select “After Source Selection” as your Action Type
- Set “Prevent default action” to No, and enable the action for App and for Shares
SetSourceFilter.js Source Code:
Paste the full code below in the JavaScript box and edit the configuration section to reflect your specific organization’s configuration:
// Set Source Filters V1.1 // Purpose: // Selects specific resource folders based on a sort selection // Action Type: After Source Selection // Prevent Default Action: No // More info on Before Event Save actions and objects here: // https://docs.dayback.com/article/140-custom-app-actions // Declare globals var options = {}; var inputs = {}; try { //----------- Configuration ------------------- // Seconds to wait to allow this action to run before reporting an error (set to 0 to deactivate) options.runTimeout = 8; // Define which Resource Folders should be selected when a Calendar is selected // for example, when the 'Management Team' calendar is selected, the // Sales Team, Campaign Managers, and Admin Staff Resource folders will be selected inputs.calendars = { 'Sales Support Team' : [ 'Service Techs', 'Jr Service Techs', 'Service Managers', 'Admin Staff' ], 'Management Team' : [ 'Sales Team', 'Campaign Managers', 'Admin Staff' ] }; //----------- End Configuration ------------------- } catch(error) { reportError(error); } //----------- The action itself: you may not need to edit this. ------------------- // Action code goes inside this function function run() { // validate configuration if (!validateConfiguration() ) { return confirmCallback(); } // determine which calendar we've selected var thisCalendar = params.data ? params.data.item : false; if (thisCalendar) { var name = thisCalendar.name; // if we've selected a mapped calendar then deselect the other mapped ones. if (inputs.calendars[thisCalendar.name] && thisCalendar.status.selected) { // determine which mapped calendars are selected var selected = selectedMapped(inputs.calendars); // deselect any selected ones that aren't the one we just clicked for (var i = 0; i < selected.length; i++) { if (selected[i].name !== name) { dbk.toggleCalendar(selected[i]); } } // update resource selection bases on calendar selection setResourceSelection(thisCalendar,inputs.calendars); dbk.resetResources(); } } return confirmCallback(); //----------- Action-specific fuctions ------------------- // configurtion validation helper function function validateConfiguration() { // make sure we have defined a list of calendars if (!inputs.calendars || typeof inputs.calendars !== 'object' || Object.keys(inputs.calendars).length === 0) { return reportError({ message: "Please configure a list of calendars"}); } var schedules = seedcodeCalendar.get('schedules'); var calendars = Object.keys(inputs.calendars); // Check if defined sources and resource folders are valid calendars.forEach((calendar, i) => { var resources = seedcodeCalendar.get('resources'); if (schedules.filter(schedule => schedule.name === calendar).length < 1) { return reportError({ message: "Calendar '" + calendar + "' is not a valid calendar"}); } for (var c = 0; c < inputs.calendars[calendar].length; c++) { if (resources.filter(rec => rec.name === inputs.calendars[calendar][c]).length < 1) { return reportError({ message: "The resource folder '" + inputs.calendars[calendar][c] + "' is not a valid resource folder"}); } } }); // config is valid return true; } // main function to set resource by calendar function setResourceSelection(thisCalendar,calendarList) { var resources = seedcodeCalendar.get('resources'); var selectedFolders = calendarList[thisCalendar.name]; var unselectedFolders = []; // iterate each calendar that is is being unselected to build unselected folders list for (var property in calendarList) { if (property != thisCalendar.name) { unselectedFolders = unselectedFolders.concat(calendarList[property]); } } // deselect all previous folders for (var r = 0; r < resources.length; r++) { for (var u = 0; u < unselectedFolders.length; u++) { if (resources[r].status.selected && resources[r].folderName === unselectedFolders[u]) { resources[r].status.selected = false; } } for (var s = 0; s < selectedFolders.length; s++) { if (!resources[r].status.selected && resources[r].folderName === selectedFolders[s]) { resources[r].status.selected = true; } } } } // helper function for returning an array of selected calendars that are mapped function selectedMapped(calendarList) { var calendars = seedcodeCalendar.get('schedules'); var selected = []; for (var i = 0; i <calendars.length; i++) { for (var mapping in calendarList ) { if (mapping == calendars[i].name && calendars[i].status.selected) { selected.push(calendars[i]); } } } return selected; } } // end run() //----------- Run function wrapper and helpers - you shouldn't need to edit below this line. ------------------- // Variables used for helper functions below var timeout; // Execute the run function as defined above try { if (!options.restrictedToAccounts || !options.restrictedToAccounts.length || (options.restrictedToAccounts && options.restrictedToAccounts.indexOf(inputs.account) > -1) ) { if (action.preventDefault && options.runTimeout) { timeoutCheck(); } run(); } else if (action.preventDefault) { confirmCallback(); } } catch(error) { reportError(error); } // Run confirm callback when preventDefault is true. Used for async actions function confirmCallback() { cancelTimeoutCheck(); if (action.callbacks.confirm) { action.callbacks.confirm(); } } // Run cancel callback when preventDefault is true. Used for async actions function cancelCallback() { cancelTimeoutCheck(); if (action.callbacks.cancel) { action.callbacks.cancel(); } } // Check if the action has run within the specified time limit when preventDefault is enabled function timeoutCheck() { timeout = setTimeout(function() { var error = { name: 'Timeout', message: 'The action was unable to execute within the allotted time and has been stopped' }; reportError(error, true); }, (options && options.runTimeout ? options.runTimeout * 1000 : 0) ); } function cancelTimeoutCheck() { if (timeout) { clearTimeout(timeout); } } // Function to report any errors that occur when running this action // Follows standard javascript error reporter format of an object with name and message properties function reportError(error) { var errorTitle = 'Error Running Custom Action'; var errorMessage = '<p>There was a problem running the action "<span style="white-space: nowrap">' + action.name + '</span>"</p><p>Error: ' + error.message + '.</p><p>This may result in unexpected behavior of the calendar.</p>'; if (action.preventDefault && timeout) { confirmCallback(); } else { cancelCallback(); } setTimeout(function() { utilities.showModal(errorTitle, errorMessage, null, null, 'OK', null, null, null, true, null, true); }, 1000); }
Curious about other app actions?
Visit our library of Custom App Actions to view all the cool stuff you can do with DayBack!
Leave a Reply