Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 44 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,45 @@
# io.Connect Desktop Tutorials

Source code for the JavaScript tutorial for developing an **io.Connect Desktop** project.

For a guide on using the tutorial code, see the [Tutorials](https://docs.interop.io/desktop/tutorials/javascript/index.html) section of the official **io.Connect Desktop** documentation.

# io.Connect Desktop Tutorials

Source code for the JavaScript and TypeScript tutorials for developing an **io.Connect Desktop** project.

For a guide on using the tutorial code, see the [Tutorials](https://docs.interop.io/desktop/tutorials/javascript/index.html) section of the official **io.Connect Desktop** documentation.

## JavaScript Version

The JavaScript tutorial is located in the `javascript` directory. It contains both starter code and the complete solution.

## TypeScript Version

The TypeScript tutorial is located in the `typescript` directory. It mirrors the JavaScript version but with TypeScript support. Both starter code and solution are provided.

### Building TypeScript Projects

1. Navigate to either the `typescript/solution` or `typescript/start` directory:

```bash
cd typescript/solution
# or
cd typescript/start
```

2. Install dependencies:

```bash
npm install
```

3. Build all applications:

```bash
npm run build
```

4. Start the applications:

```bash
npm start
```

You can also build and start individual applications using the specific build and start scripts. See the package.json for available commands.

> ⚠️ *Note that this tutorial is for a licensed product.*
14 changes: 14 additions & 0 deletions typescript/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "ts-tutorial",
"version": "1.0.0",
"description": "io.Connect Desktop TypeScript Tutorial",
"scripts": {
"install:all": "cd solution && npm install && cd ../start && npm install",
"build:solution": "cd solution && npm run build",
"build:start": "cd start && npm run build",
"build": "npm run build:solution && npm run build:start"
},
"devDependencies": {
"typescript": "^5.3.3"
}
}
12 changes: 12 additions & 0 deletions typescript/solution/app-definitions/client-details.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "client-details",
"title": "Client Details",
"type": "window",
"details": {
"url": "http://localhost:9200/"
},
"customProperties": {
"folder": "Asset Management",
"includeInWorkspaces": true
}
}
17 changes: 17 additions & 0 deletions typescript/solution/app-definitions/clients.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "clients",
"title": "Clients",
"type": "window",
"details": {
"url": "http://localhost:9000/",
"minWidth": 400,
"minHeight": 400,
"channelSelector": {
"enabled": false
}
},
"customProperties": {
"folder": "Asset Management",
"includeInWorkspaces": true
}
}
20 changes: 20 additions & 0 deletions typescript/solution/app-definitions/portfolio-downloader.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "portfolio-downloader",
"title": "Portfolio Downloader",
"type": "window",
"details": {
"url": "http://localhost:9300/"
},
"intents": [
{
"name": "ExportPortfolio",
"displayName": "Download Portfolio",
"contexts": [
"ClientPortfolio"
]
}
],
"customProperties": {
"folder": "Asset Management"
}
}
33 changes: 33 additions & 0 deletions typescript/solution/app-definitions/stocks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[
{
"name": "stocks",
"title": "Stocks",
"type": "window",
"ignoreSavedLayout": true,
"details": {
"url": "http://localhost:9100/",
"width": 500,
"height": 450,
"minWidth": 450,
"minHeight": 400,
"channelSelector": {
"enabled": false
}
},
"customProperties": {
"folder": "Asset Management",
"includeInWorkspaces": true
}
},
{
"name": "stock-details",
"title": "Stock Details",
"type": "window",
"details": {
"url": "http://localhost:9100/details"
},
"customProperties": {
"folder": "Asset Management"
}
}
]
48 changes: 48 additions & 0 deletions typescript/solution/client-details/esbuild.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const fs = require('fs');
const path = require('path');
const { build } = require('esbuild');

// Directory paths
const srcDir = path.join(__dirname, 'src');
const distDir = path.join(__dirname, 'dist');

// Ensure dist directory exists
if (!fs.existsSync(distDir)) {
fs.mkdirSync(distDir, { recursive: true });
}

// Copy HTML file
fs.copyFileSync(
path.join(srcDir, 'index.html'),
path.join(distDir, 'index.html')
);

