Skip to content

Commit

Permalink
Feat/otter training (#2551)
Browse files Browse the repository at this point in the history
## Proposed change

Design a training solution integrated in the showcase based on
webcontainers.
Implement the SDK training.

## Related issues

<!--
Please make sure to follow the [contribution
guidelines](https://github.com/amadeus-digital/Otter/blob/main/CONTRIBUTING.md)
-->

*- No issue associated -*

<!-- * 🐛 Fix #issue -->
<!-- * 🐛 Fix resolves #issue -->
<!-- * 🚀 Feature #issue -->
<!-- * 🚀 Feature resolves #issue -->
<!-- * :octocat: Pull Request #issue -->
  • Loading branch information
cpaulve-1A authored Jan 9, 2025
2 parents e116ac5 + 8b1f644 commit d45970e
Show file tree
Hide file tree
Showing 206 changed files with 5,966 additions and 160 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,6 @@
"**/.pnp.*": true
},
"typescript.enablePromptUseWorkspaceTsdk": true,
"typescript.tsserver.watchOptions": "vscode",
"typescript.tsdk": ".yarn/sdks/typescript/lib"
}
3 changes: 3 additions & 0 deletions apps/showcase/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@
dist-e2e-playwright
playwright-reports
test-results
training-assets
src/assets/trainings/**/exercise.json
src/assets/trainings/**/solution.json
8 changes: 8 additions & 0 deletions apps/showcase/e2e-playwright/sanity/lighthouse-sanity.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,12 @@ test.describe('Lighthouse tests', () => {
await page.waitForURL('**/placeholder');
await performAudit('placeholder', page, testInfo);
});

