Scope
Spruce has the ability to allow multiple Organizations to signup for accounts. It also allows them to add Locations and People under those Organizations & Locations. SkillViews can be set to a Scope to ensure operations are only done at the current Organization or Location. Here are the scopes:
- Global
- All operations are happening at the platform level.
- This is the highest level of
Scopeand requires someone to have a global role. - Someone who has this role will still not have access to all the data under
OrganizationsandLocations.
- Organization
- All operations are happening at the ‘Organization’ level.
- Someone with an
OrganizationRolehas the sameRoleat allLocationsunder thatOrganization. Rolesare configured at anOrganizationlevel, but can be given toPeopleat aLocationlevel.- We would say they are
Scopedto thatOrganization.
- Location
- All operations are happening at the
Locationlevel. - Someone with a
LocationRolecan only see data at thatLocation. - We would say they are
Scopedto thatLocation.
- All operations are happening at the
- Employed
- This
Scopeapplies only toSkillViews. EventsuseRoleto determine access.- Is used in combination with
OrganizationandLocationScopes. - Ensures the
Personhas aRolebased on the following:OwnerGroup ManagerManagerTeammate
- This
Scope in Action
The video below is the locations.root SkillView. It has been Scoped to Organization and Employed. Any SkillView that has Scope will render the ToolBelt on the right that allows you to change the Scope (in this case, changing the current Organization).
ScopeFlag
The ScopeFlag type is an enum that is used to define the Scope of a SkillView. Here is the type (exported from @sprucelabs/heartwood-view-controllers):
export type ScopeFlag = 'location' | 'organization' | 'employed' | 'none';
Applying Scope to your SkillView
Test 1: Asserting your SkillView is scoped correctly
We’re going to start with a test that already has a SkillView ready to go and is available at this.vc.
import { AbstractSpruceFixtureTest } from '@sprucelabs/spruce-test-fixtures'
import { vcAssert } from '@sprucelabs/heartwood-view-controllers'
export default class RenderingARemoteCard extends AbstractSpruceFixtureTest {
private vc!: RootSkillViewController
protected async beforeEach() {
await super.beforeEach()
this.vc = this.views.Controller('eightbitstories.root', {})
}
@test()
protected async mustBeScopedByOrganization() {
vcAssert.assertSkillViewScopedBy(this.vc, ['organization'])
}
}
Production 1: Scoping your SkillView
We’re going to start with a test that already has a SkillView ready to go and is available at this.vc.
import {
AbstractSkillViewController,
ViewControllerOptions,
SkillView,
CardViewController,
ScopeFlag,
} from '@sprucelabs/heartwood-view-controllers'
export default class RootSkillViewController extends AbstractSkillViewController {
public static id = 'root'
protected cardVc: CardViewController
public constructor(options: ViewControllerOptions) {
super(options)
}
public getScope = () => ['organization'] as ScopeFlag[]
public render(): SkillView {
return {
layouts: [
{
cards: [],
},
],
}
}
}
Pulling Scope From a SkillView
The currenty Organization or Location can be pulled out of the Scope object passed to the load() lifecycle method of your SkillView.
Note: Even though the results to
getCurrentOrganization()andgetCurrentLocation()are optional, they will always be set according to theScopeof theSkillView.
import {
AbstractSkillViewController,
ViewControllerOptions,
SkillView,
SkillViewControllerLoadOptions,
ScopeFlag,
} from '@sprucelabs/heartwood-view-controllers'
export default class OrganizationDashboardSkillViewController extends AbstractSkillViewController {
public static id = 'organization-dashboard'
public constructor(options: ViewControllerOptions) {
super(options)
}
public getScope = () => ['organization'] as ScopeFlag[]
public async load(options: SkillViewControllerLoadOptions) {
const { scope } = options
//current organization in scope, will be set because we are scoped to organization
const organization = await scope.getCurrentOrganization()
console.log('Current Organization:', organization)
//current location in scope, will be empty because we are scoped to organization
const location = await scope.getCurrentLocation()
console.log('Current Location:', location)
}
public render(): SkillView {
return buildSkillViewLayout('big-left', {
leftCards: [this.detectionsCardVc.render()],
rightCards: [this.locationsCardVc.render()],
})
}
}
