Skip to content

Commit

Permalink
wip: training
Browse files Browse the repository at this point in the history
  • Loading branch information
cpaulve-1A authored and sdo-1A committed Oct 10, 2024
1 parent 992f1ff commit 051ad6e
Show file tree
Hide file tree
Showing 85 changed files with 3,446 additions and 24 deletions.
6 changes: 4 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"jest.debugMode": true,
"jest.runMode": "on-save",
"testing.openTesting": "neverOpen",
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.enabled": false,
"explorer.fileNesting.patterns": {
"readme.md": "security.md, code_of_conduct.md, contributing.md",
"*.js": "${capture}.js.map, ${capture}.d.ts, ${capture}.d.ts.map",
Expand Down Expand Up @@ -89,5 +89,7 @@
"files.trimTrailingWhitespace": true,
"files.trimFinalNewlines": false,
"otter.extract.styling.prefix": "o3r",
"typescript.tsserver.experimental.useVsCodeWatcher": false
"typescript.tsserver.experimental.useVsCodeWatcher": false,
"editor.tabSize": 2,
"explorer.fileNesting.expand": false
}
1 change: 1 addition & 0 deletions apps/showcase/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { MonacoEditorModule } from 'ngx-monaco-editor-v2';
import { DatePickerHebrewInputPresComponent, ScrollBackTopPresComponent, SidenavPresComponent } from '../components/utilities';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import {MonacoEditorModule} from 'ngx-monaco-editor-v2';


const runtimeChecks: Partial<RuntimeChecks> = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
o3r-training {
height: calc(100vh - 4rem);
}
23 changes: 23 additions & 0 deletions apps/showcase/src/app/sdk-training/sdk-training.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { SdkTrainingComponent } from './sdk-training.component';

describe('SdkTrainingComponent', () => {
let component: SdkTrainingComponent;
let fixture: ComponentFixture<SdkTrainingComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SdkTrainingComponent]
})
.compileComponents();

