## Quick Reference

### Common Patterns

#### Creating a New Page

```typescript
import type { GraphApi, ShowCaseProduct as ShowCaseProductNode, ShowCaseProvider } from '@sage/xtrem-show-case-api';
import * as ui from '@sage/xtrem-ui';
import { applicationPages } from '../menu-items/application-pages';

@ui.decorators.page<ShowCaseProduct, ShowCaseProductNode>({
    authorizationCode: 'SHCPRDT',
    category: 'SHOWCASE',
    title: 'ShowCase - Product',
    menuItem: applicationPages,
    navigationPanel: {
        listItem: {
            title: ui.nestedFields.text({ bind: 'product', title: 'Product' }),
            line2: ui.nestedFields.text({ bind: 'description', title: 'Description' }),
            line3: ui.nestedFields.reference({
                bind: 'provider',
                node: '@sage/xtrem-show-case/ShowCaseProvider',
                title: 'Supplier',
                valueField: 'textField',
                isHiddenOnMainField: true,
            }),
            listPrice: ui.nestedFields.numeric({ bind: 'listPrice', title: 'List Price', isHiddenOnMainField: true }),
            category: ui.nestedFields.label({
                canFilter: true,
                bind: 'category',
                title: 'Category',
                optionType: '@sage/xtrem-show-case/ShowCaseProductCategory',
            }),
        },
    },
    businessActions() {
        return [this.refreshPage, this.emptyPage, this.$standardSaveAction];
    },
    createAction() {
        return this.$standardNewAction;
    },
    headerDropDownActions() {
        return [this.$standardDeleteAction];
    },
    priority: 100,
    node: '@sage/xtrem-show-case/ShowCaseProduct',
})
export class ShowCaseProduct extends ui.Page<GraphApi> {
    @ui.decorators.section<ShowCaseProduct>({})
    section: ui.containers.Section;

    @ui.decorators.block<ShowCaseProduct>({
        parent() {
            return this.section;
        },
    })
    block: ui.containers.Block;

    @ui.decorators.textField<ShowCaseProduct>({
        parent() {
            return this.block;
        },
        title: 'Product',
        isMandatory: true,
    })
    product: ui.fields.Text<ShowCaseProduct>;

    @ui.decorators.numericField<ShowCaseProduct>({
        parent() {
            return this.block;
        },
        title: 'List price',
        scale: 2,
        fetchesDefaults: true,
    })
    listPrice: ui.fields.Numeric;

    @ui.decorators.referenceField<ShowCaseProduct, ShowCaseProvider>({
        parent() {
            return this.block;
        },
        columns: [ui.nestedFields.text({ bind: 'textField' })],
        node: '@sage/xtrem-show-case/ShowCaseProvider',
        title: 'Provider',
        valueField: 'textField',
        helperTextField: '_id',
        minLookupCharacters: 0,
        tunnelPage: '@sage/xtrem-show-case/ShowCaseProvider',
    })
    provider: ui.fields.Reference;
}
```

** the pages directory does not have an index.ts **

#### Creating an Activity (Required for all Nodes)

**🚨 IMPORTANT: Every Node must have an associated Activity for authorization.**

```typescript
import { Activity } from '@sage/xtrem-core';
import * as myPackage from '..';

export const myNodeManagement = new Activity({
    description: 'My Node Management',
    node: () => myPackage.nodes.MyNode,
    permissions: ['read', 'create', 'update', 'delete', 'lookup'],
    operationGrants: {
        create: [{ operations: ['create'], on: [() => myPackage.nodes.RelatedNode] }],
        update: [{ operations: ['update', 'customMutation'] }],
    },
    permissionGrants: {
        update: [{ permissions: ['read'], on: [() => myPackage.activities.relatedActivity] }],
    },
});
```

**Key Points:**

- Activities define what operations users can perform on nodes
- Basic permissions: `read`, `create`, `update`, `delete`, `lookup`
- Activities enable cascading permissions to related nodes
- Must be defined in `lib/activities/` directory
- Required for proper authorization and security

#### Creating a New Node

