UI styling improvements: dashboard headers and navigation
- Restore blue PageHeader on Dashboard (/app-components) - Update homepage (/) with subtle header design without blue bar - Add uniform PageHeader styling to application edit page - Fix Rapporten link on homepage to point to /reports overview - Improve header descriptions spacing for better readability
This commit is contained in:
634
docs/JIRA-ASSETS-SYNC-REFACTOR-PLAN-2025-01-21
Normal file
634
docs/JIRA-ASSETS-SYNC-REFACTOR-PLAN-2025-01-21
Normal file
@@ -0,0 +1,634 @@
|
||||
# Cursor AI Prompt: Jira Assets Schema Synchronization
|
||||
|
||||
## Context
|
||||
|
||||
This application syncs Jira Assets (Data Center) data to a local database with a generic structure. Your task is to review, implement, and/or modify the schema synchronization feature that fetches the complete Jira Assets configuration structure.
|
||||
|
||||
## Objective
|
||||
|
||||
Implement or verify the schema sync functionality that extracts the complete Jira Assets schema structure using the REST API. This includes:
|
||||
- Object Schemas
|
||||
- Object Types (with hierarchy)
|
||||
- Object Type Attributes (field definitions)
|
||||
|
||||
**Note:** This task focuses on syncing the *structure/configuration* only, not the actual object data.
|
||||
|
||||
---
|
||||
|
||||
## API Reference
|
||||
|
||||
### Base URL
|
||||
```
|
||||
{JIRA_BASE_URL}/rest/assets/1.0
|
||||
```
|
||||
|
||||
### Authentication
|
||||
- HTTP Basic Authentication (username + password/API token)
|
||||
- All requests require `Accept: application/json` header
|
||||
|
||||
---
|
||||
|
||||
## Required API Endpoints & Response Structures
|
||||
|
||||
### 1. List All Schemas
|
||||
```
|
||||
GET /rest/assets/1.0/objectschema/list
|
||||
```
|
||||
|
||||
**Response Structure:**
|
||||
```json
|
||||
{
|
||||
"objectschemas": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "IT Assets",
|
||||
"objectSchemaKey": "IT",
|
||||
"status": "Ok",
|
||||
"description": "IT Asset Management Schema",
|
||||
"created": "2024-01-15T10:30:00.000Z",
|
||||
"updated": "2024-01-20T14:45:00.000Z",
|
||||
"objectCount": 1500,
|
||||
"objectTypeCount": 25
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Fields to Store:**
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| id | integer | Primary identifier |
|
||||
| name | string | Schema name |
|
||||
| objectSchemaKey | string | Unique key (e.g., "IT") |
|
||||
| status | string | Schema status |
|
||||
| description | string | Optional description |
|
||||
| created | datetime | Creation timestamp |
|
||||
| updated | datetime | Last modification |
|
||||
| objectCount | integer | Total objects in schema |
|
||||
| objectTypeCount | integer | Total object types |
|
||||
|
||||
---
|
||||
|
||||
### 2. Get Schema Details
|
||||
```
|
||||
GET /rest/assets/1.0/objectschema/:id
|
||||
```
|
||||
|
||||
**Response Structure:**
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "IT Assets",
|
||||
"objectSchemaKey": "IT",
|
||||
"status": "Ok",
|
||||
"description": "IT Asset Management Schema",
|
||||
"created": "2024-01-15T10:30:00.000Z",
|
||||
"updated": "2024-01-20T14:45:00.000Z",
|
||||
"objectCount": 1500,
|
||||
"objectTypeCount": 25
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Get Object Types (Flat List)
|
||||
```
|
||||
GET /rest/assets/1.0/objectschema/:id/objecttypes/flat
|
||||
```
|
||||
|
||||
**Response Structure:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 10,
|
||||
"name": "Hardware",
|
||||
"type": 0,
|
||||
"description": "Physical hardware assets",
|
||||
"icon": {
|
||||
"id": 1,
|
||||
"name": "Computer",
|
||||
"url16": "/rest/assets/1.0/icon/1/16",
|
||||
"url48": "/rest/assets/1.0/icon/1/48"
|
||||
},
|
||||
"position": 0,
|
||||
"created": "2024-01-15T10:30:00.000Z",
|
||||
"updated": "2024-01-20T14:45:00.000Z",
|
||||
"objectCount": 500,
|
||||
"parentObjectTypeId": null,
|
||||
"objectSchemaId": 1,
|
||||
"inherited": false,
|
||||
"abstractObjectType": false
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "Computer",
|
||||
"type": 0,
|
||||
"description": "Desktop and laptop computers",
|
||||
"icon": {
|
||||
"id": 2,
|
||||
"name": "Laptop",
|
||||
"url16": "/rest/assets/1.0/icon/2/16",
|
||||
"url48": "/rest/assets/1.0/icon/2/48"
|
||||
},
|
||||
"position": 0,
|
||||
"created": "2024-01-15T10:35:00.000Z",
|
||||
"updated": "2024-01-20T14:50:00.000Z",
|
||||
"objectCount": 200,
|
||||
"parentObjectTypeId": 10,
|
||||
"objectSchemaId": 1,
|
||||
"inherited": true,
|
||||
"abstractObjectType": false
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Fields to Store:**
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| id | integer | Primary identifier |
|
||||
| name | string | Object type name |
|
||||
| type | integer | Type classification (0=normal) |
|
||||
| description | string | Optional description |
|
||||
| icon | object | Icon details (id, name, url16, url48) |
|
||||
| position | integer | Display position in hierarchy |
|
||||
| created | datetime | Creation timestamp |
|
||||
| updated | datetime | Last modification |
|
||||
| objectCount | integer | Number of objects of this type |
|
||||
| parentObjectTypeId | integer/null | Parent type ID (null if root) |
|
||||
| objectSchemaId | integer | Parent schema ID |
|
||||
| inherited | boolean | Whether attributes are inherited |
|
||||
| abstractObjectType | boolean | Whether type is abstract (no direct objects) |
|
||||
|
||||
---
|
||||
|
||||
### 4. Get Object Type Details
|
||||
```
|
||||
GET /rest/assets/1.0/objecttype/:id
|
||||
```
|
||||
|
||||
**Response Structure:** Same as individual item in the flat list above.
|
||||
|
||||
---
|
||||
|
||||
### 5. Get Object Type Attributes
|
||||
```
|
||||
GET /rest/assets/1.0/objecttype/:id/attributes
|
||||
```
|
||||
|
||||
**Response Structure:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 100,
|
||||
"objectType": {
|
||||
"id": 11,
|
||||
"name": "Computer"
|
||||
},
|
||||
"name": "Name",
|
||||
"label": true,
|
||||
"type": 0,
|
||||
"description": "Asset name/label",
|
||||
"defaultType": {
|
||||
"id": 0,
|
||||
"name": "Text"
|
||||
},
|
||||
"typeValue": null,
|
||||
"typeValueMulti": [],
|
||||
"additionalValue": null,
|
||||
"referenceType": null,
|
||||
"referenceObjectTypeId": null,
|
||||
"referenceObjectType": null,
|
||||
"editable": true,
|
||||
"system": true,
|
||||
"sortable": true,
|
||||
"summable": false,
|
||||
"indexed": true,
|
||||
"minimumCardinality": 1,
|
||||
"maximumCardinality": 1,
|
||||
"suffix": "",
|
||||
"removable": false,
|
||||
"hidden": false,
|
||||
"includeChildObjectTypes": false,
|
||||
"uniqueAttribute": false,
|
||||
"regexValidation": null,
|
||||
"iql": null,
|
||||
"options": "",
|
||||
"position": 0
|
||||
},
|
||||
{
|
||||
"id": 101,
|
||||
"objectType": {
|
||||
"id": 11,
|
||||
"name": "Computer"
|
||||
},
|
||||
"name": "Serial Number",
|
||||
"label": false,
|
||||
"type": 0,
|
||||
"description": "Device serial number",
|
||||
"defaultType": {
|
||||
"id": 0,
|
||||
"name": "Text"
|
||||
},
|
||||
"typeValue": null,
|
||||
"typeValueMulti": [],
|
||||
"additionalValue": null,
|
||||
"referenceType": null,
|
||||
"referenceObjectTypeId": null,
|
||||
"referenceObjectType": null,
|
||||
"editable": true,
|
||||
"system": false,
|
||||
"sortable": true,
|
||||
"summable": false,
|
||||
"indexed": true,
|
||||
"minimumCardinality": 0,
|
||||
"maximumCardinality": 1,
|
||||
"suffix": "",
|
||||
"removable": true,
|
||||
"hidden": false,
|
||||
"includeChildObjectTypes": false,
|
||||
"uniqueAttribute": true,
|
||||
"regexValidation": "^[A-Z0-9]{10,20}$",
|
||||
"iql": null,
|
||||
"options": "",
|
||||
"position": 1
|
||||
},
|
||||
{
|
||||
"id": 102,
|
||||
"objectType": {
|
||||
"id": 11,
|
||||
"name": "Computer"
|
||||
},
|
||||
"name": "Assigned User",
|
||||
"label": false,
|
||||
"type": 2,
|
||||
"description": "User assigned to this asset",
|
||||
"defaultType": null,
|
||||
"typeValue": "SHOW_ON_ASSET",
|
||||
"typeValueMulti": [],
|
||||
"additionalValue": null,
|
||||
"referenceType": null,
|
||||
"referenceObjectTypeId": null,
|
||||
"referenceObjectType": null,
|
||||
"editable": true,
|
||||
"system": false,
|
||||
"sortable": true,
|
||||
"summable": false,
|
||||
"indexed": true,
|
||||
"minimumCardinality": 0,
|
||||
"maximumCardinality": 1,
|
||||
"suffix": "",
|
||||
"removable": true,
|
||||
"hidden": false,
|
||||
"includeChildObjectTypes": false,
|
||||
"uniqueAttribute": false,
|
||||
"regexValidation": null,
|
||||
"iql": null,
|
||||
"options": "",
|
||||
"position": 2
|
||||
},
|
||||
{
|
||||
"id": 103,
|
||||
"objectType": {
|
||||
"id": 11,
|
||||
"name": "Computer"
|
||||
},
|
||||
"name": "Location",
|
||||
"label": false,
|
||||
"type": 1,
|
||||
"description": "Physical location of the asset",
|
||||
"defaultType": null,
|
||||
"typeValue": null,
|
||||
"typeValueMulti": [],
|
||||
"additionalValue": null,
|
||||
"referenceType": {
|
||||
"id": 1,
|
||||
"name": "Reference",
|
||||
"description": "Standard reference",
|
||||
"color": "#0052CC",
|
||||
"url16": null,
|
||||
"removable": false,
|
||||
"objectSchemaId": 1
|
||||
},
|
||||
"referenceObjectTypeId": 20,
|
||||
"referenceObjectType": {
|
||||
"id": 20,
|
||||
"name": "Location",
|
||||
"objectSchemaId": 1
|
||||
},
|
||||
"editable": true,
|
||||
"system": false,
|
||||
"sortable": true,
|
||||
"summable": false,
|
||||
"indexed": true,
|
||||
"minimumCardinality": 0,
|
||||
"maximumCardinality": 1,
|
||||
"suffix": "",
|
||||
"removable": true,
|
||||
"hidden": false,
|
||||
"includeChildObjectTypes": true,
|
||||
"uniqueAttribute": false,
|
||||
"regexValidation": null,
|
||||
"iql": "objectType = Location",
|
||||
"options": "",
|
||||
"position": 3
|
||||
},
|
||||
{
|
||||
"id": 104,
|
||||
"objectType": {
|
||||
"id": 11,
|
||||
"name": "Computer"
|
||||
},
|
||||
"name": "Status",
|
||||
"label": false,
|
||||
"type": 7,
|
||||
"description": "Current asset status",
|
||||
"defaultType": null,
|
||||
"typeValue": "1",
|
||||
"typeValueMulti": ["1", "2", "3"],
|
||||
"additionalValue": null,
|
||||
"referenceType": null,
|
||||
"referenceObjectTypeId": null,
|
||||
"referenceObjectType": null,
|
||||
"editable": true,
|
||||
"system": false,
|
||||
"sortable": true,
|
||||
"summable": false,
|
||||
"indexed": true,
|
||||
"minimumCardinality": 1,
|
||||
"maximumCardinality": 1,
|
||||
"suffix": "",
|
||||
"removable": true,
|
||||
"hidden": false,
|
||||
"includeChildObjectTypes": false,
|
||||
"uniqueAttribute": false,
|
||||
"regexValidation": null,
|
||||
"iql": null,
|
||||
"options": "",
|
||||
"position": 4
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Attribute Fields to Store:**
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| id | integer | Attribute ID |
|
||||
| objectType | object | Parent object type {id, name} |
|
||||
| name | string | Attribute name |
|
||||
| label | boolean | Is this the label/display attribute |
|
||||
| type | integer | Attribute type (see type reference below) |
|
||||
| description | string | Optional description |
|
||||
| defaultType | object/null | Default type info {id, name} for type=0 |
|
||||
| typeValue | string/null | Type-specific configuration |
|
||||
| typeValueMulti | array | Multiple type values (e.g., allowed status IDs) |
|
||||
| additionalValue | string/null | Additional configuration |
|
||||
| referenceType | object/null | Reference type details for type=1 |
|
||||
| referenceObjectTypeId | integer/null | Target object type ID for references |
|
||||
| referenceObjectType | object/null | Target object type details |
|
||||
| editable | boolean | Can values be edited |
|
||||
| system | boolean | Is system attribute (Name, Key, Created, Updated) |
|
||||
| sortable | boolean | Can sort by this attribute |
|
||||
| summable | boolean | Can sum values (numeric types) |
|
||||
| indexed | boolean | Is indexed for search |
|
||||
| minimumCardinality | integer | Minimum required values (0=optional, 1=required) |
|
||||
| maximumCardinality | integer | Maximum values (-1=unlimited, 1=single) |
|
||||
| suffix | string | Display suffix (e.g., "GB", "USD") |
|
||||
| removable | boolean | Can attribute be deleted |
|
||||
| hidden | boolean | Is hidden from default view |
|
||||
| includeChildObjectTypes | boolean | Include child types in reference selection |
|
||||
| uniqueAttribute | boolean | Must values be unique |
|
||||
| regexValidation | string/null | Validation regex pattern |
|
||||
| iql | string/null | IQL/AQL filter for reference selection |
|
||||
| options | string | Additional options (CSV for Select type) |
|
||||
| position | integer | Display order position |
|
||||
|
||||
---
|
||||
|
||||
## Attribute Type Reference
|
||||
|
||||
### Main Types (type field)
|
||||
| Type | Name | Description | Uses defaultType |
|
||||
|------|------|-------------|------------------|
|
||||
| 0 | Default | Uses defaultType for specific type | Yes |
|
||||
| 1 | Object | Reference to another Assets object | No |
|
||||
| 2 | User | Jira user reference | No |
|
||||
| 3 | Confluence | Confluence page reference | No |
|
||||
| 4 | Group | Jira group reference | No |
|
||||
| 5 | Version | Jira version reference | No |
|
||||
| 6 | Project | Jira project reference | No |
|
||||
| 7 | Status | Status type reference | No |
|
||||
|
||||
### Default Types (defaultType.id when type=0)
|
||||
| ID | Name | Description |
|
||||
|----|------|-------------|
|
||||
| 0 | Text | Single-line text |
|
||||
| 1 | Integer | Whole number |
|
||||
| 2 | Boolean | True/False checkbox |
|
||||
| 3 | Double | Decimal number |
|
||||
| 4 | Date | Date only (no time) |
|
||||
| 5 | Time | Time only (no date) |
|
||||
| 6 | DateTime | Date and time |
|
||||
| 7 | URL | Web link |
|
||||
| 8 | Email | Email address |
|
||||
| 9 | Textarea | Multi-line text |
|
||||
| 10 | Select | Dropdown selection (options in `options` field) |
|
||||
| 11 | IP Address | IP address format |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Requirements
|
||||
|
||||
### 1. Sync Flow
|
||||
|
||||
Implement the following synchronization flow:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Schema Sync Process │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 1. GET /objectschema/list │
|
||||
│ └── Store/Update all schemas in local DB │
|
||||
│ │
|
||||
│ 2. For each schema: │
|
||||
│ ├── GET /objectschema/:id │
|
||||
│ │ └── Update schema details │
|
||||
│ │ │
|
||||
│ └── GET /objectschema/:id/objecttypes/flat │
|
||||
│ └── Store/Update all object types │
|
||||
│ │
|
||||
│ 3. For each object type: │
|
||||
│ ├── GET /objecttype/:id (optional, for latest details) │
|
||||
│ │ │
|
||||
│ └── GET /objecttype/:id/attributes │
|
||||
│ └── Store/Update all attributes │
|
||||
│ │
|
||||
│ 4. Clean up orphaned records (deleted in Jira) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2. Database Operations
|
||||
|
||||
For each entity type, implement:
|
||||
- **Upsert logic**: Insert new records, update existing ones based on Jira ID
|
||||
- **Soft delete or cleanup**: Handle items that exist locally but not in Jira anymore
|
||||
- **Relationship mapping**: Maintain foreign key relationships (schema → object types → attributes)
|
||||
|
||||
### 3. Rate Limiting
|
||||
|
||||
Implement rate limiting to avoid overloading the Jira server:
|
||||
- Add 100-200ms delay between API requests
|
||||
- Implement exponential backoff on 429 (Too Many Requests) responses
|
||||
- Maximum 3-5 concurrent requests if using parallel processing
|
||||
|
||||
```typescript
|
||||
// Example rate limiting implementation
|
||||
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
async function fetchWithRateLimit<T>(url: string): Promise<T> {
|
||||
await delay(150); // 150ms between requests
|
||||
|
||||
const response = await fetch(url, { headers: getAuthHeaders() });
|
||||
|
||||
if (response.status === 429) {
|
||||
const retryAfter = parseInt(response.headers.get('Retry-After') || '5');
|
||||
await delay(retryAfter * 1000);
|
||||
return fetchWithRateLimit(url);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Error Handling
|
||||
|
||||
Handle these scenarios:
|
||||
- **401 Unauthorized**: Invalid credentials
|
||||
- **403 Forbidden**: Insufficient permissions
|
||||
- **404 Not Found**: Schema/Type deleted during sync
|
||||
- **429 Too Many Requests**: Rate limited (implement backoff)
|
||||
- **5xx Server Errors**: Retry with exponential backoff
|
||||
|
||||
### 5. Progress Tracking
|
||||
|
||||
Implement progress reporting:
|
||||
- Total schemas to process
|
||||
- Current schema being processed
|
||||
- Total object types to process
|
||||
- Current object type being processed
|
||||
- Estimated time remaining (optional)
|
||||
|
||||
---
|
||||
|
||||
## Code Structure Suggestions
|
||||
|
||||
### Service/Repository Pattern
|
||||
|
||||
```
|
||||
src/
|
||||
├── services/
|
||||
│ └── jira-assets/
|
||||
│ ├── JiraAssetsApiClient.ts # HTTP client with auth & rate limiting
|
||||
│ ├── SchemaSyncService.ts # Main sync orchestration
|
||||
│ ├── ObjectTypeSyncService.ts # Object type sync logic
|
||||
│ └── AttributeSyncService.ts # Attribute sync logic
|
||||
├── repositories/
|
||||
│ ├── SchemaRepository.ts # Schema DB operations
|
||||
│ ├── ObjectTypeRepository.ts # Object type DB operations
|
||||
│ └── AttributeRepository.ts # Attribute DB operations
|
||||
└── models/
|
||||
├── Schema.ts # Schema entity/model
|
||||
├── ObjectType.ts # Object type entity/model
|
||||
└── ObjectTypeAttribute.ts # Attribute entity/model
|
||||
```
|
||||
|
||||
### Sync Service Interface
|
||||
|
||||
```typescript
|
||||
interface SchemaSyncService {
|
||||
/**
|
||||
* Sync all schemas and their complete structure
|
||||
* @returns Summary of sync operation
|
||||
*/
|
||||
syncAll(): Promise<SyncResult>;
|
||||
|
||||
/**
|
||||
* Sync a single schema by ID
|
||||
* @param schemaId - Jira schema ID
|
||||
*/
|
||||
syncSchema(schemaId: number): Promise<SyncResult>;
|
||||
|
||||
/**
|
||||
* Get sync status/progress
|
||||
*/
|
||||
getProgress(): SyncProgress;
|
||||
}
|
||||
|
||||
interface SyncResult {
|
||||
success: boolean;
|
||||
schemasProcessed: number;
|
||||
objectTypesProcessed: number;
|
||||
attributesProcessed: number;
|
||||
errors: SyncError[];
|
||||
duration: number; // milliseconds
|
||||
}
|
||||
|
||||
interface SyncProgress {
|
||||
status: 'idle' | 'running' | 'completed' | 'failed';
|
||||
currentSchema?: string;
|
||||
currentObjectType?: string;
|
||||
schemasTotal: number;
|
||||
schemasCompleted: number;
|
||||
objectTypesTotal: number;
|
||||
objectTypesCompleted: number;
|
||||
startedAt?: Date;
|
||||
estimatedCompletion?: Date;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
After implementation, verify:
|
||||
|
||||
- [ ] All schemas are fetched from `/objectschema/list`
|
||||
- [ ] Schema details are updated from `/objectschema/:id`
|
||||
- [ ] All object types are fetched for each schema from `/objectschema/:id/objecttypes/flat`
|
||||
- [ ] Object type hierarchy (parentObjectTypeId) is preserved
|
||||
- [ ] All attributes are fetched for each object type from `/objecttype/:id/attributes`
|
||||
- [ ] Attribute types are correctly mapped (type + defaultType)
|
||||
- [ ] Reference attributes store referenceObjectTypeId and referenceType
|
||||
- [ ] Status attributes store typeValueMulti (allowed status IDs)
|
||||
- [ ] Rate limiting prevents 429 errors
|
||||
- [ ] Error handling covers all failure scenarios
|
||||
- [ ] Sync can be resumed after failure
|
||||
- [ ] Orphaned local records are handled (deleted in Jira)
|
||||
- [ ] Foreign key relationships are maintained
|
||||
- [ ] Timestamps (created, updated) are stored correctly
|
||||
|
||||
---
|
||||
|
||||
## Testing Scenarios
|
||||
|
||||
1. **Initial sync**: Empty local database, full sync from Jira
|
||||
2. **Incremental sync**: Existing data, detect changes
|
||||
3. **Schema added**: New schema created in Jira
|
||||
4. **Schema deleted**: Schema removed from Jira
|
||||
5. **Object type added**: New type in existing schema
|
||||
6. **Object type moved**: Parent changed in hierarchy
|
||||
7. **Attribute added/modified/removed**: Changes to type attributes
|
||||
8. **Large schema**: Schema with 50+ object types, 500+ attributes
|
||||
9. **Network failure**: Handle timeouts and retries
|
||||
10. **Rate limiting**: Handle 429 responses gracefully
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- The `/objectschema/:id/objecttypes/flat` endpoint returns ALL object types in one call, which is more efficient than fetching hierarchically
|
||||
- The `label` field on attributes indicates which attribute is used as the display name for objects
|
||||
- System attributes (system=true) are: Name, Key, Created, Updated - these exist on all object types
|
||||
- The `iql` field on reference attributes contains the filter query for selecting valid reference targets
|
||||
- The `options` field on Select type attributes (type=0, defaultType.id=10) contains comma-separated options
|
||||
Reference in New Issue
Block a user