fixture = TestBed.createComponent(SdkTrainingComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
1 change: 1 addition & 0 deletions apps/showcase/src/assets/sdk-training-openapi-diagram.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
113 changes: 113 additions & 0 deletions apps/showcase/src/assets/sdk-training/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
[
{
"title": "Welcome to the Otter SDK tutorial",
"htmlContentUrl": "./steps/welcome/instructions.html"
},
{
"title": "Introduction",
"htmlContentUrl": "./steps/introduction/instructions.html"
},
{
"title": "How to use the Otter SDK?",
"htmlContentUrl": "./steps/typescript-sdk/instructions.html"
},
{
"title": "Customize your fetch client with plugins",
"htmlContentUrl": "./steps/plugins/instructions.html"
},
{
"title": "Integrate your component in Angular",
"htmlContentUrl": "./steps/angular-integration/instructions.html",
"filesConfiguration": {
"name": "angular-integration",
"startingFile": "apps/tutorial-app/src/app/app.component.ts",
"urls": {
".": "./shared/monorepo-template.json",
"./libs/sdk/src": "@o3r/training-sdk/folder-structure.json"
},
"mode": "interactive",
"commands": ["npm install --legacy-peer-deps --ignore-scripts --force", "npm run ng run sdk:build", "npm run ng run tutorial-app:serve"]
}
},
{
"title": "Generate your first SDK - Specifications",
"htmlContentUrl": "./steps/sdk-specs/instructions.html",
"filesConfiguration": {
"name": "sdk-specification",
"startingFile": "open-api.yaml",
"solutionUrls": {
".": "@o3r/training-sdk/openapi-structure.json"
},
"mode": "readonly",
"commands": []
}
},
{
"title": "Generate your first SDK - Command",
"htmlContentUrl": "./steps/sdk-generation/instructions.html",
"filesConfiguration": {
"name": "generate-sdk",
"startingFile": "src/api/dummy/dummy-api.ts",
"solutionUrls": {
"src": "@o3r/training-sdk/folder-structure.json",
".": "@o3r/training-sdk/openapi-structure.json"
},
"mode": "readonly",
"commands": []
}
},
{
"title": "SDK with Dates - Generation",
"htmlContentUrl": "./steps/date-sdk-generation/instructions.html",
"filesConfiguration": {
"name": "generate-date-sdk",
"startingFile": "open-api.yaml",
"urls": {
".": "@o3r/training-sdk/openapi-structure.json"
},
"solutionUrls": {
".": "@o3r/training-sdk/openapi-structure.json",
"./src": "@o3r/training-sdk/folder-structure.json"
},
"mode": "readonly",
"commands": []
}
},
{
"title": "SDK with Dates - How to use",
"htmlContentUrl": "./steps/date/instructions.html",
"filesConfiguration": {
"name": "utils-date",
"startingFile": "apps/app/src/app/app.component.ts",
"urls": {
".": "./shared/empty.json",
"./apps/app/src/app": "./steps/date/exercise.json"
},
"solutionUrls": {
"./apps/app/src/app": "./steps/date/solution.json"
},
"mode": "interactive",
"commands": [
"npm install --legacy-peer-deps --ignore-scripts --force",
"npm run ng run app:serve"
]
}
},
{
"title": "SDK with model extension",
"htmlContentUrl": "./steps/model-extension/instructions.html",
"filesConfiguration": {
"name": "model-extension",
"startingFile": "package.json",
"urls": {
".": "./shared/monorepo-template.json"
},
"mode": "interactive",
"commands": [
"npm install --legacy-peer-deps --ignore-scripts --force",
"npm run ng run sdk:build",
"npm run ng run tutorial-app:serve"
]
}
}
]
127 changes: 127 additions & 0 deletions apps/showcase/src/assets/sdk-training/shared/empty.json

Large diffs are not rendered by default.

428 changes: 428 additions & 0 deletions apps/showcase/src/assets/sdk-training/shared/monorepo-template.json

Large diffs are not rendered by default.

127 changes: 127 additions & 0 deletions apps/showcase/src/assets/sdk-training/shared/monorepo-with-app

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<h3>Introduction:</h3>
<p>
When dealing with an Angular project, you will need to ensure that your <code>ApiClient</code> will be shared accross
your application. The Otter framework provides the <code>ApiManager</code> service to manage your API collection.
</p>
<h3>Prerequisite:</h3>
<p>
- Install the <code>@o3r/apis-manager</code> in the project with <code>npm install @o3r/apis-manager</code>.
</p>
<h3>Objectives:</h3>
<p>
Leverage the <code>ApiManager</code> service to access two different clients to retrieve the list of available
pets and submit an order for the first pet returned.
</p>
<p>
Add a plugin to the <code>OrderApi</code> to log each time a call is sent.
</p>
<h3>Exercise</h3>
<p>
Integrate the <code>ApiManager</code> in your application module and configure it to use the <code>RequestLogPlugin</code> in the <code>OrderApi</code>.
You can inspire yourself with the following lines:
<pre>
<code>
// Default configuration for all the APIs defined in the ApiManager
const apiConfig: ApiClient = new ApiFetchClient(
{
basePath: 'https://petstore3.swagger.io/api/v3',
requestPlugins: [],
fetchPlugins: [],
logger
}
);
const apiManager = new ApiManager(apiConfig, {
// Configuration override for a specific API
OrderApi: new ApiFetchClient({
basePath: 'https://petstore3.swagger.io/api/v3',
requestPlugins: [new RequestLogPlugin()],
fetchPlugins: [],
logger
})
});

export const appConfig: ApplicationConfig = {
providers: [],
imports: [ApiManagerModule.forRoot(apiManager)]
};</code>
</pre>
</p>
<p>
Now, checkout the <code>app.component.ts</code> file and inject the ApiManager to use your unique instance of the <code>OrderApi</code> and
<code>PetApi</code>.
In your constructor, update the <code>availablePets</code> list with the result of a call to <code>findPetsByStatus</code>.
</p>
<p>Your application should be updated with the list of available pets. You only need to update the submit method to order the first available item.</p>
<p>Don't forget to refresh the list of available pets once this is done.</p>
<p>Check out your terminal, the request to the <code>OrderApi</code> have been logged just as configured in the <code>ApiManager</code></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<p>
If your specification file includes dates, there are multiple options for the generation of your SDK.
</p>
<p>
For this exercise, let's consider a specific use case. Imagine your SDK is used on a flight booking site, including international travel.
A user who is currently in France is planning a round trip from Paris to New York City. These cities are in different timezones, which needs
to be taken into account when the user books their flights. The outbound and return flights must be relative to the timezones of the airports.
</p>
<p>
To do so, the dates of the flights must be of type <code>utils.DateTime</code>.
</p>
<p>
Also, for this flight booking site, each flight has an expiration date-time for the payment, which is relative to the user's timezone.
</p>

<h3>Exercise</h3>
<p>
<i>
This exercise should be done in your local environment. We have provided the template and the solution on the right.
(Due to a Java constraint, you won't be able to generate your own SDK in the code editor provided on the right.)
</i>
</p>
<p>
Let's create a specification file for our flight booking site. This SDK should contain a definition with the properties to book a flight:
</p>
<ul>
<li>Origin location code</li>
<li>Destination location code</li>
<li>Departure date-time</li>
<li>Payment expiration date</li>
</ul>
<p>
As mentioned above, the type of the departure date-time should be <code>utils.DateTime</code> after generation, which can be defined by setting the
type of the property to <code>string</code> and adding the <code>x-local-timezone</code> vendor. Once your specification file is created, you
can generate your SDK.
</p>
<pre class="w-100 bg-body-tertiary px-5 pre-whitespace">
<code>
yarn schematics @ama-sdk/schematics:typescript-core --spec-path ./path/to/openapi.yaml
</code>
</pre>
<p>
As you may notice, your date object is generated as a <code>string</code> instead of <code>Date</code>. This is normal since the
default configuration of the SDK generator has an option <code>stringifyDate</code> that is set to <code>true</code>. To ensure that the date
object is generated correctly, this option needs to be set to false either through the command line or in <code>openapitools.json</code>. For example:
</p>
<pre class="w-100 bg-body-tertiary px-5 pre-whitespace">
<code>
yarn schematics @ama-sdk/schematics:typescript-core --spec-path ./path/to/openapi.yaml --global-property stringifyDate=false
</code>
</pre>
<p>
<i><u>Note:</u> The <code>stringifyDate</code> option does not impact the generation of a <code>utils.Date</code> object.</i>
</p>
<p>
To make sure you have generated the correct SDK locally, check out the solution in the file <code>SOLUTION/src/models/base/flight/flight.ts</code>.
</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<button type="button" class="btn btn-primary" (click)="updateValues()">Update Values</button>
<table class="table">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">Date</th>
<th scope="col">utils.DateTime</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Value</th>
<td>{{date}}</td>
<td>{{dateTime}}</td>
</tr>
</tbody>
</table>
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { utils } from '@ama-sdk/core';
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
standalone: true,
imports: [],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent {
title = 'tutorial-app';

/** Date value used to initialize the two date variables */
public dateValue = '';
/** Date variable of type Date */
public date: Date | null = null;
/** Date variable of type utils.DateTime */
public dateTime: utils.DateTime | null = null;

constructor() {
this.updateValues();
}

public updateValues() {
/** Set the values of the two variables here */
}
}
44 changes: 44 additions & 0 deletions apps/showcase/src/assets/sdk-training/steps/date/instructions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<p>
As previously explained, dates can be generated differently based on the specifications and the generator options.
The possible types include:
</p>
<ul>
<li><code>Date</code></li>
<li><code>string</code></li>
<li><code>utils.Date</code></li>
<li><code>utils.DateTime</code></li>
</ul>
<p>
For this exercise, we will focus on the types <code>Date</code> and <code>utils.DateTime</code> to compare how
these are impacted by timezones.
</p>

<h3>Exercise</h3>
<p>
As you can see on the right, we have provided a template component file to be filled. There are three variables to update:
</p>
<ul>
<li><code>dateValue</code> : A stringified date value that will be used to initialize the other two variables</li>
<li><code>date</code> : Date variable of type <code>Date</code></li>
<li><code>utils.Date</code> : Date variable of type <code>utils.DateTime</code></li>
</ul>
<p>
Start by setting <code>dateValue</code>, which should respect the following format that includes the timezone:
<b>YYYY-MM-DDTHH:MM:SS+HH:MM</b>. It is best to set a timezone different than your local environment to notice a
difference between the two variables later on.
</p>
<p>
Next, initialize the values of <code>date</code> and <code>dateTime</code> in the function <code>updateValues()</code>.
This function is called in the constructor and can be triggered when clicking the <b>"Update Values"</b> button in the
preview of the application.
</p>
<p>
If correctly set, you should see the values appear in the table of the application. Since you have set the date value in
a timezone different from your local environment, you can see that the values of the two variables are different.
This is normal since <code>utils.DateTime</code> ignores the timezone of the date value (as explained in its documentation).
</p>
<p>
You can play around with these values to see how they are impacted by changing the timezone of your local environment
and clicking on the <b>"Update Values"</b> button (do not refresh the page). You should observe that the <code>Date</code>
value is updated while the <code>utils.DateTime</code> value is not impacted.
</p>
Loading

0 comments on commit 051ad6e

Please sign in to comment.