@servicenow/sdk
Version:
ServiceNow SDK
386 lines (305 loc) • 12.1 kB
Markdown
---
tags: [workspace, dashboard, list-menu, ux, crud, navigation, workspace-configuration]
---
# Creating Workspaces Guide
Guide for creating ServiceNow Workspaces -- complete out-of-the-box solutions for managing business entities through standardized CRUD workflows. A workspace automatically generates a dashboard page, list management views, and detailed forms following ServiceNow's standard UX patterns.
## When to Use
- When creating new workspaces
- When the user asks about workspace configuration or best practices
- When building a full business process interface with dashboard, list management, and detail forms
## What is a Workspace?
A Workspace automatically generates a complete set of pages for managing a business entity:
- **Dashboard Page**: Overview dashboard with key metrics and recent activity
- **List Page**: Searchable, filterable table view with bulk operations
- **Detail/Form Page**: Full CRUD form with related records and actions
## Instructions
### Step 1: Understand the Requirement
- Identify the required tables.
- First, check whether they already exist on the platform.
- If not, look for them within the project.
- Create new tables only if they cannot be found in either location.
- Gather details about the tables' columns.
### Step 2: Configure the UX List Menu
Create a `UxListMenuConfig` inside `list-menu.now.ts` defining the navigation structure and list views.
### Step 3: Configure the Workspace
Create a `Workspace` in `workspace.now.ts`:
- Ensure you also create an ACL to secure the workspace route.
- Associate the UX List Menu configuration to the workspace.
### Step 4: Configure the Dashboard (Mandatory)
Create a `Dashboard` inside `dashboard.now.ts`:
- Associate the dashboard to the workspace via visibilities.
- The dashboard is mandatory for the workspace to function correctly.
### Step 5: Verify Integration
- Ensure the `UxListMenuConfig` is properly referenced in the workspace.
- Verify that the workspace is referenced in dashboard visibilities.
- Confirm ACL field matches workspace path pattern: `{path}.*`
- Check that all roles are properly defined and referenced.
### Step 6: Build, Install, and Provide Summary
After building and installing, read `src/fluent/generated/keys.ts` to extract the actual sys_id from `sys_ux_page_registry` for the workspace. Provide the user with:
- A clickable URL to access the workspace: `/now/{path}/{landingPath}`
- A clickable URL to edit in UI Builder: `/now/builder/ui/experience/{workspace_sys_id}`
## File Organization
```
src/
fluent/
workspaces/
incident-tracker/
workspace.now.ts
list-menu.now.ts
dashboard.now.ts
```
## Workspace URL Structure
```
/now/{path}/{landingPath}
```
If `path: 'my-example'`, the URL is `/now/my-example/home` (landingPath defaults to `home`).
---
## Workspace API Reference
### Workspace Properties
For the full property reference, see the `workspace-api` topic.
### Workspace Example
```typescript fluent
import { Workspace, UxListMenuConfig, Acl, Applicability, Role } from '@servicenow/sdk/core';
// 1. Define roles
const userRole = Role({
$id: Now.ID['asset_workspace_user_role'],
name: 'x_snc_asset.user',
containsRoles: ['canvas_user'],
});
// 2. Define applicability
const assetApplicability = Applicability({
$id: Now.ID['asset_applicability'],
name: 'Asset Management Users',
roles: [userRole],
});
// 3. Create list configuration (see UxListMenuConfig section)
const assetListConfig = UxListMenuConfig({ /* ... */ });
// 4. Create workspace
export const assetWorkspace = Workspace({
$id: Now.ID['asset_management_workspace'],
title: 'Asset Management',
path: 'asset-management',
tables: ['alm_asset', 'cmdb_ci', 'user'],
listConfig: assetListConfig,
});
// 5. Create ACL -- field MUST match workspace path + .*
Acl({
$id: Now.ID['asset_management_workspace_ACL'],
localOrExisting: 'Existing',
type: 'ux_route',
operation: 'read',
roles: ['x_snc_asset.user'],
table: 'now',
field: 'asset-management.*',
});
```
---
## UxListMenuConfig API Reference
Defines navigation structure and list views for workspaces -- categories, lists, and role-based visibility.
### UxListMenuConfig Properties
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `$id` | `Now.ID[string]` | Yes | Unique identifier |
| `name` | `string` | Yes | Name of the list configuration |
| `description` | `string` | No | Description |
| `active` | `boolean` | No | Whether active (default: `true`) |
| `categories` | `UxListCategory[]` | No | Array of categories |
### UxListCategory Properties
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `$id` | `Now.ID[string]` | Yes | Unique identifier |
| `title` | `string` | Yes | Display title in navigation |
| `order` | `number` | No | Sort order (lower = first) |
| `lists` | `UxList[]` | Yes | Array of lists |
### UxList Properties
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `$id` | `Now.ID[string]` | Yes | Unique identifier |
| `title` | `string` | Yes | Display title |
| `table` | `string` | Yes | ServiceNow table name |
| `columns` | `string` | No | Comma-separated column names |
| `condition` | `string` | No | Encoded query filter |
| `order` | `number` | No | Sort order within category |
| `applicabilities` | `ListApplicability[]` | No | Role-based visibility |
### Encoded Query Patterns
```typescript fluent
condition: 'active=true^EQ' // Active records
condition: '' // All records
condition: 'assigned_toDYNAMIC90d1921e5f510100a9ad2572f2b477fe^EQ' // Assigned to current user
condition: 'priority=1^ORpriority=2' // High priority
```
### UxListMenuConfig Example
```typescript fluent
const listConfig = UxListMenuConfig({
$id: Now.ID['itsm_workspace_list_config'],
name: 'ITSM Workspace List Configuration',
categories: [
{
$id: Now.ID['incidents_category'],
title: 'Incidents',
order: 10,
lists: [
{
$id: Now.ID['incidents_open'],
title: 'Open',
order: 10,
condition: 'active=true^EQ',
table: 'incident',
columns: 'number,short_description,priority,state',
applicabilities: [{
$id: Now.ID['incidents_open_applicability'],
applicability: userApplicability,
}],
},
{
$id: Now.ID['incidents_all'],
title: 'All',
order: 20,
condition: '',
table: 'incident',
columns: 'number,short_description,priority,state',
applicabilities: [{
$id: Now.ID['incidents_all_applicability'],
applicability: userApplicability,
}],
},
],
},
],
});
```
---
## Dashboard API Reference
The Dashboard fluent plugin defines the landing page for workspaces. Dashboards are organized into tabs containing widgets.
### Dashboard Properties
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `$id` | `Now.ID[string]` | Yes | Unique identifier |
| `name` | `string` | Yes | Display name |
| `tabs` | `DashboardTab[]` | Yes | Array of tabs |
| `visibilities` | `DashboardVisibility[]` | Yes | Links dashboard to workspaces |
| `permissions` | `DashboardPermission[]` | Yes | Access control (can be empty) |
### Widget Properties
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `$id` | `Now.ID[string]` | Yes | Unique identifier |
| `component` | `string` | Yes | Visualization type |
| `componentProps` | `object` | Yes | Component configuration |
| `height` | `number` | Yes | Height in grid units |
| `width` | `number` | Yes | Width in grid units |
| `position` | `{x, y}` | Yes | Grid position |
### Grid Layout System
Dashboards use a **48-point grid**. Common layouts:
- **Full width**: `{ width: 48, position: { x: 0, y: 0 } }`
- **Three columns**: widths 14, 17, 17 at x positions 0, 14, 31
### Widget Component Types
**Visualizations:**
| Component | Description | Data Type |
|-----------|-------------|-----------|
| `single-score` | Single metric display | Simple |
| `vertical-bar` | Vertical bar chart | Group |
| `horizontal-bar` | Horizontal bar chart | Group |
| `line` | Line chart | Trend |
| `donut` | Donut chart | Group |
| `pie` | Pie chart | Group |
| `area` | Area chart | Trend |
| `dial` | Dial gauge | Simple |
**Supporting widgets:** `heading`, `rich-text`, `image`.
### Data Type Requirements
- **Simple** (single-score, dial, gauge): requires `dataSources` and `metrics` only.
- **Group** (vertical-bar, donut, pie): requires `dataSources`, `metrics`, and `groupBy`.
- **Trend** (line, area, column): requires `dataSources`, `metrics`, and `trendBy`.
### Dashboard Example
```typescript fluent
import { Dashboard } from '@servicenow/sdk/core';
Dashboard({
$id: Now.ID['incident_dashboard'],
name: 'Incident Dashboard',
tabs: [{
$id: Now.ID['overview_tab'],
name: 'Overview',
widgets: [
{
$id: Now.ID['open_incidents_widget'],
component: 'single-score',
componentProps: {
dataSources: [{
label: 'Incident', sourceType: 'table',
tableOrViewName: 'incident', filterQuery: '',
id: 'data_source_1',
}],
headerTitle: 'Open Incidents',
metrics: [{
dataSource: 'data_source_1', id: 'metric_1',
aggregateFunction: 'COUNT', axisId: 'primary',
}],
},
height: 14, width: 14, position: { x: 0, y: 0 },
},
{
$id: Now.ID['incidents_by_priority_widget'],
component: 'vertical-bar',
componentProps: {
dataSources: [{
label: 'Incident', sourceType: 'table',
tableOrViewName: 'incident', filterQuery: '',
id: 'data_source_1',
}],
headerTitle: 'Incidents by Priority',
metrics: [{
dataSource: 'data_source_1', id: 'metric_1',
aggregateFunction: 'COUNT', axisId: 'primary',
}],
groupBy: [{
groupBy: [{ dataSource: 'data_source_1', groupByField: 'priority' }],
maxNumberOfGroups: 10, showOthers: false,
}],
sortBy: 'value',
},
height: 14, width: 17, position: { x: 14, y: 0 },
},
],
}],
visibilities: [{
$id: Now.ID['dashboard_visibility'],
experience: assetWorkspace,
}],
permissions: [],
});
```
---
## List API Reference
Configure lists (`sys_ui_list`) and their views.
| Name | Type | Description |
|------|------|-------------|
| `table` | String | Required. Table name for the list. |
| `view` | Reference | Required. UI view identifier or `default_view`. |
| `columns` | ListElement[] | Required. Array of column definitions. |
| `parent` | TableName | Parent table for related lists. |
### List Element
| Field | Type | Mandatory | Description |
|-------|------|-----------|-------------|
| `element` | string | Yes | Field name (supports dot walking) |
| `position` | number | No | Display position (defaults to array order) |
```typescript fluent
import { List } from '@servicenow/sdk/core';
const myList = List({
table: 'cmdb_ci_server',
view: app_task_view,
columns: [
{ element: 'name', position: 0 },
{ element: 'business_unit', position: 1 },
],
});
```
## Troubleshooting
### Dashboard Not Appearing
- Verify `visibilities` references the correct workspace.
- Confirm the workspace URL pattern is correct.
### Lists Not Appearing
- Check `active` is true for both category and list.
- Verify applicability includes the user's roles.
- Ensure `listConfig` is referenced in the workspace.
### Workspace Not Accessible
- Check ACL field matches `{workspace.path}.*` exactly.
- Verify users have required roles.