```typescript
import {
    BinaryStream,
    Collection,
    Context,
    date,
    decimal,
    decorators,
    integer,
    Node,
    Reference,
    TextStream,
} from '@sage/xtrem-core';
import * as xtremShowCase from '../../index';

@decorators.node<ShowCaseProvider>({
    storage: 'sql',
    canCreate: true,
    canDelete: true,
    canDeleteMany: true,
    canDuplicate: true,
    canRead: true,
    canSearch: true,
    canUpdate: true,
    indexes: [{ orderBy: { textField: 1 }, isUnique: true }],
    isPublished: true,
    isCustomizable: true,
})
export class ShowCaseProvider extends Node {
    @decorators.stringProperty<ShowCaseProvider, 'textField'>({
        dataType: () => xtremShowCase.dataTypes.descriptionDataType,
        isStored: true,
        isPublished: true,
        lookupAccess: true,
    })
    readonly textField: Promise<string>;

    @decorators.integerProperty<ShowCaseProvider, 'integerField'>({
        isStored: true,
        isPublished: true,
        lookupAccess: true,
    })
    readonly integerField: Promise<integer>;

    @decorators.decimalProperty<ShowCaseProvider, 'decimalField'>({
        dataType: () => xtremShowCase.dataTypes.defaultDecimalDataType,
        isStored: true,
        isPublished: true,
        lookupAccess: true,
    })
    readonly decimalField: Promise<decimal>;

    @decorators.booleanProperty<ShowCaseProvider, 'booleanField'>({
        isStored: true,
        isPublished: true,
        lookupAccess: true,
    })
    readonly booleanField: Promise<boolean>;

    @decorators.dateProperty<ShowCaseProvider, 'dateField'>({
        isStored: true,
        isPublished: true,
        lookupAccess: true,
    })
    readonly dateField: Promise<date>;

    @decorators.collectionProperty<ShowCaseProvider, 'products'>({
        isPublished: true,
        isVital: true,
        lookupAccess: true,
        forceFullSave: true,
        node: () => xtremShowCase.nodes.ShowCaseProduct,
        reverseReference: 'provider',
    })
    readonly products: Collection<xtremShowCase.nodes.ShowCaseProduct>;

    @decorators.referenceProperty<ShowCaseProvider, 'siteAddress'>({
        isPublished: true,
        isNullable: true,
        isStored: true,
        node: () => xtremShowCase.nodes.ShowCaseProviderAddress,
    })
    readonly siteAddress: Reference<xtremShowCase.nodes.ShowCaseProviderAddress | null>;

    @decorators.stringProperty<ShowCaseProvider, 'concatenatedAddress'>({
        async computeValue() {
            if (!(await this.siteAddress)) {
                return '';
            }
            const address: string[] = [];
            if (await (await this.siteAddress)!.addressLine1) {
                address.push(await (await this.siteAddress)!.addressLine1);
            }
            if (await (await this.siteAddress)!.addressLine2) {
                address.push(await (await this.siteAddress)!.addressLine2);
            }
            if (await (await this.siteAddress)!.city) {
                address.push(await (await this.siteAddress)!.city);
            }
            return address.join('\n');
        },
        dependsOn: ['siteAddress'],
        isPublished: true,
    })
    readonly concatenatedAddress: Promise<string>;

    @decorators.textStreamProperty<ShowCaseProvider, 'document'>({
        dataType: () =>
            new TextStreamDataType({
                maxLength: 1000000,
                allowedContentTypes: ['text/html', 'application/json', 'text/plain'],
            }),
        isPublished: true,
        isStored: true,
    })
    readonly document: Promise<TextStream>;

    @decorators.binaryStreamProperty<ShowCaseProvider, 'logo'>({
        isPublished: true,
        isStored: true,
        isNullable: true,
    })
    readonly logo: Promise<BinaryStream | null>;

    @decorators.jsonProperty<ShowCaseProvider, 'additionalInfo'>({
        isNullable: true,
        isPublished: true,
        isStored: true,
    })
    readonly additionalInfo: Promise<any | null>;

    @decorators.bulkMutation<typeof ShowCaseProvider, 'export'>({
        isPublished: true,
        parameters: [
            {
                name: 'provider',
                type: 'instance',
                node: () => ShowCaseProvider,
            },
        ],
        return: 'void',
    })
    static async export(_context: Context, provider: ShowCaseProvider): Promise<void> {
        // Custom mutation logic here
    }
}
```

