![Treelab Logo](https://treelab-misc.s3-us-west-2.amazonaws.com/treelab-logos/Treelab-Logo-Small.png)

# Usage

The Treelab Javascript API provides an easy way to integrate Treelab with any external system. The API uses JSON to encode 
objects, and relies on Google's remote procedural call system (gRPC) to signal operation outcomes. The API
enables external applications with full support for realtime data transmission through data streaming.

## Installation

<!-- tabs:start -->
#### **Install with NPM**

```typescript
npm install @treelab/treelab
```

#### **Install with YARN**

```typescript
yarn add @treelab/treelab
```

<!-- tabs:end -->

# Treelab  Object Guide

## Core

A `core` is a collection of Treelab `tables` and `views`. 

## Table

A `table` is a collection of views which have fields and rows. Each table is also made up of a series of different 
views and different views can contain different columns and rows depending on the view configuration. 

## Views 
A `view` is a materialized projection of a `table`'s data. The same table data can be visualized in a variety of different ways.
 The current view types supported are: 

1. `Grid View` 
2. `Timeline View` 
3. `List View`*(In development)*
4. `Form View` *(In development)*
5. `Kanban View` *(In development)*

Views can not only be used to create interactive visualizations, but it can also be used to pass data from one user/process to another. By applying different filter conditions, the admin user can essentially configure data flow by inviting different users to different views. 

## Field Types

Treelab has a lot of rich field types but the main field types are:

- `Text`
- `Number`
- `Record Reference`
- `Table Reference`
- `Core Reference`
- `Select`
- `Multi-Select`
- `Multi-Attachment`

# Events

Treelab is an event-driven system that encodes all state and data changes within the system into a series of `events`. These `events` are then written into a series of different `topics`, which can then be consumed by different parties for processing. Treelab's Typescript SDK abstracts these events into different objects that can then be used to read and write data from Treelab.

```json
{
  eventname: 'creb5528ed9c50539b8.CoreCreated',
  workspaceid: 'wspb5506fe4160c6310',
  coreid: 'creb5528ed9c50539b8',
  tableid: '',
  columnid: '',
  rowid: '',
  corename: 'core name',
  color: 'dark',
  icon: 'check',
  tablename: '',
  columnconfig: undefined,
  view: undefined,
  value: undefined,
  metadata: { source: 'USER' }
}
```

# Authentication

## Initialize with your apiKey:

```javascript
import { Treelab } from 'treelab';
const treelab = new Treelab({
  token: 'your_token_here',
});
```

Now you can do query or create mutations with this instance.

#### For example, create a workspace 
```javascript
const workspace = await treelab.createWorkspace({ name: 'workspace name' });
```

#### *Every instance has inherit properties like*

<!-- tabs:start -->
#### **ID**
```javascript
console.log(workspace.id);
```
```javascript
str: 'wsp322f294105fdf1'
```
#### **Name**
```javascript
console.log(workspace.name); 
```
```javascript
str: 'Test Workspace'
```
<!-- tabs:end -->

<!-- tabs:start -->
#### **Get a single core**
```javascript
const core = await workspace.core('coreId')
```
#### **Get a single table**
```javascript
const table = await core.table('tableId')
```
<!-- tabs:end -->

The table instance contains a map of rows and views as propertity

```javascript
Map{
  'viwb5506fe4f384edda' => View {
    workspaceId: 'wspb5506fe4160c6310',
    coreId: 'creb5506fe46a88de54',
    tableId: 'tblb5506fe4ca8408d8',
    id: 'viwb5506fe4f384edda',
    name: 'testView',
    type: 'GRID',
    columns:
      Map {
       'colb5506fe502834416' => [Column],
       'colb5506fe5028c62d9' => [Column],
       'colb5506fe502004bdd' => [Column]
      }
    }
  }

Map {
  'rowb5506fe58205e2f6' => Row {
    workspaceId: 'wspb5506fe4160c6310',
    coreId: 'creb5506fe46a88de54',
    tableId: 'tblb5506fe4ca8408d8',
    id: 'rowb5506fe58205e2f6',
    rowData:
      Map {
       'colb5506fe502834416' => [Cell],
       'colb5506fe502004bdd' => [Cell],
       'colb5506fe5028c62d9' => [Cell]
      }
    }
  }
```

#### All `Treelab Objects` can be listened to and be used for event callbacks. 
##### **For example** 

```javascript
const subscription = core.onUpdated(e => {
  // do something here
});
subscription.unsubscribe();
core.on(e => {
  // listen all events under the core
});
```

# Treelab object array class

All `Treelab object array` classes have an attribute, and all classes will have a select and sort method to filter or sort, and have the same listener method as a single object to batch listen for objectss.

<!-- tabs:start -->
#### **Get Method**
#### *Use the `get"Object"` method to get all objects from its parent.* 

##### *For example we can call the `getCores()` to get all cores from a Workspace*
```javascript 
const coreArrayClass = await workspace.getCores();
```
#### or 
#### *Use the `core` method to get a specific `Core` from a `Workspace`.* 
```javascript
const core = await workspace.core('cre21239120112fd')
```
#### **Create Tables**
```javascript
const tableArrayClass = await core.createTables(...);
```
#### **Object Array Methods**
The methods below apply to any `Treelab Object arrays`, but we will demontrate
how these methods work for a list of `Treelab tables`.  
#### *First, we get an array of all tables: [Table, Table...]*
```javascript
tableArrayClass = await core.getTables()
```
#### *Get three tables*
```javascript
const selectedTableArrayClass = await tableArrayClass.select(3);
```
#### *Get filtered tables*
```javascript
const filteredTableArrayClass = await tableArrayClass.select((i) => i.name === 'table name'));
```
#### *Get sorted tables by asc (Sort like `arrayObject.sort(sortby)`)*
```javascript
const filteredTableArrayClass = await tableArrayClass.sort((a, b) => a.name.localeCompare(b.name));
```
#### **Listening to Treelab Objects**

#### *Example*
Listen for all cell updated events from this `Treelab` table array
```javascript
const subscriptions = tableArrayClass.onCellUpdated(e => {
  // do something here
})
```
<!-- tabs:end -->


______________________________

_____

# Treelab API Usage Guide

Treelab's Javascript API is built on the concept of object chaining. `Treelab objects` can be chained together with different query and mutation methods upon those methods. Objects have children and parent objects and can be chained together for an elegant way to modify and get different object properties.  

From parent to child the `Treelab Objects` are organized by the following:  
- Workspace
- Core
- Table
- View
- Column
- Row
- Cell 

## Workspaces

<!-- tabs:start -->

### **Creating Workspace(s)**

#### Create a Single Workspace

```javascript
treelab.createWorkspace(createWorkspaceInput:{ name: string }): Promise<Workspace>;
```
#### *Example*

```javascript
const workspace = await treelab.createWorkspace({ name: 'workspace name' });
```
#### Create Multiple Workspaces

```javascript
treelab.createWorkspaces(): Promise<WorkspaceArray>;
```
#### *Example*

```javascript
const workspaceArrayClass = await treelab.createWorkspaces([
  { name: 'workspace 1' },
  { name: 'workspace 2' },
]);
```
### **Retrieving Workspace(s)**

#### Retrieve a Single Workspace

```javascript
treelab.workspace(id: string ): Promise<Workspace>;
```
#### *Example*
```javascript
const workspace = await treelab.workspace('wspb5506fe4160c6310');
```
#### Retrieve Multiple Workspaces

```javascript
treelab.getWorkspaces(): Promise<WorkspaceArray>;
```
#### *Example*
```javascript
const workspaceArrayClass = await treelab.getWorkspaces();
```

#### Filter for Workspaces
```javascript
workspaceArrayClass.select(maxSize: number, filter: FilterFn): WorkspaceArray;
```
#### *Example*
```javascript
// Example, select 3 workspaces whose names are 'test'
const workspaceArrayClass = await workspaceArrayClass.select(3, (i) => {
  i.name === 'test'
});
```
#### Sort Workspaces

```javascript
workspaceArrayClass.sort(sortFn: SortFn): WorkspaceArray;
```
#### *Example*
```javascript
// Example, sort workspaces in ascending order
// Sort like `arrayObject.sort(sortby)
const workspaceArrayClass = await workspaceArrayClass.sort((a, b) => a.name.localeCompare(b.name));
```

### **Subscribing to Workspace Events**

#### Listening for `coreCreated` Event

```javascript
workspace.onCoreCreated(cb: EventCallback): Subscription
```
#### *Example*
```javascript
workspace.onCoreCreated(e => {
  console.log('workspace.onCoreCreated:', e);
})
```

#### Listening for `onCoreAdded` Event

```javascript
workspace.onCoreAdded(cb: EventCallback): Subscription
```
#### *Example*
```javascript
workspace.onCoreAdded(e => {
  console.log('workspace.onCoreAdded:', e);
})
```

#### Listen for all events under a `Workspace` (Wildcard)

Use the `on` method to listen for every event under the workspace

```javascript
workspace.on(cb: EventCallback): Subscription
```

#### *Example*
```javascript
workspace.on(e => {
  console.log('workspace.on:', e);
})
```
<!-- tabs:end -->

## Cores

<!-- tabs:start -->

### **Creating Core(s)**

#### Create a Single `Core`

```javascript
treelab.createCore(createCoreInput:{ name: string, color: CoreColor, icon: Icon }): Promise<Core>;
```
#### *Example*
```javascript
const workspace = await treelab.createCore({
  name: 'core name',
  color: CoreColor.blue,
  icon: Icon.untitle
});
```

#### Create multiple `Cores`

```javascript
treelab.createCores(createCoreInput:{ name: string, color: CoreColor, icon: Icon }): Promise<CoreArray>;
```
#### *Example*
```javascript
const workspace = await treelab.createCores([
  { name: 'core1', color: CoreColor.blue, icon: Icon.untitle },
  { name: 'core2', color: CoreColor.black, icon: Icon.check }
]);
```

####  **Retrieving Core(s)**

#### Retrieve a single `Core`
```javascript
workspace.core(id: string ): Promise<Core>;
```
#### *Example*
```
const core = await workspace.core('creb5506fe46a88de54');
```

#### Use the `getCores` method to get all Cores from a Workspace

```javascript
workspace.getCores(): Promise<CoreArray>;
```
#### *Example*
```javascript
const coreArrayClass = await workspace.getCores();
```

#### Select Cores from `CoreArray`

```javascript
coreArrayClass.select(maxSize: number, filter: FilterFn): CoreArray;
```
#### *Example*
```javascript
const coreArrayClass = await coreArrayClass.select(3, (i) => {
  i.name === 'test'
});
```

#### Sorting Cores from `CoreArray`

```javascript
coreArrayClass.sort(sortFn: SortFn): CoreArray;
```
#### *Example (Sorting Cores in Ascending Order)*
```javascript 
const coreArrayClass = await coreArrayClass.sort((a, b) => a.name.localeCompare(b.name));
```


### **Subscribing to Core Events**

#### Listening for `onTableCreated` Event

```javascript
core.onTableCreated(cb: EventCallback): Subscription
```
#### *Example*
```javascript
core.onTableCreated(e => {
  console.log('core.onTableCreated:', e);
})
```
#### Listening for `onTableAdded` Event

```javascript
core.onTableAdded(cb: EventCallback): Subscription
```
#### *Example*
```javascript
core.onTableAdded(e => {
  console.log('core.onTableAdded:', e);
})
```
#### Listening for all events under a `Core` (Wildcard)

Use the `.on` method to subscribe to all events under a core 

```javascript
core.on(cb: EventCallback): Subscription
```
#### *Example*
```javascript
core.on(e => {
  console.log('core.on:', e);
})
```

<!-- tabs:end -->

## Tables 

<!-- tabs:start -->
### **Creating Table(s)**

#### Creating a Single Table

```javascript
const table = core.createTable(createTableInput:{
  name: string,
  view?: ViewInput, // defaultView: GRID
  columns?: ColumnConfig[],
  data?: any[][]
}): Promise<Table>;
```

#### *Example*
```javascript
const table = await core.createTable({
  name: 'table',
  view: { name: 'view', type: ViewType.GRID },
  columns: [
    { type: ColumnType.TEXT, name: 'f1' },
    { type: ColumnType.TEXT, name: 'f2' },
    { type: ColumnType.TEXT, name: 'f3' },
  ],
  data: [['1', '2', '3'], ['21', '22', '23'], ['31', '32', '33']],
});
```

#### Creating Multiple Tables 

```javascript
const tableArray = core.createTables(createTableInput[]:{
  name: string,
  view?: ViewInput, // defaultView: GRID
  columns?: ColumnConfig[],
  data?: any[][]
}[]): Promise<TableArray>;
```
#### *Example, create a 2 * 3 table*
```javascript
const tableArrayClass = await core.createTables([
  {
    name: 'table1',
    view: { name: 'view1', type: ViewType.GRID },
    columns: [
      { type: ColumnType.TEXT, name: 'f1' },
      { type: ColumnType.TEXT, name: 'f2' },
      { type: ColumnType.TEXT, name: 'f3' },
    ],
    data: [['1', '2', '3'], ['21', '22', '23']],
  },
  {
    name: 'table2',
    view: { name: 'view2', type: ViewType.GRID },
    columns: [
      { type: ColumnType.TEXT, name: 'f1' },
      { type: ColumnType.TEXT, name: 'f2' },
      { type: ColumnType.TEXT, name: 'f3' },
    ],
    data: [['1', '2', '3'], ['21', '22', '23']],
  }
]);
```

### **Retrieving Table(s)**


#### Retrieving a Single Table

```javascript
core.table(id: string ): Promise<Table>;
```
#### *Example*
```javascript
const table = await core.table('tblb5528eda11885051');
```

#### Retrieving Multiple Tables

```javascript
core.getTables(): Promise<TableArray>;
```
#### *Example*
```javascript
const tableArrayClass = await core.getTables();
```

#### Selecting Tables from `Table Array`

```javascript
tableArrayClass.select(maxSize: number, filter: FilterFn): TableArray;
```
#### *Example* 
*Select 3 tables whose names are 'test'*
```javascript
const tableArrayClass = await tableArrayClass.select(3, (i) => {
  i.name === 'test'
});
```

#### Sorting Tables from `TableArray`

```javascript
tableArrayClass.sort(sortFn: SortFn): TableArray;
```

#### *Example* 
*Sort tables in ascending order like `arrayObject.sort(sortby)*
```javascript
const tableArrayClass = await tableArrayClass.sort((a, b) => a.name.localeCompare(b.name));
```

### **Subscribing to Table Events**

#### Listening for `onViewAdded` Events 

```javascript
table.onViewAdded(cb: EventCallback): Subscription
```
#### *Example*
```javascript
table.onViewAdded(e => {
  console.log('table.onViewAdded:', e);
})
```

#### Listening for `onColumnAdded` Events 

```javascript
table.onColumnAdded(cb: EventCallback): Subscription
```
#### *Example*
```javascript
table.onColumnAdded(e => {
  console.log('table.onColumnAdded:', e);
})
```

#### Listening for `onRowAdded` Events 

```javascript
table.onRowAdded(cb: EventCallback): Subscription
````
#### *Example*

```javascript
table.onRowAdded(e => {
  console.log('table.onRowAdded:', e);
})
```

#### Listening for `onCellUpdated` Events 

```javascript
table.onCellUpdated(cb: EventCallback): Subscription
```

#### *Example*
```javascript
table.onCellUpdated(e => {
  console.log('table.onCellUpdated:', e);
})
```

#### Listening for all events under a `Core` (Wildcard)

Use the `.on` method to listen to all table events 
```javascript
table.on(cb: EventCallback): Subscription
```

#### *Example*
```javascript
table.on(e => {
  console.log('table.on:', e);
})
```

<!-- tabs:end -->

## Views
<!-- tabs:start -->

### **Creating View(s)**

#### Creating a Single View
```javascript
table.addView(addViewInput: {
  name: string;
  type: ViewType;
}): Promise<View>;
```
#### *Example*
```javascript
const view = await table.addView({ name: 'grid view', type: ViewType.GRID });
```

### **Retrieving View(s)**

#### Getting a Single View 

```javascript
table.view(id: string): View;
```
#### *Example*
```javascript
const view = await table.view('viwb5506fe6370f0e4b');
```
<!-- tabs:end -->

## Rows 

<!-- tabs:start -->
### **Adding a row to a table**

#### Adding a single row 
```javascript
table.addRow(): Promise<Row>;
```
#### *Example*
```javascript
const row = await table.addRow();
```

#### Adding multiple rows 

```javascript
table.addRows(number: number): Promise<RowArray>;
```
#### *Example, add 5 rows*
```javascript
const rowArray = await table.addRows(5);
```
### **Retrieving row(s)**

#### Getting a Single Row 
```javascript
view.row(id: string): Row;
```
#### *Example*
```javascript
const row = await view.row('rowb5506fe5eb875868');
```

#### Getting Multiple Rows

```javascript
view.getRows(): ColumnArray
```
#### *Example*
```javascript
const viewArray = await view.getRows()
```

### **Subscribing to Row Events**

#### Listening for `onCellUpdated` Events 

```javascript
row.onCellUpdated(cb: EventCallback): Subscription
```
#### *Example*
```javascript
row.onCellUpdated(e => {
  console.log('row.onCellUpdated:', e);
})
```
#### Listening for all events under a `Row` (Wildcard)

Use the `.on` method to subscribe to all `row` events.

```javascript
row.on(cb: EventCallback): Subscription
```
#### *Example*
```javascript
row.on(e => {
  console.log('row.on:', e);
})
```
<!-- tabs:end -->

## Columns

<!-- tabs:start -->
### **Adding Columns**

#### Adding a Single Column
```javascript
table.addColumn(conlumnConfig: {
  type: ColumnType;
  name: string;
  order?: number;
  visibility?: boolean;
  foreignTableId?: string;
  defaultNumber?: number;
  precision?: number;
  choices?: Choice[];
}): Promise<Column>;
```
#### *Example*
```javascript
const column = await table.addColumn({
  type: ColumnType.TEXT,
  name: "column",
});
```

#### Adding multiple Columns

```javascript
table.addColumns(columnConfigs: ColumnConfig[]): Promise<Column>;
```
#### *Example*
```javascript
const columnArray = await table.addColumns([
  { type: ColumnType.TEXT, name: "column1" },
  { type: ColumnType.TEXT, name: "column2" },
]);
```

### **Retrieving Column(s)**

#### Getting a single column
```javascript
view.column(id: string): View
```
#### *Example*
```javascript
const view = await view.column('colb5506fe5028c62d9')
```

#### Getting multiple columns

```javascript
view.getColumns(): ColumnArray
```
#### *Example*

```javascript
const viewArray = await view.getColumns()
```

### **Subscribing to Column Events**

#### Listening for all `cellUpdated` events under a `Column` (Wildcard)
```javascript
column.onCellUpdated(cb: EventCallback): Subscription
```
#### *Example*
```javascript
column.onCellUpdated(e => {
  console.log('column.onCellUpdated:', e);
})
```
#### Listening for all events under a `Column` (Wildcard)

Use the `.on` method for subscribe to all column events. 
```javascript
column.on(cb: EventCallback): Subscription
```
#### *Example*
```javascript
column.on(e => {
  console.log('column.on:', e);
})
```
<!-- tabs:end -->

## Cell

<!-- tabs:start -->

### **Updating Cells**

#### Update a single cell 
```javascript
table.updateCell(updateCellInput: { rowId: string, columnId: string, value: Value}): Promise<Cell>;
```
#### *Example*
```javascript
const row = await table.updateCell({
  rowId: "rowb545d20fe08226ed",
  columnId: "colb545910eed85035e",
  value: {
    type: ColumnType.TEXT,
    text: "newCell"
  }
});
```

#### Update multiple cells

```javascript
table.updateCells(updateCellInput[]: {
  rowId: string;
  columnId: string;
  value: Value;
}[]): Promise<CellArray>;
```
#### *Example*
```javascript
const cellArray = await table.updateCells([
  {
  rowId: "rowb545d20fe08226ed",
  columnId: "colb545910eed85035e",
  value: {
    type: ColumnType.TEXT,
    text: "newCell1"
  },
  {
    rowId: "rowb545d20fe08226ec",
    columnId: "colb545910eed85035c",
    value: {
      type: ColumnType.TEXT,
      text: "newCell2"
    }
  }
]);
```
### **Retrieving Cell(s)**

#### Get all cells from a column
```javascript
row.cell(columnId: string): Cell
```
#### *Example*
```javascript
const cell = await row.cell('colb5506fe5028c62d9')
```

#### Get all cells from a row

```javascript
column.cell(rowId: string): Cell
```
#### *Example*
```javascript
const cell = await column.cell('rowb5506fe5eb875868')
```

### **Subscribe to all cell events**

#### Listen to all `onCellUpdated` events for a Cell

```javascript
cell.onCellUpdated(cb: EventCallback): Subscription
```

#### *Example*
```javascript
cell.onCellUpdated(e => {
  console.log('cell.onCellUpdated:', e);
})
```
#### Listen to all events for a Cell (Wildcard)

Use the `.on` method to subscribe to all cell events. 
```javascript
cell.on(cb: EventCallback): Subscription
```

#### *Example*
```javascript
cell.on(e => {
  console.log('cell.on:', e);
})
```
<!-- tabs:end -->