// Copy lib directory
const libSrcDir = path.join(srcDir, 'lib');
const libDistDir = path.join(distDir, 'lib');

if (!fs.existsSync(libDistDir)) {
fs.mkdirSync(libDistDir, { recursive: true });
}

fs.readdirSync(libSrcDir).forEach(file => {
fs.copyFileSync(
path.join(libSrcDir, file),
path.join(libDistDir, file)
);
});

// Build with esbuild
build({
entryPoints: [path.join(srcDir, 'index.ts')],
bundle: true,
outfile: path.join(distDir, 'index.js'),
platform: 'browser',
format: 'iife',
sourcemap: true,
target: ['es2020'],
tsconfig: path.join(__dirname, 'tsconfig.json'),
}).catch((error) => {
console.error(error);
process.exit(1);
});
72 changes: 72 additions & 0 deletions typescript/solution/client-details/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!DOCTYPE html>

<!-- io.Connect THEME -->
<html lang="en" class="dark">

<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Client Details</title>

<!-- STYLES -->
<link rel="stylesheet" href="/lib/io.applications.css">

<!-- SCRIPTS -->
<!-- TODO: Chapter 3 -->
<script src="/lib/desktop.umd.js"></script>
<!-- TODO: Chapter 9.2 -->
<script src="/lib/workspaces.umd.js"></script>
<script src="./index.js"></script>
</head>

<body>
<div class="container-fluid">
<div class="row">
<div class="row m-0 px-0 py-1">
<div class="col-6 px-1">
<span id="ioConnectSpan" class="badge bg-danger">io.Connect is unavailable</span>
</div>
</div>
<div class="row m-0">
<h1 class="text-center">Client Details</h1>
</div>
</div>
<div class="row">
<table id="clientsTable" class="table table-hover">
<thead>
<tr>
<th>Detail</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<th>Full Name</th>
<td data-name></td>
</tr>
<tr>
<th>Address</th>
<td data-address></td>
</tr>
<tr>
<th>Phone Number</th>
<td data-phone></td>
</tr>
<tr>
<th>Email</th>
<td data-email></td>
</tr>
<tr>
<th>Account Manager</th>
<td data-manager></td>
</tr>
</tbody>
</table>
</div>
</div>
</body>

</html>
74 changes: 74 additions & 0 deletions typescript/solution/client-details/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
const setFields = (client: Client): void => {
const elementName = document.querySelectorAll("[data-name]")[0] as HTMLElement;
if (elementName) elementName.innerText = client.name;

const elementAddress = document.querySelectorAll("[data-address]")[0] as HTMLElement;
if (elementAddress) elementAddress.innerText = client.address || '';

const elementPhone = document.querySelectorAll("[data-phone]")[0] as HTMLElement;
if (elementPhone) elementPhone.innerText = client.contactNumbers || '';

const elementOccupation = document.querySelectorAll("[data-email]")[0] as HTMLElement;
if (elementOccupation) elementOccupation.innerText = client.email || '';

const elementManager = document.querySelectorAll("[data-manager]")[0] as HTMLElement;
if (elementManager) elementManager.innerText = client.accountManager || '';
};

// TODO: Chapter 3
const toggleIOAvailable = (): void => {
const span = document.getElementById("ioConnectSpan");
if (!span) return;

span.classList.remove("bg-danger");
span.classList.add("bg-success");
span.textContent = "io.Connect is available";
};

const start = async (): Promise<void> => {
const html = document.documentElement;
const initialTheme = iodesktop.theme;

html.className = initialTheme;

// TODO: Chapter 3
const config = {
libraries: [IOWorkspaces]
};

const io = await IODesktop(config);

window.io = io;

toggleIOAvailable();

// TODO: Chapter 12.1
const themeHandler = (newTheme: Theme): void => {
html.className = newTheme.name;
};

io.themes.onChanged(themeHandler);

// TODO: Chapter 9.4
const myWorkspace = await io.workspaces.getMyWorkspace();

if (myWorkspace) {
const updateHandler = (context: any): void => {
if (context.client) {
setFields(context.client);
myWorkspace.setTitle(context.client.name);
}
};

myWorkspace.onContextUpdated(updateHandler);
}
};

// Add io property to window object
declare global {
interface Window {
io: IODesktopAPI;
}
}

start().catch(console.error);
Loading