#### Creating an Enum

```typescript
import { EnumDataType } from '@sage/xtrem-core';

export enum ShowCaseProductCategoryEnum {
    great,
    good,
    ok,
    notBad,
    awful,
}

export type ShowCaseProductCategory = keyof typeof ShowCaseProductCategoryEnum;

export const showCaseProductCategoryDataType = new EnumDataType<ShowCaseProductCategory>({
    enum: ShowCaseProductCategoryEnum,
    filename: __filename,
});
```

#### Creating a Widget

```typescript
import * as ui from '@sage/xtrem-ui';

@ui.widgets.indicatorTile<SystemVersion>({
    title: 'System version',
    description: 'Version information about the currently installed system version',
    cacheLifespan: ui.widgets.WidgetCacheLifespan.day,
    icon: 'info',
    value() {
        return this.$.data.xtremSystem.sysPackVersion.query.edges?.[0]?.node?.version || 'N/A';
    },
    getQuery() {
        return {
            xtremSystem: {
                sysPackVersion: {
                    query: {
                        __args: { filter: "{name:'@sage/xtrem-system'}" },
                        edges: {
                            node: {
                                version: true,
                            },
                        },
                    },
                },
            },
        };
    },
})
export class SystemVersion extends ui.widgets.AbstractWidget {}
```

** the widgets directory does not have an index.ts **

### Common Decorators

#### Page Decorators

```typescript
@ui.decorators.page<MyPage>({
    authorizationCode: 'MYPAGE',        // Security authorization
    category: 'GENERAL',                // Menu category
    title: 'My Page Title',             // Display title
    isTransient: false,                 // Whether data persists
    priority: 100,                      // Menu ordering
    node: '@sage/my-package/MyNode',    // Associated node
    menuItem: myMenuItem,               // Menu placement
})
```

#### Field Decorators

```typescript
@ui.decorators.textField<MyPage>({
    parent() { return this.block; },
    title: 'Field Title',
    isMandatory: true,
    helperText: 'Additional help text',
})

@ui.decorators.numericField<MyPage>({
    parent() { return this.block; },
    title: 'Amount',
    scale: 2,                          // Decimal places
    precision: 10,                     // Total digits
})

@ui.decorators.referenceField<MyPage, TargetNode>({
    parent() { return this.block; },
    node: '@sage/package/TargetNode',
    title: 'Reference',
    valueField: 'name',
    tunnelPage: '@sage/package/TargetPage',
})
```

#### Node Property Decorators

```typescript
@decorators.stringProperty<MyNode, 'name'>({
    isStored: true,
    isPublished: true,
    lookupAccess: true,
    dataType: () => myDataType,
})

@decorators.referenceProperty<MyNode, 'parent'>({
    isStored: true,
    isPublished: true,
    isNullable: true,
    node: () => ParentNode,
})

@decorators.collectionProperty<MyNode, 'children'>({
    isPublished: true,
    isVital: true,
    node: () => ChildNode,
    reverseReference: 'parent',
})
```

## Async Processing Quick Reference

### Import Patterns

```typescript
// Server-side (preferred - re-exported from core)
import { asyncArray, funnel, getAsync, AsyncReader } from '@sage/xtrem-core';

// Client-side
import { asyncArray, funnel, getAsync, AsyncReader } from '@sage/xtrem-async-helper';
```

### Async Processing Patterns

```typescript
// Async array processing
await asyncArray(items).forEach(async item => await process(item));

// Parallel with concurrency control
await asyncArray(items).forEachParallel(5, async item => await process(item));

// Funnel for controlling concurrency
const processFunnel = funnel(10);
await Promise.all(items.map(item => processFunnel(async () => await process(item))));

// Safe nested property access
const value = await getAsync(object, 'nested.async.property');

// Map and filter operations
const results = await asyncArray(items)
    .map(async item => await transform(item))
    .filter(async result => await validate(result))
    .toArray();
```