test('sdk-intro', async ({ page }, testInfo) => {
await page.goto(baseUrl);
const appFixture = new AppFixtureComponent(new O3rElement({ element: page.locator('app-root'), page }));
await appFixture.navigateToSDKIntro();
await page.waitForURL('**/sdk-intro');
await performAudit('sdk-intro', page, testInfo);
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions apps/showcase/e2e-playwright/sanity/visual-sanity.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {
import {
AppFixtureComponent,
} from '../../src/app/app.fixture';
import {
TrainingFixtureComponent,
} from '../../src/components/training/training.fixture';

test.describe.serial('Sanity test', () => {
test('Visual comparison for each page', async ({ browserName, page }) => {
Expand Down Expand Up @@ -75,5 +78,24 @@ test.describe.serial('Sanity test', () => {
await page.waitForURL('**/placeholder');
await expect(page).toHaveScreenshot([browserName, 'placeholder.png'], { fullPage: true, mask: [page.locator('.visual-testing-ignore')] });
});

await test.step('sdk-intro', async () => {
await appFixture.navigateToSDKIntro();
await page.waitForURL('**/sdk-intro');
await expect(page).toHaveScreenshot([browserName, 'sdk-intro.png'], { fullPage: true, mask: [page.locator('.visual-testing-ignore')] });
});

await test.step('sdk-training', async () => {
await appFixture.navigateToSDKTraining();
await page.waitForURL('**/sdk-training*');
await expect(page).toHaveScreenshot([browserName, 'sdk-training.png'], { fullPage: true, mask: [page.locator('.visual-testing-ignore')] });

const trainingFixture = new TrainingFixtureComponent(new O3rElement({ element: page.locator('o3r-training'), page }));
for (let i = 1; i < 9; i++) {
await trainingFixture.clickOnNextStep();
await page.waitForURL(`**/sdk-training#${i}`);
await expect(page).toHaveScreenshot([browserName, `sdk-training-step${i + 1}.png`], { fullPage: true, mask: [page.locator('.visual-testing-ignore')] });
}
});
});
});
5 changes: 4 additions & 1 deletion apps/showcase/eslint.local.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ export default [
'dev-resources/**/*',
'playwright-reports/**/*',
'test-results/**/*',
'*.metadata.json'
'*.metadata.json',
'src/assets/trainings/sdk/**/*',
'src/coi-serviceworker.js',
'training-assets/**/*'
]
},
{
Expand Down
10 changes: 8 additions & 2 deletions apps/showcase/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
"start:no-translation": "ng serve",
"generate:translations:dev": "ng run showcase:generate-translations",
"generate:translations": "ng run showcase:generate-translations:production",
"prepare-training": "node scripts/prepare-training-exercises/index.cjs",
"cms-adapters:localizations": "ng run showcase:extract-translations",
"cms-adapters:metadata": "yarn run cms-adapters:localizations",
"update:otter": "ng update @o3r/core",
"test:playwright": "concurrently -m 1 -P 'yarn run test:playwright:* {*}' --",
"test:playwright:scenario": "USE_MOCKS=true playwright test --config=e2e-playwright/playwright-config.ts",
"test:playwright:sanity": "USE_MOCKS=true playwright test --config=e2e-playwright/playwright-config.sanity.ts",
"update-screenshots": "node scripts/update-screenshots/index.cjs",
"copy-training-assets": "node scripts/copy-training-assets/index.cjs",
"postbuild:patch": "yarn patch:package",
"patch:package": "cpy 'package.json' 'dist' && patch-package-json-main"
},
Expand Down Expand Up @@ -53,6 +55,7 @@
"@nx/jest": "~19.8.0",
"@o3r-training/showcase-sdk": "workspace:^",
"@o3r-training/training-tools": "workspace:^",
"@o3r/apis-manager": "workspace:^",
"@o3r/application": "workspace:^",
"@o3r/components": "workspace:^",
"@o3r/configuration": "workspace:^",
Expand All @@ -62,6 +65,7 @@
"@o3r/logger": "workspace:^",
"@o3r/routing": "workspace:^",
"@o3r/rules-engine": "workspace:^",
"@o3r/store-sync": "workspace:^",
"@o3r/styling": "workspace:^",
"@o3r/testing": "workspace:^",
"@popperjs/core": "^2.11.5",
Expand All @@ -71,14 +75,15 @@
"@xterm/xterm": "^5.0.0",
"ag-grid-angular": "~32.3.0",
"ag-grid-community": "~32.3.0",
"angular-split": "^18.0.0",
"bootstrap": "5.3.3",
"clipboard": "^2.0.11",
"intl-messageformat": "~10.7.0",
"marked": "^12.0.0",
"monaco-editor": "~0.52.0",
"monaco-editor": "~0.50.0",
"ngx-markdown": "^18.1.0",
"ngx-monaco-editor-v2": "^18.0.0",
"ngx-monaco-tree": "^18.1.0",
"ngx-monaco-tree": "^18.4.0",
"pixelmatch": "^5.2.1",
"pngjs": "^7.0.0",
"prism-themes": "^1.9.0",
Expand All @@ -98,6 +103,7 @@
"@angular/compiler-cli": "~18.2.0",
"@eslint-community/eslint-plugin-eslint-comments": "^4.4.0",
"@nx/eslint-plugin": "~19.8.0",
"@o3r-training/training-sdk": "workspace:^",
"@o3r/build-helpers": "workspace:^",
"@o3r/design": "workspace:^",
"@o3r/eslint-config": "workspace:^",
Expand Down
79 changes: 76 additions & 3 deletions apps/showcase/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@
},
"compile": {
"executor": "@angular-devkit/build-angular:application",
"inputs": [
"source",
"^structure",
"{projectRoot}/dev-resources",
"{projectRoot}/training-assets",
"{projectRoot}/*.metadata.json"
],
"options": {
"outputPath": "apps/showcase/dist",
"index": "apps/showcase/src/index.html",
Expand All @@ -65,6 +72,7 @@
"assets": [
"apps/showcase/src/favicon.ico",
"apps/showcase/src/favicon.svg",
"apps/showcase/src/coi-serviceworker.js",
"apps/showcase/src/assets",
"apps/showcase/src/custom-assets",
{
Expand All @@ -76,11 +84,33 @@
"glob": "*.metadata.json",
"input": "apps/showcase",
"output": "/metadata"
},
{
"glob": "**/*",
"input": "apps/showcase/training-assets/monaco-editor",
"output": "/assets/monaco/"
},
{
"glob": "**/*",
"input": "apps/showcase/training-assets/ngx-monaco-tree/assets",
"output": "/assets/"
},
{
"glob": "*.json",
"input": "packages/@o3r-training/training-sdk/dist/structure",
"output": "/assets/@o3r-training/training-sdk/structure"
},
{
"glob": "*.json",
"input": "packages/@o3r-training/showcase-sdk/dist/structure",
"output": "/assets/@o3r-training/showcase-sdk/structure"
}
],
"styles": [
"apps/showcase/src/styles.scss",
"prism-themes/themes/prism-vsc-dark-plus.css",
"apps/showcase/training-assets/@vscode/codicons/dist/codicon.css",
"apps/showcase/training-assets/@xterm/xterm/css/xterm.css",
{
"inject": false,
"input": "apps/showcase/src/style/dark-theme/dark-theme.scss",
Expand All @@ -102,7 +132,8 @@
"prismjs/components/prism-markup",
"prismjs/components/prism-regex",
"prismjs/components/prism-typescript",
"prismjs/components/prism-yaml"
"prismjs/components/prism-yaml",
"apps/showcase/src/coi-serviceworker.js"
]
},
"configurations": {
Expand Down Expand Up @@ -131,10 +162,13 @@
"defaultConfiguration": "production",
"dependsOn": [
"^build",
"^extract-folder-structure",
"generate-translations",
"generate-theme",
"generate-dark-theme",
"generate-horizon-theme"
"generate-horizon-theme",
"copy-training-assets",
"prepare-training"
]
},
"serve": {
Expand All @@ -150,11 +184,20 @@
},
"dependsOn": [
"^build-builders",
"^build"
"^build",
"^extract-folder-structure",
"copy-training-assets",
"prepare-training"
]
},
"serve-app": {
"executor": "@angular-devkit/build-angular:dev-server",
"options": {
"headers": {
"Cross-Origin-Opener-Policy": "same-origin",
"Cross-Origin-Embedder-Policy": "require-corp"
}
},
"configurations": {
"production": {
"buildTarget": "showcase:compile:production"
Expand Down Expand Up @@ -359,6 +402,36 @@
]
},
"dependsOn": ["^build-builders"]
},
"prepare-training": {
"cache": true,
"executor": "nx:run-script",
"inputs": [
"{projectRoot}/package.json",
"{projectRoot}/src/assets/**/exercise/**",
"{projectRoot}/src/assets/**/solution/**",
"{projectRoot}/scripts/prepare-training-exercises/*.cjs"
],
"outputs": [
"{projectRoot}/src/assets/**/solution.json",
"{projectRoot}/src/assets/**/exercise.json"
],
"options": {
"script": "prepare-training"
},
"dependsOn": ["^build", "^build-cli"]
},
"copy-training-assets": {
"cache": true,
"executor": "nx:run-script",
"inputs": [
"{projectRoot}/package.json",
"{projectRoot}/scripts/copy-training-assets/*.cjs"
],
"outputs": ["{projectRoot}/training-assets"],
"options": {
"script": "copy-training-assets"
}
}
},
"tags": ["showcase"]
Expand Down
122 changes: 122 additions & 0 deletions apps/showcase/schemas/training-program.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
{
"$schema": "http://json-schema.org/schema",
"type": "object",
"$id": "TrainingProgramSchema",
"title": "Training program",
"description": "Training program steps and their descriptions",
"properties": {
"$schema": {
"type": "string"
},
"trainingSteps": {
"type": "array",
"description": "Steps of the training program",
"items": {
"type": "object",
"properties": {
"stepTitle": {
"type": "string",
"description": "Step title"
},
"htmlContentUrl": {
"type": "string",
"description": "URL to step instructions (HTML content)"
},
"filesConfiguration": {
"type": "object",
"description": "Step files configuration",
"properties": {
"exerciseId": {
"type": "string",
"pattern": "^(sdk)-[a-zA-Z0-9-]+",
"description": "Unique identifier of the directory in which files will be put"
},
"startingFile": {
"type": "string",
"description": "Starting file to be displayed in the project"
},
"commands": {
"type": "array",
"description": "Commands to run in the project",
"items": {
"type": "string"
}
},
"urls": {
"type": "array",
"description": "URLs of step project",
"items": {
"type": "object",
"description": "Step project content and its corresponding path",
"properties": {
"path": {
"type": "string",
"description": "Path in step project"
},
"contentUrl": {
"type": "string",
"description": "URL of content"
}
},
"additionalProperties": false,
"required": [
"path",
"contentUrl"
]
}
},
"solutionUrls": {
"type": "array",
"description": "URLs of step solution project",
"items": {
"type": "object",
"description": "Step project content and its corresponding path",
"properties": {
"path": {
"type": "string",
"description": "Path in step project"
},
"contentUrl": {
"type": "string",
"description": "URL of content"
}
},
"additionalProperties": false,
"required": [
"path",
"contentUrl"
]
}
},
"mode": {
"type": "string",
"description": "Mode of the Code Editor",
"enum": [
"readonly",
"interactive"
]
}
},
"additionalProperties": false,
"required": [
"exerciseId",
"startingFile",
"commands",
"urls",
"mode"
]
}
},
"additionalProperties": false,
"required": [
"stepTitle",
"htmlContentUrl"
]
}
}
},
"additionalProperties": false,
"required": [
"trainingSteps"
]
}
Loading

0 comments on commit d45970e

Please sign in to comment.