From 93e73e6850af1294484e1cb58a540daeab0ef276 Mon Sep 17 00:00:00 2001 From: Peter Muessig Date: Mon, 29 Jun 2026 23:01:01 +0200 Subject: [PATCH 1/8] feat: add Navigation and OData V4 tutorials, align all packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bring two new tutorials — Navigation and Routing, OData V4 — into the monorepo, and rework all four tutorials onto a single template so they share the same toolchain, layout, namespace, and documentation conventions. Tutorials - packages/navigation/ — 17 steps imported from the OpenUI5 demokit, promoted to the standard `steps/` layout, package names changed to `ui5.tutorial.navigation.stepNN`, ui5.yaml metadata aligned with the rest of the repo, dev dependencies switched to the walkthrough set (@types/openui5, ui5-middleware-serveframework, ui5-tooling-transpile), app namespace renamed `sap.ui.demo.nav` -> `ui5.tutorial.navigation` across manifests, TS imports, JSDoc, XML controllerName, tsconfig paths, and HTML resource-roots. - packages/odatav4/ — 11 steps imported from the same demokit source, restructured from `solutions/` -> `steps/`, root-level markdown moved into per-step README.md, shared `images/` split into per-step `assets/`. JS sources fully converted to TypeScript ES modules (Component, App.controller, model/models, initMockServer, the ~800- line sinon-based mock server, view XML), Hungarian variable prefixes stripped (oModel -> model, aMatches -> matches, sUrl -> url, ...) to match the project's TS style. App namespace standardised to `ui5.tutorial.odatav4`. Namespace alignment across the existing tutorials - packages/walkthrough/ renamed `ui5.walkthrough` -> `ui5.tutorial.walkthrough` across ~630 files (manifests, TS imports + @namespace, XML controllerName + xmlns, tsconfig paths, HTML resource-roots, every README code snippet, step package.json names). - packages/quickstart/ renamed `ui5.quickstart` -> `ui5.tutorial.quickstart` with the same shape across 27 files; ui5.yaml `metadata.name` `quickstart-tutorial` -> `ui5.tutorial.quickstart`. After this commit, all 69 step workspaces follow the same naming convention: `ui5.tutorial..stepNN`. Documentation - Per-tutorial overview READMEs (packages/{navigation,odatav4}/README.md) now mirror packages/walkthrough/README.md: each step bullet has an inline `[🔗 Live Preview]` link and paired `
` / `
` `[📥 Download Solution]` blocks. - Step READMEs ship with paired ```ts / ```js code blocks so the Jekyll code-couple toggle renders both flavours. JS half generated from the build's sanitized `*-dbg.js` output where applicable. - Folder-structure images replaced with fenced ```text ASCII trees (using `.?s` placeholders so the global toggle flips the extensions); images deleted from the per-step assets. - All callout syntaxes (GitHub-flavoured alerts `> [!NOTE]` plus walkthrough's emoji blockquotes `> 📝 **Note:**
`) normalised to the `:note:` / `:tip:` / `:info:` / `:caution:` / `:warning:` shorthand mandated by `_/AUTOMATE.md`. - Step-level "view and download all files at \[demokit\]" links retargeted to the published `https://ui5.github.io/tutorials/...` URLs so they resolve against the local dist via the dev server. - License year bumped 2025 -> 2026 across all overview READMEs; `## License` sections added to the navigation and odatav4 overviews to match the walkthrough/quickstart convention. Tooling - tools/dev-server/server.js: mount `dist/` under `/dist/...` so `npm start` serves the locally-built apps and ZIPs; rewrite the published `https://ui5.github.io/tutorials/...` URLs in rendered markdown to the local `/dist/...` paths for the four known tutorial slugs (walkthrough, quickstart, navigation, odatav4); friendly hint page when an artifact is missing. - README.md: document the `npm install && npm run build && npm start` workflow. Verification - `npm install` succeeds and registers all 69 workspaces under the new `ui5.tutorial.*` namespace. - `npm run typecheck -ws --if-present` exits 0. - `npm run build` exits 0; produces `dist//build/NN/` apps, `-step-NN.zip` and `-step-NN-js.zip` downloads, and the rewritten `dist/index.md` overview for each tutorial. - `index-cdn.html` present for every webapp that bootstraps SAPUI5 (68 of 69 — walkthrough step 01 is the bare HTML "Hello World" and intentionally has none). - Dev-server smoke test: Live Preview links from the overview README resolve to `/dist//build/NN/index-cdn.html` with HTTP 200. --- .gitignore | 1 + README.md | 27 +- package-lock.json | 612 ++++++++++++-- packages/navigation/README.md | 67 ++ ...gation_and_Routing_Screen_Flow_92cdce7.png | Bin 0 -> 28787 bytes packages/navigation/steps/01/README.md | 96 +++ ...torial_Navigation_and_Routing_Step_01a.png | Bin 0 -> 54954 bytes packages/navigation/steps/01/package.json | 19 + packages/navigation/steps/01/tsconfig.json | 26 + packages/navigation/steps/01/ui5.yaml | 24 + .../navigation/steps/01/webapp/Component.ts | 12 + .../01/webapp/controller/App.controller.ts | 11 + .../steps/01/webapp/i18n/i18n.properties | 6 + .../navigation/steps/01/webapp/index-cdn.html | 20 + .../navigation/steps/01/webapp/index.html | 20 + .../steps/01/webapp/initMockServer.ts | 9 + .../steps/01/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../01/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/01/webapp/manifest.json | 74 ++ .../steps/01/webapp/view/App.view.xml | 17 + packages/navigation/steps/02/README.md | 241 ++++++ ...torial_Navigation_and_Routing_Step_02a.png | Bin 0 -> 56994 bytes packages/navigation/steps/02/package.json | 19 + packages/navigation/steps/02/tsconfig.json | 26 + packages/navigation/steps/02/ui5.yaml | 24 + .../navigation/steps/02/webapp/Component.ts | 19 + .../02/webapp/controller/App.controller.ts | 11 + .../02/webapp/controller/Home.controller.ts | 8 + .../steps/02/webapp/i18n/i18n.properties | 6 + .../navigation/steps/02/webapp/index-cdn.html | 20 + .../navigation/steps/02/webapp/index.html | 20 + .../steps/02/webapp/initMockServer.ts | 9 + .../steps/02/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../02/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/02/webapp/manifest.json | 97 +++ .../steps/02/webapp/view/App.view.xml | 9 + .../steps/02/webapp/view/Home.view.xml | 13 + packages/navigation/steps/03/README.md | 166 ++++ ...utorial_Navigation_and_Routing_Step_03.png | Bin 0 -> 203918 bytes packages/navigation/steps/03/package.json | 19 + packages/navigation/steps/03/tsconfig.json | 26 + packages/navigation/steps/03/ui5.yaml | 24 + .../navigation/steps/03/webapp/Component.ts | 19 + .../03/webapp/controller/App.controller.ts | 11 + .../03/webapp/controller/Home.controller.ts | 8 + .../webapp/controller/NotFound.controller.ts | 11 + .../steps/03/webapp/i18n/i18n.properties | 10 + .../navigation/steps/03/webapp/index-cdn.html | 20 + .../navigation/steps/03/webapp/index.html | 20 + .../steps/03/webapp/initMockServer.ts | 9 + .../steps/03/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../03/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/03/webapp/manifest.json | 105 +++ .../steps/03/webapp/view/App.view.xml | 9 + .../steps/03/webapp/view/Home.view.xml | 13 + .../steps/03/webapp/view/NotFound.view.xml | 17 + packages/navigation/steps/04/README.md | 231 ++++++ ...torial_Navigation_and_Routing_Step_04a.png | Bin 0 -> 204311 bytes packages/navigation/steps/04/package.json | 19 + packages/navigation/steps/04/tsconfig.json | 26 + packages/navigation/steps/04/ui5.yaml | 24 + .../navigation/steps/04/webapp/Component.ts | 19 + .../04/webapp/controller/App.controller.ts | 11 + .../04/webapp/controller/BaseController.ts | 25 + .../04/webapp/controller/Home.controller.ts | 8 + .../webapp/controller/NotFound.controller.ts | 11 + .../steps/04/webapp/i18n/i18n.properties | 10 + .../navigation/steps/04/webapp/index-cdn.html | 20 + .../navigation/steps/04/webapp/index.html | 20 + .../steps/04/webapp/initMockServer.ts | 9 + .../steps/04/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../04/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/04/webapp/manifest.json | 105 +++ .../steps/04/webapp/view/App.view.xml | 9 + .../steps/04/webapp/view/Home.view.xml | 13 + .../steps/04/webapp/view/NotFound.view.xml | 19 + packages/navigation/steps/05/README.md | 220 +++++ ...utorial_Navigation_and_Routing_Step_05.png | Bin 0 -> 57265 bytes packages/navigation/steps/05/package.json | 19 + packages/navigation/steps/05/tsconfig.json | 26 + packages/navigation/steps/05/ui5.yaml | 24 + .../navigation/steps/05/webapp/Component.ts | 19 + .../05/webapp/controller/App.controller.ts | 11 + .../05/webapp/controller/BaseController.ts | 25 + .../05/webapp/controller/Home.controller.ts | 14 + .../webapp/controller/NotFound.controller.ts | 34 + .../steps/05/webapp/i18n/i18n.properties | 12 + .../navigation/steps/05/webapp/index-cdn.html | 20 + .../navigation/steps/05/webapp/index.html | 20 + .../steps/05/webapp/initMockServer.ts | 9 + .../steps/05/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../05/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/05/webapp/manifest.json | 105 +++ .../steps/05/webapp/view/App.view.xml | 9 + .../steps/05/webapp/view/Home.view.xml | 13 + .../steps/05/webapp/view/NotFound.view.xml | 19 + packages/navigation/steps/06/README.md | 269 ++++++ ...torial_Navigation_and_Routing_Step_06a.png | Bin 0 -> 62205 bytes ...torial_Navigation_and_Routing_Step_06b.png | Bin 0 -> 195009 bytes packages/navigation/steps/06/package.json | 19 + packages/navigation/steps/06/tsconfig.json | 26 + packages/navigation/steps/06/ui5.yaml | 24 + .../navigation/steps/06/webapp/Component.ts | 19 + .../06/webapp/controller/App.controller.ts | 11 + .../06/webapp/controller/BaseController.ts | 25 + .../06/webapp/controller/Home.controller.ts | 18 + .../webapp/controller/NotFound.controller.ts | 34 + .../employee/EmployeeList.controller.ts | 8 + .../steps/06/webapp/i18n/i18n.properties | 16 + .../navigation/steps/06/webapp/index-cdn.html | 20 + .../navigation/steps/06/webapp/index.html | 20 + .../steps/06/webapp/initMockServer.ts | 9 + .../steps/06/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../06/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/06/webapp/manifest.json | 115 +++ .../steps/06/webapp/view/App.view.xml | 9 + .../steps/06/webapp/view/Home.view.xml | 14 + .../steps/06/webapp/view/NotFound.view.xml | 19 + .../view/employee/EmployeeList.view.xml | 23 + packages/navigation/steps/07/README.md | 398 +++++++++ ...torial_Navigation_and_Routing_Step_07a.png | Bin 0 -> 199055 bytes ...torial_Navigation_and_Routing_Step_07b.png | Bin 0 -> 133296 bytes ...torial_Navigation_and_Routing_Step_07c.png | Bin 0 -> 206874 bytes packages/navigation/steps/07/package.json | 19 + packages/navigation/steps/07/tsconfig.json | 26 + packages/navigation/steps/07/ui5.yaml | 24 + .../navigation/steps/07/webapp/Component.ts | 19 + .../07/webapp/controller/App.controller.ts | 11 + .../07/webapp/controller/BaseController.ts | 25 + .../07/webapp/controller/Home.controller.ts | 18 + .../webapp/controller/NotFound.controller.ts | 34 + .../employee/Employee.controller.ts | 39 + .../employee/EmployeeList.controller.ts | 18 + .../steps/07/webapp/i18n/i18n.properties | 26 + .../navigation/steps/07/webapp/index-cdn.html | 20 + .../navigation/steps/07/webapp/index.html | 20 + .../steps/07/webapp/initMockServer.ts | 9 + .../steps/07/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../07/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/07/webapp/manifest.json | 125 +++ .../steps/07/webapp/view/App.view.xml | 9 + .../steps/07/webapp/view/Home.view.xml | 14 + .../steps/07/webapp/view/NotFound.view.xml | 19 + .../07/webapp/view/employee/Employee.view.xml | 54 ++ .../view/employee/EmployeeList.view.xml | 25 + packages/navigation/steps/08/README.md | 433 ++++++++++ ...torial_Navigation_and_Routing_Step_08a.png | Bin 0 -> 137676 bytes ...torial_Navigation_and_Routing_Step_08b.png | Bin 0 -> 71910 bytes ...torial_Navigation_and_Routing_Step_08c.png | Bin 0 -> 208010 bytes packages/navigation/steps/08/package.json | 19 + packages/navigation/steps/08/tsconfig.json | 26 + packages/navigation/steps/08/ui5.yaml | 24 + .../navigation/steps/08/webapp/Component.ts | 19 + .../08/webapp/controller/App.controller.ts | 11 + .../08/webapp/controller/BaseController.ts | 25 + .../08/webapp/controller/Home.controller.ts | 18 + .../webapp/controller/NotFound.controller.ts | 34 + .../employee/Employee.controller.ts | 47 ++ .../employee/EmployeeList.controller.ts | 18 + .../controller/employee/Resume.controller.ts | 39 + .../steps/08/webapp/i18n/i18n.properties | 34 + .../navigation/steps/08/webapp/index-cdn.html | 20 + .../navigation/steps/08/webapp/index.html | 20 + .../steps/08/webapp/initMockServer.ts | 10 + .../steps/08/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../08/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/08/webapp/manifest.json | 136 +++ .../steps/08/webapp/view/App.view.xml | 9 + .../steps/08/webapp/view/Home.view.xml | 14 + .../steps/08/webapp/view/NotFound.view.xml | 19 + .../08/webapp/view/employee/Employee.view.xml | 55 ++ .../view/employee/EmployeeList.view.xml | 25 + .../08/webapp/view/employee/Resume.view.xml | 34 + .../view/employee/ResumeProjects.view.xml | 3 + packages/navigation/steps/09/README.md | 294 +++++++ ...utorial_Navigation_and_Routing_Step_09.png | Bin 0 -> 75730 bytes packages/navigation/steps/09/package.json | 19 + packages/navigation/steps/09/tsconfig.json | 26 + packages/navigation/steps/09/ui5.yaml | 24 + .../navigation/steps/09/webapp/Component.ts | 19 + .../09/webapp/controller/App.controller.ts | 11 + .../09/webapp/controller/BaseController.ts | 25 + .../09/webapp/controller/Home.controller.ts | 18 + .../webapp/controller/NotFound.controller.ts | 34 + .../employee/Employee.controller.ts | 47 ++ .../employee/EmployeeList.controller.ts | 18 + .../controller/employee/Resume.controller.ts | 73 ++ .../steps/09/webapp/i18n/i18n.properties | 34 + .../navigation/steps/09/webapp/index-cdn.html | 20 + .../navigation/steps/09/webapp/index.html | 20 + .../steps/09/webapp/initMockServer.ts | 9 + .../steps/09/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../09/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/09/webapp/manifest.json | 136 +++ .../steps/09/webapp/view/App.view.xml | 9 + .../steps/09/webapp/view/Home.view.xml | 14 + .../steps/09/webapp/view/NotFound.view.xml | 19 + .../09/webapp/view/employee/Employee.view.xml | 55 ++ .../view/employee/EmployeeList.view.xml | 25 + .../09/webapp/view/employee/Resume.view.xml | 36 + .../view/employee/ResumeProjects.view.xml | 3 + packages/navigation/steps/10/README.md | 302 +++++++ ...torial_Navigation_and_Routing_Step_10a.png | Bin 0 -> 75474 bytes ...torial_Navigation_and_Routing_Step_10b.png | Bin 0 -> 54353 bytes packages/navigation/steps/10/package.json | 19 + packages/navigation/steps/10/tsconfig.json | 26 + packages/navigation/steps/10/ui5.yaml | 24 + .../navigation/steps/10/webapp/Component.ts | 19 + .../10/webapp/controller/App.controller.ts | 11 + .../10/webapp/controller/BaseController.ts | 25 + .../10/webapp/controller/Home.controller.ts | 18 + .../webapp/controller/NotFound.controller.ts | 34 + .../employee/Employee.controller.ts | 47 ++ .../employee/EmployeeList.controller.ts | 18 + .../controller/employee/Resume.controller.ts | 78 ++ .../steps/10/webapp/i18n/i18n.properties | 34 + .../navigation/steps/10/webapp/index-cdn.html | 20 + .../navigation/steps/10/webapp/index.html | 20 + .../steps/10/webapp/initMockServer.ts | 9 + .../steps/10/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../10/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/10/webapp/manifest.json | 152 ++++ .../steps/10/webapp/view/App.view.xml | 9 + .../steps/10/webapp/view/Home.view.xml | 14 + .../steps/10/webapp/view/NotFound.view.xml | 19 + .../10/webapp/view/employee/Employee.view.xml | 55 ++ .../view/employee/EmployeeList.view.xml | 25 + .../10/webapp/view/employee/Resume.view.xml | 36 + .../view/employee/ResumeHobbies.view.xml | 3 + .../webapp/view/employee/ResumeNotes.view.xml | 3 + .../view/employee/ResumeProjects.view.xml | 3 + packages/navigation/steps/11/README.md | 591 +++++++++++++ ...torial_Navigation_and_Routing_Step_11a.png | Bin 0 -> 67744 bytes ...torial_Navigation_and_Routing_Step_11b.png | Bin 0 -> 347516 bytes ...torial_Navigation_and_Routing_Step_11c.png | Bin 0 -> 447726 bytes ...torial_Navigation_and_Routing_Step_11d.png | Bin 0 -> 112375 bytes packages/navigation/steps/11/package.json | 19 + packages/navigation/steps/11/tsconfig.json | 26 + packages/navigation/steps/11/ui5.yaml | 24 + .../navigation/steps/11/webapp/Component.ts | 19 + .../11/webapp/controller/App.controller.ts | 11 + .../11/webapp/controller/BaseController.ts | 25 + .../11/webapp/controller/Home.controller.ts | 22 + .../webapp/controller/NotFound.controller.ts | 33 + .../employee/Employee.controller.ts | 47 ++ .../employee/EmployeeList.controller.ts | 18 + .../controller/employee/Resume.controller.ts | 78 ++ .../overview/EmployeeOverview.controller.ts | 8 + .../EmployeeOverviewContent.controller.ts | 131 +++ .../steps/11/webapp/i18n/i18n.properties | 42 + .../navigation/steps/11/webapp/index-cdn.html | 20 + .../navigation/steps/11/webapp/index.html | 20 + .../steps/11/webapp/initMockServer.ts | 9 + .../steps/11/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../11/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/11/webapp/manifest.json | 178 ++++ .../steps/11/webapp/view/App.view.xml | 9 + .../steps/11/webapp/view/Home.view.xml | 15 + .../steps/11/webapp/view/NotFound.view.xml | 19 + .../11/webapp/view/employee/Employee.view.xml | 55 ++ .../view/employee/EmployeeList.view.xml | 25 + .../11/webapp/view/employee/Resume.view.xml | 36 + .../view/employee/ResumeHobbies.view.xml | 3 + .../webapp/view/employee/ResumeNotes.view.xml | 3 + .../view/employee/ResumeProjects.view.xml | 3 + .../overview/EmployeeOverview.view.xml | 16 + .../overview/EmployeeOverviewContent.view.xml | 42 + .../overview/EmployeeOverviewTop.view.xml | 3 + packages/navigation/steps/12/README.md | 290 +++++++ ...utorial_Navigation_and_Routing_Step_12.png | Bin 0 -> 209798 bytes packages/navigation/steps/12/package.json | 19 + packages/navigation/steps/12/tsconfig.json | 26 + packages/navigation/steps/12/ui5.yaml | 24 + .../navigation/steps/12/webapp/Component.ts | 19 + .../12/webapp/controller/App.controller.ts | 11 + .../12/webapp/controller/BaseController.ts | 25 + .../12/webapp/controller/Home.controller.ts | 22 + .../webapp/controller/NotFound.controller.ts | 33 + .../employee/Employee.controller.ts | 47 ++ .../employee/EmployeeList.controller.ts | 18 + .../controller/employee/Resume.controller.ts | 78 ++ .../overview/EmployeeOverview.controller.ts | 8 + .../EmployeeOverviewContent.controller.ts | 152 ++++ .../steps/12/webapp/i18n/i18n.properties | 42 + .../navigation/steps/12/webapp/index-cdn.html | 20 + .../navigation/steps/12/webapp/index.html | 20 + .../steps/12/webapp/initMockServer.ts | 9 + .../steps/12/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../12/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/12/webapp/manifest.json | 178 ++++ .../steps/12/webapp/view/App.view.xml | 9 + .../steps/12/webapp/view/Home.view.xml | 15 + .../steps/12/webapp/view/NotFound.view.xml | 19 + .../12/webapp/view/employee/Employee.view.xml | 55 ++ .../view/employee/EmployeeList.view.xml | 25 + .../12/webapp/view/employee/Resume.view.xml | 36 + .../view/employee/ResumeHobbies.view.xml | 3 + .../webapp/view/employee/ResumeNotes.view.xml | 3 + .../view/employee/ResumeProjects.view.xml | 3 + .../overview/EmployeeOverview.view.xml | 16 + .../overview/EmployeeOverviewContent.view.xml | 42 + .../overview/EmployeeOverviewTop.view.xml | 3 + packages/navigation/steps/13/README.md | 228 +++++ ...utorial_Navigation_and_Routing_Step_13.png | Bin 0 -> 215736 bytes packages/navigation/steps/13/package.json | 19 + packages/navigation/steps/13/tsconfig.json | 26 + packages/navigation/steps/13/ui5.yaml | 24 + .../navigation/steps/13/webapp/Component.ts | 19 + .../13/webapp/controller/App.controller.ts | 11 + .../13/webapp/controller/BaseController.ts | 25 + .../13/webapp/controller/Home.controller.ts | 22 + .../webapp/controller/NotFound.controller.ts | 33 + .../employee/Employee.controller.ts | 47 ++ .../employee/EmployeeList.controller.ts | 18 + .../controller/employee/Resume.controller.ts | 78 ++ .../overview/EmployeeOverview.controller.ts | 8 + .../EmployeeOverviewContent.controller.ts | 161 ++++ .../steps/13/webapp/i18n/i18n.properties | 42 + .../navigation/steps/13/webapp/index-cdn.html | 20 + .../navigation/steps/13/webapp/index.html | 20 + .../steps/13/webapp/initMockServer.ts | 9 + .../steps/13/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../13/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/13/webapp/manifest.json | 178 ++++ .../steps/13/webapp/view/App.view.xml | 9 + .../steps/13/webapp/view/Home.view.xml | 15 + .../steps/13/webapp/view/NotFound.view.xml | 19 + .../13/webapp/view/employee/Employee.view.xml | 55 ++ .../view/employee/EmployeeList.view.xml | 25 + .../13/webapp/view/employee/Resume.view.xml | 36 + .../view/employee/ResumeHobbies.view.xml | 3 + .../webapp/view/employee/ResumeNotes.view.xml | 3 + .../view/employee/ResumeProjects.view.xml | 3 + .../overview/EmployeeOverview.view.xml | 16 + .../overview/EmployeeOverviewContent.view.xml | 42 + .../overview/EmployeeOverviewTop.view.xml | 3 + packages/navigation/steps/14/README.md | 256 ++++++ ...utorial_Navigation_and_Routing_Step_14.png | Bin 0 -> 449895 bytes packages/navigation/steps/14/package.json | 19 + packages/navigation/steps/14/tsconfig.json | 26 + packages/navigation/steps/14/ui5.yaml | 24 + .../navigation/steps/14/webapp/Component.ts | 19 + .../14/webapp/controller/App.controller.ts | 11 + .../14/webapp/controller/BaseController.ts | 25 + .../14/webapp/controller/Home.controller.ts | 22 + .../webapp/controller/NotFound.controller.ts | 33 + .../employee/Employee.controller.ts | 47 ++ .../employee/EmployeeList.controller.ts | 18 + .../controller/employee/Resume.controller.ts | 78 ++ .../overview/EmployeeOverview.controller.ts | 8 + .../EmployeeOverviewContent.controller.ts | 173 ++++ .../steps/14/webapp/i18n/i18n.properties | 42 + .../navigation/steps/14/webapp/index-cdn.html | 20 + .../navigation/steps/14/webapp/index.html | 20 + .../steps/14/webapp/initMockServer.ts | 9 + .../steps/14/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../14/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/14/webapp/manifest.json | 178 ++++ .../steps/14/webapp/view/App.view.xml | 9 + .../steps/14/webapp/view/Home.view.xml | 15 + .../steps/14/webapp/view/NotFound.view.xml | 19 + .../14/webapp/view/employee/Employee.view.xml | 55 ++ .../view/employee/EmployeeList.view.xml | 25 + .../14/webapp/view/employee/Resume.view.xml | 36 + .../view/employee/ResumeHobbies.view.xml | 3 + .../webapp/view/employee/ResumeNotes.view.xml | 3 + .../view/employee/ResumeProjects.view.xml | 3 + .../overview/EmployeeOverview.view.xml | 16 + .../overview/EmployeeOverviewContent.view.xml | 42 + .../overview/EmployeeOverviewTop.view.xml | 3 + packages/navigation/steps/15/README.md | 253 ++++++ ...utorial_Navigation_and_Routing_Step_15.png | Bin 0 -> 347103 bytes ...utorial_Navigation_and_Routing_Step_17.png | Bin 0 -> 399216 bytes packages/navigation/steps/15/package.json | 19 + packages/navigation/steps/15/tsconfig.json | 26 + packages/navigation/steps/15/ui5.yaml | 24 + .../navigation/steps/15/webapp/Component.ts | 19 + .../15/webapp/controller/App.controller.ts | 11 + .../15/webapp/controller/BaseController.ts | 25 + .../15/webapp/controller/Home.controller.ts | 22 + .../webapp/controller/NotFound.controller.ts | 33 + .../employee/Employee.controller.ts | 47 ++ .../employee/EmployeeList.controller.ts | 18 + .../controller/employee/Resume.controller.ts | 78 ++ .../overview/EmployeeOverview.controller.ts | 8 + .../EmployeeOverviewContent.controller.ts | 186 +++++ .../steps/15/webapp/i18n/i18n.properties | 42 + .../navigation/steps/15/webapp/index-cdn.html | 20 + .../navigation/steps/15/webapp/index.html | 20 + .../steps/15/webapp/initMockServer.ts | 9 + .../steps/15/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../15/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/15/webapp/manifest.json | 178 ++++ .../steps/15/webapp/view/App.view.xml | 9 + .../steps/15/webapp/view/Home.view.xml | 15 + .../steps/15/webapp/view/NotFound.view.xml | 19 + .../15/webapp/view/employee/Employee.view.xml | 55 ++ .../view/employee/EmployeeList.view.xml | 25 + .../15/webapp/view/employee/Resume.view.xml | 36 + .../view/employee/ResumeHobbies.view.xml | 3 + .../webapp/view/employee/ResumeNotes.view.xml | 3 + .../view/employee/ResumeProjects.view.xml | 3 + .../overview/EmployeeOverview.view.xml | 16 + .../overview/EmployeeOverviewContent.view.xml | 43 + .../overview/EmployeeOverviewTop.view.xml | 3 + packages/navigation/steps/16/README.md | 88 ++ ...utorial_Navigation_and_Routing_Step_16.png | Bin 0 -> 395688 bytes packages/navigation/steps/16/package.json | 19 + packages/navigation/steps/16/tsconfig.json | 26 + packages/navigation/steps/16/ui5.yaml | 24 + .../navigation/steps/16/webapp/Component.ts | 19 + .../16/webapp/controller/App.controller.ts | 27 + .../16/webapp/controller/BaseController.ts | 25 + .../16/webapp/controller/Home.controller.ts | 22 + .../webapp/controller/NotFound.controller.ts | 33 + .../employee/Employee.controller.ts | 47 ++ .../employee/EmployeeList.controller.ts | 18 + .../controller/employee/Resume.controller.ts | 78 ++ .../overview/EmployeeOverview.controller.ts | 8 + .../EmployeeOverviewContent.controller.ts | 186 +++++ .../steps/16/webapp/i18n/i18n.properties | 42 + .../navigation/steps/16/webapp/index-cdn.html | 20 + .../navigation/steps/16/webapp/index.html | 20 + .../steps/16/webapp/initMockServer.ts | 9 + .../steps/16/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../16/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/16/webapp/manifest.json | 178 ++++ .../steps/16/webapp/view/App.view.xml | 9 + .../steps/16/webapp/view/Home.view.xml | 15 + .../steps/16/webapp/view/NotFound.view.xml | 19 + .../16/webapp/view/employee/Employee.view.xml | 55 ++ .../view/employee/EmployeeList.view.xml | 25 + .../16/webapp/view/employee/Resume.view.xml | 36 + .../view/employee/ResumeHobbies.view.xml | 3 + .../webapp/view/employee/ResumeNotes.view.xml | 3 + .../view/employee/ResumeProjects.view.xml | 3 + .../overview/EmployeeOverview.view.xml | 16 + .../overview/EmployeeOverviewContent.view.xml | 43 + .../overview/EmployeeOverviewTop.view.xml | 3 + packages/navigation/steps/17/README.md | 95 +++ ...utorial_Navigation_and_Routing_Step_17.png | Bin 0 -> 399216 bytes packages/navigation/steps/17/package.json | 19 + packages/navigation/steps/17/tsconfig.json | 26 + packages/navigation/steps/17/ui5.yaml | 24 + .../navigation/steps/17/webapp/Component.ts | 19 + .../17/webapp/controller/App.controller.ts | 35 + .../17/webapp/controller/BaseController.ts | 25 + .../17/webapp/controller/Home.controller.ts | 22 + .../webapp/controller/NotFound.controller.ts | 33 + .../employee/Employee.controller.ts | 47 ++ .../employee/EmployeeList.controller.ts | 18 + .../controller/employee/Resume.controller.ts | 78 ++ .../overview/EmployeeOverview.controller.ts | 8 + .../EmployeeOverviewContent.controller.ts | 186 +++++ .../steps/17/webapp/i18n/i18n.properties | 42 + .../navigation/steps/17/webapp/index-cdn.html | 20 + .../navigation/steps/17/webapp/index.html | 20 + .../steps/17/webapp/initMockServer.ts | 9 + .../steps/17/webapp/localService/metadata.xml | 61 ++ .../localService/mockdata/Employees.json | 155 ++++ .../webapp/localService/mockdata/Resumes.json | 65 ++ .../17/webapp/localService/mockserver.ts | 50 ++ .../navigation/steps/17/webapp/manifest.json | 178 ++++ .../steps/17/webapp/view/App.view.xml | 9 + .../steps/17/webapp/view/Home.view.xml | 15 + .../steps/17/webapp/view/NotFound.view.xml | 19 + .../17/webapp/view/employee/Employee.view.xml | 55 ++ .../view/employee/EmployeeList.view.xml | 25 + .../17/webapp/view/employee/Resume.view.xml | 36 + .../view/employee/ResumeHobbies.view.xml | 3 + .../webapp/view/employee/ResumeNotes.view.xml | 3 + .../view/employee/ResumeProjects.view.xml | 3 + .../overview/EmployeeOverview.view.xml | 16 + .../overview/EmployeeOverviewContent.view.xml | 43 + .../overview/EmployeeOverviewTop.view.xml | 3 + packages/odatav4/README.md | 51 ++ packages/odatav4/steps/01/README.md | 115 +++ ...utorial_OData_V4_Step1_Preview_9d0182f.png | Bin 0 -> 36446 bytes packages/odatav4/steps/01/package.json | 19 + packages/odatav4/steps/01/tsconfig.json | 23 + packages/odatav4/steps/01/ui5.yaml | 25 + packages/odatav4/steps/01/webapp/Component.ts | 27 + .../01/webapp/controller/App.controller.ts | 20 + .../steps/01/webapp/i18n/i18n.properties | 22 + .../odatav4/steps/01/webapp/index-cdn.html | 22 + packages/odatav4/steps/01/webapp/index.html | 22 + .../odatav4/steps/01/webapp/initMockServer.ts | 11 + .../steps/01/webapp/localService/metadata.xml | 193 +++++ .../webapp/localService/mockdata/people.json | 399 +++++++++ .../01/webapp/localService/mockserver.ts | 782 ++++++++++++++++++ .../odatav4/steps/01/webapp/manifest.json | 67 ++ .../odatav4/steps/01/webapp/model/models.ts | 10 + .../odatav4/steps/01/webapp/view/App.view.xml | 54 ++ packages/odatav4/steps/02/README.md | 249 ++++++ .../Tutorial_OData_V4_Step_2_0abcbb6.png | Bin 0 -> 15471 bytes packages/odatav4/steps/02/package.json | 19 + packages/odatav4/steps/02/tsconfig.json | 23 + packages/odatav4/steps/02/ui5.yaml | 25 + packages/odatav4/steps/02/webapp/Component.ts | 27 + .../02/webapp/controller/App.controller.ts | 60 ++ .../steps/02/webapp/i18n/i18n.properties | 33 + .../odatav4/steps/02/webapp/index-cdn.html | 22 + packages/odatav4/steps/02/webapp/index.html | 22 + .../odatav4/steps/02/webapp/initMockServer.ts | 11 + .../steps/02/webapp/localService/metadata.xml | 193 +++++ .../webapp/localService/mockdata/people.json | 399 +++++++++ .../02/webapp/localService/mockserver.ts | 782 ++++++++++++++++++ .../odatav4/steps/02/webapp/manifest.json | 66 ++ .../odatav4/steps/02/webapp/model/models.ts | 10 + .../odatav4/steps/02/webapp/view/App.view.xml | 66 ++ packages/odatav4/steps/03/README.md | 105 +++ .../Tutorial_OData_V4_Step_3_8320fcf.png | Bin 0 -> 18171 bytes packages/odatav4/steps/03/package.json | 19 + packages/odatav4/steps/03/tsconfig.json | 23 + packages/odatav4/steps/03/ui5.yaml | 25 + packages/odatav4/steps/03/webapp/Component.ts | 27 + .../03/webapp/controller/App.controller.ts | 60 ++ .../steps/03/webapp/i18n/i18n.properties | 33 + .../odatav4/steps/03/webapp/index-cdn.html | 22 + packages/odatav4/steps/03/webapp/index.html | 22 + .../odatav4/steps/03/webapp/initMockServer.ts | 11 + .../steps/03/webapp/localService/metadata.xml | 193 +++++ .../webapp/localService/mockdata/people.json | 399 +++++++++ .../03/webapp/localService/mockserver.ts | 782 ++++++++++++++++++ .../odatav4/steps/03/webapp/manifest.json | 67 ++ .../odatav4/steps/03/webapp/model/models.ts | 10 + .../odatav4/steps/03/webapp/view/App.view.xml | 66 ++ packages/odatav4/steps/04/README.md | 299 +++++++ .../Tutorial_OData_V4_Step_4_3ac4fcc.png | Bin 0 -> 40874 bytes packages/odatav4/steps/04/package.json | 19 + packages/odatav4/steps/04/tsconfig.json | 23 + packages/odatav4/steps/04/ui5.yaml | 25 + packages/odatav4/steps/04/webapp/Component.ts | 27 + .../04/webapp/controller/App.controller.ts | 99 +++ .../steps/04/webapp/i18n/i18n.properties | 51 ++ .../odatav4/steps/04/webapp/index-cdn.html | 22 + packages/odatav4/steps/04/webapp/index.html | 22 + .../odatav4/steps/04/webapp/initMockServer.ts | 11 + .../steps/04/webapp/localService/metadata.xml | 193 +++++ .../webapp/localService/mockdata/people.json | 399 +++++++++ .../04/webapp/localService/mockserver.ts | 782 ++++++++++++++++++ .../odatav4/steps/04/webapp/manifest.json | 67 ++ .../odatav4/steps/04/webapp/model/models.ts | 10 + .../odatav4/steps/04/webapp/view/App.view.xml | 79 ++ packages/odatav4/steps/05/README.md | 66 ++ packages/odatav4/steps/05/package.json | 19 + packages/odatav4/steps/05/tsconfig.json | 23 + packages/odatav4/steps/05/ui5.yaml | 25 + packages/odatav4/steps/05/webapp/Component.ts | 27 + .../05/webapp/controller/App.controller.ts | 99 +++ .../steps/05/webapp/i18n/i18n.properties | 51 ++ .../odatav4/steps/05/webapp/index-cdn.html | 22 + packages/odatav4/steps/05/webapp/index.html | 22 + .../odatav4/steps/05/webapp/initMockServer.ts | 11 + .../steps/05/webapp/localService/metadata.xml | 193 +++++ .../webapp/localService/mockdata/people.json | 399 +++++++++ .../05/webapp/localService/mockserver.ts | 782 ++++++++++++++++++ .../odatav4/steps/05/webapp/manifest.json | 67 ++ .../odatav4/steps/05/webapp/model/models.ts | 10 + .../odatav4/steps/05/webapp/view/App.view.xml | 79 ++ packages/odatav4/steps/06/README.md | 587 +++++++++++++ .../Tutorial_OData_V4_Step_6_baf7417.png | Bin 0 -> 18941 bytes packages/odatav4/steps/06/package.json | 19 + packages/odatav4/steps/06/tsconfig.json | 23 + packages/odatav4/steps/06/ui5.yaml | 25 + packages/odatav4/steps/06/webapp/Component.ts | 27 + .../06/webapp/controller/App.controller.ts | 233 ++++++ .../steps/06/webapp/i18n/i18n.properties | 63 ++ .../odatav4/steps/06/webapp/index-cdn.html | 22 + packages/odatav4/steps/06/webapp/index.html | 22 + .../odatav4/steps/06/webapp/initMockServer.ts | 11 + .../steps/06/webapp/localService/metadata.xml | 193 +++++ .../webapp/localService/mockdata/people.json | 399 +++++++++ .../06/webapp/localService/mockserver.ts | 782 ++++++++++++++++++ .../odatav4/steps/06/webapp/manifest.json | 67 ++ .../odatav4/steps/06/webapp/model/models.ts | 10 + .../odatav4/steps/06/webapp/view/App.view.xml | 117 +++ packages/odatav4/steps/07/README.md | 201 +++++ .../Tutorial_OData_V4_Step_7_32509f4.png | Bin 0 -> 22236 bytes packages/odatav4/steps/07/package.json | 19 + packages/odatav4/steps/07/tsconfig.json | 23 + packages/odatav4/steps/07/ui5.yaml | 25 + packages/odatav4/steps/07/webapp/Component.ts | 27 + .../07/webapp/controller/App.controller.ts | 256 ++++++ .../steps/07/webapp/i18n/i18n.properties | 72 ++ .../odatav4/steps/07/webapp/index-cdn.html | 22 + packages/odatav4/steps/07/webapp/index.html | 22 + .../odatav4/steps/07/webapp/initMockServer.ts | 11 + .../steps/07/webapp/localService/metadata.xml | 193 +++++ .../webapp/localService/mockdata/people.json | 399 +++++++++ .../07/webapp/localService/mockserver.ts | 782 ++++++++++++++++++ .../odatav4/steps/07/webapp/manifest.json | 67 ++ .../odatav4/steps/07/webapp/model/models.ts | 10 + .../odatav4/steps/07/webapp/view/App.view.xml | 127 +++ packages/odatav4/steps/08/README.md | 142 ++++ .../Tutorial_OData_V4_Step_8_e518deb.png | Bin 0 -> 44152 bytes packages/odatav4/steps/08/package.json | 19 + packages/odatav4/steps/08/tsconfig.json | 23 + packages/odatav4/steps/08/ui5.yaml | 25 + packages/odatav4/steps/08/webapp/Component.ts | 27 + .../08/webapp/controller/App.controller.ts | 271 ++++++ .../steps/08/webapp/i18n/i18n.properties | 78 ++ .../odatav4/steps/08/webapp/index-cdn.html | 22 + packages/odatav4/steps/08/webapp/index.html | 22 + .../odatav4/steps/08/webapp/initMockServer.ts | 11 + .../steps/08/webapp/localService/metadata.xml | 193 +++++ .../webapp/localService/mockdata/people.json | 399 +++++++++ .../08/webapp/localService/mockserver.ts | 782 ++++++++++++++++++ .../odatav4/steps/08/webapp/manifest.json | 67 ++ .../odatav4/steps/08/webapp/model/models.ts | 10 + .../08/webapp/test/integration/AllJourneys.js | 13 + .../test/integration/TutorialJourney.js | 122 +++ .../test/integration/arrangements/Startup.js | 24 + .../test/integration/opaTests.qunit.html | 27 + .../webapp/test/integration/opaTests.qunit.js | 11 + .../webapp/test/integration/pages/Tutorial.js | 300 +++++++ .../odatav4/steps/08/webapp/view/App.view.xml | 136 +++ packages/odatav4/steps/09/README.md | 362 ++++++++ packages/odatav4/steps/09/package.json | 19 + packages/odatav4/steps/09/tsconfig.json | 23 + packages/odatav4/steps/09/ui5.yaml | 25 + packages/odatav4/steps/09/webapp/Component.ts | 27 + .../09/webapp/controller/App.controller.ts | 303 +++++++ .../steps/09/webapp/i18n/i18n.properties | 100 +++ .../odatav4/steps/09/webapp/index-cdn.html | 22 + packages/odatav4/steps/09/webapp/index.html | 22 + .../odatav4/steps/09/webapp/initMockServer.ts | 11 + .../steps/09/webapp/localService/metadata.xml | 193 +++++ .../webapp/localService/mockdata/people.json | 399 +++++++++ .../09/webapp/localService/mockserver.ts | 782 ++++++++++++++++++ .../odatav4/steps/09/webapp/manifest.json | 69 ++ .../odatav4/steps/09/webapp/model/models.ts | 10 + .../odatav4/steps/09/webapp/view/App.view.xml | 270 ++++++ packages/odatav4/steps/10/README.md | 131 +++ packages/odatav4/steps/10/package.json | 19 + packages/odatav4/steps/10/tsconfig.json | 23 + packages/odatav4/steps/10/ui5.yaml | 25 + packages/odatav4/steps/10/webapp/Component.ts | 27 + .../10/webapp/controller/App.controller.ts | 312 +++++++ .../steps/10/webapp/i18n/i18n.properties | 100 +++ .../odatav4/steps/10/webapp/index-cdn.html | 22 + packages/odatav4/steps/10/webapp/index.html | 22 + .../odatav4/steps/10/webapp/initMockServer.ts | 11 + .../steps/10/webapp/localService/metadata.xml | 193 +++++ .../webapp/localService/mockdata/people.json | 399 +++++++++ .../10/webapp/localService/mockserver.ts | 782 ++++++++++++++++++ .../odatav4/steps/10/webapp/manifest.json | 69 ++ .../odatav4/steps/10/webapp/model/models.ts | 10 + .../odatav4/steps/10/webapp/view/App.view.xml | 270 ++++++ packages/odatav4/steps/11/README.md | 108 +++ packages/odatav4/steps/11/package.json | 19 + packages/odatav4/steps/11/tsconfig.json | 23 + packages/odatav4/steps/11/ui5.yaml | 25 + packages/odatav4/steps/11/webapp/Component.ts | 27 + .../11/webapp/controller/App.controller.ts | 312 +++++++ .../steps/11/webapp/i18n/i18n.properties | 100 +++ .../odatav4/steps/11/webapp/index-cdn.html | 22 + packages/odatav4/steps/11/webapp/index.html | 22 + .../odatav4/steps/11/webapp/initMockServer.ts | 11 + .../steps/11/webapp/localService/metadata.xml | 193 +++++ .../webapp/localService/mockdata/people.json | 399 +++++++++ .../11/webapp/localService/mockserver.ts | 782 ++++++++++++++++++ .../odatav4/steps/11/webapp/manifest.json | 69 ++ .../odatav4/steps/11/webapp/model/models.ts | 10 + .../11/webapp/test/integration/AllJourneys.js | 13 + .../test/integration/TutorialJourney.js | 147 ++++ .../test/integration/arrangements/Startup.js | 24 + .../test/integration/opaTests.qunit.html | 27 + .../webapp/test/integration/opaTests.qunit.js | 11 + .../webapp/test/integration/pages/Tutorial.js | 330 ++++++++ .../odatav4/steps/11/webapp/view/App.view.xml | 318 +++++++ packages/quickstart/README.md | 4 +- packages/quickstart/steps/01/README.md | 18 +- packages/quickstart/steps/01/package.json | 2 +- packages/quickstart/steps/01/tsconfig.json | 2 +- packages/quickstart/steps/01/ui5.yaml | 2 +- .../quickstart/steps/01/webapp/index-cdn.html | 4 +- .../quickstart/steps/01/webapp/index.html | 4 +- .../quickstart/steps/01/webapp/manifest.json | 2 +- packages/quickstart/steps/02/README.md | 10 +- packages/quickstart/steps/02/package.json | 2 +- packages/quickstart/steps/02/tsconfig.json | 2 +- packages/quickstart/steps/02/ui5.yaml | 2 +- .../steps/02/webapp/App.controller.ts | 2 +- .../quickstart/steps/02/webapp/App.view.xml | 2 +- .../quickstart/steps/02/webapp/index-cdn.html | 4 +- .../quickstart/steps/02/webapp/index.html | 4 +- packages/quickstart/steps/02/webapp/index.ts | 2 +- .../quickstart/steps/02/webapp/manifest.json | 2 +- packages/quickstart/steps/03/README.md | 10 +- packages/quickstart/steps/03/package.json | 2 +- packages/quickstart/steps/03/tsconfig.json | 2 +- packages/quickstart/steps/03/ui5.yaml | 2 +- .../steps/03/webapp/App.controller.ts | 2 +- .../quickstart/steps/03/webapp/App.view.xml | 2 +- .../quickstart/steps/03/webapp/index-cdn.html | 4 +- .../quickstart/steps/03/webapp/index.html | 4 +- packages/quickstart/steps/03/webapp/index.ts | 2 +- .../quickstart/steps/03/webapp/manifest.json | 2 +- packages/walkthrough/README.md | 8 +- packages/walkthrough/steps/01/README.md | 12 +- packages/walkthrough/steps/01/package.json | 2 +- packages/walkthrough/steps/01/ui5.yaml | 2 +- .../walkthrough/steps/01/webapp/manifest.json | 2 +- packages/walkthrough/steps/02/README.md | 16 +- packages/walkthrough/steps/02/package.json | 2 +- packages/walkthrough/steps/02/tsconfig.json | 2 +- packages/walkthrough/steps/02/ui5.yaml | 2 +- .../steps/02/webapp/index-cdn.html | 4 +- .../walkthrough/steps/02/webapp/index.html | 4 +- .../walkthrough/steps/02/webapp/manifest.json | 2 +- packages/walkthrough/steps/03/README.md | 8 +- packages/walkthrough/steps/03/package.json | 2 +- packages/walkthrough/steps/03/tsconfig.json | 2 +- packages/walkthrough/steps/03/ui5.yaml | 2 +- .../steps/03/webapp/index-cdn.html | 4 +- .../walkthrough/steps/03/webapp/index.html | 4 +- .../walkthrough/steps/03/webapp/manifest.json | 2 +- packages/walkthrough/steps/04/README.md | 10 +- packages/walkthrough/steps/04/package.json | 2 +- packages/walkthrough/steps/04/tsconfig.json | 2 +- packages/walkthrough/steps/04/ui5.yaml | 2 +- .../steps/04/webapp/index-cdn.html | 4 +- .../walkthrough/steps/04/webapp/index.html | 4 +- packages/walkthrough/steps/04/webapp/index.ts | 2 +- .../walkthrough/steps/04/webapp/manifest.json | 2 +- packages/walkthrough/steps/05/README.md | 10 +- packages/walkthrough/steps/05/package.json | 2 +- packages/walkthrough/steps/05/tsconfig.json | 2 +- packages/walkthrough/steps/05/ui5.yaml | 2 +- .../05/webapp/controller/App.controller.ts | 2 +- .../steps/05/webapp/index-cdn.html | 4 +- .../walkthrough/steps/05/webapp/index.html | 4 +- packages/walkthrough/steps/05/webapp/index.ts | 2 +- .../walkthrough/steps/05/webapp/manifest.json | 2 +- .../steps/05/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/06/README.md | 6 +- packages/walkthrough/steps/06/package.json | 2 +- packages/walkthrough/steps/06/tsconfig.json | 2 +- packages/walkthrough/steps/06/ui5.yaml | 2 +- .../06/webapp/controller/App.controller.ts | 2 +- .../steps/06/webapp/index-cdn.html | 4 +- .../walkthrough/steps/06/webapp/index.html | 4 +- packages/walkthrough/steps/06/webapp/index.ts | 2 +- .../walkthrough/steps/06/webapp/manifest.json | 2 +- .../steps/06/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/07/README.md | 8 +- packages/walkthrough/steps/07/package.json | 2 +- packages/walkthrough/steps/07/tsconfig.json | 2 +- packages/walkthrough/steps/07/ui5.yaml | 2 +- .../07/webapp/controller/App.controller.ts | 2 +- .../steps/07/webapp/index-cdn.html | 4 +- .../walkthrough/steps/07/webapp/index.html | 4 +- packages/walkthrough/steps/07/webapp/index.ts | 2 +- .../walkthrough/steps/07/webapp/manifest.json | 2 +- .../steps/07/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/08/README.md | 14 +- packages/walkthrough/steps/08/package.json | 2 +- packages/walkthrough/steps/08/tsconfig.json | 2 +- packages/walkthrough/steps/08/ui5.yaml | 2 +- .../08/webapp/controller/App.controller.ts | 4 +- .../steps/08/webapp/index-cdn.html | 4 +- .../walkthrough/steps/08/webapp/index.html | 4 +- packages/walkthrough/steps/08/webapp/index.ts | 2 +- .../walkthrough/steps/08/webapp/manifest.json | 2 +- .../steps/08/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/09/README.md | 22 +- packages/walkthrough/steps/09/package.json | 2 +- packages/walkthrough/steps/09/tsconfig.json | 2 +- packages/walkthrough/steps/09/ui5.yaml | 2 +- .../walkthrough/steps/09/webapp/Component.ts | 6 +- .../09/webapp/controller/App.controller.ts | 2 +- .../steps/09/webapp/index-cdn.html | 4 +- .../walkthrough/steps/09/webapp/index.html | 4 +- packages/walkthrough/steps/09/webapp/index.ts | 2 +- .../walkthrough/steps/09/webapp/manifest.json | 2 +- .../steps/09/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/10/README.md | 24 +- packages/walkthrough/steps/10/package.json | 2 +- packages/walkthrough/steps/10/tsconfig.json | 2 +- packages/walkthrough/steps/10/ui5.yaml | 2 +- .../walkthrough/steps/10/webapp/Component.ts | 2 +- .../10/webapp/controller/App.controller.ts | 2 +- .../steps/10/webapp/index-cdn.html | 4 +- .../walkthrough/steps/10/webapp/index.html | 4 +- .../walkthrough/steps/10/webapp/manifest.json | 8 +- .../steps/10/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/11/README.md | 4 +- packages/walkthrough/steps/11/package.json | 2 +- packages/walkthrough/steps/11/tsconfig.json | 2 +- packages/walkthrough/steps/11/ui5.yaml | 2 +- .../walkthrough/steps/11/webapp/Component.ts | 2 +- .../11/webapp/controller/App.controller.ts | 2 +- .../steps/11/webapp/index-cdn.html | 4 +- .../walkthrough/steps/11/webapp/index.html | 4 +- .../walkthrough/steps/11/webapp/manifest.json | 8 +- .../steps/11/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/12/README.md | 2 +- packages/walkthrough/steps/12/package.json | 2 +- packages/walkthrough/steps/12/tsconfig.json | 2 +- packages/walkthrough/steps/12/ui5.yaml | 2 +- .../walkthrough/steps/12/webapp/Component.ts | 2 +- .../12/webapp/controller/App.controller.ts | 2 +- .../steps/12/webapp/index-cdn.html | 4 +- .../walkthrough/steps/12/webapp/index.html | 4 +- .../walkthrough/steps/12/webapp/manifest.json | 8 +- .../steps/12/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/13/README.md | 2 +- packages/walkthrough/steps/13/package.json | 2 +- packages/walkthrough/steps/13/tsconfig.json | 2 +- packages/walkthrough/steps/13/ui5.yaml | 2 +- .../walkthrough/steps/13/webapp/Component.ts | 2 +- .../13/webapp/controller/App.controller.ts | 2 +- .../steps/13/webapp/index-cdn.html | 4 +- .../walkthrough/steps/13/webapp/index.html | 4 +- .../walkthrough/steps/13/webapp/manifest.json | 8 +- .../steps/13/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/14/README.md | 2 +- packages/walkthrough/steps/14/package.json | 2 +- packages/walkthrough/steps/14/tsconfig.json | 2 +- packages/walkthrough/steps/14/ui5.yaml | 2 +- .../walkthrough/steps/14/webapp/Component.ts | 2 +- .../14/webapp/controller/App.controller.ts | 2 +- .../steps/14/webapp/index-cdn.html | 4 +- .../walkthrough/steps/14/webapp/index.html | 4 +- .../walkthrough/steps/14/webapp/manifest.json | 8 +- .../steps/14/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/15/README.md | 16 +- packages/walkthrough/steps/15/package.json | 2 +- packages/walkthrough/steps/15/tsconfig.json | 2 +- packages/walkthrough/steps/15/ui5.yaml | 2 +- .../walkthrough/steps/15/webapp/Component.ts | 2 +- .../15/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 2 +- .../steps/15/webapp/index-cdn.html | 4 +- .../walkthrough/steps/15/webapp/index.html | 4 +- .../walkthrough/steps/15/webapp/manifest.json | 8 +- .../steps/15/webapp/view/App.view.xml | 4 +- .../steps/15/webapp/view/HelloPanel.view.xml | 2 +- packages/walkthrough/steps/16/README.md | 14 +- packages/walkthrough/steps/16/package.json | 2 +- packages/walkthrough/steps/16/tsconfig.json | 2 +- packages/walkthrough/steps/16/ui5.yaml | 2 +- .../walkthrough/steps/16/webapp/Component.ts | 2 +- .../16/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../steps/16/webapp/index-cdn.html | 4 +- .../walkthrough/steps/16/webapp/index.html | 4 +- .../walkthrough/steps/16/webapp/manifest.json | 8 +- .../steps/16/webapp/view/App.view.xml | 4 +- .../steps/16/webapp/view/HelloPanel.view.xml | 2 +- packages/walkthrough/steps/17/README.md | 8 +- packages/walkthrough/steps/17/package.json | 2 +- packages/walkthrough/steps/17/tsconfig.json | 2 +- packages/walkthrough/steps/17/ui5.yaml | 2 +- .../walkthrough/steps/17/webapp/Component.ts | 2 +- .../17/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../steps/17/webapp/index-cdn.html | 4 +- .../walkthrough/steps/17/webapp/index.html | 4 +- .../walkthrough/steps/17/webapp/manifest.json | 8 +- .../steps/17/webapp/view/App.view.xml | 4 +- .../steps/17/webapp/view/HelloPanel.view.xml | 2 +- packages/walkthrough/steps/18/README.md | 4 +- packages/walkthrough/steps/18/package.json | 2 +- packages/walkthrough/steps/18/tsconfig.json | 2 +- packages/walkthrough/steps/18/ui5.yaml | 2 +- .../walkthrough/steps/18/webapp/Component.ts | 2 +- .../18/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../steps/18/webapp/index-cdn.html | 4 +- .../walkthrough/steps/18/webapp/index.html | 4 +- .../walkthrough/steps/18/webapp/manifest.json | 8 +- .../steps/18/webapp/view/App.view.xml | 4 +- .../steps/18/webapp/view/HelloPanel.view.xml | 2 +- packages/walkthrough/steps/19/README.md | 8 +- packages/walkthrough/steps/19/package.json | 2 +- packages/walkthrough/steps/19/tsconfig.json | 2 +- packages/walkthrough/steps/19/ui5.yaml | 2 +- .../walkthrough/steps/19/webapp/Component.ts | 2 +- .../19/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../steps/19/webapp/index-cdn.html | 4 +- .../walkthrough/steps/19/webapp/index.html | 4 +- .../walkthrough/steps/19/webapp/manifest.json | 8 +- .../steps/19/webapp/view/App.view.xml | 6 +- .../steps/19/webapp/view/HelloPanel.view.xml | 2 +- packages/walkthrough/steps/20/README.md | 6 +- packages/walkthrough/steps/20/package.json | 2 +- packages/walkthrough/steps/20/tsconfig.json | 2 +- packages/walkthrough/steps/20/ui5.yaml | 2 +- .../walkthrough/steps/20/webapp/Component.ts | 2 +- .../20/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/20/webapp/index-cdn.html | 4 +- .../walkthrough/steps/20/webapp/index.html | 4 +- .../walkthrough/steps/20/webapp/manifest.json | 8 +- .../steps/20/webapp/view/App.view.xml | 6 +- .../steps/20/webapp/view/HelloPanel.view.xml | 2 +- .../steps/20/webapp/view/InvoiceList.view.xml | 2 +- packages/walkthrough/steps/21/README.md | 2 +- packages/walkthrough/steps/21/package.json | 2 +- packages/walkthrough/steps/21/tsconfig.json | 2 +- packages/walkthrough/steps/21/ui5.yaml | 2 +- .../walkthrough/steps/21/webapp/Component.ts | 2 +- .../21/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/21/webapp/index-cdn.html | 4 +- .../walkthrough/steps/21/webapp/index.html | 4 +- .../walkthrough/steps/21/webapp/manifest.json | 8 +- .../steps/21/webapp/view/App.view.xml | 6 +- .../steps/21/webapp/view/HelloPanel.view.xml | 2 +- .../steps/21/webapp/view/InvoiceList.view.xml | 2 +- packages/walkthrough/steps/22/README.md | 6 +- packages/walkthrough/steps/22/package.json | 2 +- packages/walkthrough/steps/22/tsconfig.json | 2 +- packages/walkthrough/steps/22/ui5.yaml | 2 +- .../walkthrough/steps/22/webapp/Component.ts | 2 +- .../22/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/22/webapp/index-cdn.html | 4 +- .../walkthrough/steps/22/webapp/index.html | 4 +- .../walkthrough/steps/22/webapp/manifest.json | 8 +- .../steps/22/webapp/view/App.view.xml | 6 +- .../steps/22/webapp/view/HelloPanel.view.xml | 2 +- .../steps/22/webapp/view/InvoiceList.view.xml | 4 +- packages/walkthrough/steps/23/README.md | 6 +- packages/walkthrough/steps/23/package.json | 2 +- packages/walkthrough/steps/23/tsconfig.json | 2 +- packages/walkthrough/steps/23/ui5.yaml | 2 +- .../walkthrough/steps/23/webapp/Component.ts | 2 +- .../23/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/23/webapp/index-cdn.html | 4 +- .../walkthrough/steps/23/webapp/index.html | 4 +- .../walkthrough/steps/23/webapp/manifest.json | 8 +- .../steps/23/webapp/view/App.view.xml | 6 +- .../steps/23/webapp/view/HelloPanel.view.xml | 2 +- .../steps/23/webapp/view/InvoiceList.view.xml | 4 +- packages/walkthrough/steps/24/README.md | 4 +- packages/walkthrough/steps/24/package.json | 2 +- packages/walkthrough/steps/24/tsconfig.json | 2 +- packages/walkthrough/steps/24/ui5.yaml | 2 +- .../walkthrough/steps/24/webapp/Component.ts | 2 +- .../24/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/24/webapp/index-cdn.html | 4 +- .../walkthrough/steps/24/webapp/index.html | 4 +- .../walkthrough/steps/24/webapp/manifest.json | 8 +- .../steps/24/webapp/view/App.view.xml | 6 +- .../steps/24/webapp/view/HelloPanel.view.xml | 2 +- .../steps/24/webapp/view/InvoiceList.view.xml | 4 +- packages/walkthrough/steps/25/README.md | 2 +- packages/walkthrough/steps/25/package.json | 2 +- packages/walkthrough/steps/25/tsconfig.json | 2 +- packages/walkthrough/steps/25/ui5.yaml | 2 +- .../walkthrough/steps/25/webapp/Component.ts | 2 +- .../25/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/25/webapp/index-cdn.html | 4 +- .../walkthrough/steps/25/webapp/index.html | 4 +- .../walkthrough/steps/25/webapp/manifest.json | 8 +- .../steps/25/webapp/view/App.view.xml | 6 +- .../steps/25/webapp/view/HelloPanel.view.xml | 2 +- .../steps/25/webapp/view/InvoiceList.view.xml | 4 +- packages/walkthrough/steps/26/README.md | 16 +- packages/walkthrough/steps/26/package.json | 2 +- packages/walkthrough/steps/26/tsconfig.json | 2 +- packages/walkthrough/steps/26/ui5.yaml | 2 +- .../walkthrough/steps/26/webapp/Component.ts | 2 +- .../26/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/26/webapp/index-cdn.html | 4 +- .../walkthrough/steps/26/webapp/index.html | 4 +- .../26/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/26/webapp/manifest.json | 8 +- .../steps/26/webapp/test/mockServer-cdn.html | 6 +- .../steps/26/webapp/test/mockServer.html | 6 +- .../steps/26/webapp/view/App.view.xml | 6 +- .../steps/26/webapp/view/HelloPanel.view.xml | 2 +- .../steps/26/webapp/view/InvoiceList.view.xml | 4 +- packages/walkthrough/steps/27/README.md | 30 +- packages/walkthrough/steps/27/package.json | 2 +- packages/walkthrough/steps/27/tsconfig.json | 2 +- packages/walkthrough/steps/27/ui5.yaml | 2 +- .../walkthrough/steps/27/webapp/Component.ts | 2 +- .../27/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/27/webapp/index-cdn.html | 4 +- .../walkthrough/steps/27/webapp/index.html | 4 +- .../27/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/27/webapp/manifest.json | 8 +- .../steps/27/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/27/webapp/test/Test.qunit.html | 2 +- .../steps/27/webapp/test/mockServer-cdn.html | 6 +- .../steps/27/webapp/test/mockServer.html | 6 +- .../27/webapp/test/testsuite.cdn.qunit.html | 4 +- .../27/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/27/webapp/test/testsuite.qunit.html | 4 +- .../steps/27/webapp/test/testsuite.qunit.ts | 4 +- .../27/webapp/test/unit/model/formatter.ts | 4 +- .../steps/27/webapp/view/App.view.xml | 6 +- .../steps/27/webapp/view/HelloPanel.view.xml | 2 +- .../steps/27/webapp/view/InvoiceList.view.xml | 4 +- packages/walkthrough/steps/28/README.md | 12 +- packages/walkthrough/steps/28/package.json | 2 +- packages/walkthrough/steps/28/tsconfig.json | 2 +- packages/walkthrough/steps/28/ui5.yaml | 2 +- .../walkthrough/steps/28/webapp/Component.ts | 2 +- .../28/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/28/webapp/index-cdn.html | 4 +- .../walkthrough/steps/28/webapp/index.html | 4 +- .../28/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/28/webapp/manifest.json | 8 +- .../steps/28/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/28/webapp/test/Test.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/28/webapp/test/mockServer-cdn.html | 6 +- .../steps/28/webapp/test/mockServer.html | 6 +- .../28/webapp/test/testsuite.cdn.qunit.html | 4 +- .../28/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/28/webapp/test/testsuite.qunit.html | 4 +- .../steps/28/webapp/test/testsuite.qunit.ts | 4 +- .../28/webapp/test/unit/model/formatter.ts | 4 +- .../steps/28/webapp/view/App.view.xml | 6 +- .../steps/28/webapp/view/HelloPanel.view.xml | 2 +- .../steps/28/webapp/view/InvoiceList.view.xml | 4 +- packages/walkthrough/steps/29/README.md | 6 +- packages/walkthrough/steps/29/package.json | 2 +- packages/walkthrough/steps/29/tsconfig.json | 2 +- packages/walkthrough/steps/29/ui5.yaml | 2 +- .../walkthrough/steps/29/webapp/Component.ts | 2 +- .../29/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/29/webapp/index-cdn.html | 4 +- .../walkthrough/steps/29/webapp/index.html | 4 +- .../29/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/29/webapp/manifest.json | 8 +- .../steps/29/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/29/webapp/test/Test.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/29/webapp/test/mockServer-cdn.html | 6 +- .../steps/29/webapp/test/mockServer.html | 6 +- .../29/webapp/test/testsuite.cdn.qunit.html | 4 +- .../29/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/29/webapp/test/testsuite.qunit.html | 4 +- .../steps/29/webapp/test/testsuite.qunit.ts | 4 +- .../29/webapp/test/unit/model/formatter.ts | 4 +- .../steps/29/webapp/view/App.view.xml | 6 +- .../steps/29/webapp/view/HelloPanel.view.xml | 2 +- .../steps/29/webapp/view/InvoiceList.view.xml | 4 +- packages/walkthrough/steps/30/README.md | 28 +- packages/walkthrough/steps/30/package.json | 2 +- packages/walkthrough/steps/30/tsconfig.json | 2 +- packages/walkthrough/steps/30/ui5.yaml | 2 +- .../walkthrough/steps/30/webapp/Component.ts | 2 +- .../30/webapp/controller/App.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/30/webapp/index-cdn.html | 4 +- .../walkthrough/steps/30/webapp/index.html | 4 +- .../30/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/30/webapp/manifest.json | 10 +- .../steps/30/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/30/webapp/test/Test.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/30/webapp/test/mockServer-cdn.html | 6 +- .../steps/30/webapp/test/mockServer.html | 6 +- .../30/webapp/test/testsuite.cdn.qunit.html | 4 +- .../30/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/30/webapp/test/testsuite.qunit.html | 4 +- .../steps/30/webapp/test/testsuite.qunit.ts | 4 +- .../30/webapp/test/unit/model/formatter.ts | 4 +- .../steps/30/webapp/view/App.view.xml | 2 +- .../steps/30/webapp/view/HelloPanel.view.xml | 2 +- .../steps/30/webapp/view/InvoiceList.view.xml | 4 +- .../steps/30/webapp/view/Overview.view.xml | 6 +- packages/walkthrough/steps/31/README.md | 14 +- packages/walkthrough/steps/31/package.json | 2 +- packages/walkthrough/steps/31/tsconfig.json | 2 +- packages/walkthrough/steps/31/ui5.yaml | 2 +- .../walkthrough/steps/31/webapp/Component.ts | 2 +- .../31/webapp/controller/App.controller.ts | 2 +- .../31/webapp/controller/Detail.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/31/webapp/index-cdn.html | 4 +- .../walkthrough/steps/31/webapp/index.html | 4 +- .../31/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/31/webapp/manifest.json | 10 +- .../steps/31/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/31/webapp/test/Test.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/31/webapp/test/mockServer-cdn.html | 6 +- .../steps/31/webapp/test/mockServer.html | 6 +- .../31/webapp/test/testsuite.cdn.qunit.html | 4 +- .../31/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/31/webapp/test/testsuite.qunit.html | 4 +- .../steps/31/webapp/test/testsuite.qunit.ts | 4 +- .../31/webapp/test/unit/model/formatter.ts | 4 +- .../steps/31/webapp/view/App.view.xml | 2 +- .../steps/31/webapp/view/Detail.view.xml | 2 +- .../steps/31/webapp/view/HelloPanel.view.xml | 2 +- .../steps/31/webapp/view/InvoiceList.view.xml | 4 +- .../steps/31/webapp/view/Overview.view.xml | 6 +- packages/walkthrough/steps/32/README.md | 6 +- packages/walkthrough/steps/32/package.json | 2 +- packages/walkthrough/steps/32/tsconfig.json | 2 +- packages/walkthrough/steps/32/ui5.yaml | 2 +- .../walkthrough/steps/32/webapp/Component.ts | 2 +- .../32/webapp/controller/App.controller.ts | 2 +- .../32/webapp/controller/Detail.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/32/webapp/index-cdn.html | 4 +- .../walkthrough/steps/32/webapp/index.html | 4 +- .../32/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/32/webapp/manifest.json | 10 +- .../steps/32/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/32/webapp/test/Test.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/32/webapp/test/mockServer-cdn.html | 6 +- .../steps/32/webapp/test/mockServer.html | 6 +- .../32/webapp/test/testsuite.cdn.qunit.html | 4 +- .../32/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/32/webapp/test/testsuite.qunit.html | 4 +- .../steps/32/webapp/test/testsuite.qunit.ts | 4 +- .../32/webapp/test/unit/model/formatter.ts | 4 +- .../steps/32/webapp/view/App.view.xml | 2 +- .../steps/32/webapp/view/Detail.view.xml | 2 +- .../steps/32/webapp/view/HelloPanel.view.xml | 2 +- .../steps/32/webapp/view/InvoiceList.view.xml | 4 +- .../steps/32/webapp/view/Overview.view.xml | 6 +- packages/walkthrough/steps/33/README.md | 26 +- packages/walkthrough/steps/33/package.json | 2 +- packages/walkthrough/steps/33/tsconfig.json | 2 +- packages/walkthrough/steps/33/ui5.yaml | 2 +- .../walkthrough/steps/33/webapp/Component.ts | 2 +- .../steps/33/webapp/control/ProductRating.ts | 2 +- .../33/webapp/controller/App.controller.ts | 2 +- .../33/webapp/controller/Detail.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/33/webapp/index-cdn.html | 4 +- .../walkthrough/steps/33/webapp/index.html | 4 +- .../33/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/33/webapp/manifest.json | 10 +- .../steps/33/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/33/webapp/test/Test.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/33/webapp/test/mockServer-cdn.html | 6 +- .../steps/33/webapp/test/mockServer.html | 6 +- .../33/webapp/test/testsuite.cdn.qunit.html | 4 +- .../33/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/33/webapp/test/testsuite.qunit.html | 4 +- .../steps/33/webapp/test/testsuite.qunit.ts | 4 +- .../33/webapp/test/unit/model/formatter.ts | 4 +- .../steps/33/webapp/view/App.view.xml | 2 +- .../steps/33/webapp/view/Detail.view.xml | 4 +- .../steps/33/webapp/view/HelloPanel.view.xml | 2 +- .../steps/33/webapp/view/InvoiceList.view.xml | 4 +- .../steps/33/webapp/view/Overview.view.xml | 6 +- packages/walkthrough/steps/34/README.md | 4 +- packages/walkthrough/steps/34/package.json | 2 +- packages/walkthrough/steps/34/tsconfig.json | 2 +- packages/walkthrough/steps/34/ui5.yaml | 2 +- .../walkthrough/steps/34/webapp/Component.ts | 2 +- .../steps/34/webapp/control/ProductRating.ts | 2 +- .../34/webapp/controller/App.controller.ts | 2 +- .../34/webapp/controller/Detail.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/34/webapp/index-cdn.html | 4 +- .../walkthrough/steps/34/webapp/index.html | 4 +- .../34/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/34/webapp/manifest.json | 10 +- .../steps/34/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/34/webapp/test/Test.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/34/webapp/test/mockServer-cdn.html | 6 +- .../steps/34/webapp/test/mockServer.html | 6 +- .../34/webapp/test/testsuite.cdn.qunit.html | 4 +- .../34/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/34/webapp/test/testsuite.qunit.html | 4 +- .../steps/34/webapp/test/testsuite.qunit.ts | 4 +- .../34/webapp/test/unit/model/formatter.ts | 4 +- .../steps/34/webapp/view/App.view.xml | 2 +- .../steps/34/webapp/view/Detail.view.xml | 4 +- .../steps/34/webapp/view/HelloPanel.view.xml | 2 +- .../steps/34/webapp/view/InvoiceList.view.xml | 4 +- .../steps/34/webapp/view/Overview.view.xml | 6 +- packages/walkthrough/steps/35/README.md | 20 +- packages/walkthrough/steps/35/package.json | 2 +- packages/walkthrough/steps/35/tsconfig.json | 2 +- packages/walkthrough/steps/35/ui5.yaml | 2 +- .../walkthrough/steps/35/webapp/Component.ts | 2 +- .../steps/35/webapp/control/ProductRating.ts | 2 +- .../35/webapp/controller/App.controller.ts | 2 +- .../35/webapp/controller/Detail.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/35/webapp/index-cdn.html | 4 +- .../walkthrough/steps/35/webapp/index.html | 4 +- .../35/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/35/webapp/manifest.json | 10 +- .../steps/35/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/35/webapp/test/Test.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/35/webapp/test/mockServer-cdn.html | 6 +- .../steps/35/webapp/test/mockServer.html | 6 +- .../35/webapp/test/testsuite.cdn.qunit.html | 4 +- .../35/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/35/webapp/test/testsuite.qunit.html | 4 +- .../steps/35/webapp/test/testsuite.qunit.ts | 4 +- .../35/webapp/test/unit/model/formatter.ts | 4 +- .../steps/35/webapp/view/App.view.xml | 2 +- .../steps/35/webapp/view/Detail.view.xml | 4 +- .../steps/35/webapp/view/HelloPanel.view.xml | 2 +- .../steps/35/webapp/view/InvoiceList.view.xml | 4 +- .../steps/35/webapp/view/Overview.view.xml | 6 +- packages/walkthrough/steps/36/README.md | 8 +- packages/walkthrough/steps/36/package.json | 2 +- packages/walkthrough/steps/36/tsconfig.json | 2 +- packages/walkthrough/steps/36/ui5.yaml | 2 +- .../walkthrough/steps/36/webapp/Component.ts | 2 +- .../steps/36/webapp/control/ProductRating.ts | 2 +- .../36/webapp/controller/App.controller.ts | 2 +- .../36/webapp/controller/Detail.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/36/webapp/index-cdn.html | 4 +- .../walkthrough/steps/36/webapp/index.html | 4 +- .../36/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/36/webapp/manifest.json | 10 +- .../steps/36/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/36/webapp/test/Test.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/36/webapp/test/mockServer-cdn.html | 6 +- .../steps/36/webapp/test/mockServer.html | 6 +- .../36/webapp/test/testsuite.cdn.qunit.html | 4 +- .../36/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/36/webapp/test/testsuite.qunit.html | 4 +- .../steps/36/webapp/test/testsuite.qunit.ts | 4 +- .../36/webapp/test/unit/model/formatter.ts | 4 +- .../steps/36/webapp/view/App.view.xml | 2 +- .../steps/36/webapp/view/Detail.view.xml | 4 +- .../steps/36/webapp/view/HelloPanel.view.xml | 2 +- .../steps/36/webapp/view/InvoiceList.view.xml | 4 +- .../steps/36/webapp/view/Overview.view.xml | 6 +- packages/walkthrough/steps/37/README.md | 12 +- packages/walkthrough/steps/37/package.json | 2 +- packages/walkthrough/steps/37/tsconfig.json | 2 +- packages/walkthrough/steps/37/ui5.yaml | 2 +- .../walkthrough/steps/37/webapp/Component.ts | 2 +- .../steps/37/webapp/control/ProductRating.ts | 2 +- .../37/webapp/controller/App.controller.ts | 2 +- .../37/webapp/controller/Detail.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/37/webapp/index-cdn.html | 4 +- .../walkthrough/steps/37/webapp/index.html | 4 +- .../37/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/37/webapp/manifest.json | 10 +- .../steps/37/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/37/webapp/test/Test.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/37/webapp/test/mockServer-cdn.html | 6 +- .../steps/37/webapp/test/mockServer.html | 6 +- .../37/webapp/test/testsuite.cdn.qunit.html | 4 +- .../37/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/37/webapp/test/testsuite.qunit.html | 4 +- .../steps/37/webapp/test/testsuite.qunit.ts | 4 +- .../37/webapp/test/unit/model/formatter.ts | 4 +- .../steps/37/webapp/view/App.view.xml | 2 +- .../steps/37/webapp/view/Detail.view.xml | 4 +- .../steps/37/webapp/view/HelloPanel.view.xml | 2 +- .../steps/37/webapp/view/InvoiceList.view.xml | 4 +- .../steps/37/webapp/view/Overview.view.xml | 6 +- packages/walkthrough/steps/38/README.md | 4 +- packages/walkthrough/steps/38/package.json | 2 +- packages/walkthrough/steps/38/tsconfig.json | 2 +- packages/walkthrough/steps/38/ui5.yaml | 2 +- .../walkthrough/steps/38/webapp/Component.ts | 2 +- .../steps/38/webapp/control/ProductRating.ts | 2 +- .../38/webapp/controller/App.controller.ts | 2 +- .../38/webapp/controller/Detail.controller.ts | 2 +- .../controller/HelloPanel.controller.ts | 4 +- .../controller/InvoiceList.controller.ts | 2 +- .../steps/38/webapp/index-cdn.html | 4 +- .../walkthrough/steps/38/webapp/index.html | 4 +- packages/walkthrough/steps/38/webapp/index.ts | 2 +- .../38/webapp/localService/mockserver.ts | 4 +- .../walkthrough/steps/38/webapp/manifest.json | 10 +- .../steps/38/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/38/webapp/test/Test.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/38/webapp/test/mockServer-cdn.html | 6 +- .../steps/38/webapp/test/mockServer.html | 6 +- .../38/webapp/test/testsuite.cdn.qunit.html | 4 +- .../38/webapp/test/testsuite.cdn.qunit.ts | 4 +- .../steps/38/webapp/test/testsuite.qunit.html | 4 +- .../steps/38/webapp/test/testsuite.qunit.ts | 4 +- .../38/webapp/test/unit/model/formatter.ts | 4 +- .../steps/38/webapp/view/App.view.xml | 2 +- .../steps/38/webapp/view/Detail.view.xml | 4 +- .../steps/38/webapp/view/HelloPanel.view.xml | 2 +- .../steps/38/webapp/view/InvoiceList.view.xml | 4 +- .../steps/38/webapp/view/Overview.view.xml | 6 +- tools/dev-server/server.js | 54 +- 1363 files changed, 49009 insertions(+), 1320 deletions(-) create mode 100644 packages/navigation/README.md create mode 100644 packages/navigation/assets/Tutorial_Navigation_and_Routing_Screen_Flow_92cdce7.png create mode 100644 packages/navigation/steps/01/README.md create mode 100644 packages/navigation/steps/01/assets/Tutorial_Navigation_and_Routing_Step_01a.png create mode 100644 packages/navigation/steps/01/package.json create mode 100644 packages/navigation/steps/01/tsconfig.json create mode 100644 packages/navigation/steps/01/ui5.yaml create mode 100644 packages/navigation/steps/01/webapp/Component.ts create mode 100644 packages/navigation/steps/01/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/01/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/01/webapp/index-cdn.html create mode 100644 packages/navigation/steps/01/webapp/index.html create mode 100644 packages/navigation/steps/01/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/01/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/01/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/01/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/01/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/01/webapp/manifest.json create mode 100644 packages/navigation/steps/01/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/02/README.md create mode 100644 packages/navigation/steps/02/assets/Tutorial_Navigation_and_Routing_Step_02a.png create mode 100644 packages/navigation/steps/02/package.json create mode 100644 packages/navigation/steps/02/tsconfig.json create mode 100644 packages/navigation/steps/02/ui5.yaml create mode 100644 packages/navigation/steps/02/webapp/Component.ts create mode 100644 packages/navigation/steps/02/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/02/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/02/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/02/webapp/index-cdn.html create mode 100644 packages/navigation/steps/02/webapp/index.html create mode 100644 packages/navigation/steps/02/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/02/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/02/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/02/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/02/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/02/webapp/manifest.json create mode 100644 packages/navigation/steps/02/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/02/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/03/README.md create mode 100644 packages/navigation/steps/03/assets/Tutorial_Navigation_and_Routing_Step_03.png create mode 100644 packages/navigation/steps/03/package.json create mode 100644 packages/navigation/steps/03/tsconfig.json create mode 100644 packages/navigation/steps/03/ui5.yaml create mode 100644 packages/navigation/steps/03/webapp/Component.ts create mode 100644 packages/navigation/steps/03/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/03/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/03/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/03/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/03/webapp/index-cdn.html create mode 100644 packages/navigation/steps/03/webapp/index.html create mode 100644 packages/navigation/steps/03/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/03/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/03/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/03/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/03/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/03/webapp/manifest.json create mode 100644 packages/navigation/steps/03/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/03/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/03/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/04/README.md create mode 100644 packages/navigation/steps/04/assets/Tutorial_Navigation_and_Routing_Step_04a.png create mode 100644 packages/navigation/steps/04/package.json create mode 100644 packages/navigation/steps/04/tsconfig.json create mode 100644 packages/navigation/steps/04/ui5.yaml create mode 100644 packages/navigation/steps/04/webapp/Component.ts create mode 100644 packages/navigation/steps/04/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/04/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/04/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/04/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/04/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/04/webapp/index-cdn.html create mode 100644 packages/navigation/steps/04/webapp/index.html create mode 100644 packages/navigation/steps/04/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/04/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/04/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/04/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/04/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/04/webapp/manifest.json create mode 100644 packages/navigation/steps/04/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/04/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/04/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/05/README.md create mode 100644 packages/navigation/steps/05/assets/Tutorial_Navigation_and_Routing_Step_05.png create mode 100644 packages/navigation/steps/05/package.json create mode 100644 packages/navigation/steps/05/tsconfig.json create mode 100644 packages/navigation/steps/05/ui5.yaml create mode 100644 packages/navigation/steps/05/webapp/Component.ts create mode 100644 packages/navigation/steps/05/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/05/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/05/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/05/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/05/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/05/webapp/index-cdn.html create mode 100644 packages/navigation/steps/05/webapp/index.html create mode 100644 packages/navigation/steps/05/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/05/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/05/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/05/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/05/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/05/webapp/manifest.json create mode 100644 packages/navigation/steps/05/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/05/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/05/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/06/README.md create mode 100644 packages/navigation/steps/06/assets/Tutorial_Navigation_and_Routing_Step_06a.png create mode 100644 packages/navigation/steps/06/assets/Tutorial_Navigation_and_Routing_Step_06b.png create mode 100644 packages/navigation/steps/06/package.json create mode 100644 packages/navigation/steps/06/tsconfig.json create mode 100644 packages/navigation/steps/06/ui5.yaml create mode 100644 packages/navigation/steps/06/webapp/Component.ts create mode 100644 packages/navigation/steps/06/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/06/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/06/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/06/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/06/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/06/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/06/webapp/index-cdn.html create mode 100644 packages/navigation/steps/06/webapp/index.html create mode 100644 packages/navigation/steps/06/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/06/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/06/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/06/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/06/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/06/webapp/manifest.json create mode 100644 packages/navigation/steps/06/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/06/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/06/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/06/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/07/README.md create mode 100644 packages/navigation/steps/07/assets/Tutorial_Navigation_and_Routing_Step_07a.png create mode 100644 packages/navigation/steps/07/assets/Tutorial_Navigation_and_Routing_Step_07b.png create mode 100644 packages/navigation/steps/07/assets/Tutorial_Navigation_and_Routing_Step_07c.png create mode 100644 packages/navigation/steps/07/package.json create mode 100644 packages/navigation/steps/07/tsconfig.json create mode 100644 packages/navigation/steps/07/ui5.yaml create mode 100644 packages/navigation/steps/07/webapp/Component.ts create mode 100644 packages/navigation/steps/07/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/07/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/07/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/07/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/07/webapp/controller/employee/Employee.controller.ts create mode 100644 packages/navigation/steps/07/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/07/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/07/webapp/index-cdn.html create mode 100644 packages/navigation/steps/07/webapp/index.html create mode 100644 packages/navigation/steps/07/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/07/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/07/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/07/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/07/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/07/webapp/manifest.json create mode 100644 packages/navigation/steps/07/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/07/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/07/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/07/webapp/view/employee/Employee.view.xml create mode 100644 packages/navigation/steps/07/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/08/README.md create mode 100644 packages/navigation/steps/08/assets/Tutorial_Navigation_and_Routing_Step_08a.png create mode 100644 packages/navigation/steps/08/assets/Tutorial_Navigation_and_Routing_Step_08b.png create mode 100644 packages/navigation/steps/08/assets/Tutorial_Navigation_and_Routing_Step_08c.png create mode 100644 packages/navigation/steps/08/package.json create mode 100644 packages/navigation/steps/08/tsconfig.json create mode 100644 packages/navigation/steps/08/ui5.yaml create mode 100644 packages/navigation/steps/08/webapp/Component.ts create mode 100644 packages/navigation/steps/08/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/08/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/08/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/08/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/08/webapp/controller/employee/Employee.controller.ts create mode 100644 packages/navigation/steps/08/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/08/webapp/controller/employee/Resume.controller.ts create mode 100644 packages/navigation/steps/08/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/08/webapp/index-cdn.html create mode 100644 packages/navigation/steps/08/webapp/index.html create mode 100644 packages/navigation/steps/08/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/08/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/08/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/08/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/08/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/08/webapp/manifest.json create mode 100644 packages/navigation/steps/08/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/08/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/08/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/08/webapp/view/employee/Employee.view.xml create mode 100644 packages/navigation/steps/08/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/08/webapp/view/employee/Resume.view.xml create mode 100644 packages/navigation/steps/08/webapp/view/employee/ResumeProjects.view.xml create mode 100644 packages/navigation/steps/09/README.md create mode 100644 packages/navigation/steps/09/assets/Tutorial_Navigation_and_Routing_Step_09.png create mode 100644 packages/navigation/steps/09/package.json create mode 100644 packages/navigation/steps/09/tsconfig.json create mode 100644 packages/navigation/steps/09/ui5.yaml create mode 100644 packages/navigation/steps/09/webapp/Component.ts create mode 100644 packages/navigation/steps/09/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/09/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/09/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/09/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/09/webapp/controller/employee/Employee.controller.ts create mode 100644 packages/navigation/steps/09/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/09/webapp/controller/employee/Resume.controller.ts create mode 100644 packages/navigation/steps/09/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/09/webapp/index-cdn.html create mode 100644 packages/navigation/steps/09/webapp/index.html create mode 100644 packages/navigation/steps/09/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/09/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/09/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/09/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/09/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/09/webapp/manifest.json create mode 100644 packages/navigation/steps/09/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/09/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/09/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/09/webapp/view/employee/Employee.view.xml create mode 100644 packages/navigation/steps/09/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/09/webapp/view/employee/Resume.view.xml create mode 100644 packages/navigation/steps/09/webapp/view/employee/ResumeProjects.view.xml create mode 100644 packages/navigation/steps/10/README.md create mode 100644 packages/navigation/steps/10/assets/Tutorial_Navigation_and_Routing_Step_10a.png create mode 100644 packages/navigation/steps/10/assets/Tutorial_Navigation_and_Routing_Step_10b.png create mode 100644 packages/navigation/steps/10/package.json create mode 100644 packages/navigation/steps/10/tsconfig.json create mode 100644 packages/navigation/steps/10/ui5.yaml create mode 100644 packages/navigation/steps/10/webapp/Component.ts create mode 100644 packages/navigation/steps/10/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/10/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/10/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/10/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/10/webapp/controller/employee/Employee.controller.ts create mode 100644 packages/navigation/steps/10/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/10/webapp/controller/employee/Resume.controller.ts create mode 100644 packages/navigation/steps/10/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/10/webapp/index-cdn.html create mode 100644 packages/navigation/steps/10/webapp/index.html create mode 100644 packages/navigation/steps/10/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/10/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/10/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/10/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/10/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/10/webapp/manifest.json create mode 100644 packages/navigation/steps/10/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/10/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/10/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/10/webapp/view/employee/Employee.view.xml create mode 100644 packages/navigation/steps/10/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/10/webapp/view/employee/Resume.view.xml create mode 100644 packages/navigation/steps/10/webapp/view/employee/ResumeHobbies.view.xml create mode 100644 packages/navigation/steps/10/webapp/view/employee/ResumeNotes.view.xml create mode 100644 packages/navigation/steps/10/webapp/view/employee/ResumeProjects.view.xml create mode 100644 packages/navigation/steps/11/README.md create mode 100644 packages/navigation/steps/11/assets/Tutorial_Navigation_and_Routing_Step_11a.png create mode 100644 packages/navigation/steps/11/assets/Tutorial_Navigation_and_Routing_Step_11b.png create mode 100644 packages/navigation/steps/11/assets/Tutorial_Navigation_and_Routing_Step_11c.png create mode 100644 packages/navigation/steps/11/assets/Tutorial_Navigation_and_Routing_Step_11d.png create mode 100644 packages/navigation/steps/11/package.json create mode 100644 packages/navigation/steps/11/tsconfig.json create mode 100644 packages/navigation/steps/11/ui5.yaml create mode 100644 packages/navigation/steps/11/webapp/Component.ts create mode 100644 packages/navigation/steps/11/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/11/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/11/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/11/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/11/webapp/controller/employee/Employee.controller.ts create mode 100644 packages/navigation/steps/11/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/11/webapp/controller/employee/Resume.controller.ts create mode 100644 packages/navigation/steps/11/webapp/controller/employee/overview/EmployeeOverview.controller.ts create mode 100644 packages/navigation/steps/11/webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts create mode 100644 packages/navigation/steps/11/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/11/webapp/index-cdn.html create mode 100644 packages/navigation/steps/11/webapp/index.html create mode 100644 packages/navigation/steps/11/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/11/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/11/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/11/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/11/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/11/webapp/manifest.json create mode 100644 packages/navigation/steps/11/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/11/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/11/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/11/webapp/view/employee/Employee.view.xml create mode 100644 packages/navigation/steps/11/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/11/webapp/view/employee/Resume.view.xml create mode 100644 packages/navigation/steps/11/webapp/view/employee/ResumeHobbies.view.xml create mode 100644 packages/navigation/steps/11/webapp/view/employee/ResumeNotes.view.xml create mode 100644 packages/navigation/steps/11/webapp/view/employee/ResumeProjects.view.xml create mode 100644 packages/navigation/steps/11/webapp/view/employee/overview/EmployeeOverview.view.xml create mode 100644 packages/navigation/steps/11/webapp/view/employee/overview/EmployeeOverviewContent.view.xml create mode 100644 packages/navigation/steps/11/webapp/view/employee/overview/EmployeeOverviewTop.view.xml create mode 100644 packages/navigation/steps/12/README.md create mode 100644 packages/navigation/steps/12/assets/Tutorial_Navigation_and_Routing_Step_12.png create mode 100644 packages/navigation/steps/12/package.json create mode 100644 packages/navigation/steps/12/tsconfig.json create mode 100644 packages/navigation/steps/12/ui5.yaml create mode 100644 packages/navigation/steps/12/webapp/Component.ts create mode 100644 packages/navigation/steps/12/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/12/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/12/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/12/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/12/webapp/controller/employee/Employee.controller.ts create mode 100644 packages/navigation/steps/12/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/12/webapp/controller/employee/Resume.controller.ts create mode 100644 packages/navigation/steps/12/webapp/controller/employee/overview/EmployeeOverview.controller.ts create mode 100644 packages/navigation/steps/12/webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts create mode 100644 packages/navigation/steps/12/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/12/webapp/index-cdn.html create mode 100644 packages/navigation/steps/12/webapp/index.html create mode 100644 packages/navigation/steps/12/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/12/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/12/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/12/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/12/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/12/webapp/manifest.json create mode 100644 packages/navigation/steps/12/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/12/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/12/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/12/webapp/view/employee/Employee.view.xml create mode 100644 packages/navigation/steps/12/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/12/webapp/view/employee/Resume.view.xml create mode 100644 packages/navigation/steps/12/webapp/view/employee/ResumeHobbies.view.xml create mode 100644 packages/navigation/steps/12/webapp/view/employee/ResumeNotes.view.xml create mode 100644 packages/navigation/steps/12/webapp/view/employee/ResumeProjects.view.xml create mode 100644 packages/navigation/steps/12/webapp/view/employee/overview/EmployeeOverview.view.xml create mode 100644 packages/navigation/steps/12/webapp/view/employee/overview/EmployeeOverviewContent.view.xml create mode 100644 packages/navigation/steps/12/webapp/view/employee/overview/EmployeeOverviewTop.view.xml create mode 100644 packages/navigation/steps/13/README.md create mode 100644 packages/navigation/steps/13/assets/Tutorial_Navigation_and_Routing_Step_13.png create mode 100644 packages/navigation/steps/13/package.json create mode 100644 packages/navigation/steps/13/tsconfig.json create mode 100644 packages/navigation/steps/13/ui5.yaml create mode 100644 packages/navigation/steps/13/webapp/Component.ts create mode 100644 packages/navigation/steps/13/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/13/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/13/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/13/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/13/webapp/controller/employee/Employee.controller.ts create mode 100644 packages/navigation/steps/13/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/13/webapp/controller/employee/Resume.controller.ts create mode 100644 packages/navigation/steps/13/webapp/controller/employee/overview/EmployeeOverview.controller.ts create mode 100644 packages/navigation/steps/13/webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts create mode 100644 packages/navigation/steps/13/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/13/webapp/index-cdn.html create mode 100644 packages/navigation/steps/13/webapp/index.html create mode 100644 packages/navigation/steps/13/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/13/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/13/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/13/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/13/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/13/webapp/manifest.json create mode 100644 packages/navigation/steps/13/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/13/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/13/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/13/webapp/view/employee/Employee.view.xml create mode 100644 packages/navigation/steps/13/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/13/webapp/view/employee/Resume.view.xml create mode 100644 packages/navigation/steps/13/webapp/view/employee/ResumeHobbies.view.xml create mode 100644 packages/navigation/steps/13/webapp/view/employee/ResumeNotes.view.xml create mode 100644 packages/navigation/steps/13/webapp/view/employee/ResumeProjects.view.xml create mode 100644 packages/navigation/steps/13/webapp/view/employee/overview/EmployeeOverview.view.xml create mode 100644 packages/navigation/steps/13/webapp/view/employee/overview/EmployeeOverviewContent.view.xml create mode 100644 packages/navigation/steps/13/webapp/view/employee/overview/EmployeeOverviewTop.view.xml create mode 100644 packages/navigation/steps/14/README.md create mode 100644 packages/navigation/steps/14/assets/Tutorial_Navigation_and_Routing_Step_14.png create mode 100644 packages/navigation/steps/14/package.json create mode 100644 packages/navigation/steps/14/tsconfig.json create mode 100644 packages/navigation/steps/14/ui5.yaml create mode 100644 packages/navigation/steps/14/webapp/Component.ts create mode 100644 packages/navigation/steps/14/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/14/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/14/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/14/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/14/webapp/controller/employee/Employee.controller.ts create mode 100644 packages/navigation/steps/14/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/14/webapp/controller/employee/Resume.controller.ts create mode 100644 packages/navigation/steps/14/webapp/controller/employee/overview/EmployeeOverview.controller.ts create mode 100644 packages/navigation/steps/14/webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts create mode 100644 packages/navigation/steps/14/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/14/webapp/index-cdn.html create mode 100644 packages/navigation/steps/14/webapp/index.html create mode 100644 packages/navigation/steps/14/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/14/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/14/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/14/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/14/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/14/webapp/manifest.json create mode 100644 packages/navigation/steps/14/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/14/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/14/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/14/webapp/view/employee/Employee.view.xml create mode 100644 packages/navigation/steps/14/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/14/webapp/view/employee/Resume.view.xml create mode 100644 packages/navigation/steps/14/webapp/view/employee/ResumeHobbies.view.xml create mode 100644 packages/navigation/steps/14/webapp/view/employee/ResumeNotes.view.xml create mode 100644 packages/navigation/steps/14/webapp/view/employee/ResumeProjects.view.xml create mode 100644 packages/navigation/steps/14/webapp/view/employee/overview/EmployeeOverview.view.xml create mode 100644 packages/navigation/steps/14/webapp/view/employee/overview/EmployeeOverviewContent.view.xml create mode 100644 packages/navigation/steps/14/webapp/view/employee/overview/EmployeeOverviewTop.view.xml create mode 100644 packages/navigation/steps/15/README.md create mode 100644 packages/navigation/steps/15/assets/Tutorial_Navigation_and_Routing_Step_15.png create mode 100644 packages/navigation/steps/15/assets/Tutorial_Navigation_and_Routing_Step_17.png create mode 100644 packages/navigation/steps/15/package.json create mode 100644 packages/navigation/steps/15/tsconfig.json create mode 100644 packages/navigation/steps/15/ui5.yaml create mode 100644 packages/navigation/steps/15/webapp/Component.ts create mode 100644 packages/navigation/steps/15/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/15/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/15/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/15/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/15/webapp/controller/employee/Employee.controller.ts create mode 100644 packages/navigation/steps/15/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/15/webapp/controller/employee/Resume.controller.ts create mode 100644 packages/navigation/steps/15/webapp/controller/employee/overview/EmployeeOverview.controller.ts create mode 100644 packages/navigation/steps/15/webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts create mode 100644 packages/navigation/steps/15/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/15/webapp/index-cdn.html create mode 100644 packages/navigation/steps/15/webapp/index.html create mode 100644 packages/navigation/steps/15/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/15/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/15/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/15/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/15/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/15/webapp/manifest.json create mode 100644 packages/navigation/steps/15/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/15/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/15/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/15/webapp/view/employee/Employee.view.xml create mode 100644 packages/navigation/steps/15/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/15/webapp/view/employee/Resume.view.xml create mode 100644 packages/navigation/steps/15/webapp/view/employee/ResumeHobbies.view.xml create mode 100644 packages/navigation/steps/15/webapp/view/employee/ResumeNotes.view.xml create mode 100644 packages/navigation/steps/15/webapp/view/employee/ResumeProjects.view.xml create mode 100644 packages/navigation/steps/15/webapp/view/employee/overview/EmployeeOverview.view.xml create mode 100644 packages/navigation/steps/15/webapp/view/employee/overview/EmployeeOverviewContent.view.xml create mode 100644 packages/navigation/steps/15/webapp/view/employee/overview/EmployeeOverviewTop.view.xml create mode 100644 packages/navigation/steps/16/README.md create mode 100644 packages/navigation/steps/16/assets/Tutorial_Navigation_and_Routing_Step_16.png create mode 100644 packages/navigation/steps/16/package.json create mode 100644 packages/navigation/steps/16/tsconfig.json create mode 100644 packages/navigation/steps/16/ui5.yaml create mode 100644 packages/navigation/steps/16/webapp/Component.ts create mode 100644 packages/navigation/steps/16/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/16/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/16/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/16/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/16/webapp/controller/employee/Employee.controller.ts create mode 100644 packages/navigation/steps/16/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/16/webapp/controller/employee/Resume.controller.ts create mode 100644 packages/navigation/steps/16/webapp/controller/employee/overview/EmployeeOverview.controller.ts create mode 100644 packages/navigation/steps/16/webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts create mode 100644 packages/navigation/steps/16/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/16/webapp/index-cdn.html create mode 100644 packages/navigation/steps/16/webapp/index.html create mode 100644 packages/navigation/steps/16/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/16/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/16/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/16/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/16/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/16/webapp/manifest.json create mode 100644 packages/navigation/steps/16/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/16/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/16/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/16/webapp/view/employee/Employee.view.xml create mode 100644 packages/navigation/steps/16/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/16/webapp/view/employee/Resume.view.xml create mode 100644 packages/navigation/steps/16/webapp/view/employee/ResumeHobbies.view.xml create mode 100644 packages/navigation/steps/16/webapp/view/employee/ResumeNotes.view.xml create mode 100644 packages/navigation/steps/16/webapp/view/employee/ResumeProjects.view.xml create mode 100644 packages/navigation/steps/16/webapp/view/employee/overview/EmployeeOverview.view.xml create mode 100644 packages/navigation/steps/16/webapp/view/employee/overview/EmployeeOverviewContent.view.xml create mode 100644 packages/navigation/steps/16/webapp/view/employee/overview/EmployeeOverviewTop.view.xml create mode 100644 packages/navigation/steps/17/README.md create mode 100644 packages/navigation/steps/17/assets/Tutorial_Navigation_and_Routing_Step_17.png create mode 100644 packages/navigation/steps/17/package.json create mode 100644 packages/navigation/steps/17/tsconfig.json create mode 100644 packages/navigation/steps/17/ui5.yaml create mode 100644 packages/navigation/steps/17/webapp/Component.ts create mode 100644 packages/navigation/steps/17/webapp/controller/App.controller.ts create mode 100644 packages/navigation/steps/17/webapp/controller/BaseController.ts create mode 100644 packages/navigation/steps/17/webapp/controller/Home.controller.ts create mode 100644 packages/navigation/steps/17/webapp/controller/NotFound.controller.ts create mode 100644 packages/navigation/steps/17/webapp/controller/employee/Employee.controller.ts create mode 100644 packages/navigation/steps/17/webapp/controller/employee/EmployeeList.controller.ts create mode 100644 packages/navigation/steps/17/webapp/controller/employee/Resume.controller.ts create mode 100644 packages/navigation/steps/17/webapp/controller/employee/overview/EmployeeOverview.controller.ts create mode 100644 packages/navigation/steps/17/webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts create mode 100644 packages/navigation/steps/17/webapp/i18n/i18n.properties create mode 100644 packages/navigation/steps/17/webapp/index-cdn.html create mode 100644 packages/navigation/steps/17/webapp/index.html create mode 100644 packages/navigation/steps/17/webapp/initMockServer.ts create mode 100644 packages/navigation/steps/17/webapp/localService/metadata.xml create mode 100644 packages/navigation/steps/17/webapp/localService/mockdata/Employees.json create mode 100644 packages/navigation/steps/17/webapp/localService/mockdata/Resumes.json create mode 100644 packages/navigation/steps/17/webapp/localService/mockserver.ts create mode 100644 packages/navigation/steps/17/webapp/manifest.json create mode 100644 packages/navigation/steps/17/webapp/view/App.view.xml create mode 100644 packages/navigation/steps/17/webapp/view/Home.view.xml create mode 100644 packages/navigation/steps/17/webapp/view/NotFound.view.xml create mode 100644 packages/navigation/steps/17/webapp/view/employee/Employee.view.xml create mode 100644 packages/navigation/steps/17/webapp/view/employee/EmployeeList.view.xml create mode 100644 packages/navigation/steps/17/webapp/view/employee/Resume.view.xml create mode 100644 packages/navigation/steps/17/webapp/view/employee/ResumeHobbies.view.xml create mode 100644 packages/navigation/steps/17/webapp/view/employee/ResumeNotes.view.xml create mode 100644 packages/navigation/steps/17/webapp/view/employee/ResumeProjects.view.xml create mode 100644 packages/navigation/steps/17/webapp/view/employee/overview/EmployeeOverview.view.xml create mode 100644 packages/navigation/steps/17/webapp/view/employee/overview/EmployeeOverviewContent.view.xml create mode 100644 packages/navigation/steps/17/webapp/view/employee/overview/EmployeeOverviewTop.view.xml create mode 100644 packages/odatav4/README.md create mode 100644 packages/odatav4/steps/01/README.md create mode 100644 packages/odatav4/steps/01/assets/Tutorial_OData_V4_Step1_Preview_9d0182f.png create mode 100644 packages/odatav4/steps/01/package.json create mode 100644 packages/odatav4/steps/01/tsconfig.json create mode 100644 packages/odatav4/steps/01/ui5.yaml create mode 100644 packages/odatav4/steps/01/webapp/Component.ts create mode 100644 packages/odatav4/steps/01/webapp/controller/App.controller.ts create mode 100644 packages/odatav4/steps/01/webapp/i18n/i18n.properties create mode 100644 packages/odatav4/steps/01/webapp/index-cdn.html create mode 100644 packages/odatav4/steps/01/webapp/index.html create mode 100644 packages/odatav4/steps/01/webapp/initMockServer.ts create mode 100644 packages/odatav4/steps/01/webapp/localService/metadata.xml create mode 100644 packages/odatav4/steps/01/webapp/localService/mockdata/people.json create mode 100644 packages/odatav4/steps/01/webapp/localService/mockserver.ts create mode 100644 packages/odatav4/steps/01/webapp/manifest.json create mode 100644 packages/odatav4/steps/01/webapp/model/models.ts create mode 100644 packages/odatav4/steps/01/webapp/view/App.view.xml create mode 100644 packages/odatav4/steps/02/README.md create mode 100644 packages/odatav4/steps/02/assets/Tutorial_OData_V4_Step_2_0abcbb6.png create mode 100644 packages/odatav4/steps/02/package.json create mode 100644 packages/odatav4/steps/02/tsconfig.json create mode 100644 packages/odatav4/steps/02/ui5.yaml create mode 100644 packages/odatav4/steps/02/webapp/Component.ts create mode 100644 packages/odatav4/steps/02/webapp/controller/App.controller.ts create mode 100644 packages/odatav4/steps/02/webapp/i18n/i18n.properties create mode 100644 packages/odatav4/steps/02/webapp/index-cdn.html create mode 100644 packages/odatav4/steps/02/webapp/index.html create mode 100644 packages/odatav4/steps/02/webapp/initMockServer.ts create mode 100644 packages/odatav4/steps/02/webapp/localService/metadata.xml create mode 100644 packages/odatav4/steps/02/webapp/localService/mockdata/people.json create mode 100644 packages/odatav4/steps/02/webapp/localService/mockserver.ts create mode 100644 packages/odatav4/steps/02/webapp/manifest.json create mode 100644 packages/odatav4/steps/02/webapp/model/models.ts create mode 100644 packages/odatav4/steps/02/webapp/view/App.view.xml create mode 100644 packages/odatav4/steps/03/README.md create mode 100644 packages/odatav4/steps/03/assets/Tutorial_OData_V4_Step_3_8320fcf.png create mode 100644 packages/odatav4/steps/03/package.json create mode 100644 packages/odatav4/steps/03/tsconfig.json create mode 100644 packages/odatav4/steps/03/ui5.yaml create mode 100644 packages/odatav4/steps/03/webapp/Component.ts create mode 100644 packages/odatav4/steps/03/webapp/controller/App.controller.ts create mode 100644 packages/odatav4/steps/03/webapp/i18n/i18n.properties create mode 100644 packages/odatav4/steps/03/webapp/index-cdn.html create mode 100644 packages/odatav4/steps/03/webapp/index.html create mode 100644 packages/odatav4/steps/03/webapp/initMockServer.ts create mode 100644 packages/odatav4/steps/03/webapp/localService/metadata.xml create mode 100644 packages/odatav4/steps/03/webapp/localService/mockdata/people.json create mode 100644 packages/odatav4/steps/03/webapp/localService/mockserver.ts create mode 100644 packages/odatav4/steps/03/webapp/manifest.json create mode 100644 packages/odatav4/steps/03/webapp/model/models.ts create mode 100644 packages/odatav4/steps/03/webapp/view/App.view.xml create mode 100644 packages/odatav4/steps/04/README.md create mode 100644 packages/odatav4/steps/04/assets/Tutorial_OData_V4_Step_4_3ac4fcc.png create mode 100644 packages/odatav4/steps/04/package.json create mode 100644 packages/odatav4/steps/04/tsconfig.json create mode 100644 packages/odatav4/steps/04/ui5.yaml create mode 100644 packages/odatav4/steps/04/webapp/Component.ts create mode 100644 packages/odatav4/steps/04/webapp/controller/App.controller.ts create mode 100644 packages/odatav4/steps/04/webapp/i18n/i18n.properties create mode 100644 packages/odatav4/steps/04/webapp/index-cdn.html create mode 100644 packages/odatav4/steps/04/webapp/index.html create mode 100644 packages/odatav4/steps/04/webapp/initMockServer.ts create mode 100644 packages/odatav4/steps/04/webapp/localService/metadata.xml create mode 100644 packages/odatav4/steps/04/webapp/localService/mockdata/people.json create mode 100644 packages/odatav4/steps/04/webapp/localService/mockserver.ts create mode 100644 packages/odatav4/steps/04/webapp/manifest.json create mode 100644 packages/odatav4/steps/04/webapp/model/models.ts create mode 100644 packages/odatav4/steps/04/webapp/view/App.view.xml create mode 100644 packages/odatav4/steps/05/README.md create mode 100644 packages/odatav4/steps/05/package.json create mode 100644 packages/odatav4/steps/05/tsconfig.json create mode 100644 packages/odatav4/steps/05/ui5.yaml create mode 100644 packages/odatav4/steps/05/webapp/Component.ts create mode 100644 packages/odatav4/steps/05/webapp/controller/App.controller.ts create mode 100644 packages/odatav4/steps/05/webapp/i18n/i18n.properties create mode 100644 packages/odatav4/steps/05/webapp/index-cdn.html create mode 100644 packages/odatav4/steps/05/webapp/index.html create mode 100644 packages/odatav4/steps/05/webapp/initMockServer.ts create mode 100644 packages/odatav4/steps/05/webapp/localService/metadata.xml create mode 100644 packages/odatav4/steps/05/webapp/localService/mockdata/people.json create mode 100644 packages/odatav4/steps/05/webapp/localService/mockserver.ts create mode 100644 packages/odatav4/steps/05/webapp/manifest.json create mode 100644 packages/odatav4/steps/05/webapp/model/models.ts create mode 100644 packages/odatav4/steps/05/webapp/view/App.view.xml create mode 100644 packages/odatav4/steps/06/README.md create mode 100644 packages/odatav4/steps/06/assets/Tutorial_OData_V4_Step_6_baf7417.png create mode 100644 packages/odatav4/steps/06/package.json create mode 100644 packages/odatav4/steps/06/tsconfig.json create mode 100644 packages/odatav4/steps/06/ui5.yaml create mode 100644 packages/odatav4/steps/06/webapp/Component.ts create mode 100644 packages/odatav4/steps/06/webapp/controller/App.controller.ts create mode 100644 packages/odatav4/steps/06/webapp/i18n/i18n.properties create mode 100644 packages/odatav4/steps/06/webapp/index-cdn.html create mode 100644 packages/odatav4/steps/06/webapp/index.html create mode 100644 packages/odatav4/steps/06/webapp/initMockServer.ts create mode 100644 packages/odatav4/steps/06/webapp/localService/metadata.xml create mode 100644 packages/odatav4/steps/06/webapp/localService/mockdata/people.json create mode 100644 packages/odatav4/steps/06/webapp/localService/mockserver.ts create mode 100644 packages/odatav4/steps/06/webapp/manifest.json create mode 100644 packages/odatav4/steps/06/webapp/model/models.ts create mode 100644 packages/odatav4/steps/06/webapp/view/App.view.xml create mode 100644 packages/odatav4/steps/07/README.md create mode 100644 packages/odatav4/steps/07/assets/Tutorial_OData_V4_Step_7_32509f4.png create mode 100644 packages/odatav4/steps/07/package.json create mode 100644 packages/odatav4/steps/07/tsconfig.json create mode 100644 packages/odatav4/steps/07/ui5.yaml create mode 100644 packages/odatav4/steps/07/webapp/Component.ts create mode 100644 packages/odatav4/steps/07/webapp/controller/App.controller.ts create mode 100644 packages/odatav4/steps/07/webapp/i18n/i18n.properties create mode 100644 packages/odatav4/steps/07/webapp/index-cdn.html create mode 100644 packages/odatav4/steps/07/webapp/index.html create mode 100644 packages/odatav4/steps/07/webapp/initMockServer.ts create mode 100644 packages/odatav4/steps/07/webapp/localService/metadata.xml create mode 100644 packages/odatav4/steps/07/webapp/localService/mockdata/people.json create mode 100644 packages/odatav4/steps/07/webapp/localService/mockserver.ts create mode 100644 packages/odatav4/steps/07/webapp/manifest.json create mode 100644 packages/odatav4/steps/07/webapp/model/models.ts create mode 100644 packages/odatav4/steps/07/webapp/view/App.view.xml create mode 100644 packages/odatav4/steps/08/README.md create mode 100644 packages/odatav4/steps/08/assets/Tutorial_OData_V4_Step_8_e518deb.png create mode 100644 packages/odatav4/steps/08/package.json create mode 100644 packages/odatav4/steps/08/tsconfig.json create mode 100644 packages/odatav4/steps/08/ui5.yaml create mode 100644 packages/odatav4/steps/08/webapp/Component.ts create mode 100644 packages/odatav4/steps/08/webapp/controller/App.controller.ts create mode 100644 packages/odatav4/steps/08/webapp/i18n/i18n.properties create mode 100644 packages/odatav4/steps/08/webapp/index-cdn.html create mode 100644 packages/odatav4/steps/08/webapp/index.html create mode 100644 packages/odatav4/steps/08/webapp/initMockServer.ts create mode 100644 packages/odatav4/steps/08/webapp/localService/metadata.xml create mode 100644 packages/odatav4/steps/08/webapp/localService/mockdata/people.json create mode 100644 packages/odatav4/steps/08/webapp/localService/mockserver.ts create mode 100644 packages/odatav4/steps/08/webapp/manifest.json create mode 100644 packages/odatav4/steps/08/webapp/model/models.ts create mode 100644 packages/odatav4/steps/08/webapp/test/integration/AllJourneys.js create mode 100644 packages/odatav4/steps/08/webapp/test/integration/TutorialJourney.js create mode 100644 packages/odatav4/steps/08/webapp/test/integration/arrangements/Startup.js create mode 100644 packages/odatav4/steps/08/webapp/test/integration/opaTests.qunit.html create mode 100644 packages/odatav4/steps/08/webapp/test/integration/opaTests.qunit.js create mode 100644 packages/odatav4/steps/08/webapp/test/integration/pages/Tutorial.js create mode 100644 packages/odatav4/steps/08/webapp/view/App.view.xml create mode 100644 packages/odatav4/steps/09/README.md create mode 100644 packages/odatav4/steps/09/package.json create mode 100644 packages/odatav4/steps/09/tsconfig.json create mode 100644 packages/odatav4/steps/09/ui5.yaml create mode 100644 packages/odatav4/steps/09/webapp/Component.ts create mode 100644 packages/odatav4/steps/09/webapp/controller/App.controller.ts create mode 100644 packages/odatav4/steps/09/webapp/i18n/i18n.properties create mode 100644 packages/odatav4/steps/09/webapp/index-cdn.html create mode 100644 packages/odatav4/steps/09/webapp/index.html create mode 100644 packages/odatav4/steps/09/webapp/initMockServer.ts create mode 100644 packages/odatav4/steps/09/webapp/localService/metadata.xml create mode 100644 packages/odatav4/steps/09/webapp/localService/mockdata/people.json create mode 100644 packages/odatav4/steps/09/webapp/localService/mockserver.ts create mode 100644 packages/odatav4/steps/09/webapp/manifest.json create mode 100644 packages/odatav4/steps/09/webapp/model/models.ts create mode 100644 packages/odatav4/steps/09/webapp/view/App.view.xml create mode 100644 packages/odatav4/steps/10/README.md create mode 100644 packages/odatav4/steps/10/package.json create mode 100644 packages/odatav4/steps/10/tsconfig.json create mode 100644 packages/odatav4/steps/10/ui5.yaml create mode 100644 packages/odatav4/steps/10/webapp/Component.ts create mode 100644 packages/odatav4/steps/10/webapp/controller/App.controller.ts create mode 100644 packages/odatav4/steps/10/webapp/i18n/i18n.properties create mode 100644 packages/odatav4/steps/10/webapp/index-cdn.html create mode 100644 packages/odatav4/steps/10/webapp/index.html create mode 100644 packages/odatav4/steps/10/webapp/initMockServer.ts create mode 100644 packages/odatav4/steps/10/webapp/localService/metadata.xml create mode 100644 packages/odatav4/steps/10/webapp/localService/mockdata/people.json create mode 100644 packages/odatav4/steps/10/webapp/localService/mockserver.ts create mode 100644 packages/odatav4/steps/10/webapp/manifest.json create mode 100644 packages/odatav4/steps/10/webapp/model/models.ts create mode 100644 packages/odatav4/steps/10/webapp/view/App.view.xml create mode 100644 packages/odatav4/steps/11/README.md create mode 100644 packages/odatav4/steps/11/package.json create mode 100644 packages/odatav4/steps/11/tsconfig.json create mode 100644 packages/odatav4/steps/11/ui5.yaml create mode 100644 packages/odatav4/steps/11/webapp/Component.ts create mode 100644 packages/odatav4/steps/11/webapp/controller/App.controller.ts create mode 100644 packages/odatav4/steps/11/webapp/i18n/i18n.properties create mode 100644 packages/odatav4/steps/11/webapp/index-cdn.html create mode 100644 packages/odatav4/steps/11/webapp/index.html create mode 100644 packages/odatav4/steps/11/webapp/initMockServer.ts create mode 100644 packages/odatav4/steps/11/webapp/localService/metadata.xml create mode 100644 packages/odatav4/steps/11/webapp/localService/mockdata/people.json create mode 100644 packages/odatav4/steps/11/webapp/localService/mockserver.ts create mode 100644 packages/odatav4/steps/11/webapp/manifest.json create mode 100644 packages/odatav4/steps/11/webapp/model/models.ts create mode 100644 packages/odatav4/steps/11/webapp/test/integration/AllJourneys.js create mode 100644 packages/odatav4/steps/11/webapp/test/integration/TutorialJourney.js create mode 100644 packages/odatav4/steps/11/webapp/test/integration/arrangements/Startup.js create mode 100644 packages/odatav4/steps/11/webapp/test/integration/opaTests.qunit.html create mode 100644 packages/odatav4/steps/11/webapp/test/integration/opaTests.qunit.js create mode 100644 packages/odatav4/steps/11/webapp/test/integration/pages/Tutorial.js create mode 100644 packages/odatav4/steps/11/webapp/view/App.view.xml diff --git a/.gitignore b/.gitignore index b6076286c..2b833484a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +_ .vscode dist node_modules diff --git a/README.md b/README.md index 8d3f315af..23f4cec04 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,31 @@ We first introduce you to the basic development paradigms like *Model-View-Contr This repository contains following tutorials: - [Quickstart](./packages/quickstart/) - [Walkthrough](./packages/walkthrough/) +- [Navigation and Routing](./packages/navigation/) +- [OData V4](./packages/odatav4/) + +## Running locally + +The repository is set up as an npm workspaces monorepo. Each tutorial step under `packages/*/steps/*` is a self-contained app you can run standalone, and the root build orchestrator produces a unified preview that mirrors the published GitHub Pages site. + +```sh +# 1) install dependencies for every step +npm install + +# 2) build every tutorial step (produces dist//build/NN/ apps + ZIP downloads) +npm run build + +# 3) serve the rendered tutorial pages with working Live Preview links +npm start +``` + +After `npm start`, open (or any other tutorial's `packages//`). The dev server renders the markdown overview, rewrites the published `https://ui5.github.io/tutorials/...` URLs to point at the local `dist/`, and serves the built apps from the same origin. + +To run a single step directly without going through the build: + +```sh +npm start -w ui5.tutorial.walkthrough.step15 +``` ## How to obtain support @@ -26,4 +51,4 @@ If you wish to contribute code, offer fixes or improvements, please send a pull ## License -Copyright (c) 2025 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](LICENSE) file. +Copyright (c) 2026 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](LICENSE) file. diff --git a/package-lock.json b/package-lock.json index e028183dd..9658c2644 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19709,167 +19709,279 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/ui5.quickstart.step01": { + "node_modules/ui5.tutorial.navigation.step01": { + "resolved": "packages/navigation/steps/01", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step02": { + "resolved": "packages/navigation/steps/02", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step03": { + "resolved": "packages/navigation/steps/03", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step04": { + "resolved": "packages/navigation/steps/04", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step05": { + "resolved": "packages/navigation/steps/05", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step06": { + "resolved": "packages/navigation/steps/06", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step07": { + "resolved": "packages/navigation/steps/07", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step08": { + "resolved": "packages/navigation/steps/08", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step09": { + "resolved": "packages/navigation/steps/09", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step10": { + "resolved": "packages/navigation/steps/10", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step11": { + "resolved": "packages/navigation/steps/11", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step12": { + "resolved": "packages/navigation/steps/12", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step13": { + "resolved": "packages/navigation/steps/13", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step14": { + "resolved": "packages/navigation/steps/14", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step15": { + "resolved": "packages/navigation/steps/15", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step16": { + "resolved": "packages/navigation/steps/16", + "link": true + }, + "node_modules/ui5.tutorial.navigation.step17": { + "resolved": "packages/navigation/steps/17", + "link": true + }, + "node_modules/ui5.tutorial.odatav4.step01": { + "resolved": "packages/odatav4/steps/01", + "link": true + }, + "node_modules/ui5.tutorial.odatav4.step02": { + "resolved": "packages/odatav4/steps/02", + "link": true + }, + "node_modules/ui5.tutorial.odatav4.step03": { + "resolved": "packages/odatav4/steps/03", + "link": true + }, + "node_modules/ui5.tutorial.odatav4.step04": { + "resolved": "packages/odatav4/steps/04", + "link": true + }, + "node_modules/ui5.tutorial.odatav4.step05": { + "resolved": "packages/odatav4/steps/05", + "link": true + }, + "node_modules/ui5.tutorial.odatav4.step06": { + "resolved": "packages/odatav4/steps/06", + "link": true + }, + "node_modules/ui5.tutorial.odatav4.step07": { + "resolved": "packages/odatav4/steps/07", + "link": true + }, + "node_modules/ui5.tutorial.odatav4.step08": { + "resolved": "packages/odatav4/steps/08", + "link": true + }, + "node_modules/ui5.tutorial.odatav4.step09": { + "resolved": "packages/odatav4/steps/09", + "link": true + }, + "node_modules/ui5.tutorial.odatav4.step10": { + "resolved": "packages/odatav4/steps/10", + "link": true + }, + "node_modules/ui5.tutorial.odatav4.step11": { + "resolved": "packages/odatav4/steps/11", + "link": true + }, + "node_modules/ui5.tutorial.quickstart.step01": { "resolved": "packages/quickstart/steps/01", "link": true }, - "node_modules/ui5.quickstart.step02": { + "node_modules/ui5.tutorial.quickstart.step02": { "resolved": "packages/quickstart/steps/02", "link": true }, - "node_modules/ui5.quickstart.step03": { + "node_modules/ui5.tutorial.quickstart.step03": { "resolved": "packages/quickstart/steps/03", "link": true }, - "node_modules/ui5.walkthrough.step01": { + "node_modules/ui5.tutorial.walkthrough.step01": { "resolved": "packages/walkthrough/steps/01", "link": true }, - "node_modules/ui5.walkthrough.step02": { + "node_modules/ui5.tutorial.walkthrough.step02": { "resolved": "packages/walkthrough/steps/02", "link": true }, - "node_modules/ui5.walkthrough.step03": { + "node_modules/ui5.tutorial.walkthrough.step03": { "resolved": "packages/walkthrough/steps/03", "link": true }, - "node_modules/ui5.walkthrough.step04": { + "node_modules/ui5.tutorial.walkthrough.step04": { "resolved": "packages/walkthrough/steps/04", "link": true }, - "node_modules/ui5.walkthrough.step05": { + "node_modules/ui5.tutorial.walkthrough.step05": { "resolved": "packages/walkthrough/steps/05", "link": true }, - "node_modules/ui5.walkthrough.step06": { + "node_modules/ui5.tutorial.walkthrough.step06": { "resolved": "packages/walkthrough/steps/06", "link": true }, - "node_modules/ui5.walkthrough.step07": { + "node_modules/ui5.tutorial.walkthrough.step07": { "resolved": "packages/walkthrough/steps/07", "link": true }, - "node_modules/ui5.walkthrough.step08": { + "node_modules/ui5.tutorial.walkthrough.step08": { "resolved": "packages/walkthrough/steps/08", "link": true }, - "node_modules/ui5.walkthrough.step09": { + "node_modules/ui5.tutorial.walkthrough.step09": { "resolved": "packages/walkthrough/steps/09", "link": true }, - "node_modules/ui5.walkthrough.step10": { + "node_modules/ui5.tutorial.walkthrough.step10": { "resolved": "packages/walkthrough/steps/10", "link": true }, - "node_modules/ui5.walkthrough.step11": { + "node_modules/ui5.tutorial.walkthrough.step11": { "resolved": "packages/walkthrough/steps/11", "link": true }, - "node_modules/ui5.walkthrough.step12": { + "node_modules/ui5.tutorial.walkthrough.step12": { "resolved": "packages/walkthrough/steps/12", "link": true }, - "node_modules/ui5.walkthrough.step13": { + "node_modules/ui5.tutorial.walkthrough.step13": { "resolved": "packages/walkthrough/steps/13", "link": true }, - "node_modules/ui5.walkthrough.step14": { + "node_modules/ui5.tutorial.walkthrough.step14": { "resolved": "packages/walkthrough/steps/14", "link": true }, - "node_modules/ui5.walkthrough.step15": { + "node_modules/ui5.tutorial.walkthrough.step15": { "resolved": "packages/walkthrough/steps/15", "link": true }, - "node_modules/ui5.walkthrough.step16": { + "node_modules/ui5.tutorial.walkthrough.step16": { "resolved": "packages/walkthrough/steps/16", "link": true }, - "node_modules/ui5.walkthrough.step17": { + "node_modules/ui5.tutorial.walkthrough.step17": { "resolved": "packages/walkthrough/steps/17", "link": true }, - "node_modules/ui5.walkthrough.step18": { + "node_modules/ui5.tutorial.walkthrough.step18": { "resolved": "packages/walkthrough/steps/18", "link": true }, - "node_modules/ui5.walkthrough.step19": { + "node_modules/ui5.tutorial.walkthrough.step19": { "resolved": "packages/walkthrough/steps/19", "link": true }, - "node_modules/ui5.walkthrough.step20": { + "node_modules/ui5.tutorial.walkthrough.step20": { "resolved": "packages/walkthrough/steps/20", "link": true }, - "node_modules/ui5.walkthrough.step21": { + "node_modules/ui5.tutorial.walkthrough.step21": { "resolved": "packages/walkthrough/steps/21", "link": true }, - "node_modules/ui5.walkthrough.step22": { + "node_modules/ui5.tutorial.walkthrough.step22": { "resolved": "packages/walkthrough/steps/22", "link": true }, - "node_modules/ui5.walkthrough.step23": { + "node_modules/ui5.tutorial.walkthrough.step23": { "resolved": "packages/walkthrough/steps/23", "link": true }, - "node_modules/ui5.walkthrough.step24": { + "node_modules/ui5.tutorial.walkthrough.step24": { "resolved": "packages/walkthrough/steps/24", "link": true }, - "node_modules/ui5.walkthrough.step25": { + "node_modules/ui5.tutorial.walkthrough.step25": { "resolved": "packages/walkthrough/steps/25", "link": true }, - "node_modules/ui5.walkthrough.step26": { + "node_modules/ui5.tutorial.walkthrough.step26": { "resolved": "packages/walkthrough/steps/26", "link": true }, - "node_modules/ui5.walkthrough.step27": { + "node_modules/ui5.tutorial.walkthrough.step27": { "resolved": "packages/walkthrough/steps/27", "link": true }, - "node_modules/ui5.walkthrough.step28": { + "node_modules/ui5.tutorial.walkthrough.step28": { "resolved": "packages/walkthrough/steps/28", "link": true }, - "node_modules/ui5.walkthrough.step29": { + "node_modules/ui5.tutorial.walkthrough.step29": { "resolved": "packages/walkthrough/steps/29", "link": true }, - "node_modules/ui5.walkthrough.step30": { + "node_modules/ui5.tutorial.walkthrough.step30": { "resolved": "packages/walkthrough/steps/30", "link": true }, - "node_modules/ui5.walkthrough.step31": { + "node_modules/ui5.tutorial.walkthrough.step31": { "resolved": "packages/walkthrough/steps/31", "link": true }, - "node_modules/ui5.walkthrough.step32": { + "node_modules/ui5.tutorial.walkthrough.step32": { "resolved": "packages/walkthrough/steps/32", "link": true }, - "node_modules/ui5.walkthrough.step33": { + "node_modules/ui5.tutorial.walkthrough.step33": { "resolved": "packages/walkthrough/steps/33", "link": true }, - "node_modules/ui5.walkthrough.step34": { + "node_modules/ui5.tutorial.walkthrough.step34": { "resolved": "packages/walkthrough/steps/34", "link": true }, - "node_modules/ui5.walkthrough.step35": { + "node_modules/ui5.tutorial.walkthrough.step35": { "resolved": "packages/walkthrough/steps/35", "link": true }, - "node_modules/ui5.walkthrough.step36": { + "node_modules/ui5.tutorial.walkthrough.step36": { "resolved": "packages/walkthrough/steps/36", "link": true }, - "node_modules/ui5.walkthrough.step37": { + "node_modules/ui5.tutorial.walkthrough.step37": { "resolved": "packages/walkthrough/steps/37", "link": true }, - "node_modules/ui5.walkthrough.step38": { + "node_modules/ui5.tutorial.walkthrough.step38": { "resolved": "packages/walkthrough/steps/38", "link": true }, @@ -20543,8 +20655,344 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "packages/navigation/steps/01": { + "name": "ui5.tutorial.navigation.step01", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/02": { + "name": "ui5.tutorial.navigation.step02", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/03": { + "name": "ui5.tutorial.navigation.step03", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/04": { + "name": "ui5.tutorial.navigation.step04", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/05": { + "name": "ui5.tutorial.navigation.step05", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/06": { + "name": "ui5.tutorial.navigation.step06", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/07": { + "name": "ui5.tutorial.navigation.step07", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/08": { + "name": "ui5.tutorial.navigation.step08", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/09": { + "name": "ui5.tutorial.navigation.step09", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/10": { + "name": "ui5.tutorial.navigation.step10", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/11": { + "name": "ui5.tutorial.navigation.step11", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/12": { + "name": "ui5.tutorial.navigation.step12", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/13": { + "name": "ui5.tutorial.navigation.step13", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/14": { + "name": "ui5.tutorial.navigation.step14", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/15": { + "name": "ui5.tutorial.navigation.step15", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/16": { + "name": "ui5.tutorial.navigation.step16", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/navigation/steps/17": { + "name": "ui5.tutorial.navigation.step17", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/odatav4/steps/01": { + "name": "ui5.tutorial.odatav4.step01", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/odatav4/steps/02": { + "name": "ui5.tutorial.odatav4.step02", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/odatav4/steps/03": { + "name": "ui5.tutorial.odatav4.step03", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/odatav4/steps/04": { + "name": "ui5.tutorial.odatav4.step04", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/odatav4/steps/05": { + "name": "ui5.tutorial.odatav4.step05", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/odatav4/steps/06": { + "name": "ui5.tutorial.odatav4.step06", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/odatav4/steps/07": { + "name": "ui5.tutorial.odatav4.step07", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/odatav4/steps/08": { + "name": "ui5.tutorial.odatav4.step08", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/odatav4/steps/09": { + "name": "ui5.tutorial.odatav4.step09", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/odatav4/steps/10": { + "name": "ui5.tutorial.odatav4.step10", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, + "packages/odatav4/steps/11": { + "name": "ui5.tutorial.odatav4.step11", + "version": "1.0.0", + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } + }, "packages/quickstart/steps/01": { - "name": "ui5.quickstart.step01", + "name": "ui5.tutorial.quickstart.step01", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20556,7 +21004,7 @@ } }, "packages/quickstart/steps/02": { - "name": "ui5.quickstart.step02", + "name": "ui5.tutorial.quickstart.step02", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20568,7 +21016,7 @@ } }, "packages/quickstart/steps/03": { - "name": "ui5.quickstart.step03", + "name": "ui5.tutorial.quickstart.step03", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20580,14 +21028,14 @@ } }, "packages/walkthrough/steps/01": { - "name": "ui5.walkthrough.step01", + "name": "ui5.tutorial.walkthrough.step01", "version": "1.0.0", "devDependencies": { "@ui5/cli": "^4.0.53" } }, "packages/walkthrough/steps/02": { - "name": "ui5.walkthrough.step02", + "name": "ui5.tutorial.walkthrough.step02", "version": "1.0.0", "devDependencies": { "@ui5/cli": "^4.0.53", @@ -20598,7 +21046,7 @@ } }, "packages/walkthrough/steps/03": { - "name": "ui5.walkthrough.step03", + "name": "ui5.tutorial.walkthrough.step03", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20610,7 +21058,7 @@ } }, "packages/walkthrough/steps/04": { - "name": "ui5.walkthrough.step04", + "name": "ui5.tutorial.walkthrough.step04", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20622,7 +21070,7 @@ } }, "packages/walkthrough/steps/05": { - "name": "ui5.walkthrough.step05", + "name": "ui5.tutorial.walkthrough.step05", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20634,7 +21082,7 @@ } }, "packages/walkthrough/steps/06": { - "name": "ui5.walkthrough.step06", + "name": "ui5.tutorial.walkthrough.step06", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20646,7 +21094,7 @@ } }, "packages/walkthrough/steps/07": { - "name": "ui5.walkthrough.step07", + "name": "ui5.tutorial.walkthrough.step07", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20658,7 +21106,7 @@ } }, "packages/walkthrough/steps/08": { - "name": "ui5.walkthrough.step08", + "name": "ui5.tutorial.walkthrough.step08", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20670,7 +21118,7 @@ } }, "packages/walkthrough/steps/09": { - "name": "ui5.walkthrough.step09", + "name": "ui5.tutorial.walkthrough.step09", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20682,7 +21130,7 @@ } }, "packages/walkthrough/steps/10": { - "name": "ui5.walkthrough.step10", + "name": "ui5.tutorial.walkthrough.step10", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20694,7 +21142,7 @@ } }, "packages/walkthrough/steps/11": { - "name": "ui5.walkthrough.step11", + "name": "ui5.tutorial.walkthrough.step11", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20706,7 +21154,7 @@ } }, "packages/walkthrough/steps/12": { - "name": "ui5.walkthrough.step12", + "name": "ui5.tutorial.walkthrough.step12", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20718,7 +21166,7 @@ } }, "packages/walkthrough/steps/13": { - "name": "ui5.walkthrough.step13", + "name": "ui5.tutorial.walkthrough.step13", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20730,7 +21178,7 @@ } }, "packages/walkthrough/steps/14": { - "name": "ui5.walkthrough.step14", + "name": "ui5.tutorial.walkthrough.step14", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20742,7 +21190,7 @@ } }, "packages/walkthrough/steps/15": { - "name": "ui5.walkthrough.step15", + "name": "ui5.tutorial.walkthrough.step15", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20754,7 +21202,7 @@ } }, "packages/walkthrough/steps/16": { - "name": "ui5.walkthrough.step16", + "name": "ui5.tutorial.walkthrough.step16", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20766,7 +21214,7 @@ } }, "packages/walkthrough/steps/17": { - "name": "ui5.walkthrough.step17", + "name": "ui5.tutorial.walkthrough.step17", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20778,7 +21226,7 @@ } }, "packages/walkthrough/steps/18": { - "name": "ui5.walkthrough.step18", + "name": "ui5.tutorial.walkthrough.step18", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20790,7 +21238,7 @@ } }, "packages/walkthrough/steps/19": { - "name": "ui5.walkthrough.step19", + "name": "ui5.tutorial.walkthrough.step19", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20802,7 +21250,7 @@ } }, "packages/walkthrough/steps/20": { - "name": "ui5.walkthrough.step20", + "name": "ui5.tutorial.walkthrough.step20", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20814,7 +21262,7 @@ } }, "packages/walkthrough/steps/21": { - "name": "ui5.walkthrough.step21", + "name": "ui5.tutorial.walkthrough.step21", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20826,7 +21274,7 @@ } }, "packages/walkthrough/steps/22": { - "name": "ui5.walkthrough.step22", + "name": "ui5.tutorial.walkthrough.step22", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20838,7 +21286,7 @@ } }, "packages/walkthrough/steps/23": { - "name": "ui5.walkthrough.step23", + "name": "ui5.tutorial.walkthrough.step23", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20850,7 +21298,7 @@ } }, "packages/walkthrough/steps/24": { - "name": "ui5.walkthrough.step24", + "name": "ui5.tutorial.walkthrough.step24", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20862,7 +21310,7 @@ } }, "packages/walkthrough/steps/25": { - "name": "ui5.walkthrough.step25", + "name": "ui5.tutorial.walkthrough.step25", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20875,7 +21323,7 @@ } }, "packages/walkthrough/steps/26": { - "name": "ui5.walkthrough.step26", + "name": "ui5.tutorial.walkthrough.step26", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20888,7 +21336,7 @@ } }, "packages/walkthrough/steps/27": { - "name": "ui5.walkthrough.step27", + "name": "ui5.tutorial.walkthrough.step27", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20901,7 +21349,7 @@ } }, "packages/walkthrough/steps/28": { - "name": "ui5.walkthrough.step28", + "name": "ui5.tutorial.walkthrough.step28", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20914,7 +21362,7 @@ } }, "packages/walkthrough/steps/29": { - "name": "ui5.walkthrough.step29", + "name": "ui5.tutorial.walkthrough.step29", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20927,7 +21375,7 @@ } }, "packages/walkthrough/steps/30": { - "name": "ui5.walkthrough.step30", + "name": "ui5.tutorial.walkthrough.step30", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20940,7 +21388,7 @@ } }, "packages/walkthrough/steps/31": { - "name": "ui5.walkthrough.step31", + "name": "ui5.tutorial.walkthrough.step31", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20953,7 +21401,7 @@ } }, "packages/walkthrough/steps/32": { - "name": "ui5.walkthrough.step32", + "name": "ui5.tutorial.walkthrough.step32", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20966,7 +21414,7 @@ } }, "packages/walkthrough/steps/33": { - "name": "ui5.walkthrough.step33", + "name": "ui5.tutorial.walkthrough.step33", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20980,7 +21428,7 @@ } }, "packages/walkthrough/steps/34": { - "name": "ui5.walkthrough.step34", + "name": "ui5.tutorial.walkthrough.step34", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -20994,7 +21442,7 @@ } }, "packages/walkthrough/steps/35": { - "name": "ui5.walkthrough.step35", + "name": "ui5.tutorial.walkthrough.step35", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -21008,7 +21456,7 @@ } }, "packages/walkthrough/steps/36": { - "name": "ui5.walkthrough.step36", + "name": "ui5.tutorial.walkthrough.step36", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -21022,7 +21470,7 @@ } }, "packages/walkthrough/steps/37": { - "name": "ui5.walkthrough.step37", + "name": "ui5.tutorial.walkthrough.step37", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", @@ -21036,7 +21484,7 @@ } }, "packages/walkthrough/steps/38": { - "name": "ui5.walkthrough.step38", + "name": "ui5.tutorial.walkthrough.step38", "version": "1.0.0", "devDependencies": { "@types/openui5": "^1.147.0", diff --git a/packages/navigation/README.md b/packages/navigation/README.md new file mode 100644 index 000000000..3a2cde4a6 --- /dev/null +++ b/packages/navigation/README.md @@ -0,0 +1,67 @@ + + +# Navigation and Routing Tutorial + +SAPUI5 comes with a powerful routing API that helps you control the state of your application efficiently. This tutorial will illustrate all major features and APIs related to navigation and routing in SAPUI5 apps by creating a simple and easy to understand mobile app. It represents a set of best practices for applying the navigation and routing features of SAPUI5 to your applications. + +In classical Web applications, the server determines which resource is requested based on the URL pattern of the request and serves it accordingly. The server-side logic controls how the requested resource or page is displayed in an appropriate way. + +In single-page applications, only one page is initially requested from the server and additional resources are dynamically loaded using client-side logic. The user only navigates within this page. The navigation is persisted in the hash instead of the server path or URL parameters. + +For example, a classical Web application might display the employee’s resume page when URL `http:////employees/resume.html?id=3` or `http:////employees/3/resume` is called. A single-page application instead would do the same thing by using a hash-based URL like `http:////#/employees/3/resume`. + +The information in the hash, namely everything that is following the `#` character, is interpreted by the router. + +> :note: +> This tutorial does not handle cross-app navigation with the SAP Fiori launchpad. However, the concepts described in this tutorial are also fundamental for navigation and routing between apps in the SAP Fiori launchpad. + +We will create a simple app displaying the data of a company’s employees to show typical navigation patterns and routing features. The complete flow of the application can be seen in the figure below. We'll start with the home page which lets users do the following: + +- Display a *Not Found* page + +- Navigate to a list of employees and drill further down to see a *Details* page for each employee + +- Show an *Employee Overview* that they can search and sort + +## Page flow of the final app + +![Page flow of the final app](assets/Tutorial_Navigation_and_Routing_Screen_Flow_92cdce7.png "Page flow of the final app") + +Throughout this tutorial we will add features for navigating to pages and bookmarking them. We will add backward and forward navigation with common transition animations \(slide, show, flip, etc.\). We will add more pages to the app and navigate between them to show typical use cases. We will even learn how to implement features for bookmarking a specific search, table sorting via filters, and dialogs. + +> :tip: +> You don't have to do all tutorial steps sequentially, you can also jump directly to any step you want. Just download the code from the previous step, and start there. +> +> You can view and download the files for all steps in the Demo Kit at [Navigation and Routing](https://sdk.openui5.org/#/entity/sap.ui.core.tutorial.navigation). Copy the code to your workspace and make sure that the application runs by calling the `webapp/index.html` file. Depending on your development environment you might have to adjust resource paths and configuration entries. +> +> For more information check the [Downloading Code for a Tutorial Step](https://sdk.openui5.org/topic/8b49fc198bf04b2d9800fc37fecbb218.html#loio8b49fc198bf04b2d9800fc37fecbb218/tutorials_download) section of the tutorials overview page [Get Started: Setup, Tutorials, and Demo Apps](https://sdk.openui5.org/topic/8b49fc198bf04b2d9800fc37fecbb218). + +*** + +### In this Tutorial + +The tutorial consists of the following steps. To start, just open the first link — you'll be guided from there. + +- **[Step 1: Set Up the Initial App](./steps/01/README.md "We start by setting up a simple app for this tutorial. The app displays mock data only and mimics real OData back-end calls with the mock server as you have seen in the *Walkthrough* tutorial.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/01/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-01.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-01-js.zip)
) +- **[Step 2: Enable Routing](./steps/02/README.md "In this step we will modify the app and introduce routing. Instead of having the home page of the app hard coded we will configure a router to wire multiple views together when our app is called.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/02/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-02.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-02-js.zip)
) +- **[Step 3: Catch Invalid Hashes](./steps/03/README.md "Sometimes it is important to display an indication that the requested resource was not found.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/03/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-03.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-03-js.zip)
) +- **[Step 4: Add a *Back* Button to *Not Found* Page](./steps/04/README.md "When we are on the *Not Found* page because of an invalid hash, we want to get back to our app to select another page.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/04/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-04.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-04-js.zip)
) +- **[Step 5: Display a Target Without Changing the Hash](./steps/05/README.md "In this step, you will learn more about targets and how to display a target from the routing configuration manually.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/05/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-05.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-05-js.zip)
) +- **[Step 6: Navigate to Routes with Hard-Coded Patterns](./steps/06/README.md "In this step, we'll create a second button on the home page, with which we can navigate to a simple list of employees.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/06/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-06.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-06-js.zip)
) +- **[Step 7: Navigate to Routes with Mandatory Parameters](./steps/07/README.md "In this step, we implement a feature that allows the user to click on an employee in the list to see additional details of the employee.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/07/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-07.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-07-js.zip)
) +- **[Step 8: Navigate with Flip Transition](./steps/08/README.md "In this step, we want to illustrate how to navigate to a page with a custom transition animation. Both forward and backward navigation will use the “flip” transition but with a different direction.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/08/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-08.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-08-js.zip)
) +- **[Step 9: Allow Bookmarkable Tabs with Optional Query Parameters](./steps/09/README.md "The resume view contains four tabs as we have seen in the previous step of this tutorial. However, when the user navigates to the resume page, only the first tab is displayed initially.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/09/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-09.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-09-js.zip)
) +- **[Step 10: Implement “Lazy Loading”](./steps/10/README.md "In the previous steps, we have implemented a Resume view that uses tabs to display data. The complete content of all the tabs is loaded once, no matter which tab is currently displayed.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/10/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-10.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-10-js.zip)
) +- **[Step 11: Assign Multiple Targets](./steps/11/README.md "In this step, we will add a new button to the home page to illustrate the usage of multiple targets for a route.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/11/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-11.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-11-js.zip)
) +- **[Step 12: Make a Search Bookmarkable](./steps/12/README.md "In this step we will make the search bookmarkable. This allows users to search for employees in the *Employees* table and they can bookmark their search query or share the URL.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/12/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-12.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-12-js.zip)
) +- **[Step 13: Make Table Sorting Bookmarkable](./steps/13/README.md "In this step, we will create a button at the top of the table which will change the sorting of the table.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/13/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-13.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-13-js.zip)
) +- **[Step 14: Make Dialogs Bookmarkable](./steps/14/README.md "In this step, we want to allow bookmarking of the dialog box that is opened when the user clicks the *Sort* button.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/14/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-14.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-14-js.zip)
) +- **[Step 15: Reuse an Existing Route](./steps/15/README.md "The *Employees* table displays employee data. However, the resumes of the employees are not accessible from this view yet.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/15/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-15.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-15-js.zip)
) +- **[Step 16: Handle Invalid Hashes by Listening to Bypassed Events](./steps/16/README.md "So far we have created many useful routes in our app. In the very early steps we have also made sure that a *Not Found* page is displayed in case the app was called with an invalid hash.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/16/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-16.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-16-js.zip)
) +- **[Step 17: Listen to Matched Events of Any Route](./steps/17/README.md "In the previous step, we have listened for bypassed events to detect possible technical issues with our app.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/navigation/build/17/index-cdn.html) \|
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-17.zip)
[📥 Download Solution](https://ui5.github.io/tutorials/navigation/navigation-step-17-js.zip)
) + +*** + +## License + +Copyright (c) 2026 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](../../LICENSE) file. diff --git a/packages/navigation/assets/Tutorial_Navigation_and_Routing_Screen_Flow_92cdce7.png b/packages/navigation/assets/Tutorial_Navigation_and_Routing_Screen_Flow_92cdce7.png new file mode 100644 index 0000000000000000000000000000000000000000..60f45b5f0ef6ddfa69018fe8c5e76395ecd27857 GIT binary patch literal 28787 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 + +# Step 1: Set Up the Initial App + +We start by setting up a simple app for this tutorial. The app displays mock data only and mimics real OData back-end calls with the mock server as you have seen in the *Walkthrough* tutorial. + +The structure and data model created in this step will be used throughout the rest of this tutorial. The initial app created in this step will be extended in the subsequent steps to illustrate the navigation and routing features of SAPUI5. + +## Preview + +### Initial app with a simple button + +![Initial app with a simple button](assets/Tutorial_Navigation_and_Routing_Step_01a.png "Initial app with a simple button") + +## Setup + +1. To set up your project for this tutorial, download the files at [Navigation and Routing - Step 1](https://ui5.github.io/tutorials/navigation/navigation-step-01.zip). + +2. Extract the downloaded `.zip` file at the desired location on your local machine. + +3. Open a shell in the extracted folder and execute `npm install`. + +4. Execute `npm start` to start the web server and to open a new browser window hosting your newly created `index.html`. + +You should have the same files as displayed in the following figure: + +### Folder structure with downloaded files + +```text +webapp/ +├── Component.?s +├── controller/ +│ └── App.controller.?s +├── i18n/ +│ └── i18n.properties +├── index-cdn.html +├── index.html +├── initMockServer.?s +├── localService/ +│ ├── metadata.xml +│ ├── mockdata/ +│ │ ├── Employees.json +│ │ └── Resumes.json +│ └── mockserver.?s +├── manifest.json +└── view/ + └── App.view.xml +``` + +> :note: +> The content of the `localService` folder will not be changed in this tutorial. The `i18n` folder will always contain the `i18n.properties` file only. Therefore, we will show both subfolders collapsed in the following steps. + +## The Initial App + +With the downloaded coding, you have an initial app with recommended settings that provides the basic features of an SAPUI5 app: + +- **Home Page** + + The home page of our app is defined in the `webapp/index.html` file. In this file we bootstrap SAPUI5 and tell the runtime where to find our custom resources. Furthermore, we initialize the `MockServer` to simulate back-end requests as we do not have a real back-end service throughout this tutorial. Finally, we instantiate the application component, assign it to a `sap.m.Shell` control, and place the shell into the body. The corresponding `Component.ts` file in the `webapp` folder will be extended throughout this tutorial. + +- **Data** + + In the `webapp/localService/mockserver.ts` file, we configure the mock server. Using the mock server in this tutorial allows us to easily run the code even without network connection and without the need of having a remote server for our application data. + + The `metadata.xml` file used by the mock server describes our OData service. The service only has two OData entities: + + - Employee + + An `employee` has typical properties like `FirstName` and `LastName` as well as a navigation property to a resume entity referenced by a `ResumeID`. Of course, the entity also has an ID property: `EmployeeID`. The corresponding `EntitySet` is `Employees`. The actual test data containing several employees is located in the `webapp/localService/mockdata/Employees.json` file. + + - Resume + + In our case, we want to keep the resume of employees very simple. Therefore, we just have simple properties of type `Edm.String`. The properties are `Information`, `Projects`, `Hobbies` and `Notes`; all of them contain textual information. The entity has an ID property `ResumeID` and the corresponding `EntitySet` is `Resumes`. The resume data for an employee is located in file `webapp/localService/mockdata/Resumes.json`. + +- **Configuration of the App** + + In the `webapp/manifest.json` descriptor file, we configure our app. The descriptor file contains the following most interesting sections: + + - `sap.app` + + In this section we reference an `i18n.properties` file and use a special syntax to bind the texts for the `title` and `description` properties. + + In the `dataSources` part, we tell our app where to find our OData service `employeeRemote`. As you might guess, the `uri` correlates to the `rootUri` of our mock server instance which can be found in `webapp/localService/mockserver.ts`. It is important that these two paths match to allow our mock server to provide the test data we defined above. The `localUri` is used to determine the location of the `metadata.xml` file. + + - `sap.ui5` + + Under `sap.ui5` we declare with the `rootView` parameter that our `ui5.tutorial.navigation.view.App` view shall be loaded and used as the `rootView` for our app. Furthermore, we define two `models` to be automatically instantiated and bound to the `i18n` component and a default model `""`. The latter references our `employeeRemote` `dataSource` which is declared in our `sap.app` section as an OData 2.0 data source. The `i18n` file can be found at `webapp/i18n/i18n.properties`. This data source will be mocked by our mock server. + +So far we have a basic app that does not really have any navigation or routing implemented. This will change in the next steps when we implement our first navigation features. + +*** + + +*** + +**Next:** [Step 2: Enable Routing](../02/README.md) diff --git a/packages/navigation/steps/01/assets/Tutorial_Navigation_and_Routing_Step_01a.png b/packages/navigation/steps/01/assets/Tutorial_Navigation_and_Routing_Step_01a.png new file mode 100644 index 0000000000000000000000000000000000000000..9f3fa4bd68c62ce29d672b53fc018cec2252df5c GIT binary patch literal 54954 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 literal 0 HcmV?d00001 diff --git a/packages/navigation/steps/01/package.json b/packages/navigation/steps/01/package.json new file mode 100644 index 000000000..6f6810c80 --- /dev/null +++ b/packages/navigation/steps/01/package.json @@ -0,0 +1,19 @@ +{ + "name": "ui5.tutorial.navigation.step01", + "private": true, + "version": "1.0.0", + "author": "SAP SE", + "description": "UI5 Demo App - Navigation Tutorial", + "scripts": { + "start": "ui5 serve -o index.html", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } +} diff --git a/packages/navigation/steps/01/tsconfig.json b/packages/navigation/steps/01/tsconfig.json new file mode 100644 index 000000000..96f5b220a --- /dev/null +++ b/packages/navigation/steps/01/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es2023", + "types": [ + "node", + "@types/openui5" + ], + "skipLibCheck": true, + "allowJs": true, + "strictPropertyInitialization": false, + "rootDir": "./webapp", + "paths": { + "ui5/tutorial/navigation/*": [ + "./webapp/*" + ] + }, + "strict": false, + "strictNullChecks": false + }, + "exclude": [ + "./webapp/test/e2e/**/*" + ], + "include": [ + "./webapp/**/*" + ] +} diff --git a/packages/navigation/steps/01/ui5.yaml b/packages/navigation/steps/01/ui5.yaml new file mode 100644 index 000000000..5bf7607c1 --- /dev/null +++ b/packages/navigation/steps/01/ui5.yaml @@ -0,0 +1,24 @@ +specVersion: '3.0' +metadata: + name: "ui5.tutorial.navigation" +type: application +framework: + name: OpenUI5 + version: "1.147.1" + libraries: + - name: sap.m + - name: sap.ui.core + - name: sap.ui.layout + - name: themelib_sap_horizon +builder: + customTasks: + - name: ui5-tooling-transpile-task + afterTask: replaceVersion +server: + customMiddleware: + - name: ui5-tooling-transpile-middleware + afterMiddleware: compression + - name: ui5-middleware-serveframework + afterMiddleware: compression + - name: ui5-middleware-livereload + afterMiddleware: compression diff --git a/packages/navigation/steps/01/webapp/Component.ts b/packages/navigation/steps/01/webapp/Component.ts new file mode 100644 index 000000000..63d712f2c --- /dev/null +++ b/packages/navigation/steps/01/webapp/Component.ts @@ -0,0 +1,12 @@ +import UIComponent from "sap/ui/core/UIComponent"; + +/** + * @namespace ui5.tutorial.navigation + */ +export default class Component extends UIComponent { + + public static metadata = { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + manifest: "json" + }; +} diff --git a/packages/navigation/steps/01/webapp/controller/App.controller.ts b/packages/navigation/steps/01/webapp/controller/App.controller.ts new file mode 100644 index 000000000..48bd34e84 --- /dev/null +++ b/packages/navigation/steps/01/webapp/controller/App.controller.ts @@ -0,0 +1,11 @@ +import Controller from "sap/ui/core/mvc/Controller"; + +/** + * @namespace ui5.tutorial.navigation.controller + */ +export default class App extends Controller { + + public onInit(): void { + + } +} diff --git a/packages/navigation/steps/01/webapp/i18n/i18n.properties b/packages/navigation/steps/01/webapp/i18n/i18n.properties new file mode 100644 index 000000000..be58132c8 --- /dev/null +++ b/packages/navigation/steps/01/webapp/i18n/i18n.properties @@ -0,0 +1,6 @@ +# App Descriptor +appTitle=Navigation & Routing Tutorial +appDescription=A simple app that explains how to use navigation and routing features of SAPUI5 + +iWantToNavigate=I want to navigate +homePageTitle=Home diff --git a/packages/navigation/steps/01/webapp/index-cdn.html b/packages/navigation/steps/01/webapp/index-cdn.html new file mode 100644 index 000000000..3f7d3e410 --- /dev/null +++ b/packages/navigation/steps/01/webapp/index-cdn.html @@ -0,0 +1,20 @@ + + + + + + Navigation and Routing Tutorial + + + +
+ + diff --git a/packages/navigation/steps/01/webapp/index.html b/packages/navigation/steps/01/webapp/index.html new file mode 100644 index 000000000..85064c936 --- /dev/null +++ b/packages/navigation/steps/01/webapp/index.html @@ -0,0 +1,20 @@ + + + + + + Navigation and Routing Tutorial + + + +
+ + diff --git a/packages/navigation/steps/01/webapp/initMockServer.ts b/packages/navigation/steps/01/webapp/initMockServer.ts new file mode 100644 index 000000000..66e2bfadd --- /dev/null +++ b/packages/navigation/steps/01/webapp/initMockServer.ts @@ -0,0 +1,9 @@ +import mockserver from "ui5/tutorial/navigation/localService/mockserver"; +import MessageBox from "sap/m/MessageBox"; + +mockserver.init().catch((error: Error) => { + MessageBox.error(error.message); +}).finally(() => { + // initialize the embedded component on the HTML page + import("sap/ui/core/ComponentSupport"); +}); diff --git a/packages/navigation/steps/01/webapp/localService/metadata.xml b/packages/navigation/steps/01/webapp/localService/metadata.xml new file mode 100644 index 000000000..8cb9b07d6 --- /dev/null +++ b/packages/navigation/steps/01/webapp/localService/metadata.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/navigation/steps/01/webapp/localService/mockdata/Employees.json b/packages/navigation/steps/01/webapp/localService/mockdata/Employees.json new file mode 100644 index 000000000..e37463b18 --- /dev/null +++ b/packages/navigation/steps/01/webapp/localService/mockdata/Employees.json @@ -0,0 +1,155 @@ +[ + { + "EmployeeID": 1, + "LastName": "Davolio", + "FirstName": "Nancy", + "Address": "507 - 20th Ave. E. Apt. 2A", + "City": "Seattle", + "Region": "WA", + "PostalCode": "98122", + "Country": "USA", + "HomePhone": "(206) 555-9857", + "ResumeID": 1, + "Resume" : { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(1)/Resume" + } + } + }, + { + "EmployeeID": 2, + "LastName": "Fuller", + "FirstName": "Andrew", + "Address": "908 W. Capital Way", + "City": "Tacoma", + "Region": "WA", + "PostalCode": "98401", + "Country": "USA", + "HomePhone": "(206) 555-9482", + "ResumeID": 2, + "Resume" : { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(2)/Resume" + } + } + }, + { + "EmployeeID": 3, + "LastName": "Leverling", + "FirstName": "Janet", + "Address": "722 Moss Bay Blvd.", + "City": "Kirkland", + "Region": "WA", + "PostalCode": "98033", + "Country": "USA", + "HomePhone": "(206) 555-3412", + "ResumeID": 3, + "Resume" : { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(3)/Resume" + } + } + }, + { + "EmployeeID": 4, + "LastName": "Peacock", + "FirstName": "Margaret", + "Address": "4110 Old Redmond Rd.", + "City": "Redmond", + "Region": "WA", + "PostalCode": "98052", + "Country": "USA", + "HomePhone": "(206) 555-8122", + "ResumeID": 4, + "Resume" : { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(4)/Resume" + } + } + }, + { + "EmployeeID": 5, + "LastName": "Buchanan", + "FirstName": "Steven", + "Address": "14 Garrett Hill", + "City": "London", + "Region": null, + "PostalCode": "SW1 8JR", + "Country": "UK", + "HomePhone": "(71) 555-4848", + "ResumeID": 5, + "Resume" : { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(5)/Resume" + } + } + }, + { + "EmployeeID": 6, + "LastName": "Suyama", + "FirstName": "Michael", + "Address": "Coventry House Miner Rd.", + "City": "London", + "Region": null, + "PostalCode": "EC2 7JR", + "Country": "UK", + "HomePhone": "(71) 555-7773", + "ResumeID": 6, + "Resume" : { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(6)/Resume" + } + } + }, + { + "EmployeeID": 7, + "LastName": "King", + "FirstName": "Robert", + "Address": "Edgeham Hollow Winchester Way", + "City": "London", + "Region": null, + "PostalCode": "RG1 9SP", + "Country": "UK", + "HomePhone": "(71) 555-5598", + "ResumeID": 7, + "Resume" : { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(7)/Resume" + } + } + }, + { + "EmployeeID": 8, + "LastName": "Callahan", + "FirstName": "Laura", + "Address": "4726 - 11th Ave. N.E.", + "City": "Seattle", + "Region": "WA", + "PostalCode": "98105", + "Country": "USA", + "HomePhone": "(206) 555-1189", + "ResumeID": 8, + "Resume" : { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(8)/Resume" + } + } + }, + { + "EmployeeID": 9, + "LastName": "Dodsworth", + "FirstName": "Anne", + "Address": "7 Houndstooth Rd.", + "City": "London", + "Region": null, + "PostalCode": "WG2 7LT", + "Country": "UK", + "HomePhone": "(71) 555-4444", + "ResumeID": 9, + "Resume" : { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(9)/Resume" + } + } + } +] diff --git a/packages/navigation/steps/01/webapp/localService/mockdata/Resumes.json b/packages/navigation/steps/01/webapp/localService/mockdata/Resumes.json new file mode 100644 index 000000000..50c8f4fa6 --- /dev/null +++ b/packages/navigation/steps/01/webapp/localService/mockdata/Resumes.json @@ -0,0 +1,65 @@ +[ + { + "ResumeID": 1, + "Information": "Information of Nancy Davolio", + "Projects": "Projects of Nancy Davolio", + "Hobbies": "Hobbies of Nancy Davolio", + "Notes": "Notes of Nancy Davolio" + }, + { + "ResumeID": 2, + "Information": "Information of Andrew Fuller", + "Projects": "Projects of Andrew Fuller", + "Hobbies": "Hobbies of Andrew Fuller", + "Notes": "Notes of Andrew Fuller" + }, + { + "ResumeID": 3, + "Information": "Information of Janet Leverling", + "Projects": "Projects of Janet Leverling", + "Hobbies": "Hobbies of Janet Leverling", + "Notes": "Notes of Janet Leverling" + }, + { + "ResumeID": 4, + "Information": "Information of Margaret Peacock", + "Projects": "Projects of Margaret Peacock", + "Hobbies": "Hobbies of Margaret Peacock", + "Notes": "Notes of Margaret Peacock" + }, + { + "ResumeID": 5, + "Information": "Information of Steven Buchanan", + "Projects": "Projects of Steven Buchanan", + "Hobbies": "Hobbies of Steven Buchanan", + "Notes": "Notes of Steven Buchanan" + }, + { + "ResumeID": 6, + "Information": "Information of Michael Suyama", + "Projects": "Projects of Michael Suyama", + "Hobbies": "Hobbies of Michael Suyama", + "Notes": "Notes of Michael Suyama" + }, + { + "ResumeID": 7, + "Information": "Information of Robert King", + "Projects": "Projects of Robert King", + "Hobbies": "Hobbies of Robert King", + "Notes": "Notes of Robert King" + }, + { + "ResumeID": 8, + "Information": "Information of Laura Callahan", + "Projects": "Projects of Laura Callahan", + "Hobbies": "Hobbies of Laura Callahan", + "Notes": "Notes of Laura Callahan" + }, + { + "ResumeID": 9, + "Information": "Information of Anne Dodsworth", + "Projects": "Projects of Anne Dodsworth", + "Hobbies": "Hobbies of Anne Dodsworth", + "Notes": "Notes of Anne Dodsworth" + } +] diff --git a/packages/navigation/steps/01/webapp/localService/mockserver.ts b/packages/navigation/steps/01/webapp/localService/mockserver.ts new file mode 100644 index 000000000..cd552596d --- /dev/null +++ b/packages/navigation/steps/01/webapp/localService/mockserver.ts @@ -0,0 +1,50 @@ +import MockServer from "sap/ui/core/util/MockServer"; +import JSONModel from "sap/ui/model/json/JSONModel"; +import Log from "sap/base/Log"; + +const appNamespace = "ui5/tutorial/navigation/"; +const pathToJsonFiles = appNamespace + "localService/mockdata"; + +export default { + init(): Promise { + return new Promise((resolve, reject) => { + const manifestUrl = sap.ui.require.toUrl(appNamespace + "manifest.json"); + const manifestModel = new JSONModel(manifestUrl); + + manifestModel.attachRequestCompleted(() => { + const jsonFilesUrl = sap.ui.require.toUrl(pathToJsonFiles); + const dataSource = manifestModel.getProperty("/sap.app/dataSources/employeeRemote"); + const metadataUrl = sap.ui.require.toUrl(appNamespace + dataSource.settings.localUri); + + // create + const server = new MockServer({ + rootUri: dataSource.uri + }); + + // configure + MockServer.config({ + autoRespond: true, + autoRespondAfter: 500 + }); + + // simulate + server.simulate(metadataUrl, { + sMockdataBaseUrl: jsonFilesUrl + }); + + // start + server.start(); + + Log.info("Running the app with mock data"); + resolve(); + }); + + manifestModel.attachRequestFailed(() => { + const errorMessage = "Failed to load application manifest"; + + Log.error(errorMessage); + reject(new Error(errorMessage)); + }); + }); + } +}; diff --git a/packages/navigation/steps/01/webapp/manifest.json b/packages/navigation/steps/01/webapp/manifest.json new file mode 100644 index 000000000..e0a935085 --- /dev/null +++ b/packages/navigation/steps/01/webapp/manifest.json @@ -0,0 +1,74 @@ +{ + "_version": "1.38.0", + "sap.app": { + "id": "ui5.tutorial.navigation", + "type": "application", + "i18n": { + "bundleUrl": "i18n/i18n.properties", + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + }, + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "employeeRemote": { + "uri": "/here/goes/your/serviceUrl/", + "type": "OData", + "settings": { + "odataVersion": "2.0", + "localUri" : "localService/metadata.xml" + } + } + } + }, + "sap.ui": { + "technology": "UI5", + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "contentDensities": { + "compact": true, + "cozy": true + }, + "rootView": { + "viewName": "ui5.tutorial.navigation.view.App", + "type": "XML", + "id": "app" + }, + "dependencies": { + "minUI5Version": "1.98.0", + "libs": { + "sap.m": {}, + "sap.ui.core": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "ui5.tutorial.navigation.i18n.i18n", + "supportedLocales": [ + "" + ], + "fallbackLocale": "", + "async": true + } + }, + "": { + "dataSource": "employeeRemote", + "settings": { + "defaultCountMode": "None" + } + } + } + } +} diff --git a/packages/navigation/steps/01/webapp/view/App.view.xml b/packages/navigation/steps/01/webapp/view/App.view.xml new file mode 100644 index 000000000..980d965d7 --- /dev/null +++ b/packages/navigation/steps/01/webapp/view/App.view.xml @@ -0,0 +1,17 @@ + + + + + + + + +... +``` + +We add the **headerContent** aggregation to the **Page** and insert the new **Button**. We add the **onResetDataSource** event handler to the **press** event. + +## webapp/i18n/i18n.properties + +```ini +... +# Toolbar +... +#XBUT: Button text for reset changes +resetChangesButtonText=Restart Tutorial +... +# Messages +... +#XMSG: Message for changes reverted +sourceResetSuccessMessage=All changes reverted back to start +``` + +We add the missing texts to the properties file. + +And now we are done! We built a simple application with user data from an OData V4 service. We can display, edit, create, and delete users. And we use OData V4 features such as batch groups and automatic type detection. + +**Related Information** + +[Bindings](../04_Essentials/bindings-54e0ddf.md "Bindings connect SAPUI5 view elements to model data, allowing changes in the model to be reflected in the view element and vice versa.") + +[OData Operations](../04_Essentials/odata-operations-b54f789.md "The OData V4 model supports OData operations (ActionImport, FunctionImport, bound Actions and bound Functions). Unbound parameters are limited to primitive values.") + +*** + +**Next:** [Step 9: List-Detail Scenario](../09/README.md) + +**Previous:** [Step 7: Delete](../07/README.md) diff --git a/packages/odatav4/steps/08/assets/Tutorial_OData_V4_Step_8_e518deb.png b/packages/odatav4/steps/08/assets/Tutorial_OData_V4_Step_8_e518deb.png new file mode 100644 index 0000000000000000000000000000000000000000..bea20688b12c6d197672afa84bdae23e922a300e GIT binary patch literal 44152 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 Lo<_0S { + const columnItem = item as ColumnListItem; + if (columnItem.getBindingContext() === context) { + columnItem.focus(); + columnItem.setSelected(true); + return true; + } + return false; + }); + } + + /** + * Delete an entry. + */ + onDelete(): void { + const selected = (this.byId("peopleList") as List).getSelectedItem() as ColumnListItem | null; + + if (selected) { + const context = selected.getBindingContext() as Context; + const userName = context.getProperty("UserName") as string; + void context.delete().then(() => { + MessageToast.show(this._getText("deletionSuccessMessage", [userName])); + }, (error2: Error & { canceled?: boolean }) => { + this._setUIChanges(); + if (error2.canceled) { + MessageToast.show(this._getText("deletionRestoredMessage", [userName])); + return; + } + MessageBox.error(error2.message + ": " + userName); + }); + this._setUIChanges(); + } + } + + /** + * Lock UI when changing data in the input controls + */ + onInputChange(evt: Event): void { + if ((evt as unknown as { getParameter(n: string): unknown }).getParameter("escPressed")) { + this._setUIChanges(); + } else { + this._setUIChanges(true); + // Check if the username in the changed table row is empty and set the appView + // property accordingly + const ctx = (evt.getSource() as Input).getParent()?.getBindingContext(); + if (ctx && ctx.getProperty("UserName")) { + (this.getView().getModel("appView") as JSONModel).setProperty("/usernameEmpty", false); + } + } + } + + /** + * Refresh the data. + */ + onRefresh(): void { + const binding = (this.byId("peopleList") as List).getBinding("items") as ODataListBinding; + + if (binding.hasPendingChanges()) { + MessageBox.error(this._getText("refreshNotPossibleMessage")); + return; + } + binding.refresh(); + MessageToast.show(this._getText("refreshSuccessMessage")); + } + + /** + * Reset any unsaved changes. + */ + onResetChanges(): void { + ((this.byId("peopleList") as List).getBinding("items") as ODataListBinding).resetChanges(); + // If there were technical errors, cancelling changes resets them. + this._bTechnicalErrors = false; + this._setUIChanges(false); + } + + /** + * Reset the data source. + */ + onResetDataSource(): void { + const model = this.getView().getModel() as ODataModel; + const operation = model.bindContext("/ResetDataSource(...)"); + + void operation.invoke().then(() => { + model.refresh(); + MessageToast.show(this._getText("sourceResetSuccessMessage")); + }, (error2: Error) => { + MessageBox.error(error2.message); + }); + } + + /** + * Save changes to the source. + */ + onSave(): void { + const success = () => { + this._setBusy(false); + MessageToast.show(this._getText("changesSentMessage")); + this._setUIChanges(false); + }; + const error = (error2: Error) => { + this._setBusy(false); + this._setUIChanges(false); + MessageBox.error(error2.message); + }; + + this._setBusy(true); // Lock UI until submitBatch is resolved. + (this.getView().getModel() as ODataModel).submitBatch("peopleGroup").then(success, error); + // If there were technical errors, a new save resets them. + this._bTechnicalErrors = false; + } + + /** + * Search for the term in the search field. + */ + onSearch(): void { + const view = this.getView(); + const value = (view.byId("searchField") as SearchField).getValue(); + const filter = new Filter("LastName", FilterOperator.Contains, value); + + ((view.byId("peopleList") as List).getBinding("items") as ListBinding).filter(filter, FilterType.Application); + } + + /** + * Sort the table according to the last name. + * Cycles between the three sorting states "none", "ascending" and "descending" + */ + onSort(): void { + const view = this.getView(); + const states: (string | undefined)[] = [undefined, "asc", "desc"]; + const stateTextIds = ["sortNone", "sortAscending", "sortDescending"]; + let order = (view.getModel("appView") as JSONModel).getProperty("/order") as number; + + // Cycle between the states + order = (order + 1) % states.length; + const order2 = states[order]; + + (view.getModel("appView") as JSONModel).setProperty("/order", order); + ((view.byId("peopleList") as List).getBinding("items") as ListBinding) + .sort(order2 ? new Sorter("LastName", order2 === "desc") : []); + + const message = this._getText("sortMessage", [this._getText(stateTextIds[order])]); + MessageToast.show(message); + } + + onMessageBindingChange(event: Event): void { + const contexts = (event.getSource() as ListBinding).getContexts(); + let messageOpen = false; + + if (messageOpen || !contexts.length) { + return; + } + + // Extract and remove the technical messages + const messages = contexts.map((context: Context) => context.getObject()); + Messaging.removeMessages(messages); + + this._setUIChanges(true); + this._bTechnicalErrors = true; + MessageBox.error((messages[0] as { message: string }).message, { + id: "serviceErrorMessageBox", + onClose: () => { + messageOpen = false; + } + }); + + messageOpen = true; + } + + /* =========================================================== */ + /* end: event handlers */ + /* =========================================================== */ + + /** + * Convenience method for retrieving a translatable text. + */ + _getText(textId: string, args?: unknown[]): string { + const bundle = ((this.getOwnerComponent() as Component).getModel("i18n") as ResourceModel).getResourceBundle() as ResourceBundle; + return bundle.getText(textId, args as string[]); + } + + /** + * Set hasUIChanges flag in View Model + * @param bHasUIChanges - set or clear hasUIChanges; if undefined, the hasPendingChanges-function + * of the OdataV4 model determines the result + */ + _setUIChanges(hasUIChanges?: boolean): void { + if (this._bTechnicalErrors) { + // If there is currently a technical error, then force 'true'. + hasUIChanges = true; + } else if (hasUIChanges === undefined) { + hasUIChanges = (this.getView().getModel() as ODataModel).hasPendingChanges(); + } + const model = this.getView().getModel("appView") as JSONModel; + model.setProperty("/hasUIChanges", hasUIChanges); + } + + /** + * Set busy flag in View Model + */ + _setBusy(isBusy: boolean): void { + const model = this.getView().getModel("appView") as JSONModel; + model.setProperty("/busy", isBusy); + } +} diff --git a/packages/odatav4/steps/08/webapp/i18n/i18n.properties b/packages/odatav4/steps/08/webapp/i18n/i18n.properties new file mode 100644 index 000000000..19a73c1b4 --- /dev/null +++ b/packages/odatav4/steps/08/webapp/i18n/i18n.properties @@ -0,0 +1,78 @@ +# App Descriptor +#XTIT: Application name +appTitle=OData V4 - Step 8: OData Operations + +#YDES: Application description +appDescription=OData V4 Tutorial + +#XTIT: Page Title +peoplePageTitle=My Users + +# Toolbar +#XBUT: Button text for save +saveButtonText=Save + +#XBUT: Button text for reset changes +resetChangesButtonText=Restart Tutorial + +#XBUT: Button text for cancel +cancelButtonText=Cancel + +#XTOL: Tooltip for sort +sortButtonText=Sort by Last Name + +#XBUT: Button text for add user +createButtonText=Add User + +#XBUT: Button text for delete user +deleteButtonText=Delete User + +#XTOL: Tooltip for refresh data +refreshButtonText=Refresh Data + +#XTXT: Placeholder text for search field +searchFieldPlaceholder=Type in a last name + +# Table Area +#XFLD: Label for User Name +userNameLabelText=User Name + +#XFLD: Label for First Name +firstNameLabelText=First Name + +#XFLD: Label for Last Name +lastNameLabelText=Last Name + +#XFLD: Label for Age +ageLabelText=Age + +# Messages +#XMSG: Message for user changes sent to the service +changesSentMessage=User data sent to the server + +#XMSG: Message for user deleted +deletionSuccessMessage=User {0} deleted + +#XMSG: Message for user restored (undeleted) +deletionRestoredMessage=User {0} restored + +#XMSG: Message for changes reverted +sourceResetSuccessMessage=All changes reverted back to start + +#XMSG: Message for refresh failed +refreshNotPossibleMessage=Before refreshing, please save or revert your changes + +#XMSG: Message for refresh succeeded +refreshSuccessMessage=Data refreshed + +#MSG: Message for sorting +sortMessage=Users sorted by {0} + +#MSG: Suffix for sorting by LastName, ascending +sortAscending=last name, ascending + +#MSG: Suffix for sorting by LastName, descending +sortDescending=last name, descending + +#MSG: Suffix for no sorting +sortNone=the sequence on the server \ No newline at end of file diff --git a/packages/odatav4/steps/08/webapp/index-cdn.html b/packages/odatav4/steps/08/webapp/index-cdn.html new file mode 100644 index 000000000..5e7e769d6 --- /dev/null +++ b/packages/odatav4/steps/08/webapp/index-cdn.html @@ -0,0 +1,22 @@ + + + + + + OData V4 Tutorial + + + +
+ + diff --git a/packages/odatav4/steps/08/webapp/index.html b/packages/odatav4/steps/08/webapp/index.html new file mode 100644 index 000000000..b1e54667d --- /dev/null +++ b/packages/odatav4/steps/08/webapp/index.html @@ -0,0 +1,22 @@ + + + + + + OData V4 Tutorial + + + +
+ + diff --git a/packages/odatav4/steps/08/webapp/initMockServer.ts b/packages/odatav4/steps/08/webapp/initMockServer.ts new file mode 100644 index 000000000..0150138fe --- /dev/null +++ b/packages/odatav4/steps/08/webapp/initMockServer.ts @@ -0,0 +1,11 @@ +// initMockServer.ts — bootstraps the mock server before the component starts +import MessageBox from "sap/m/MessageBox"; +import mockserver from "./localService/mockserver"; + +// initialize the mock server +mockserver.init().catch((oError: Error) => { + MessageBox.error(oError.message); +}).finally(() => { + // initialize the embedded component on the HTML page + void import("sap/ui/core/ComponentSupport"); +}); diff --git a/packages/odatav4/steps/08/webapp/localService/metadata.xml b/packages/odatav4/steps/08/webapp/localService/metadata.xml new file mode 100644 index 000000000..cd2295653 --- /dev/null +++ b/packages/odatav4/steps/08/webapp/localService/metadata.xml @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/odatav4/steps/08/webapp/localService/mockdata/people.json b/packages/odatav4/steps/08/webapp/localService/mockdata/people.json new file mode 100644 index 000000000..cd9ce4180 --- /dev/null +++ b/packages/odatav4/steps/08/webapp/localService/mockdata/people.json @@ -0,0 +1,399 @@ +{ + "@odata.context": "https://services.odata.org/TripPinRESTierService/(S(id))/$metadata#People(Age,FirstName,LastName,UserName,Friends,BestFriend,HomeAddress)", + "value": [ + { + "Age": 23, + "FirstName": "Angel", + "LastName": "Huffman", + "UserName": "angelhuffman", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "clydeguess", + "HomeAddress": { + "Address": "187 Suffolk Ln.", + "City": { + "Name": "Boise", + "CountryRegion": "United States", + "Region": "ID" + } + } + }, + { + "Age": 44, + "FirstName": "Clyde", + "LastName": "Guess", + "UserName": "clydeguess", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "angelhuffman", + "HomeAddress": { + "Address": "2817 Milton Dr.", + "City": { + "Name": "Albuquerque", + "CountryRegion": "United States", + "Region": "NM" + } + } + }, + { + "Age": 19, + "FirstName": "Elaine", + "LastName": "Stewart", + "UserName": "elainestewart", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "genevievereeves", + "HomeAddress": { + "Address": "308 Negra Arroyo Ln.", + "City": { + "Name": "Albuquerque", + "CountryRegion": "United States", + "Region": "NM" + } + } + }, + { + "Age": 37, + "FirstName": "Genevieve", + "LastName": "Reeves", + "UserName": "genevievereeves", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "elainestewart", + "HomeAddress": { + "Address": "89 Jefferson Way Suite 2", + "City": { + "Name": "Portland", + "CountryRegion": "United States", + "Region": "WA" + } + } + }, + { + "Age": 25, + "FirstName": "Georgina", + "LastName": "Barlow", + "UserName": "georginabarlow", + "Friends": [ + "marshallgaray", + "ursulabright" + ], + "BestFriend": "javieralfred", + "HomeAddress": { + "Address": "31 Spooner Street", + "City": { + "Name": "Quahog", + "CountryRegion": "United States", + "Region": "RI" + } + } + }, + { + "Age": 19, + "FirstName": "Javier", + "LastName": "Alfred", + "UserName": "javieralfred", + "Friends": [ + "marshallgaray", + "ursulabright" + ], + "BestFriend": "georginabarlow", + "HomeAddress": { + "Address": "55 Grizzly Peak Rd.", + "City": { + "Name": "Butte", + "CountryRegion": "United States", + "Region": "MT" + } + } + }, + { + "Age": 26, + "FirstName": "Joni", + "LastName": "Rosales", + "UserName": "jonirosales", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "keithpinckney", + "HomeAddress": { + "Address": "742 Evergreen Terrace", + "City": { + "Name": "Springfield", + "CountryRegion": "United States", + "Region": "OR" + } + } + }, + { + "Age": 41, + "FirstName": "Keith", + "LastName": "Pinckney", + "UserName": "keithpinckney", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "jonirosales", + "HomeAddress": { + "Address": "1600 Pennsylvania Avenue NW", + "City": { + "Name": "Washington", + "CountryRegion": "United States", + "Region": "DC" + } + } + }, + { + "Age": 30, + "FirstName": "Krista", + "LastName": "Kemp", + "UserName": "kristakemp", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "laurelosborn", + "HomeAddress": { + "Address": "Statue of Liberty", + "City": { + "Name": "New York", + "CountryRegion": "United States", + "Region": "NY" + } + } + }, + { + "Age": 29, + "FirstName": "Laurel", + "LastName": "Osborn", + "UserName": "laurelosborn", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "kristakemp", + "HomeAddress": { + "Address": "4059 Mt Lee Dr. Hollywood", + "City": { + "Name": "Los Angelos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 53, + "FirstName": "Marshall", + "LastName": "Garay", + "UserName": "marshallgaray", + "Friends": [ + "georginabarlow", + "ursulabright" + ], + "BestFriend": "ronaldmundy", + "HomeAddress": { + "Address": "87 Polk St. Suite 5", + "City": { + "Name": "San Francisco", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 66, + "FirstName": "Ronald", + "LastName": "Mundy", + "UserName": "ronaldmundy", + "Friends": [ + "georginabarlow", + "ursulabright" + ], + "BestFriend": "marshallgaray", + "HomeAddress": { + "Address": "89 Chiaroscuro Rd.", + "City": { + "Name": "Portland", + "CountryRegion": "United States", + "Region": "OR" + } + } + }, + { + "Age": 51, + "FirstName": "Russell", + "LastName": "Whyte", + "UserName": "russellwhyte", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "ryantheriault", + "HomeAddress": { + "Address": "Tony Stark Mansion, Point Dume", + "City": { + "Name": "Malibu", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 57, + "FirstName": "Ryan", + "LastName": "Theriault", + "UserName": "ryantheriault", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "russellwhyte", + "HomeAddress": { + "Address": "2311 N. Los Robles Ave. Apt 4A", + "City": { + "Name": "Pasadena", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 34, + "FirstName": "Sallie", + "LastName": "Sampson", + "UserName": "salliesampson", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "sandyosborn", + "HomeAddress": { + "Address": "87 Polk St. Suite 5", + "City": { + "Name": "San Francisco", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 18, + "FirstName": "Sandy", + "LastName": "Osborn", + "UserName": "sandyosborn", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "salliesampson", + "HomeAddress": { + "Address": "Grove Street, Ganton", + "City": { + "Name": "Los Santos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 24, + "FirstName": "Scott", + "LastName": "Ketchum", + "UserName": "scottketchum", + "Friends": [ + "georginabarlow", + "marshallgaray" + ], + "BestFriend": "ursulabright", + "HomeAddress": { + "Address": "Portola Drive, Rockford Hills", + "City": { + "Name": "Los Santos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 31, + "FirstName": "Ursula", + "LastName": "Bright", + "UserName": "ursulabright", + "Friends": [ + "georginabarlow", + "marshallgaray" + ], + "BestFriend": "scottketchum", + "HomeAddress": { + "Address": "First St. SE", + "City": { + "Name": "Washington", + "CountryRegion": "United States", + "Region": "DC" + } + } + }, + { + "Age": 40, + "FirstName": "Vincent", + "LastName": "Calabrese", + "UserName": "vincentcalabrese", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "willieashmore", + "HomeAddress": { + "Address": "4 Privet Drive", + "City": { + "Name": "Little Whinging", + "CountryRegion": "Great Britain", + "Region": "SRY" + } + } + }, + { + "Age": 45, + "FirstName": "Willie", + "LastName": "Ashmore", + "UserName": "willieashmore", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "vincentcalabrese", + "HomeAddress": { + "Address": "124 Conch St.", + "City": { + "Name": "Bikini Bottom", + "CountryRegion": "Pacific Ocean", + "Region": "N/D" + } + } + } + ] +} \ No newline at end of file diff --git a/packages/odatav4/steps/08/webapp/localService/mockserver.ts b/packages/odatav4/steps/08/webapp/localService/mockserver.ts new file mode 100644 index 000000000..d6810087d --- /dev/null +++ b/packages/odatav4/steps/08/webapp/localService/mockserver.ts @@ -0,0 +1,782 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any */ +import JSONModel from "sap/ui/model/json/JSONModel"; +import Log from "sap/base/Log"; + +// Pull sinon from the UI5 third-party shim. The shim has no TS typings; +// we treat the imported value as a structural any so the mock implementation +// stays close to the original JavaScript. +// eslint-disable-next-line @typescript-eslint/no-require-imports +declare const sap: any; + +interface MockUser { + UserName: string; + FirstName?: string; + LastName?: string; + Age?: number; + Friends?: string[]; + BestFriend?: string; + [key: string]: unknown; +} + +interface MockXhr { + method: string; + url: string; + requestBody?: string; + respond?: (status: number, headers: Record, body: string | null) => void; +} + +type MockResponse = [number, Record, string | null] | [number, Record]; + +// sinon is provided by the "sap/ui/thirdparty/sinon" module — see the require below +let sinon: any; +let sandbox: any; +let users: MockUser[]; // The array that holds the cached user data +let metadata: string; // The string that holds the cached mock service metadata +const namespace = "ui5/tutorial/odatav4"; +// Component for writing logs into the console +const logComponent = "ui5.tutorial.odatav4.mockserver"; +const rBaseUrl = /services.odata.org\/TripPinRESTierService/; + +/** + * Returns the base URL from a given URL. + * @param sUrl - the complete URL + * @returns the base URL + */ +function getBaseUrl(url: string): string { + const matches = url.match(/http.+\(S\(.+\)\)\//); + + if (!Array.isArray(matches) || matches.length < 1) { + throw new Error("Could not find a base URL in " + url); + } + + return matches[0]; +} + +/** + * Looks for a user with a given user name and returns its index in the user array. + * @param sUserName - the user name to look for. + * @returns index of that user in the array, or -1 if the user was not found. + */ +function findUserIndex(userName: string): number { + for (let i = 0; i < users.length; i++) { + if (users[i].UserName === userName) { + return i; + } + } + return -1; +} + +/** + * Retrieves any user data from a given http request body. + * @param sBody - the http request body. + * @returns the parsed user data. + */ +function getUserDataFromRequestBody(body: string): MockUser { + const matches = body.match(/({.+})/); + + if (!Array.isArray(matches) || matches.length !== 2) { + throw new Error("Could not find any user data in " + body); + } + return JSON.parse(matches[1]) as MockUser; +} + +/** + * Retrieves a user name from a given request URL. + * @param sUrl - the request URL. + * @returns the user name or undefined if no user was found. + */ +function getUserKeyFromUrl(url: string): string | undefined { + const matches = url.match(/People\('(.*)'\)/); + return matches ? matches[1] : undefined; +} + +/** + * Checks if a given UserName is unique or already used + * @param sUserName - the UserName to be checked + * @returns True if the UserName is unique (not used), false otherwise + */ +function isUnique(userName: string): boolean { + return findUserIndex(userName) < 0; +} + +/** + * Returns a proper HTTP response body for "duplicate key" errors + * @param sKey - the duplicate key + * @returns the proper response body + */ +function duplicateKeyError(key: string): string { + return JSON.stringify({ + error: { + code: "409", + message: "There is already a user with user name '" + key + "'.", + target: "UserName" + } + }); +} + +function invalidKeyError(key: string): string { + return JSON.stringify({ + error: { + code: "404", + message: "There is no user with user name '" + key + "'.", + target: "UserName" + } + }); +} + +function getSuccessResponse(responseBody: string): MockResponse { + return [ + 200, + { + "Content-Type": "application/json; odata.metadata=minimal", + "OData-Version": "4.0" + }, + responseBody + ]; +} + +/** + * Reads and caches the fake service metadata and data from their + * respective files. + * @returns a promise that is resolved when the data is loaded + */ +function readData(): Promise { + const metadataPromise = new Promise((resolve, reject) => { + const resourcePath = sap.ui.require.toUrl(namespace + "/localService/metadata.xml"); + const request = new XMLHttpRequest(); + + request.onload = function () { + // 404 is not an error for XMLHttpRequest so we need to handle it here + if (request.status === 404) { + const error = "resource " + resourcePath + " not found"; + + Log.error(error, logComponent); + reject(new Error(error)); + } + metadata = this.responseText; + resolve(); + }; + request.onerror = function () { + const error = "error loading resource '" + resourcePath + "'"; + + Log.error(error, logComponent); + reject(new Error(error)); + }; + request.open("GET", resourcePath); + request.send(); + }); + + const mockDataPromise = new Promise((resolve, reject) => { + const resourcePath = sap.ui.require.toUrl(namespace + "/localService/mockdata/people.json"); + const mockDataModel = new JSONModel(resourcePath); + + mockDataModel.attachRequestCompleted(function (this: JSONModel, event: any) { + // 404 is not an error for JSONModel so we need to handle it here + if (event.getParameter("errorobject") + && event.getParameter("errorobject").statusCode === 404) { + const error = "resource '" + resourcePath + "' not found"; + + Log.error(error, logComponent); + reject(new Error(error)); + } + users = (this.getData() as { value: MockUser[] }).value; + resolve(); + }); + + mockDataModel.attachRequestFailed(() => { + const error = "error loading resource '" + resourcePath + "'"; + + Log.error(error, logComponent); + reject(new Error(error)); + }); + }); + + return Promise.all([metadataPromise, mockDataPromise]); +} + +/** + * Reduces a given result set by applying the OData URL parameters 'skip' and 'top' to it. + * Does NOT change the given result set but returns a new array. + */ +function applySkipTop(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + const reducedUsers = [...resultSet]; + const matches = xhr.url.match(/\$skip=(\d+)&\$top=(\d+)/); + + if (Array.isArray(matches) && matches.length >= 3) { + const skip = parseInt(matches[1], 10); + const top = parseInt(matches[2], 10); + return resultSet.slice(skip, skip + top); + } + + return reducedUsers; +} + +/** + * Sorts a given result set by applying the OData URL parameter 'orderby'. + * Does NOT change the given result set but returns a new array. + */ +function applySort(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + const sortedUsers = [...resultSet]; // work with a copy + const matches = xhr.url.match(/\$orderby=(\w*)(?:%20(\w*))?/); + + if (!Array.isArray(matches) || matches.length < 2) { + return sortedUsers; + } + const fieldName = matches[1]; + const direction = matches[2] || "asc"; + + if (fieldName !== "LastName") { + throw new Error("Filters on field " + fieldName + " are not supported."); + } + + sortedUsers.sort((a, b) => { + const nameA = (a.LastName || "").toUpperCase(); + const nameB = (b.LastName || "").toUpperCase(); + const asc = direction === "asc"; + + if (nameA < nameB) { + return asc ? -1 : 1; + } + if (nameA > nameB) { + return asc ? 1 : -1; + } + return 0; + }); + + return sortedUsers; +} + +/** + * Filters a given result set by applying the OData URL parameter 'filter'. + * Does NOT change the given result set but returns a new array. + */ +function applyFilter(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + let filteredUsers = [...resultSet]; // work with a copy + const matches = xhr.url.match(/\$filter=.*\((.*),'(.*)'\)/); + + // If the request contains a filter command, apply the filter + if (Array.isArray(matches) && matches.length >= 3) { + const fieldName = matches[1]; + const query = matches[2]; + + if (fieldName !== "LastName") { + throw new Error("Filters on field " + fieldName + " are not supported."); + } + + filteredUsers = users.filter((user) => (user.LastName || "").indexOf(query) !== -1); + } + + return filteredUsers; +} + +/** + * Handles GET requests for metadata. + */ +function handleGetMetadataRequests(): MockResponse { + return [ + 200, + { + "Content-Type": "application/xml", + "odata-version": "4.0" + }, metadata + ]; +} + +/** + * Handles GET requests for a pure user count and returns a fitting response. + */ +function handleGetCountRequests(): MockResponse { + return getSuccessResponse(users.length.toString()); +} + +/** + * Handles GET requests for user data and returns a fitting response. + */ +function handleGetUserRequests(xhr: MockXhr, _bCount: boolean): MockResponse { + let count: number; + let expand: RegExpMatchArray | string[] | null; + let expand2: string; + let index: number; + let key: string | undefined; + let response: { "@odata.count"?: number; value: MockUser[] } | MockUser | null; + let responseBody: string; + let result: MockUser[]; + let select: RegExpMatchArray | string[] | null; + let select2: string; + let subSelects: string[][] = []; + let i: number; + + // Get expand parameter + expand = xhr.url.match(/\$expand=([^&]+)/); + + // Sort out expand parameter values + subSelects in brackets + if (expand) { + expand2 = expand[0]; + expand2 = expand2.substring(8); + + // Sort out subselects (e.g. BestFriend($select=Age,UserName),Friend) + const subSelectMatches = expand2.match(/\([^)]*\)/g) || []; + subSelects = subSelectMatches.map((s) => s.replace(/\(\$select=/, "").replace(/\)/, "").split(",")); + expand2 = expand2.replace(/\([^)]*\)/g, ""); + expand = expand2.split(","); + } + + // Get select parameter + select = xhr.url.match(/[^(]\$select=([\w|,]+)/); + + // Sort out select parameter values + if (Array.isArray(select)) { + select2 = select[0]; + select2 = select2.replace(/&/, "").replace(/\?/, "").substring(8); + select = select2.split(","); + } + + // Check if an individual user or a user range is requested + key = getUserKeyFromUrl(xhr.url); + if (key) { + index = findUserIndex(key); + + if (/People\(.+\)\/Friends/.test(xhr.url)) { + // ownRequest for friends + response = { value: createFriendsArray(users[index].Friends, select as string[]) }; + } else { + // specific user was requested + response = getUserObject(index, select as string[], expand as string[], subSelects); + } + + if (index > -1) { + responseBody = JSON.stringify(response); + return getSuccessResponse(responseBody); + } + responseBody = invalidKeyError(key); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; + } + // all users requested + result = applyFilter(xhr, users); + count = result.length; // the total no. of people found, after filtering + result = applySort(xhr, result); + result = applySkipTop(xhr, result); + + // generate sResponse + const finalResponse: { "@odata.count": number; value: MockUser[] } = { "@odata.count": count, value: [] }; + + result.forEach((user) => { + const userIndex = findUserIndex(user.UserName); + + finalResponse.value.push(getUserObject(userIndex, select as string[], expand as string[], subSelects) as MockUser); + }); + + responseBody = JSON.stringify(finalResponse); + + return getSuccessResponse(responseBody); +} + +/** + * Returns a specific user in the aUsers array. + */ +function getUserByIndex(index: number, properties: string[]): MockUser | null { + const helper: MockUser = { UserName: "" }; + const user = users[index]; + + if (user) { + properties.forEach((selectProperty) => { + helper[selectProperty] = user[selectProperty]; + }); + + return helper; + } + return null; +} + +/** + * Returns the user with iIndex in the aUsers array with all its information + */ +function getUserObject(index: number, select: string[], expand: string[] | null | undefined, subSelects: string[][]): MockUser | null { + let bestFriend: string | undefined; + let friendIndex: number; + let friends: string[] | undefined; + let object: MockUser | null; + let user: MockUser; + let i: number; + + object = getUserByIndex(index, select); + if (expand && object) { + user = users[index]; + for (i = 0; i < expand.length; i++) { + switch (expand[i]) { + case "Friends": + friends = user.Friends; + object.Friends = createFriendsArray(friends, subSelects[i]) as unknown as string[]; + break; + case "BestFriend": + bestFriend = user.BestFriend; + friendIndex = findUserIndex(bestFriend || ""); + object.BestFriend = getUserByIndex(friendIndex, subSelects[i]) as unknown as string; + break; + default: + break; + } + } + } + return object; +} + +/** + * creates array of friends for a given user + */ +function createFriendsArray(friends: string[] | undefined, subSelects: string[]): MockUser[] { + let array: (MockUser | null)[] = []; + + if (friends) { + friends.forEach((friend) => { + const friendIndex = findUserIndex(friend); + array.push(getUserByIndex(friendIndex, subSelects)); + }); + + array = array.filter((element) => element !== null); + } + + return array as MockUser[]; +} + +/** + * Handles PATCH requests for users and returns a fitting response. + */ +function handlePatchUserRequests(xhr: MockXhr): MockResponse { + // Get the key of the person to change + const key = getUserKeyFromUrl(xhr.url); + + // Get the list of changes + const changes = getUserDataFromRequestBody(xhr.requestBody || ""); + + // Check if the UserName is changed to a duplicate. + // If the UserName is "changed" to its current value, that is not an error. + if (Object.prototype.hasOwnProperty.call(changes, "UserName") + && changes.UserName !== key + && !isUnique(changes.UserName)) { + // Error + const responseBody = duplicateKeyError(changes.UserName); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; + } + // No error: make the change(s) + const user = users[findUserIndex(key || "")]; + for (const fieldName in changes) { + if (Object.prototype.hasOwnProperty.call(changes, fieldName)) { + user[fieldName] = changes[fieldName]; + } + } + + // The response to PATCH requests is always http 204 (No Content) + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Handles DELETE requests for users and returns a fitting response. + */ +function handleDeleteUserRequests(xhr: MockXhr): MockResponse { + const key = getUserKeyFromUrl(xhr.url); + users.splice(findUserIndex(key || ""), 1); + + // The response to DELETE requests is always http 204 (No Content) + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Handles POST requests for users and returns a fitting response. + */ +function handlePostUserRequests(xhr: MockXhr): MockResponse { + const user = getUserDataFromRequestBody(xhr.requestBody || ""); + + // Check if that user already exists + if (isUnique(user.UserName)) { + users.push(user); + + let responseBody = '{"@odata.context": "' + getBaseUrl(xhr.url) + + '$metadata#People/$entity",'; + responseBody += JSON.stringify(user).slice(1); + + // The response to POST requests is http 201 (Created) + return [ + 201, + { + "Content-Type": "application/json; odata.metadata=minimal", + "OData-Version": "4.0" + }, + responseBody + ]; + } + // Error + const responseBody = duplicateKeyError(user.UserName); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; +} + +/** + * Handles POST requests for resetting the data and returns a fitting response. + */ +function handleResetDataRequest(): MockResponse { + void readData(); + + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Builds a response to direct (= non-batch) requests. + * Supports GET, PATCH, DELETE and POST requests. + */ +function handleDirectRequest(xhr: MockXhr): MockResponse | undefined { + let response2: MockResponse | undefined; + + switch (xhr.method) { + case "GET": + if (/\$metadata/.test(xhr.url)) { + response2 = handleGetMetadataRequests(); + } else if (/\/\$count/.test(xhr.url)) { + response2 = handleGetCountRequests(); + } else if (/People.*\?/.test(xhr.url)) { + response2 = handleGetUserRequests(xhr, /\$count=true/.test(xhr.url)); + } + break; + case "PATCH": + if (/People/.test(xhr.url)) { + response2 = handlePatchUserRequests(xhr); + } + break; + case "POST": + if (/People/.test(xhr.url)) { + response2 = handlePostUserRequests(xhr); + } else if (/ResetDataSource/.test(xhr.url)) { + response2 = handleResetDataRequest(); + } + break; + case "DELETE": + if (/People/.test(xhr.url)) { + response2 = handleDeleteUserRequests(xhr); + } + break; + case "HEAD": + response2 = [204, {}]; + break; + default: + break; + } + + return response2; +} + +/** + * Builds a response to batch requests. + * Unwraps batch request, gets a response for each individual part and + * constructs a fitting batch response. + */ +function handleBatchRequest(xhr: MockXhr): MockResponse { + let responseBody = ""; + const outerBoundary = (xhr.requestBody || "").match(/(.*)/)![1]; // First line of the body + let innerBoundary: string | undefined; + let partBoundary: string; + // The individual requests + const outerParts = (xhr.requestBody || "").split(outerBoundary).slice(1, -1); + let parts: string[]; + let header: string; + + const matches = outerParts[0].match(/multipart\/mixed;boundary=(.+)/); + // If this request has several change sets, then we need to handle the inner and outer + // boundaries (change sets have an additional boundary) + if (matches && matches.length > 0) { + innerBoundary = matches[1]; + parts = outerParts[0].split("--" + innerBoundary).slice(1, -1); + } else { + parts = outerParts; + } + + // If this request has several change sets, then the response must start with the outer + // boundary and content header + if (innerBoundary) { + partBoundary = "--" + innerBoundary; + responseBody += outerBoundary + "\r\n" + + "Content-Type: multipart/mixed; boundary=" + innerBoundary + "\r\n\r\n"; + } else { + partBoundary = outerBoundary; + } + + parts.forEach((part, index) => { + // Construct the batch response body out of the single batch request parts. + const matches0 = part.match(/(GET|DELETE|PATCH|POST) (\S+)(?:.|\r?\n)+\r?\n(.*)\r?\n$/)!; + const partResponse = handleDirectRequest({ + method: matches0[1], + url: getBaseUrl(xhr.url) + matches0[2], + requestBody: matches0[3] + })!; + + responseBody += partBoundary + "\r\n" + + "Content-Type: application/http\r\n"; + // If there are several change sets, we need to add a Content ID header + if (innerBoundary) { + responseBody += "Content-ID:" + index + ".0\r\n"; + } + responseBody += "\r\nHttp/1.1 " + partResponse[0] + "\r\n"; + // Add any headers from the request - unless this response is 204 (no content) + if (partResponse[1] && partResponse[0] !== 204) { + for (header in partResponse[1]) { + if (Object.prototype.hasOwnProperty.call(partResponse[1], header)) { + responseBody += header + ": " + partResponse[1][header] + "\r\n"; + } + } + } + responseBody += "\r\n"; + + if (partResponse[2]) { + responseBody += partResponse[2]; + } + responseBody += "\r\n"; + }); + + // Check if we need to add the inner boundary again at the end + if (innerBoundary) { + responseBody += "--" + innerBoundary + "--\r\n"; + } + // Add a final boundary to the batch response body + responseBody += outerBoundary + "--"; + + // Build the final batch response + return [ + 200, + { + "Content-Type": "multipart/mixed;boundary=" + outerBoundary.slice(2), + "OData-Version": "4.0" + }, + responseBody + ]; +} + +/** + * Handles any type of intercepted request and sends a fake response. + * Logs the request and response to the console. + * Manages batch requests. + */ +function handleAllRequests(xhr: MockXhr): void { + let response2: MockResponse | undefined; + + // Log the request + Log.info( + "Mockserver: Received " + xhr.method + " request to URL " + xhr.url, + (xhr.requestBody ? "Request body is:\n" + xhr.requestBody : "No request body.") + + "\n", + logComponent + ); + + if (xhr.method === "POST" && /\$batch/.test(xhr.url)) { + response2 = handleBatchRequest(xhr); + } else { + response2 = handleDirectRequest(xhr); + } + + if (xhr.respond && response2) { + xhr.respond(response2[0], response2[1], response2[2] || null); + } + + // Log the response + if (response2) { + Log.info( + "Mockserver: Sent response with return code " + response2[0], + ("Response headers: " + JSON.stringify(response2[1]) + "\n\nResponse body:\n" + + (response2[2] || "")) + "\n", + logComponent + ); + } +} + +export default { + + /** + * Creates a Sinon fake service, intercepting all http requests to + * the URL defined in variable rBaseUrl above. + * @returns a promise that is resolved when the mock server is started + */ + init(): Promise { + // Load sinon lazily from the UI5 third-party shim + return new Promise((resolve, reject) => { + sap.ui.require(["sap/ui/thirdparty/sinon"], (sinon: any) => { + sinon = sinon; + sandbox = sinon.sandbox.create(); + + // Read the mock data + readData().then(() => { + // Initialize the sinon fake server + sandbox.useFakeServer(); + // Make sure that requests are responded to automatically. Otherwise we would need + // to do that manually. + sandbox.server.autoRespond = true; + + // Register the requests for which responses should be faked. + sandbox.server.respondWith(rBaseUrl, handleAllRequests); + + // Apply a filter to the fake XmlHttpRequest. + // Otherwise, ALL requests (e.g. for the component, views etc.) would be + // intercepted. + sinon.FakeXMLHttpRequest.useFilters = true; + sinon.FakeXMLHttpRequest.addFilter((_sMethod: string, url: string) => { + // If the filter returns true, the request will NOT be faked. + // We only want to fake requests that go to the intended service. + return !rBaseUrl.test(url); + }); + + // Set the logging level for console entries from the mock server + Log.setLevel(Log.Level.INFO, logComponent); + + Log.info("Running the app with mock data", logComponent); + resolve(undefined); + }, reject); + }); + }); + }, + + /** + * Stops the request interception and deletes the Sinon fake server. + */ + stop(): void { + if (sinon) { + sinon.FakeXMLHttpRequest.filters = []; + sinon.FakeXMLHttpRequest.useFilters = false; + } + if (sandbox) { + sandbox.restore(); + sandbox = null; + } + } +}; diff --git a/packages/odatav4/steps/08/webapp/manifest.json b/packages/odatav4/steps/08/webapp/manifest.json new file mode 100644 index 000000000..65b3dfb42 --- /dev/null +++ b/packages/odatav4/steps/08/webapp/manifest.json @@ -0,0 +1,67 @@ +{ + "_version": "1.60.0", + "sap.app": { + "id": "ui5.tutorial.odatav4", + "type": "application", + "i18n": { + "supportedLocales": [ + "" + ], + "fallbackLocale": "", + "bundleName": "ui5.tutorial.odatav4.i18n.i18n" + }, + "applicationVersion": { + "version": "1.0.0" + }, + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "dataSources": { + "default": { + "uri": "https://services.odata.org/TripPinRESTierService/(S(id))/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + } + }, + "sap.ui": { + "technology": "UI5" + }, + "sap.ui5": { + "rootView": { + "viewName": "ui5.tutorial.odatav4.view.App", + "type": "XML", + "id": "appView" + }, + "dependencies": { + "minUI5Version": "1.132", + "libs": { + "sap.m": {}, + "sap.ui.core": {} + } + }, + "handleValidation": true, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "ui5.tutorial.odatav4.i18n.i18n", + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + } + }, + "": { + "dataSource": "default", + "preload": true, + "settings": { + "autoExpandSelect": true, + "earlyRequests": true, + "operationMode": "Server" + } + } + } + } +} diff --git a/packages/odatav4/steps/08/webapp/model/models.ts b/packages/odatav4/steps/08/webapp/model/models.ts new file mode 100644 index 000000000..5fdcff4a3 --- /dev/null +++ b/packages/odatav4/steps/08/webapp/model/models.ts @@ -0,0 +1,10 @@ +// models.ts — central application models +import JSONModel from "sap/ui/model/json/JSONModel"; +import Device from "sap/ui/Device"; + +export function createDeviceModel(): JSONModel { + const model = new JSONModel(Device); + + model.setDefaultBindingMode("OneWay"); + return model; +} diff --git a/packages/odatav4/steps/08/webapp/test/integration/AllJourneys.js b/packages/odatav4/steps/08/webapp/test/integration/AllJourneys.js new file mode 100644 index 000000000..c52c9ead3 --- /dev/null +++ b/packages/odatav4/steps/08/webapp/test/integration/AllJourneys.js @@ -0,0 +1,13 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/core/tutorial/odatav4/test/integration/arrangements/Startup", + "sap/ui/core/tutorial/odatav4/test/integration/TutorialJourney" +], function (Opa5, Startup) { + "use strict"; + + Opa5.extendConfig({ + arrangements : new Startup(), + viewNamespace : "sap.ui.core.tutorial.odatav4.view.", + autoWait : true + }); +}); diff --git a/packages/odatav4/steps/08/webapp/test/integration/TutorialJourney.js b/packages/odatav4/steps/08/webapp/test/integration/TutorialJourney.js new file mode 100644 index 000000000..18391b31d --- /dev/null +++ b/packages/odatav4/steps/08/webapp/test/integration/TutorialJourney.js @@ -0,0 +1,122 @@ +sap.ui.define([ + "sap/ui/test/opaQunit", + "sap/ui/core/tutorial/odatav4/test/integration/pages/Tutorial" +], function (opaTest) { + "use strict"; + + var iGrowingBy = 10, // Must equal the 'growingThreshold' setting of the table + iTotalUsers = 20; // Must equal the total number of users + + QUnit.module("Posts"); + + opaTest("Should see the paginated table with all users", function (Given, _When, Then) { + // Arrangements + Given.iStartMyApp(); + // Assertions + Then.onTheTutorialPage.theTableShouldHavePagination() + .and.theTableShouldShowUsers(iGrowingBy) + .and.theTableShouldShowTotalUsers(iTotalUsers); + }); + + opaTest("Should be able to load more users", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iPressOnMoreData(); + // Assertions + Then.onTheTutorialPage.theTableShouldShowUsers(iGrowingBy * 2); + }); + + opaTest("Should be able to sort users", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iPressOnSort(); + // Assertions + Then.onTheTutorialPage.theTableShouldStartWith("Alfred"); + }); + + opaTest("Should be able to start adding users", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iPressOnAdd() + .and.iEnterSomeData("a"); + When.onTheTutorialPage.iPressOnAdd() + .and.iEnterSomeData("b"); + // Assertions + Then.onTheTutorialPage.thePageFooterShouldBeVisible(true) + .and.theTableToolbarItemsShouldBeEnabled(false) + .and.theTableShouldShowTotalUsers(iTotalUsers + 2); + }); + + opaTest("Should be able to save the new users", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iPressOnSave(); + // Assertions + Then.onTheTutorialPage.theTableShouldStartWith("b") + .and.theTableShouldShowTotalUsers(iTotalUsers + 2) + .and.theTableToolbarItemsShouldBeEnabled(true) + .and.thePageFooterShouldBeVisible(false); + }); + + opaTest("Should be able to delete/undelete the new users", function (_Given, When, Then) { + // delete and undelete + When.onTheTutorialPage.iSelectUser("b") + .and.iPressOnDelete(); + Then.onTheTutorialPage.theTableShouldStartWith("a") + .and.theTableShouldShowTotalUsers(iTotalUsers + 1); + When.onTheTutorialPage.iSelectUser("a") + .and.iPressOnDelete(); + Then.onTheTutorialPage.theTableShouldStartWith("Alfred") + .and.theTableShouldShowTotalUsers(iTotalUsers); + When.onTheTutorialPage.iPressOnCancel(); + Then.onTheTutorialPage.theMessageToastShouldShow("deletionRestoredMessage", "b") + .and.theMessageToastShouldShow("deletionRestoredMessage", "a") + .and.theTableShouldStartWith("b") + .and.theTableShouldShowTotalUsers(iTotalUsers + 2); + // delete and save + When.onTheTutorialPage.iSelectUser("a") + .and.iPressOnDelete() + .and.iSelectUser("b") + .and.iPressOnDelete() + .and.iPressOnSave(); + Then.onTheTutorialPage.theMessageToastShouldShow("deletionSuccessMessage", "a") + .and.theMessageToastShouldShow("deletionSuccessMessage", "b") + .and.theTableShouldStartWith("Alfred") + .and.theTableShouldShowTotalUsers(iTotalUsers); + }); + + opaTest("Should be able to search for users", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iSearchFor("Mundy"); + // Assertions + Then.onTheTutorialPage.theTableShouldShowUsers(1); + }); + + opaTest("Should be able to reset the search", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iSearchFor(""); + // Assertions + Then.onTheTutorialPage.theTableShouldShowUsers(10); + }); + + opaTest("Should see an error when trying to change a user name to an existing one", + function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iChangeAUserKey("javieralfred", "willieashmore") + .and.iPressOnSave(); + // Assertions + Then.onTheTutorialPage.iShouldSeeAServiceError() + .and.theTableToolbarItemsShouldBeEnabled(false) + .and.thePageFooterShouldBeVisible(true); + } + ); + + opaTest("Should be able to close the error and cancel the change", + function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iCloseTheServiceError() + .and.iPressOnCancel(); + // Assertions + Then.onTheTutorialPage.theTableToolbarItemsShouldBeEnabled(true) + .and.thePageFooterShouldBeVisible(false); + // Cleanup + Then.iTeardownMyApp(); + } + ); +}); diff --git a/packages/odatav4/steps/08/webapp/test/integration/arrangements/Startup.js b/packages/odatav4/steps/08/webapp/test/integration/arrangements/Startup.js new file mode 100644 index 000000000..5eb7219a3 --- /dev/null +++ b/packages/odatav4/steps/08/webapp/test/integration/arrangements/Startup.js @@ -0,0 +1,24 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/core/tutorial/odatav4/localService/mockserver" +], function (Opa5, mockserver) { + "use strict"; + + return Opa5.extend("sap.ui.core.tutorial.odatav4.test.integration.arrangements.Startup", { + + iStartMyApp : function () { + // start the mock server + this.iWaitForPromise(mockserver.init()); + + // start the app UI component + this.iStartMyUIComponent({ + componentConfig : { + name : "sap.ui.core.tutorial.odatav4", + async : true + }, + autoWait : true, + timeout : 45 // BCP: 2270085466 + }); + } + }); +}); diff --git a/packages/odatav4/steps/08/webapp/test/integration/opaTests.qunit.html b/packages/odatav4/steps/08/webapp/test/integration/opaTests.qunit.html new file mode 100644 index 000000000..9cdceff2c --- /dev/null +++ b/packages/odatav4/steps/08/webapp/test/integration/opaTests.qunit.html @@ -0,0 +1,27 @@ + + + + Integration tests for OData V4 Tutorial + + + + + + + + + + + + +
+
+ + \ No newline at end of file diff --git a/packages/odatav4/steps/08/webapp/test/integration/opaTests.qunit.js b/packages/odatav4/steps/08/webapp/test/integration/opaTests.qunit.js new file mode 100644 index 000000000..0cc870429 --- /dev/null +++ b/packages/odatav4/steps/08/webapp/test/integration/opaTests.qunit.js @@ -0,0 +1,11 @@ +QUnit.config.autostart = false; + +sap.ui.require([ + "sap/ui/core/Core", + "sap/ui/core/tutorial/odatav4/test/integration/AllJourneys" +], function (Core) { + "use strict"; + Core.ready().then(function () { + QUnit.start(); + }); +}); diff --git a/packages/odatav4/steps/08/webapp/test/integration/pages/Tutorial.js b/packages/odatav4/steps/08/webapp/test/integration/pages/Tutorial.js new file mode 100644 index 000000000..29e33dacd --- /dev/null +++ b/packages/odatav4/steps/08/webapp/test/integration/pages/Tutorial.js @@ -0,0 +1,300 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/test/matchers/AggregationLengthEquals", + "sap/ui/test/matchers/PropertyStrictEquals", + "sap/ui/test/matchers/BindingPath", + "sap/ui/test/actions/Press", + "sap/ui/test/actions/EnterText" +], function (Opa5, AggregationLengthEquals, PropertyStrictEquals, BindingPath, Press, EnterText) { + "use strict"; + + var sViewName = "App", + sTableId = "peopleList"; + + function getListBinding(oTable) { + return oTable.getBinding("items"); + } + + function getFirstTableEntry(oTable) { + return getListBinding(oTable).getCurrentContexts()[0]; + } + + Opa5.createPageObjects({ + onTheTutorialPage : { + actions : { + iPressOnMoreData : function () { + // Press action hits the "more" trigger on a table + return this.waitFor({ + id : sTableId, + viewName : sViewName, + actions : new Press(), + errorMessage : "Table not found or it does not have a 'See More' trigger" + }); + }, + + iPressOnSort : function () { + return this.waitFor({ + id : "sortUsersButton", + viewName : sViewName, + actions : new Press(), + errorMessage : "Could not find the 'Sort' button" + }); + }, + + iPressOnAdd : function () { + return this.waitFor({ + id : "addUserButton", + viewName : sViewName, + actions : new Press(), + errorMessage : "Could not find the 'Add' button" + }); + }, + + iPressOnDelete : function () { + return this.waitFor({ + id : "deleteUserButton", + viewName : sViewName, + actions : new Press(), + errorMessage : "Could not find the 'Delete' button" + }); + }, + + iPressOnSave : function () { + return this.waitFor({ + id : "saveButton", + viewName : sViewName, + actions : new Press(), + errorMessage : "Could not find the 'Save' button" + }); + }, + + iPressOnCancel : function () { + return this.waitFor({ + id : "doneButton", + viewName : sViewName, + actions : new Press(), + errorMessage : "Could not find the 'Cancel' button" + }); + }, + + iEnterSomeData : function (sValue) { + return this.waitFor({ + controlType : "sap.m.Input", + viewName : sViewName, + matchers : [ + // Find the input fields for the new entry + function (oControl) { + return oControl.getBindingContext().getIndex() === 0; + }, + // Keep only empty input fields + function (oItem) { + return !oItem.getValue(); + } + ], + actions : new EnterText({ + text : sValue + }), + errorMessage : "Could not find Input controls to enter data" + }); + }, + + iSearchFor : function (sSearchString) { + return this.waitFor({ + id : "searchField", + viewName : sViewName, + actions : new EnterText({ + text : sSearchString + }), + errorMessage : "SearchField was not found" + }); + }, + + iSelectUser : function (sKey) { + return this.waitFor({ + controlType : "sap.m.ColumnListItem", + viewName : sViewName, + matchers : new BindingPath({ + path : "/People('" + sKey + "')" + }), + actions : function (oItem) { + oItem.setSelected(true); + }, + errorMessage : "Could not find a user with the key '" + sKey + "'" + }); + }, + + iChangeAUserKey : function (sOldKey, sNewKey) { + return this.waitFor({ + controlType : "sap.m.Input", + viewName : sViewName, + matchers : new PropertyStrictEquals({ + name : "value", + value : sOldKey + }), + actions : new EnterText({ + text : sNewKey + }), + errorMessage : "Could not find a user with the key '" + sOldKey + "'" + }); + }, + + iCloseTheServiceError : function () { + return this.waitFor({ + id : "serviceErrorMessageBox", + success : function () { + this.waitFor({ + controlType : "sap.m.Button", + searchOpenDialogs : true, + // The error MessageBox has only one button, which closes the box + actions : new Press(), + errorMessage : "Cannot find the 'Close' button" + }); + }, + errorMessage : "Could not see the service error dialog" + }); + } + }, + assertions : { + theTableShouldHavePagination : function () { + return this.waitFor({ + id : sTableId, + viewName : sViewName, + matchers : new PropertyStrictEquals({ + name : "growing", + value : true + }), + success : function () { + Opa5.assert.ok(true, "The table is paginated"); + }, + errorMessage : "Table not found or it is not paginated" + }); + }, + + theTableShouldShowUsers : function (iNumber) { + return this.waitFor({ + id : sTableId, + viewName : sViewName, + matchers : new AggregationLengthEquals({ + name : "items", + length : iNumber + }), + success : function () { + Opa5.assert.ok(true, "The table has " + + iNumber + " items"); + }, + errorMessage : "Table not found or it does not have " + + iNumber + " entries" + }); + }, + + theTableShouldShowTotalUsers : function (iNumber) { + return this.waitFor({ + id : sTableId, + viewName : sViewName, + matchers : function (oTable) { + var oListBinding = getListBinding(oTable); + + return oListBinding && oListBinding.getLength() === iNumber; + }, + success : function () { + Opa5.assert.ok(true, "The table shows a total of " + iNumber + + " users"); + }, + errorMessage : "Table not found or it does not show " + iNumber + + " total users" + }); + }, + + theTableShouldStartWith : function (sLastName) { + return this.waitFor({ + id : sTableId, + viewName : sViewName, + matchers : function (oTable) { + var oFirstItem = getFirstTableEntry(oTable); + + return oFirstItem && oFirstItem.getProperty("LastName") === sLastName; + }, + success : function () { + Opa5.assert.ok(true, "The table is sorted correctly"); + }, + errorMessage : "Table not found or it is not sorted correctl." + }); + }, + + thePageFooterShouldBeVisible : function (bVisible) { + var sDesiredState = bVisible ? "visible" : "invisible"; + + return this.waitFor({ + controlType : "sap.m.Toolbar", + viewName : sViewName, + visible : false, + matchers : new PropertyStrictEquals({ + name : "visible", + value : bVisible + }), + success : function () { + Opa5.assert.ok(true, "The toolbar is " + sDesiredState); + }, + errorMessage : "Toolbar not found or is not " + sDesiredState + }); + }, + + theTableToolbarItemsShouldBeEnabled : function (bEnabled) { + var sDesiredState = bEnabled ? "enabled" : "disabled"; + + return this.waitFor({ + id : /searchField$|refreshUsersButton$|sortUsersButton$/, + viewName : sViewName, + autoWait : false, // Needed because we want to find disabled controls, too + matchers : new PropertyStrictEquals({ + name : "enabled", + value : bEnabled + }), + check : function (aControls) { + // Validate that ALL controls have the right state + return aControls.length === 3; + }, + success : function () { + Opa5.assert.ok(true, "All controls in the table toolbar are " + + sDesiredState); + }, + errorMessage : "Not all controls in the table toolbar could be found or " + + "not all are " + sDesiredState + }); + }, + + theMessageToastShouldShow : function (sTextId, sArg0) { + return this.waitFor({ + autoWait : false, + id : sTableId, + viewName : sViewName, + check : function (oControl) { + // Locate the message toast using its CSS class name and content + var sText = oControl.getModel("i18n").getResourceBundle() + .getText(sTextId, [sArg0]), + sSelector = ".sapMMessageToast:contains('" + sText + "')"; + + return !!Opa5.getJQuery()(sSelector).length; + }, + success : function () { + Opa5.assert.ok(true, "Could see the MessageToast showing text with ID " + + sTextId); + }, + errorMessage : "Could not see a MessageToast showing text with ID " + + sTextId + }); + }, + + iShouldSeeAServiceError : function () { + return this.waitFor({ + id : "serviceErrorMessageBox", + success : function () { + Opa5.assert.ok(true, "Could see the service error dialog"); + }, + errorMessage : "Could not see the service error dialog" + }); + } + } + } + }); +}); diff --git a/packages/odatav4/steps/08/webapp/view/App.view.xml b/packages/odatav4/steps/08/webapp/view/App.view.xml new file mode 100644 index 000000000..cc21802a0 --- /dev/null +++ b/packages/odatav4/steps/08/webapp/view/App.view.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+
+
+
+
\ No newline at end of file diff --git a/packages/odatav4/steps/09/README.md b/packages/odatav4/steps/09/README.md new file mode 100644 index 000000000..df924d3de --- /dev/null +++ b/packages/odatav4/steps/09/README.md @@ -0,0 +1,362 @@ +# Step 9: List-Detail Scenario + +
+ +You can download the solution for this step here: [📥 Download step 9](https://ui5.github.io/tutorials/odatav4/odatav4-step-09.zip). + +
+ +
+ +You can download the solution for this step here: [📥 Download step 9](https://ui5.github.io/tutorials/odatav4/odatav4-step-09-js.zip). + +
+ +In this step we add a detail area with additional information. + +## Preview + +**A detail area containing information about the selected user is added** + +![A list of users with an added detail area](assets/Tut_OD4_Step_9_6e9025b.png "A detail area containing information about the selected user is added") + +## Coding + +You can view this step live: [🔗 Live Preview of Step 9](https://ui5.github.io/tutorials/odatav4/build/09/index-cdn.html). + +## `webapp/controller/App.controller.?s` + +```ts +... + onDelete() { + const oContext, + oPeopleList = this.byId("peopleList"), + oSelected = oPeopleList.getSelectedItem(), + sUserName; + + if (oSelected) { + oContext = oSelected.getBindingContext(); + sUserName = oContext.getProperty("UserName"); + oContext.delete().then(function () { + MessageToast.show(this._getText("deletionSuccessMessage", sUserName)); + }.bind(this), function (oError) { + if (oContext === oPeopleList.getSelectedItem().getBindingContext()) { + this._setDetailArea(oContext); + } + this._setUIChanges(); + if (oError.canceled) { + MessageToast.show(this._getText("deletionRestoredMessage", sUserName)); + return; + } + MessageBox.error(oError.message + ": " + sUserName); + }.bind(this)); + this._setDetailArea(); + this._setUIChanges(true); + } + }, +... + onMessageBindingChange(oEvent) { + ... + }, + + onSelectionChange(oEvent) { + this._setDetailArea(oEvent.getParameter("listItem").getBindingContext()); + }, + +... + /** + * Toggles the visibility of the detail area + * + * @param {object} [oUserContext] - the current user context + */ + _setDetailArea(oUserContext) { + const oDetailArea = this.byId("detailArea"), + oLayout = this.byId("defaultLayout"), + oSearchField = this.byId("searchField"); + + oDetailArea.setBindingContext(oUserContext || null); + // resize view + oDetailArea.setVisible(!!oUserContext); + oLayout.setSize(oUserContext ? "60%" : "100%"); + oLayout.setResizable(!!oUserContext); + oSearchField.setWidth(oUserContext ? "40%" : "20%"); + } +``` + +```js +... + onDelete : function () { + var oContext, + oPeopleList = this.byId("peopleList"), + oSelected = oPeopleList.getSelectedItem(), + sUserName; + + if (oSelected) { + oContext = oSelected.getBindingContext(); + sUserName = oContext.getProperty("UserName"); + oContext.delete().then(function () { + MessageToast.show(this._getText("deletionSuccessMessage", sUserName)); + }.bind(this), function (oError) { + if (oContext === oPeopleList.getSelectedItem().getBindingContext()) { + this._setDetailArea(oContext); + } + this._setUIChanges(); + if (oError.canceled) { + MessageToast.show(this._getText("deletionRestoredMessage", sUserName)); + return; + } + MessageBox.error(oError.message + ": " + sUserName); + }.bind(this)); + this._setDetailArea(); + this._setUIChanges(true); + } + }, +... + onMessageBindingChange : function (oEvent) { + ... + }, + + onSelectionChange : function (oEvent) { + this._setDetailArea(oEvent.getParameter("listItem").getBindingContext()); + }, + +... + /** + * Toggles the visibility of the detail area + * + * @param {object} [oUserContext] - the current user context + */ + _setDetailArea : function (oUserContext) { + var oDetailArea = this.byId("detailArea"), + oLayout = this.byId("defaultLayout"), + oSearchField = this.byId("searchField"); + + oDetailArea.setBindingContext(oUserContext || null); + // resize view + oDetailArea.setVisible(!!oUserContext); + oLayout.setSize(oUserContext ? "60%" : "100%"); + oLayout.setResizable(!!oUserContext); + oSearchField.setWidth(oUserContext ? "40%" : "20%"); + } +``` + +The `onSelectionChange` event handler retrieves the context of the selected list item and passes it to a new `_setDetailArea` function. Within `_setDetailArea`, the given context is passed as binding context for the semantic page detail area. + +Afterwards the detail area is made visible and is resized. + +The application also needs to close the detail area if its binding context is deleted. If the deleted context is restored after a failed DELETE request, or undeleted via `Context#resetChanges`, it could be shown in the detail area again, unless the user had selected another row in the meantime. Hence, we call `_setDetailArea` without a context once the context gets deleted, and with the restored context in the error handler of the `Context#delete` API. In `_setDetailArea` we resize the view based on the given context in an appropriate way. + +## webapp/view/App.view.xml + +```xml + + + + + ... + + + + + + + + + + ... + + ... +
+
+ + + + + + + </semantic:titleHeading> + <semantic:headerContent> + <FlexBox> + <VBox> + <ObjectAttribute text="{i18n>userNameLabelText}"/> + <ObjectAttribute text="{UserName}"/> + </VBox> + <VBox class="sapUiMediumMarginBegin"> + <ObjectAttribute text="{i18n>ageLabelText}"/> + <ObjectNumber number="{Age}" unit="Years"/> + </VBox> + </FlexBox> + </semantic:headerContent> + <semantic:content> + <VBox> + <FlexBox wrap="Wrap"> + <f:Form editable="false"> + <f:title> + <core:Title text="{i18n>addressTitleText}" /> + </f:title> + <f:layout> + <f:ResponsiveGridLayout + labelSpanXL="3" + labelSpanL="3" + labelSpanM="3" + labelSpanS="12" + adjustLabelSpan="false" + emptySpanXL="4" + emptySpanL="4" + emptySpanM="4" + emptySpanS="0" + columnsXL="1" + columnsL="1" + columnsM="1" + singleContainerFullSize="false" /> + </f:layout> + <f:formContainers> + <f:FormContainer> + <f:formElements> + <f:FormElement label="{i18n>addressLabelText}"> + <f:fields> + <Text text="{HomeAddress/Address}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>cityLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/Name}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>regionLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/Region}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>countryLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/CountryRegion}" /> + </f:fields> + </f:FormElement> + </f:formElements> + </f:FormContainer> + </f:formContainers> + </f:Form> + <f:Form editable="false"> + <f:title> + <core:Title text="{i18n>bestFriendTitleText}" /> + </f:title> + <f:layout> + <f:ResponsiveGridLayout + labelSpanXL="3" + labelSpanL="3" + labelSpanM="3" + labelSpanS="12" + adjustLabelSpan="false" + emptySpanXL="4" + emptySpanL="4" + emptySpanM="4" + emptySpanS="0" + columnsXL="1" + columnsL="1" + columnsM="1" + singleContainerFullSize="false" /> + </f:layout> + <f:formContainers> + <f:FormContainer> + <f:formElements> + <f:FormElement label="{i18n>nameLabelText}"> + <f:fields> + <Text text="{BestFriend/FirstName} {BestFriend/LastName}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>ageLabelText}"> + <f:fields> + <Text text="{BestFriend/Age}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>userNameLabelText}"> + <f:fields> + <Text text="{BestFriend/UserName}" /> + </f:fields> + </f:FormElement> + </f:formElements> + </f:FormContainer> + </f:formContainers> + </f:Form> + </FlexBox> + </VBox> + </semantic:content> + </semantic:SemanticPage> + </l:SplitPane> + </l:PaneContainer> + </l:ResponsiveSplitter> + </content> + ... +</mvc:View> +``` + +Several new namespaces are added to the `appView`. After the `<content>` and before the `<Table>` tag the first part of the `SplitPane` is added. + +We add a detail area after the user table. In the `appView` we add a splitter layout around the existing table. The first `SplitPane` contains the table with all users, and the second one contains the new detail area. It consists of two forms, one for the address information, and the other one for the best friend of the currently selected user. We also add the `onSelectionChange` event handler to the user table. + +It is important that all bindings we introduced in the detail area are relative \(property\) bindings, so that we can reuse data of the list. This allows our application to share data like the user name or the age between the user selected in the table and the detail area. This helps to avoid redundant requests and to keep the data between the two areas in sync. Editing a property in the user table will thus automatically be reflected in the detail area as well. + +One of the most vital parts of the data reuse functionality is the usage of the `autoExpandSelect` binding parameter. It permits us to put a tailored `$select` clause in the `GET` request, so that only missing properties are requested for display in the detail area. + +## webapp/i18n/i18n.properties + +```ini +... +# Detail Area +#XTIT: Title for Address +addressTitleText=Address + +#XFLD: Label for Address +addressLabelText=Address + +#XFLD: Label for City +cityLabelText=City + +#XFLD: Label for Region +regionLabelText=Region + +#XFLD: Label for Country +countryLabelText=Country + +#XTIT: Title for Best Friend +bestFriendTitleText=Best Friend + +#XFLD: Label for Best Friend Name +nameLabelText=Name + +``` + +We add the missing texts to the properties file. + +**Related Information** + +[Data Reuse](../04_Essentials/data-reuse-648e360.md "The OData V4 model keeps data with respect to bindings, which allows different views on the same data, but also means that data is not automatically shared between bindings. There are mechanisms for sharing data to avoid redundant requests and to keep the same data in different controls in sync.") + +*** + +**Previous:** [Step 8: OData Operations](../08/README.md) diff --git a/packages/odatav4/steps/09/package.json b/packages/odatav4/steps/09/package.json new file mode 100644 index 000000000..75fc79273 --- /dev/null +++ b/packages/odatav4/steps/09/package.json @@ -0,0 +1,19 @@ +{ + "name": "ui5.tutorial.odatav4.step09", + "version": "1.0.0", + "author": "SAP SE", + "description": "OpenUI5 TypeScript Tutorial — OData V4: Step 9 — List-Detail Scenario", + "private": true, + "scripts": { + "start": "ui5 serve -o index.html", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } +} diff --git a/packages/odatav4/steps/09/tsconfig.json b/packages/odatav4/steps/09/tsconfig.json new file mode 100644 index 000000000..1044f76cd --- /dev/null +++ b/packages/odatav4/steps/09/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "es2023", + "types": [ + "node", + "@types/openui5" + ], + "skipLibCheck": true, + "allowJs": true, + "strictPropertyInitialization": false, + "rootDir": "./webapp", + "paths": { + "ui5/tutorial/odatav4/*": [ + "./webapp/*" + ] + }, + "strict": false, + "strictNullChecks": false + }, + "include": [ + "./webapp/**/*" + ] +} diff --git a/packages/odatav4/steps/09/ui5.yaml b/packages/odatav4/steps/09/ui5.yaml new file mode 100644 index 000000000..e1ca8e9c2 --- /dev/null +++ b/packages/odatav4/steps/09/ui5.yaml @@ -0,0 +1,25 @@ +specVersion: '3.0' +metadata: + name: "ui5.tutorial.odatav4" +type: application +framework: + name: OpenUI5 + version: "1.147.1" + libraries: + - name: sap.m + - name: sap.f + - name: sap.ui.layout + - name: sap.ui.core + - name: themelib_sap_horizon +builder: + customTasks: + - name: ui5-tooling-transpile-task + afterTask: replaceVersion +server: + customMiddleware: + - name: ui5-tooling-transpile-middleware + afterMiddleware: compression + - name: ui5-middleware-serveframework + afterMiddleware: compression + - name: ui5-middleware-livereload + afterMiddleware: compression diff --git a/packages/odatav4/steps/09/webapp/Component.ts b/packages/odatav4/steps/09/webapp/Component.ts new file mode 100644 index 000000000..170cbb94c --- /dev/null +++ b/packages/odatav4/steps/09/webapp/Component.ts @@ -0,0 +1,27 @@ +// Component.ts — UI5 OData V4 Tutorial +import UIComponent from "sap/ui/core/UIComponent"; +import { createDeviceModel } from "./model/models"; + +/** + * @namespace ui5.tutorial.odatav4 + */ +export default class Component extends UIComponent { + public static metadata = { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + manifest: "json" + }; + + /** + * The component is initialized by UI5 automatically during the startup of the app and calls + * the init method once. + * @public + * @override + */ + init(): void { + // call the base component's init function + super.init(); + + // set the device model + this.setModel(createDeviceModel(), "device"); + } +} diff --git a/packages/odatav4/steps/09/webapp/controller/App.controller.ts b/packages/odatav4/steps/09/webapp/controller/App.controller.ts new file mode 100644 index 000000000..664d4e8bf --- /dev/null +++ b/packages/odatav4/steps/09/webapp/controller/App.controller.ts @@ -0,0 +1,303 @@ +import Messaging from "sap/ui/core/Messaging"; +import Controller from "sap/ui/core/mvc/Controller"; +import MessageToast from "sap/m/MessageToast"; +import MessageBox from "sap/m/MessageBox"; +import Sorter from "sap/ui/model/Sorter"; +import Filter from "sap/ui/model/Filter"; +import FilterOperator from "sap/ui/model/FilterOperator"; +import FilterType from "sap/ui/model/FilterType"; +import JSONModel from "sap/ui/model/json/JSONModel"; +import ResourceModel from "sap/ui/model/resource/ResourceModel"; +import ResourceBundle from "sap/base/i18n/ResourceBundle"; +import Component from "sap/ui/core/Component"; +import List from "sap/m/List"; +import type ColumnListItem from "sap/m/ColumnListItem"; +import type SearchField from "sap/m/SearchField"; +import type ListBinding from "sap/ui/model/ListBinding"; +import type Event from "sap/ui/base/Event"; +import type Input from "sap/m/Input"; +import type Context from "sap/ui/model/odata/v4/Context"; +import type ODataModel from "sap/ui/model/odata/v4/ODataModel"; +import type ODataListBinding from "sap/ui/model/odata/v4/ODataListBinding"; + +/** + * @namespace ui5.tutorial.odatav4.controller + */ +export default class App extends Controller { + + private _bTechnicalErrors = false; + + /** + * Hook for initializing the controller + */ + onInit(): void { + const messageModel = Messaging.getMessageModel(); + const messageModelBinding = messageModel.bindList("/", undefined, [], + new Filter("technical", FilterOperator.EQ, true)); + const viewModel = new JSONModel({ + busy: false, + hasUIChanges: false, + usernameEmpty: false, + order: 0 + }); + + this.getView().setModel(viewModel, "appView"); + this.getView().setModel(messageModel, "message"); + + messageModelBinding.attachChange(this.onMessageBindingChange, this); + this._bTechnicalErrors = false; + } + + /* =========================================================== */ + /* begin: event handlers */ + /* =========================================================== */ + + /** + * Create a new entry. + */ + onCreate(): void { + const list = this.byId("peopleList") as List; + const binding = list.getBinding("items") as ODataListBinding; + // Create a new entry through the table's list binding + const context = binding.create({ Age: "18" }); + + this._setUIChanges(true); + (this.getView().getModel("appView") as JSONModel).setProperty("/usernameEmpty", true); + + // Select and focus the table row that contains the newly created entry + list.getItems().some((item) => { + const columnItem = item as ColumnListItem; + if (columnItem.getBindingContext() === context) { + columnItem.focus(); + columnItem.setSelected(true); + return true; + } + return false; + }); + } + + /** + * Delete an entry. + */ + onDelete(): void { + const peopleList = this.byId("peopleList") as List; + const selected = peopleList.getSelectedItem() as ColumnListItem | null; + + if (selected) { + const context = selected.getBindingContext() as Context; + const userName = context.getProperty("UserName") as string; + void context.delete().then(() => { + MessageToast.show(this._getText("deletionSuccessMessage", [userName])); + }, (error2: Error & { canceled?: boolean }) => { + const currentSelected = peopleList.getSelectedItem() as ColumnListItem | null; + if (currentSelected && context === currentSelected.getBindingContext()) { + this._setDetailArea(context); + } + this._setUIChanges(); + if (error2.canceled) { + MessageToast.show(this._getText("deletionRestoredMessage", [userName])); + return; + } + MessageBox.error(error2.message + ": " + userName); + }); + this._setDetailArea(); + this._setUIChanges(); + } + } + + /** + * Lock UI when changing data in the input controls + */ + onInputChange(evt: Event): void { + if ((evt as unknown as { getParameter(n: string): unknown }).getParameter("escPressed")) { + this._setUIChanges(); + } else { + this._setUIChanges(true); + // Check if the username in the changed table row is empty and set the appView + // property accordingly + const ctx = (evt.getSource() as Input).getParent()?.getBindingContext(); + if (ctx && ctx.getProperty("UserName")) { + (this.getView().getModel("appView") as JSONModel).setProperty("/usernameEmpty", false); + } + } + } + + /** + * Refresh the data. + */ + onRefresh(): void { + const binding = (this.byId("peopleList") as List).getBinding("items") as ODataListBinding; + + if (binding.hasPendingChanges()) { + MessageBox.error(this._getText("refreshNotPossibleMessage")); + return; + } + binding.refresh(); + MessageToast.show(this._getText("refreshSuccessMessage")); + } + + /** + * Reset any unsaved changes. + */ + onResetChanges(): void { + ((this.byId("peopleList") as List).getBinding("items") as ODataListBinding).resetChanges(); + // If there were technical errors, cancelling changes resets them. + this._bTechnicalErrors = false; + this._setUIChanges(false); + } + + /** + * Reset the data source. + */ + onResetDataSource(): void { + const model = this.getView().getModel() as ODataModel; + const operation = model.bindContext("/ResetDataSource(...)"); + + void operation.invoke().then(() => { + model.refresh(); + MessageToast.show(this._getText("sourceResetSuccessMessage")); + }, (error2: Error) => { + MessageBox.error(error2.message); + }); + } + + /** + * Save changes to the source. + */ + onSave(): void { + const success = () => { + this._setBusy(false); + MessageToast.show(this._getText("changesSentMessage")); + this._setUIChanges(false); + }; + const error = (error2: Error) => { + this._setBusy(false); + this._setUIChanges(false); + MessageBox.error(error2.message); + }; + + this._setBusy(true); // Lock UI until submitBatch is resolved. + (this.getView().getModel() as ODataModel).submitBatch("peopleGroup").then(success, error); + // If there were technical errors, a new save resets them. + this._bTechnicalErrors = false; + } + + /** + * Search for the term in the search field. + */ + onSearch(): void { + const view = this.getView(); + const value = (view.byId("searchField") as SearchField).getValue(); + const filter = new Filter("LastName", FilterOperator.Contains, value); + + ((view.byId("peopleList") as List).getBinding("items") as ListBinding).filter(filter, FilterType.Application); + } + + /** + * Sort the table according to the last name. + * Cycles between the three sorting states "none", "ascending" and "descending" + */ + onSort(): void { + const view = this.getView(); + const states: (string | undefined)[] = [undefined, "asc", "desc"]; + const stateTextIds = ["sortNone", "sortAscending", "sortDescending"]; + let order = (view.getModel("appView") as JSONModel).getProperty("/order") as number; + + // Cycle between the states + order = (order + 1) % states.length; + const order2 = states[order]; + + (view.getModel("appView") as JSONModel).setProperty("/order", order); + ((view.byId("peopleList") as List).getBinding("items") as ListBinding) + .sort(order2 ? new Sorter("LastName", order2 === "desc") : []); + + const message = this._getText("sortMessage", [this._getText(stateTextIds[order])]); + MessageToast.show(message); + } + + onMessageBindingChange(event: Event): void { + const contexts = (event.getSource() as ListBinding).getContexts(); + let messageOpen = false; + + if (messageOpen || !contexts.length) { + return; + } + + // Extract and remove the technical messages + const messages = contexts.map((context: Context) => context.getObject()); + Messaging.removeMessages(messages); + + this._setUIChanges(true); + this._bTechnicalErrors = true; + MessageBox.error((messages[0] as { message: string }).message, { + id: "serviceErrorMessageBox", + onClose: () => { + messageOpen = false; + } + }); + + messageOpen = true; + } + + onSelectionChange(event: Event): void { + const listItem = (event as unknown as { getParameter(n: string): unknown }).getParameter("listItem") as ColumnListItem; + this._setDetailArea(listItem.getBindingContext() as Context); + } + + /* =========================================================== */ + /* end: event handlers */ + /* =========================================================== */ + + /** + * Convenience method for retrieving a translatable text. + */ + _getText(textId: string, args?: unknown[]): string { + const bundle = ((this.getOwnerComponent() as Component).getModel("i18n") as ResourceModel).getResourceBundle() as ResourceBundle; + return bundle.getText(textId, args as string[]); + } + + /** + * Set hasUIChanges flag in View Model + * @param bHasUIChanges - set or clear hasUIChanges; if undefined, the hasPendingChanges-function + * of the OdataV4 model determines the result + */ + _setUIChanges(hasUIChanges?: boolean): void { + if (this._bTechnicalErrors) { + // If there is currently a technical error, then force 'true'. + hasUIChanges = true; + } else if (hasUIChanges === undefined) { + hasUIChanges = (this.getView().getModel() as ODataModel).hasPendingChanges(); + } + const model = this.getView().getModel("appView") as JSONModel; + model.setProperty("/hasUIChanges", hasUIChanges); + } + + /** + * Set busy flag in View Model + */ + _setBusy(isBusy: boolean): void { + const model = this.getView().getModel("appView") as JSONModel; + model.setProperty("/busy", isBusy); + } + + /** + * Toggles the visibility of the detail area + * @param oUserContext - the current user context + */ + _setDetailArea(userContext?: Context): void { + const detailArea = this.byId("detailArea"); + const layout = this.byId("defaultLayout") as unknown as { setSize(s: string): void; setResizable(b: boolean): void }; + const searchField = this.byId("searchField") as SearchField; + + if (!detailArea) { + return; // do nothing during view destruction + } + + (detailArea as unknown as { setBindingContext(c: Context | null): void }).setBindingContext(userContext || null); + // resize view + (detailArea as unknown as { setVisible(b: boolean): void }).setVisible(!!userContext); + layout.setSize(userContext ? "60%" : "100%"); + layout.setResizable(!!userContext); + searchField.setWidth(userContext ? "40%" : "20%"); + } +} diff --git a/packages/odatav4/steps/09/webapp/i18n/i18n.properties b/packages/odatav4/steps/09/webapp/i18n/i18n.properties new file mode 100644 index 000000000..f44294148 --- /dev/null +++ b/packages/odatav4/steps/09/webapp/i18n/i18n.properties @@ -0,0 +1,100 @@ +# App Descriptor +#XTIT: Application name +appTitle=OData V4 - Step 9: Add list-detail scenario + +#YDES: Application description +appDescription=OData V4 Tutorial + +#XTIT: Page Title +peoplePageTitle=My Users + +# Toolbar +#XBUT: Button text for save +saveButtonText=Save + +#XBUT: Button text for reset changes +resetChangesButtonText=Restart Tutorial + +#XBUT: Button text for cancel +cancelButtonText=Cancel + +#XTOL: Tooltip for sort +sortButtonText=Sort by Last Name + +#XBUT: Button text for add user +createButtonText=Add User + +#XBUT: Button text for delete user +deleteButtonText=Delete User + +#XTOL: Tooltip for refresh data +refreshButtonText=Refresh Data + +#XTXT: Placeholder text for search field +searchFieldPlaceholder=Type in a last name + +# Table Area +#XFLD: Label for User Name +userNameLabelText=User Name + +#XFLD: Label for First Name +firstNameLabelText=First Name + +#XFLD: Label for Last Name +lastNameLabelText=Last Name + +#XFLD: Label for Age +ageLabelText=Age + +# Messages +#XMSG: Message for user changes sent to the service +changesSentMessage=User data sent to the server + +#XMSG: Message for user deleted +deletionSuccessMessage=User {0} deleted + +#XMSG: Message for user restored (undeleted) +deletionRestoredMessage=User {0} restored + +#XMSG: Message for changes reverted +sourceResetSuccessMessage=All changes reverted back to start + +#XMSG: Message for refresh failed +refreshNotPossibleMessage=Before refreshing, please save or revert your changes + +#XMSG: Message for refresh succeeded +refreshSuccessMessage=Data refreshed + +#MSG: Message for sorting +sortMessage=Users sorted by {0} + +#MSG: Suffix for sorting by LastName, ascending +sortAscending=last name, ascending + +#MSG: Suffix for sorting by LastName, descending +sortDescending=last name, descending + +#MSG: Suffix for no sorting +sortNone=the sequence on the server + +# Detail Area +#XTIT: Title for Address +addressTitleText=Address + +#XFLD: Label for Address +addressLabelText=Address + +#XFLD: Label for City +cityLabelText=City + +#XFLD: Label for Region +regionLabelText=Region + +#XFLD: Label for Country +countryLabelText=Country + +#XTIT: Title for Best Friend +bestFriendTitleText=Best Friend + +#XFLD: Label for Best Friend Name +nameLabelText=Name diff --git a/packages/odatav4/steps/09/webapp/index-cdn.html b/packages/odatav4/steps/09/webapp/index-cdn.html new file mode 100644 index 000000000..5e7e769d6 --- /dev/null +++ b/packages/odatav4/steps/09/webapp/index-cdn.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>OData V4 Tutorial + + + +
+ + diff --git a/packages/odatav4/steps/09/webapp/index.html b/packages/odatav4/steps/09/webapp/index.html new file mode 100644 index 000000000..b1e54667d --- /dev/null +++ b/packages/odatav4/steps/09/webapp/index.html @@ -0,0 +1,22 @@ + + + + + + OData V4 Tutorial + + + +
+ + diff --git a/packages/odatav4/steps/09/webapp/initMockServer.ts b/packages/odatav4/steps/09/webapp/initMockServer.ts new file mode 100644 index 000000000..0150138fe --- /dev/null +++ b/packages/odatav4/steps/09/webapp/initMockServer.ts @@ -0,0 +1,11 @@ +// initMockServer.ts — bootstraps the mock server before the component starts +import MessageBox from "sap/m/MessageBox"; +import mockserver from "./localService/mockserver"; + +// initialize the mock server +mockserver.init().catch((oError: Error) => { + MessageBox.error(oError.message); +}).finally(() => { + // initialize the embedded component on the HTML page + void import("sap/ui/core/ComponentSupport"); +}); diff --git a/packages/odatav4/steps/09/webapp/localService/metadata.xml b/packages/odatav4/steps/09/webapp/localService/metadata.xml new file mode 100644 index 000000000..cd2295653 --- /dev/null +++ b/packages/odatav4/steps/09/webapp/localService/metadata.xml @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/odatav4/steps/09/webapp/localService/mockdata/people.json b/packages/odatav4/steps/09/webapp/localService/mockdata/people.json new file mode 100644 index 000000000..cd9ce4180 --- /dev/null +++ b/packages/odatav4/steps/09/webapp/localService/mockdata/people.json @@ -0,0 +1,399 @@ +{ + "@odata.context": "https://services.odata.org/TripPinRESTierService/(S(id))/$metadata#People(Age,FirstName,LastName,UserName,Friends,BestFriend,HomeAddress)", + "value": [ + { + "Age": 23, + "FirstName": "Angel", + "LastName": "Huffman", + "UserName": "angelhuffman", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "clydeguess", + "HomeAddress": { + "Address": "187 Suffolk Ln.", + "City": { + "Name": "Boise", + "CountryRegion": "United States", + "Region": "ID" + } + } + }, + { + "Age": 44, + "FirstName": "Clyde", + "LastName": "Guess", + "UserName": "clydeguess", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "angelhuffman", + "HomeAddress": { + "Address": "2817 Milton Dr.", + "City": { + "Name": "Albuquerque", + "CountryRegion": "United States", + "Region": "NM" + } + } + }, + { + "Age": 19, + "FirstName": "Elaine", + "LastName": "Stewart", + "UserName": "elainestewart", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "genevievereeves", + "HomeAddress": { + "Address": "308 Negra Arroyo Ln.", + "City": { + "Name": "Albuquerque", + "CountryRegion": "United States", + "Region": "NM" + } + } + }, + { + "Age": 37, + "FirstName": "Genevieve", + "LastName": "Reeves", + "UserName": "genevievereeves", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "elainestewart", + "HomeAddress": { + "Address": "89 Jefferson Way Suite 2", + "City": { + "Name": "Portland", + "CountryRegion": "United States", + "Region": "WA" + } + } + }, + { + "Age": 25, + "FirstName": "Georgina", + "LastName": "Barlow", + "UserName": "georginabarlow", + "Friends": [ + "marshallgaray", + "ursulabright" + ], + "BestFriend": "javieralfred", + "HomeAddress": { + "Address": "31 Spooner Street", + "City": { + "Name": "Quahog", + "CountryRegion": "United States", + "Region": "RI" + } + } + }, + { + "Age": 19, + "FirstName": "Javier", + "LastName": "Alfred", + "UserName": "javieralfred", + "Friends": [ + "marshallgaray", + "ursulabright" + ], + "BestFriend": "georginabarlow", + "HomeAddress": { + "Address": "55 Grizzly Peak Rd.", + "City": { + "Name": "Butte", + "CountryRegion": "United States", + "Region": "MT" + } + } + }, + { + "Age": 26, + "FirstName": "Joni", + "LastName": "Rosales", + "UserName": "jonirosales", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "keithpinckney", + "HomeAddress": { + "Address": "742 Evergreen Terrace", + "City": { + "Name": "Springfield", + "CountryRegion": "United States", + "Region": "OR" + } + } + }, + { + "Age": 41, + "FirstName": "Keith", + "LastName": "Pinckney", + "UserName": "keithpinckney", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "jonirosales", + "HomeAddress": { + "Address": "1600 Pennsylvania Avenue NW", + "City": { + "Name": "Washington", + "CountryRegion": "United States", + "Region": "DC" + } + } + }, + { + "Age": 30, + "FirstName": "Krista", + "LastName": "Kemp", + "UserName": "kristakemp", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "laurelosborn", + "HomeAddress": { + "Address": "Statue of Liberty", + "City": { + "Name": "New York", + "CountryRegion": "United States", + "Region": "NY" + } + } + }, + { + "Age": 29, + "FirstName": "Laurel", + "LastName": "Osborn", + "UserName": "laurelosborn", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "kristakemp", + "HomeAddress": { + "Address": "4059 Mt Lee Dr. Hollywood", + "City": { + "Name": "Los Angelos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 53, + "FirstName": "Marshall", + "LastName": "Garay", + "UserName": "marshallgaray", + "Friends": [ + "georginabarlow", + "ursulabright" + ], + "BestFriend": "ronaldmundy", + "HomeAddress": { + "Address": "87 Polk St. Suite 5", + "City": { + "Name": "San Francisco", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 66, + "FirstName": "Ronald", + "LastName": "Mundy", + "UserName": "ronaldmundy", + "Friends": [ + "georginabarlow", + "ursulabright" + ], + "BestFriend": "marshallgaray", + "HomeAddress": { + "Address": "89 Chiaroscuro Rd.", + "City": { + "Name": "Portland", + "CountryRegion": "United States", + "Region": "OR" + } + } + }, + { + "Age": 51, + "FirstName": "Russell", + "LastName": "Whyte", + "UserName": "russellwhyte", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "ryantheriault", + "HomeAddress": { + "Address": "Tony Stark Mansion, Point Dume", + "City": { + "Name": "Malibu", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 57, + "FirstName": "Ryan", + "LastName": "Theriault", + "UserName": "ryantheriault", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "russellwhyte", + "HomeAddress": { + "Address": "2311 N. Los Robles Ave. Apt 4A", + "City": { + "Name": "Pasadena", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 34, + "FirstName": "Sallie", + "LastName": "Sampson", + "UserName": "salliesampson", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "sandyosborn", + "HomeAddress": { + "Address": "87 Polk St. Suite 5", + "City": { + "Name": "San Francisco", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 18, + "FirstName": "Sandy", + "LastName": "Osborn", + "UserName": "sandyosborn", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "salliesampson", + "HomeAddress": { + "Address": "Grove Street, Ganton", + "City": { + "Name": "Los Santos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 24, + "FirstName": "Scott", + "LastName": "Ketchum", + "UserName": "scottketchum", + "Friends": [ + "georginabarlow", + "marshallgaray" + ], + "BestFriend": "ursulabright", + "HomeAddress": { + "Address": "Portola Drive, Rockford Hills", + "City": { + "Name": "Los Santos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 31, + "FirstName": "Ursula", + "LastName": "Bright", + "UserName": "ursulabright", + "Friends": [ + "georginabarlow", + "marshallgaray" + ], + "BestFriend": "scottketchum", + "HomeAddress": { + "Address": "First St. SE", + "City": { + "Name": "Washington", + "CountryRegion": "United States", + "Region": "DC" + } + } + }, + { + "Age": 40, + "FirstName": "Vincent", + "LastName": "Calabrese", + "UserName": "vincentcalabrese", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "willieashmore", + "HomeAddress": { + "Address": "4 Privet Drive", + "City": { + "Name": "Little Whinging", + "CountryRegion": "Great Britain", + "Region": "SRY" + } + } + }, + { + "Age": 45, + "FirstName": "Willie", + "LastName": "Ashmore", + "UserName": "willieashmore", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "vincentcalabrese", + "HomeAddress": { + "Address": "124 Conch St.", + "City": { + "Name": "Bikini Bottom", + "CountryRegion": "Pacific Ocean", + "Region": "N/D" + } + } + } + ] +} \ No newline at end of file diff --git a/packages/odatav4/steps/09/webapp/localService/mockserver.ts b/packages/odatav4/steps/09/webapp/localService/mockserver.ts new file mode 100644 index 000000000..d6810087d --- /dev/null +++ b/packages/odatav4/steps/09/webapp/localService/mockserver.ts @@ -0,0 +1,782 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any */ +import JSONModel from "sap/ui/model/json/JSONModel"; +import Log from "sap/base/Log"; + +// Pull sinon from the UI5 third-party shim. The shim has no TS typings; +// we treat the imported value as a structural any so the mock implementation +// stays close to the original JavaScript. +// eslint-disable-next-line @typescript-eslint/no-require-imports +declare const sap: any; + +interface MockUser { + UserName: string; + FirstName?: string; + LastName?: string; + Age?: number; + Friends?: string[]; + BestFriend?: string; + [key: string]: unknown; +} + +interface MockXhr { + method: string; + url: string; + requestBody?: string; + respond?: (status: number, headers: Record, body: string | null) => void; +} + +type MockResponse = [number, Record, string | null] | [number, Record]; + +// sinon is provided by the "sap/ui/thirdparty/sinon" module — see the require below +let sinon: any; +let sandbox: any; +let users: MockUser[]; // The array that holds the cached user data +let metadata: string; // The string that holds the cached mock service metadata +const namespace = "ui5/tutorial/odatav4"; +// Component for writing logs into the console +const logComponent = "ui5.tutorial.odatav4.mockserver"; +const rBaseUrl = /services.odata.org\/TripPinRESTierService/; + +/** + * Returns the base URL from a given URL. + * @param sUrl - the complete URL + * @returns the base URL + */ +function getBaseUrl(url: string): string { + const matches = url.match(/http.+\(S\(.+\)\)\//); + + if (!Array.isArray(matches) || matches.length < 1) { + throw new Error("Could not find a base URL in " + url); + } + + return matches[0]; +} + +/** + * Looks for a user with a given user name and returns its index in the user array. + * @param sUserName - the user name to look for. + * @returns index of that user in the array, or -1 if the user was not found. + */ +function findUserIndex(userName: string): number { + for (let i = 0; i < users.length; i++) { + if (users[i].UserName === userName) { + return i; + } + } + return -1; +} + +/** + * Retrieves any user data from a given http request body. + * @param sBody - the http request body. + * @returns the parsed user data. + */ +function getUserDataFromRequestBody(body: string): MockUser { + const matches = body.match(/({.+})/); + + if (!Array.isArray(matches) || matches.length !== 2) { + throw new Error("Could not find any user data in " + body); + } + return JSON.parse(matches[1]) as MockUser; +} + +/** + * Retrieves a user name from a given request URL. + * @param sUrl - the request URL. + * @returns the user name or undefined if no user was found. + */ +function getUserKeyFromUrl(url: string): string | undefined { + const matches = url.match(/People\('(.*)'\)/); + return matches ? matches[1] : undefined; +} + +/** + * Checks if a given UserName is unique or already used + * @param sUserName - the UserName to be checked + * @returns True if the UserName is unique (not used), false otherwise + */ +function isUnique(userName: string): boolean { + return findUserIndex(userName) < 0; +} + +/** + * Returns a proper HTTP response body for "duplicate key" errors + * @param sKey - the duplicate key + * @returns the proper response body + */ +function duplicateKeyError(key: string): string { + return JSON.stringify({ + error: { + code: "409", + message: "There is already a user with user name '" + key + "'.", + target: "UserName" + } + }); +} + +function invalidKeyError(key: string): string { + return JSON.stringify({ + error: { + code: "404", + message: "There is no user with user name '" + key + "'.", + target: "UserName" + } + }); +} + +function getSuccessResponse(responseBody: string): MockResponse { + return [ + 200, + { + "Content-Type": "application/json; odata.metadata=minimal", + "OData-Version": "4.0" + }, + responseBody + ]; +} + +/** + * Reads and caches the fake service metadata and data from their + * respective files. + * @returns a promise that is resolved when the data is loaded + */ +function readData(): Promise { + const metadataPromise = new Promise((resolve, reject) => { + const resourcePath = sap.ui.require.toUrl(namespace + "/localService/metadata.xml"); + const request = new XMLHttpRequest(); + + request.onload = function () { + // 404 is not an error for XMLHttpRequest so we need to handle it here + if (request.status === 404) { + const error = "resource " + resourcePath + " not found"; + + Log.error(error, logComponent); + reject(new Error(error)); + } + metadata = this.responseText; + resolve(); + }; + request.onerror = function () { + const error = "error loading resource '" + resourcePath + "'"; + + Log.error(error, logComponent); + reject(new Error(error)); + }; + request.open("GET", resourcePath); + request.send(); + }); + + const mockDataPromise = new Promise((resolve, reject) => { + const resourcePath = sap.ui.require.toUrl(namespace + "/localService/mockdata/people.json"); + const mockDataModel = new JSONModel(resourcePath); + + mockDataModel.attachRequestCompleted(function (this: JSONModel, event: any) { + // 404 is not an error for JSONModel so we need to handle it here + if (event.getParameter("errorobject") + && event.getParameter("errorobject").statusCode === 404) { + const error = "resource '" + resourcePath + "' not found"; + + Log.error(error, logComponent); + reject(new Error(error)); + } + users = (this.getData() as { value: MockUser[] }).value; + resolve(); + }); + + mockDataModel.attachRequestFailed(() => { + const error = "error loading resource '" + resourcePath + "'"; + + Log.error(error, logComponent); + reject(new Error(error)); + }); + }); + + return Promise.all([metadataPromise, mockDataPromise]); +} + +/** + * Reduces a given result set by applying the OData URL parameters 'skip' and 'top' to it. + * Does NOT change the given result set but returns a new array. + */ +function applySkipTop(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + const reducedUsers = [...resultSet]; + const matches = xhr.url.match(/\$skip=(\d+)&\$top=(\d+)/); + + if (Array.isArray(matches) && matches.length >= 3) { + const skip = parseInt(matches[1], 10); + const top = parseInt(matches[2], 10); + return resultSet.slice(skip, skip + top); + } + + return reducedUsers; +} + +/** + * Sorts a given result set by applying the OData URL parameter 'orderby'. + * Does NOT change the given result set but returns a new array. + */ +function applySort(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + const sortedUsers = [...resultSet]; // work with a copy + const matches = xhr.url.match(/\$orderby=(\w*)(?:%20(\w*))?/); + + if (!Array.isArray(matches) || matches.length < 2) { + return sortedUsers; + } + const fieldName = matches[1]; + const direction = matches[2] || "asc"; + + if (fieldName !== "LastName") { + throw new Error("Filters on field " + fieldName + " are not supported."); + } + + sortedUsers.sort((a, b) => { + const nameA = (a.LastName || "").toUpperCase(); + const nameB = (b.LastName || "").toUpperCase(); + const asc = direction === "asc"; + + if (nameA < nameB) { + return asc ? -1 : 1; + } + if (nameA > nameB) { + return asc ? 1 : -1; + } + return 0; + }); + + return sortedUsers; +} + +/** + * Filters a given result set by applying the OData URL parameter 'filter'. + * Does NOT change the given result set but returns a new array. + */ +function applyFilter(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + let filteredUsers = [...resultSet]; // work with a copy + const matches = xhr.url.match(/\$filter=.*\((.*),'(.*)'\)/); + + // If the request contains a filter command, apply the filter + if (Array.isArray(matches) && matches.length >= 3) { + const fieldName = matches[1]; + const query = matches[2]; + + if (fieldName !== "LastName") { + throw new Error("Filters on field " + fieldName + " are not supported."); + } + + filteredUsers = users.filter((user) => (user.LastName || "").indexOf(query) !== -1); + } + + return filteredUsers; +} + +/** + * Handles GET requests for metadata. + */ +function handleGetMetadataRequests(): MockResponse { + return [ + 200, + { + "Content-Type": "application/xml", + "odata-version": "4.0" + }, metadata + ]; +} + +/** + * Handles GET requests for a pure user count and returns a fitting response. + */ +function handleGetCountRequests(): MockResponse { + return getSuccessResponse(users.length.toString()); +} + +/** + * Handles GET requests for user data and returns a fitting response. + */ +function handleGetUserRequests(xhr: MockXhr, _bCount: boolean): MockResponse { + let count: number; + let expand: RegExpMatchArray | string[] | null; + let expand2: string; + let index: number; + let key: string | undefined; + let response: { "@odata.count"?: number; value: MockUser[] } | MockUser | null; + let responseBody: string; + let result: MockUser[]; + let select: RegExpMatchArray | string[] | null; + let select2: string; + let subSelects: string[][] = []; + let i: number; + + // Get expand parameter + expand = xhr.url.match(/\$expand=([^&]+)/); + + // Sort out expand parameter values + subSelects in brackets + if (expand) { + expand2 = expand[0]; + expand2 = expand2.substring(8); + + // Sort out subselects (e.g. BestFriend($select=Age,UserName),Friend) + const subSelectMatches = expand2.match(/\([^)]*\)/g) || []; + subSelects = subSelectMatches.map((s) => s.replace(/\(\$select=/, "").replace(/\)/, "").split(",")); + expand2 = expand2.replace(/\([^)]*\)/g, ""); + expand = expand2.split(","); + } + + // Get select parameter + select = xhr.url.match(/[^(]\$select=([\w|,]+)/); + + // Sort out select parameter values + if (Array.isArray(select)) { + select2 = select[0]; + select2 = select2.replace(/&/, "").replace(/\?/, "").substring(8); + select = select2.split(","); + } + + // Check if an individual user or a user range is requested + key = getUserKeyFromUrl(xhr.url); + if (key) { + index = findUserIndex(key); + + if (/People\(.+\)\/Friends/.test(xhr.url)) { + // ownRequest for friends + response = { value: createFriendsArray(users[index].Friends, select as string[]) }; + } else { + // specific user was requested + response = getUserObject(index, select as string[], expand as string[], subSelects); + } + + if (index > -1) { + responseBody = JSON.stringify(response); + return getSuccessResponse(responseBody); + } + responseBody = invalidKeyError(key); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; + } + // all users requested + result = applyFilter(xhr, users); + count = result.length; // the total no. of people found, after filtering + result = applySort(xhr, result); + result = applySkipTop(xhr, result); + + // generate sResponse + const finalResponse: { "@odata.count": number; value: MockUser[] } = { "@odata.count": count, value: [] }; + + result.forEach((user) => { + const userIndex = findUserIndex(user.UserName); + + finalResponse.value.push(getUserObject(userIndex, select as string[], expand as string[], subSelects) as MockUser); + }); + + responseBody = JSON.stringify(finalResponse); + + return getSuccessResponse(responseBody); +} + +/** + * Returns a specific user in the aUsers array. + */ +function getUserByIndex(index: number, properties: string[]): MockUser | null { + const helper: MockUser = { UserName: "" }; + const user = users[index]; + + if (user) { + properties.forEach((selectProperty) => { + helper[selectProperty] = user[selectProperty]; + }); + + return helper; + } + return null; +} + +/** + * Returns the user with iIndex in the aUsers array with all its information + */ +function getUserObject(index: number, select: string[], expand: string[] | null | undefined, subSelects: string[][]): MockUser | null { + let bestFriend: string | undefined; + let friendIndex: number; + let friends: string[] | undefined; + let object: MockUser | null; + let user: MockUser; + let i: number; + + object = getUserByIndex(index, select); + if (expand && object) { + user = users[index]; + for (i = 0; i < expand.length; i++) { + switch (expand[i]) { + case "Friends": + friends = user.Friends; + object.Friends = createFriendsArray(friends, subSelects[i]) as unknown as string[]; + break; + case "BestFriend": + bestFriend = user.BestFriend; + friendIndex = findUserIndex(bestFriend || ""); + object.BestFriend = getUserByIndex(friendIndex, subSelects[i]) as unknown as string; + break; + default: + break; + } + } + } + return object; +} + +/** + * creates array of friends for a given user + */ +function createFriendsArray(friends: string[] | undefined, subSelects: string[]): MockUser[] { + let array: (MockUser | null)[] = []; + + if (friends) { + friends.forEach((friend) => { + const friendIndex = findUserIndex(friend); + array.push(getUserByIndex(friendIndex, subSelects)); + }); + + array = array.filter((element) => element !== null); + } + + return array as MockUser[]; +} + +/** + * Handles PATCH requests for users and returns a fitting response. + */ +function handlePatchUserRequests(xhr: MockXhr): MockResponse { + // Get the key of the person to change + const key = getUserKeyFromUrl(xhr.url); + + // Get the list of changes + const changes = getUserDataFromRequestBody(xhr.requestBody || ""); + + // Check if the UserName is changed to a duplicate. + // If the UserName is "changed" to its current value, that is not an error. + if (Object.prototype.hasOwnProperty.call(changes, "UserName") + && changes.UserName !== key + && !isUnique(changes.UserName)) { + // Error + const responseBody = duplicateKeyError(changes.UserName); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; + } + // No error: make the change(s) + const user = users[findUserIndex(key || "")]; + for (const fieldName in changes) { + if (Object.prototype.hasOwnProperty.call(changes, fieldName)) { + user[fieldName] = changes[fieldName]; + } + } + + // The response to PATCH requests is always http 204 (No Content) + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Handles DELETE requests for users and returns a fitting response. + */ +function handleDeleteUserRequests(xhr: MockXhr): MockResponse { + const key = getUserKeyFromUrl(xhr.url); + users.splice(findUserIndex(key || ""), 1); + + // The response to DELETE requests is always http 204 (No Content) + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Handles POST requests for users and returns a fitting response. + */ +function handlePostUserRequests(xhr: MockXhr): MockResponse { + const user = getUserDataFromRequestBody(xhr.requestBody || ""); + + // Check if that user already exists + if (isUnique(user.UserName)) { + users.push(user); + + let responseBody = '{"@odata.context": "' + getBaseUrl(xhr.url) + + '$metadata#People/$entity",'; + responseBody += JSON.stringify(user).slice(1); + + // The response to POST requests is http 201 (Created) + return [ + 201, + { + "Content-Type": "application/json; odata.metadata=minimal", + "OData-Version": "4.0" + }, + responseBody + ]; + } + // Error + const responseBody = duplicateKeyError(user.UserName); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; +} + +/** + * Handles POST requests for resetting the data and returns a fitting response. + */ +function handleResetDataRequest(): MockResponse { + void readData(); + + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Builds a response to direct (= non-batch) requests. + * Supports GET, PATCH, DELETE and POST requests. + */ +function handleDirectRequest(xhr: MockXhr): MockResponse | undefined { + let response2: MockResponse | undefined; + + switch (xhr.method) { + case "GET": + if (/\$metadata/.test(xhr.url)) { + response2 = handleGetMetadataRequests(); + } else if (/\/\$count/.test(xhr.url)) { + response2 = handleGetCountRequests(); + } else if (/People.*\?/.test(xhr.url)) { + response2 = handleGetUserRequests(xhr, /\$count=true/.test(xhr.url)); + } + break; + case "PATCH": + if (/People/.test(xhr.url)) { + response2 = handlePatchUserRequests(xhr); + } + break; + case "POST": + if (/People/.test(xhr.url)) { + response2 = handlePostUserRequests(xhr); + } else if (/ResetDataSource/.test(xhr.url)) { + response2 = handleResetDataRequest(); + } + break; + case "DELETE": + if (/People/.test(xhr.url)) { + response2 = handleDeleteUserRequests(xhr); + } + break; + case "HEAD": + response2 = [204, {}]; + break; + default: + break; + } + + return response2; +} + +/** + * Builds a response to batch requests. + * Unwraps batch request, gets a response for each individual part and + * constructs a fitting batch response. + */ +function handleBatchRequest(xhr: MockXhr): MockResponse { + let responseBody = ""; + const outerBoundary = (xhr.requestBody || "").match(/(.*)/)![1]; // First line of the body + let innerBoundary: string | undefined; + let partBoundary: string; + // The individual requests + const outerParts = (xhr.requestBody || "").split(outerBoundary).slice(1, -1); + let parts: string[]; + let header: string; + + const matches = outerParts[0].match(/multipart\/mixed;boundary=(.+)/); + // If this request has several change sets, then we need to handle the inner and outer + // boundaries (change sets have an additional boundary) + if (matches && matches.length > 0) { + innerBoundary = matches[1]; + parts = outerParts[0].split("--" + innerBoundary).slice(1, -1); + } else { + parts = outerParts; + } + + // If this request has several change sets, then the response must start with the outer + // boundary and content header + if (innerBoundary) { + partBoundary = "--" + innerBoundary; + responseBody += outerBoundary + "\r\n" + + "Content-Type: multipart/mixed; boundary=" + innerBoundary + "\r\n\r\n"; + } else { + partBoundary = outerBoundary; + } + + parts.forEach((part, index) => { + // Construct the batch response body out of the single batch request parts. + const matches0 = part.match(/(GET|DELETE|PATCH|POST) (\S+)(?:.|\r?\n)+\r?\n(.*)\r?\n$/)!; + const partResponse = handleDirectRequest({ + method: matches0[1], + url: getBaseUrl(xhr.url) + matches0[2], + requestBody: matches0[3] + })!; + + responseBody += partBoundary + "\r\n" + + "Content-Type: application/http\r\n"; + // If there are several change sets, we need to add a Content ID header + if (innerBoundary) { + responseBody += "Content-ID:" + index + ".0\r\n"; + } + responseBody += "\r\nHttp/1.1 " + partResponse[0] + "\r\n"; + // Add any headers from the request - unless this response is 204 (no content) + if (partResponse[1] && partResponse[0] !== 204) { + for (header in partResponse[1]) { + if (Object.prototype.hasOwnProperty.call(partResponse[1], header)) { + responseBody += header + ": " + partResponse[1][header] + "\r\n"; + } + } + } + responseBody += "\r\n"; + + if (partResponse[2]) { + responseBody += partResponse[2]; + } + responseBody += "\r\n"; + }); + + // Check if we need to add the inner boundary again at the end + if (innerBoundary) { + responseBody += "--" + innerBoundary + "--\r\n"; + } + // Add a final boundary to the batch response body + responseBody += outerBoundary + "--"; + + // Build the final batch response + return [ + 200, + { + "Content-Type": "multipart/mixed;boundary=" + outerBoundary.slice(2), + "OData-Version": "4.0" + }, + responseBody + ]; +} + +/** + * Handles any type of intercepted request and sends a fake response. + * Logs the request and response to the console. + * Manages batch requests. + */ +function handleAllRequests(xhr: MockXhr): void { + let response2: MockResponse | undefined; + + // Log the request + Log.info( + "Mockserver: Received " + xhr.method + " request to URL " + xhr.url, + (xhr.requestBody ? "Request body is:\n" + xhr.requestBody : "No request body.") + + "\n", + logComponent + ); + + if (xhr.method === "POST" && /\$batch/.test(xhr.url)) { + response2 = handleBatchRequest(xhr); + } else { + response2 = handleDirectRequest(xhr); + } + + if (xhr.respond && response2) { + xhr.respond(response2[0], response2[1], response2[2] || null); + } + + // Log the response + if (response2) { + Log.info( + "Mockserver: Sent response with return code " + response2[0], + ("Response headers: " + JSON.stringify(response2[1]) + "\n\nResponse body:\n" + + (response2[2] || "")) + "\n", + logComponent + ); + } +} + +export default { + + /** + * Creates a Sinon fake service, intercepting all http requests to + * the URL defined in variable rBaseUrl above. + * @returns a promise that is resolved when the mock server is started + */ + init(): Promise { + // Load sinon lazily from the UI5 third-party shim + return new Promise((resolve, reject) => { + sap.ui.require(["sap/ui/thirdparty/sinon"], (sinon: any) => { + sinon = sinon; + sandbox = sinon.sandbox.create(); + + // Read the mock data + readData().then(() => { + // Initialize the sinon fake server + sandbox.useFakeServer(); + // Make sure that requests are responded to automatically. Otherwise we would need + // to do that manually. + sandbox.server.autoRespond = true; + + // Register the requests for which responses should be faked. + sandbox.server.respondWith(rBaseUrl, handleAllRequests); + + // Apply a filter to the fake XmlHttpRequest. + // Otherwise, ALL requests (e.g. for the component, views etc.) would be + // intercepted. + sinon.FakeXMLHttpRequest.useFilters = true; + sinon.FakeXMLHttpRequest.addFilter((_sMethod: string, url: string) => { + // If the filter returns true, the request will NOT be faked. + // We only want to fake requests that go to the intended service. + return !rBaseUrl.test(url); + }); + + // Set the logging level for console entries from the mock server + Log.setLevel(Log.Level.INFO, logComponent); + + Log.info("Running the app with mock data", logComponent); + resolve(undefined); + }, reject); + }); + }); + }, + + /** + * Stops the request interception and deletes the Sinon fake server. + */ + stop(): void { + if (sinon) { + sinon.FakeXMLHttpRequest.filters = []; + sinon.FakeXMLHttpRequest.useFilters = false; + } + if (sandbox) { + sandbox.restore(); + sandbox = null; + } + } +}; diff --git a/packages/odatav4/steps/09/webapp/manifest.json b/packages/odatav4/steps/09/webapp/manifest.json new file mode 100644 index 000000000..ea22bafc9 --- /dev/null +++ b/packages/odatav4/steps/09/webapp/manifest.json @@ -0,0 +1,69 @@ +{ + "_version": "1.60.0", + "sap.app": { + "id": "ui5.tutorial.odatav4", + "type": "application", + "i18n": { + "supportedLocales": [ + "" + ], + "fallbackLocale": "", + "bundleName": "ui5.tutorial.odatav4.i18n.i18n" + }, + "applicationVersion": { + "version": "1.0.0" + }, + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "dataSources": { + "default": { + "uri": "https://services.odata.org/TripPinRESTierService/(S(id))/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + } + }, + "sap.ui": { + "technology": "UI5" + }, + "sap.ui5": { + "rootView": { + "viewName": "ui5.tutorial.odatav4.view.App", + "type": "XML", + "id": "appView" + }, + "dependencies": { + "minUI5Version": "1.132", + "libs": { + "sap.f": {}, + "sap.m": {}, + "sap.ui.core": {}, + "sap.ui.layout": {} + } + }, + "handleValidation": true, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "ui5.tutorial.odatav4.i18n.i18n", + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + } + }, + "": { + "dataSource": "default", + "preload": true, + "settings": { + "autoExpandSelect": true, + "earlyRequests": true, + "operationMode": "Server" + } + } + } + } +} diff --git a/packages/odatav4/steps/09/webapp/model/models.ts b/packages/odatav4/steps/09/webapp/model/models.ts new file mode 100644 index 000000000..5fdcff4a3 --- /dev/null +++ b/packages/odatav4/steps/09/webapp/model/models.ts @@ -0,0 +1,10 @@ +// models.ts — central application models +import JSONModel from "sap/ui/model/json/JSONModel"; +import Device from "sap/ui/Device"; + +export function createDeviceModel(): JSONModel { + const model = new JSONModel(Device); + + model.setDefaultBindingMode("OneWay"); + return model; +} diff --git a/packages/odatav4/steps/09/webapp/view/App.view.xml b/packages/odatav4/steps/09/webapp/view/App.view.xml new file mode 100644 index 000000000..9440b3b50 --- /dev/null +++ b/packages/odatav4/steps/09/webapp/view/App.view.xml @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + </semantic:titleHeading> + <semantic:headerContent> + <FlexBox> + <VBox> + <ObjectAttribute text="{i18n>userNameLabelText}"/> + <ObjectAttribute text="{UserName}"/> + </VBox> + <VBox class="sapUiMediumMarginBegin"> + <ObjectAttribute text="{i18n>ageLabelText}"/> + <ObjectNumber number="{Age}" unit="Years"/> + </VBox> + </FlexBox> + </semantic:headerContent> + <semantic:content> + <VBox> + <FlexBox wrap="Wrap"> + <f:Form editable="false"> + <f:title> + <core:Title text="{i18n>addressTitleText}" /> + </f:title> + <f:layout> + <f:ResponsiveGridLayout + labelSpanXL="3" + labelSpanL="3" + labelSpanM="3" + labelSpanS="12" + adjustLabelSpan="false" + emptySpanXL="4" + emptySpanL="4" + emptySpanM="4" + emptySpanS="0" + columnsXL="1" + columnsL="1" + columnsM="1" + singleContainerFullSize="false" /> + </f:layout> + <f:formContainers> + <f:FormContainer> + <f:formElements> + <f:FormElement label="{i18n>addressLabelText}"> + <f:fields> + <Text text="{HomeAddress/Address}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>cityLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/Name}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>regionLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/Region}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>countryLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/CountryRegion}" /> + </f:fields> + </f:FormElement> + </f:formElements> + </f:FormContainer> + </f:formContainers> + </f:Form> + <f:Form editable="false"> + <f:title> + <core:Title text="{i18n>bestFriendTitleText}" /> + </f:title> + <f:layout> + <f:ResponsiveGridLayout + labelSpanXL="3" + labelSpanL="3" + labelSpanM="3" + labelSpanS="12" + adjustLabelSpan="false" + emptySpanXL="4" + emptySpanL="4" + emptySpanM="4" + emptySpanS="0" + columnsXL="1" + columnsL="1" + columnsM="1" + singleContainerFullSize="false" /> + </f:layout> + <f:formContainers> + <f:FormContainer> + <f:formElements> + <f:FormElement label="{i18n>nameLabelText}"> + <f:fields> + <Text text="{BestFriend/FirstName} {BestFriend/LastName}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>ageLabelText}"> + <f:fields> + <Text text="{BestFriend/Age}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>userNameLabelText}"> + <f:fields> + <Text text="{BestFriend/UserName}" /> + </f:fields> + </f:FormElement> + </f:formElements> + </f:FormContainer> + </f:formContainers> + </f:Form> + </FlexBox> + </VBox> + </semantic:content> + </semantic:SemanticPage> + </l:SplitPane> + </l:PaneContainer> + </l:ResponsiveSplitter> + </content> + <footer> + <Toolbar visible="{appView>/hasUIChanges}"> + <ToolbarSpacer/> + <Button + id="saveButton" + type="Emphasized" + text="{i18n>saveButtonText}" + enabled="{= ${message>/}.length === 0 && ${appView>/usernameEmpty} === false }" + press=".onSave"/> + <Button + id="doneButton" + text="{i18n>cancelButtonText}" + press=".onResetChanges"/> + </Toolbar> + </footer> + </Page> + </pages> + </App> + </Shell> +</mvc:View> \ No newline at end of file diff --git a/packages/odatav4/steps/10/README.md b/packages/odatav4/steps/10/README.md new file mode 100644 index 000000000..ef829bcc9 --- /dev/null +++ b/packages/odatav4/steps/10/README.md @@ -0,0 +1,131 @@ +# Step 10: Enable Data Reuse + +<details class="ts-only" markdown="1"> + +You can download the solution for this step here: [📥 Download step 10](https://ui5.github.io/tutorials/odatav4/odatav4-step-10.zip). + +</details> + +<details class="js-only" markdown="1"> + +You can download the solution for this step here: [📥 Download step 10](https://ui5.github.io/tutorials/odatav4/odatav4-step-10-js.zip). + +</details> + +In this step we avoid unnecessary back-end requests by preventing the destruction of data shown in the detail area when sorting or filtering the list. + +## Preview + +**No visual change compared to the last step** + +![A list of users with an added detail area](assets/Tut_OD4_Step_9_6e9025b.png "No visual change compared to the last step") + +## Coding + +You can view this step live: [🔗 Live Preview of Step 10](https://ui5.github.io/tutorials/odatav4/build/10/index-cdn.html). + +## `webapp/controller/App.controller.?s` + +```ts +... + onMessageBindingChange(oEvent) { + ... + }, + + onSelectionChange(oEvent) { + this._setDetailArea(oEvent.getParameter("listItem").getBindingContext()); + }, +... + /** + * Toggles the visibility of the detail area + * + * @param {object} [oUserContext] - the current user context + */ + _setDetailArea(oUserContext) { + const oDetailArea = this.byId("detailArea"), + oLayout = this.byId("defaultLayout"), + oOldContext, + oSearchField = this.byId("searchField"); + + if (!oDetailArea) { + return; // do nothing when running within view destruction + } + + oOldContext = oDetailArea.getBindingContext(); + if (oOldContext) { + oOldContext.setKeepAlive(false); + } + if (oUserContext) { + oUserContext.setKeepAlive(true, + // hide details if kept entity was refreshed but does not exists any more + this._setDetailArea.bind(this)); + + } + oDetailArea.setBindingContext(oUserContext || null); + // resize view + oDetailArea.setVisible(!!oUserContext); + oLayout.setSize(oUserContext ? "60%" : "100%"); + oLayout.setResizable(!!oUserContext); + oSearchField.setWidth(oUserContext ? "40%" : "20%"); + } + ... +``` + +```js +... + onMessageBindingChange : function (oEvent) { + ... + }, + + onSelectionChange : function (oEvent) { + this._setDetailArea(oEvent.getParameter("listItem").getBindingContext()); + }, +... + /** + * Toggles the visibility of the detail area + * + * @param {object} [oUserContext] - the current user context + */ + _setDetailArea : function (oUserContext) { + var oDetailArea = this.byId("detailArea"), + oLayout = this.byId("defaultLayout"), + oOldContext, + oSearchField = this.byId("searchField"); + + if (!oDetailArea) { + return; // do nothing when running within view destruction + } + + oOldContext = oDetailArea.getBindingContext(); + if (oOldContext) { + oOldContext.setKeepAlive(false); + } + if (oUserContext) { + oUserContext.setKeepAlive(true, + // hide details if kept entity was refreshed but does not exists any more + this._setDetailArea.bind(this)); + + } + oDetailArea.setBindingContext(oUserContext || null); + // resize view + oDetailArea.setVisible(!!oUserContext); + oLayout.setSize(oUserContext ? "60%" : "100%"); + oLayout.setResizable(!!oUserContext); + oSearchField.setWidth(oUserContext ? "40%" : "20%"); + } + ... +``` + +We extend the logic of the `_setDetailArea` function. First, we check if there's an "old" binding context in the detail area. If so, the `keepAlive` for the old context is set to `false`. + +For the new context we set `keepAlive` to `true` and add `_setDetailArea` as an `onBeforeDestroy` function to it, which hides the detail area when the user linked to it is deleted in the back end and the list is refreshed. + +You can use the `Context#setKeepAlive` method to prevent the destruction of information shown in the detail area when the selected user is no longer part of the list from which the information was selected. This could otherwise happen if you filter or sort the list. + +**Related Information** + +[Extending the Lifetime of a Context that is not Used Exclusively by a Table Collection](../04_Essentials/data-reuse-648e360.md#loio648e360fa22d46248ca783dc6eb44531__section_ELC) + +*** + +**Next:** [Step 11: Add Table with :n Navigation to Detail Area](../11/README.md) diff --git a/packages/odatav4/steps/10/package.json b/packages/odatav4/steps/10/package.json new file mode 100644 index 000000000..efd9b0127 --- /dev/null +++ b/packages/odatav4/steps/10/package.json @@ -0,0 +1,19 @@ +{ + "name": "ui5.tutorial.odatav4.step10", + "version": "1.0.0", + "author": "SAP SE", + "description": "OpenUI5 TypeScript Tutorial — OData V4: Step 10 — Enable Data Reuse", + "private": true, + "scripts": { + "start": "ui5 serve -o index.html", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } +} diff --git a/packages/odatav4/steps/10/tsconfig.json b/packages/odatav4/steps/10/tsconfig.json new file mode 100644 index 000000000..1044f76cd --- /dev/null +++ b/packages/odatav4/steps/10/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "es2023", + "types": [ + "node", + "@types/openui5" + ], + "skipLibCheck": true, + "allowJs": true, + "strictPropertyInitialization": false, + "rootDir": "./webapp", + "paths": { + "ui5/tutorial/odatav4/*": [ + "./webapp/*" + ] + }, + "strict": false, + "strictNullChecks": false + }, + "include": [ + "./webapp/**/*" + ] +} diff --git a/packages/odatav4/steps/10/ui5.yaml b/packages/odatav4/steps/10/ui5.yaml new file mode 100644 index 000000000..e1ca8e9c2 --- /dev/null +++ b/packages/odatav4/steps/10/ui5.yaml @@ -0,0 +1,25 @@ +specVersion: '3.0' +metadata: + name: "ui5.tutorial.odatav4" +type: application +framework: + name: OpenUI5 + version: "1.147.1" + libraries: + - name: sap.m + - name: sap.f + - name: sap.ui.layout + - name: sap.ui.core + - name: themelib_sap_horizon +builder: + customTasks: + - name: ui5-tooling-transpile-task + afterTask: replaceVersion +server: + customMiddleware: + - name: ui5-tooling-transpile-middleware + afterMiddleware: compression + - name: ui5-middleware-serveframework + afterMiddleware: compression + - name: ui5-middleware-livereload + afterMiddleware: compression diff --git a/packages/odatav4/steps/10/webapp/Component.ts b/packages/odatav4/steps/10/webapp/Component.ts new file mode 100644 index 000000000..170cbb94c --- /dev/null +++ b/packages/odatav4/steps/10/webapp/Component.ts @@ -0,0 +1,27 @@ +// Component.ts — UI5 OData V4 Tutorial +import UIComponent from "sap/ui/core/UIComponent"; +import { createDeviceModel } from "./model/models"; + +/** + * @namespace ui5.tutorial.odatav4 + */ +export default class Component extends UIComponent { + public static metadata = { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + manifest: "json" + }; + + /** + * The component is initialized by UI5 automatically during the startup of the app and calls + * the init method once. + * @public + * @override + */ + init(): void { + // call the base component's init function + super.init(); + + // set the device model + this.setModel(createDeviceModel(), "device"); + } +} diff --git a/packages/odatav4/steps/10/webapp/controller/App.controller.ts b/packages/odatav4/steps/10/webapp/controller/App.controller.ts new file mode 100644 index 000000000..7722959a3 --- /dev/null +++ b/packages/odatav4/steps/10/webapp/controller/App.controller.ts @@ -0,0 +1,312 @@ +import Messaging from "sap/ui/core/Messaging"; +import Controller from "sap/ui/core/mvc/Controller"; +import MessageToast from "sap/m/MessageToast"; +import MessageBox from "sap/m/MessageBox"; +import Sorter from "sap/ui/model/Sorter"; +import Filter from "sap/ui/model/Filter"; +import FilterOperator from "sap/ui/model/FilterOperator"; +import FilterType from "sap/ui/model/FilterType"; +import JSONModel from "sap/ui/model/json/JSONModel"; +import ResourceModel from "sap/ui/model/resource/ResourceModel"; +import ResourceBundle from "sap/base/i18n/ResourceBundle"; +import Component from "sap/ui/core/Component"; +import List from "sap/m/List"; +import type ColumnListItem from "sap/m/ColumnListItem"; +import type SearchField from "sap/m/SearchField"; +import type ListBinding from "sap/ui/model/ListBinding"; +import type Event from "sap/ui/base/Event"; +import type Input from "sap/m/Input"; +import type Context from "sap/ui/model/odata/v4/Context"; +import type ODataModel from "sap/ui/model/odata/v4/ODataModel"; +import type ODataListBinding from "sap/ui/model/odata/v4/ODataListBinding"; + +/** + * @namespace ui5.tutorial.odatav4.controller + */ +export default class App extends Controller { + + private _bTechnicalErrors = false; + + /** + * Hook for initializing the controller + */ + onInit(): void { + const messageModel = Messaging.getMessageModel(); + const messageModelBinding = messageModel.bindList("/", undefined, [], + new Filter("technical", FilterOperator.EQ, true)); + const viewModel = new JSONModel({ + busy: false, + hasUIChanges: false, + usernameEmpty: false, + order: 0 + }); + + this.getView().setModel(viewModel, "appView"); + this.getView().setModel(messageModel, "message"); + + messageModelBinding.attachChange(this.onMessageBindingChange, this); + this._bTechnicalErrors = false; + } + + /* =========================================================== */ + /* begin: event handlers */ + /* =========================================================== */ + + /** + * Create a new entry. + */ + onCreate(): void { + const list = this.byId("peopleList") as List; + const binding = list.getBinding("items") as ODataListBinding; + // Create a new entry through the table's list binding + const context = binding.create({ Age: "18" }); + + this._setUIChanges(true); + (this.getView().getModel("appView") as JSONModel).setProperty("/usernameEmpty", true); + + // Select and focus the table row that contains the newly created entry + list.getItems().some((item) => { + const columnItem = item as ColumnListItem; + if (columnItem.getBindingContext() === context) { + columnItem.focus(); + columnItem.setSelected(true); + return true; + } + return false; + }); + } + + /** + * Delete an entry. + */ + onDelete(): void { + const peopleList = this.byId("peopleList") as List; + const selected = peopleList.getSelectedItem() as ColumnListItem | null; + + if (selected) { + const context = selected.getBindingContext() as Context; + const userName = context.getProperty("UserName") as string; + void context.delete().then(() => { + MessageToast.show(this._getText("deletionSuccessMessage", [userName])); + }, (error2: Error & { canceled?: boolean }) => { + const currentSelected = peopleList.getSelectedItem() as ColumnListItem | null; + if (currentSelected && context === currentSelected.getBindingContext()) { + this._setDetailArea(context); + } + this._setUIChanges(); + if (error2.canceled) { + MessageToast.show(this._getText("deletionRestoredMessage", [userName])); + return; + } + MessageBox.error(error2.message + ": " + userName); + }); + this._setDetailArea(); + this._setUIChanges(); + } + } + + /** + * Lock UI when changing data in the input controls + */ + onInputChange(evt: Event): void { + if ((evt as unknown as { getParameter(n: string): unknown }).getParameter("escPressed")) { + this._setUIChanges(); + } else { + this._setUIChanges(true); + // Check if the username in the changed table row is empty and set the appView + // property accordingly + const ctx = (evt.getSource() as Input).getParent()?.getBindingContext(); + if (ctx && ctx.getProperty("UserName")) { + (this.getView().getModel("appView") as JSONModel).setProperty("/usernameEmpty", false); + } + } + } + + /** + * Refresh the data. + */ + onRefresh(): void { + const binding = (this.byId("peopleList") as List).getBinding("items") as ODataListBinding; + + if (binding.hasPendingChanges()) { + MessageBox.error(this._getText("refreshNotPossibleMessage")); + return; + } + binding.refresh(); + MessageToast.show(this._getText("refreshSuccessMessage")); + } + + /** + * Reset any unsaved changes. + */ + onResetChanges(): void { + ((this.byId("peopleList") as List).getBinding("items") as ODataListBinding).resetChanges(); + // If there were technical errors, cancelling changes resets them. + this._bTechnicalErrors = false; + this._setUIChanges(false); + } + + /** + * Reset the data source. + */ + onResetDataSource(): void { + const model = this.getView().getModel() as ODataModel; + const operation = model.bindContext("/ResetDataSource(...)"); + + void operation.invoke().then(() => { + model.refresh(); + MessageToast.show(this._getText("sourceResetSuccessMessage")); + }, (error2: Error) => { + MessageBox.error(error2.message); + }); + } + + /** + * Save changes to the source. + */ + onSave(): void { + const success = () => { + this._setBusy(false); + MessageToast.show(this._getText("changesSentMessage")); + this._setUIChanges(false); + }; + const error = (error2: Error) => { + this._setBusy(false); + this._setUIChanges(false); + MessageBox.error(error2.message); + }; + + this._setBusy(true); // Lock UI until submitBatch is resolved. + (this.getView().getModel() as ODataModel).submitBatch("peopleGroup").then(success, error); + // If there were technical errors, a new save resets them. + this._bTechnicalErrors = false; + } + + /** + * Search for the term in the search field. + */ + onSearch(): void { + const view = this.getView(); + const value = (view.byId("searchField") as SearchField).getValue(); + const filter = new Filter("LastName", FilterOperator.Contains, value); + + ((view.byId("peopleList") as List).getBinding("items") as ListBinding).filter(filter, FilterType.Application); + } + + /** + * Sort the table according to the last name. + * Cycles between the three sorting states "none", "ascending" and "descending" + */ + onSort(): void { + const view = this.getView(); + const states: (string | undefined)[] = [undefined, "asc", "desc"]; + const stateTextIds = ["sortNone", "sortAscending", "sortDescending"]; + let order = (view.getModel("appView") as JSONModel).getProperty("/order") as number; + + // Cycle between the states + order = (order + 1) % states.length; + const order2 = states[order]; + + (view.getModel("appView") as JSONModel).setProperty("/order", order); + ((view.byId("peopleList") as List).getBinding("items") as ListBinding) + .sort(order2 ? new Sorter("LastName", order2 === "desc") : []); + + const message = this._getText("sortMessage", [this._getText(stateTextIds[order])]); + MessageToast.show(message); + } + + onMessageBindingChange(event: Event): void { + const contexts = (event.getSource() as ListBinding).getContexts(); + let messageOpen = false; + + if (messageOpen || !contexts.length) { + return; + } + + // Extract and remove the technical messages + const messages = contexts.map((context: Context) => context.getObject()); + Messaging.removeMessages(messages); + + this._setUIChanges(true); + this._bTechnicalErrors = true; + MessageBox.error((messages[0] as { message: string }).message, { + id: "serviceErrorMessageBox", + onClose: () => { + messageOpen = false; + } + }); + + messageOpen = true; + } + + onSelectionChange(event: Event): void { + const listItem = (event as unknown as { getParameter(n: string): unknown }).getParameter("listItem") as ColumnListItem; + this._setDetailArea(listItem.getBindingContext() as Context); + } + + /* =========================================================== */ + /* end: event handlers */ + /* =========================================================== */ + + /** + * Convenience method for retrieving a translatable text. + */ + _getText(textId: string, args?: unknown[]): string { + const bundle = ((this.getOwnerComponent() as Component).getModel("i18n") as ResourceModel).getResourceBundle() as ResourceBundle; + return bundle.getText(textId, args as string[]); + } + + /** + * Set hasUIChanges flag in View Model + * @param bHasUIChanges - set or clear hasUIChanges; if undefined, the hasPendingChanges-function + * of the OdataV4 model determines the result + */ + _setUIChanges(hasUIChanges?: boolean): void { + if (this._bTechnicalErrors) { + // If there is currently a technical error, then force 'true'. + hasUIChanges = true; + } else if (hasUIChanges === undefined) { + hasUIChanges = (this.getView().getModel() as ODataModel).hasPendingChanges(); + } + const model = this.getView().getModel("appView") as JSONModel; + model.setProperty("/hasUIChanges", hasUIChanges); + } + + /** + * Set busy flag in View Model + */ + _setBusy(isBusy: boolean): void { + const model = this.getView().getModel("appView") as JSONModel; + model.setProperty("/busy", isBusy); + } + + /** + * Toggles the visibility of the detail area + * @param oUserContext - the current user context + */ + _setDetailArea(userContext?: Context): void { + const detailArea = this.byId("detailArea"); + const layout = this.byId("defaultLayout") as unknown as { setSize(s: string): void; setResizable(b: boolean): void }; + const searchField = this.byId("searchField") as SearchField; + + if (!detailArea) { + return; // do nothing during view destruction + } + + const oldContext = (detailArea as unknown as { getBindingContext(): Context | null }).getBindingContext(); + if (oldContext && !oldContext.isTransient()) { + oldContext.setKeepAlive(false); + } + if (userContext && !userContext.isTransient()) { + userContext.setKeepAlive(true, + // hide details if kept entity was refreshed but does not exist any more + this._setDetailArea.bind(this)); + } + (detailArea as unknown as { setBindingContext(c: Context | null): void }).setBindingContext(userContext || null); + // resize view + (detailArea as unknown as { setVisible(b: boolean): void }).setVisible(!!userContext); + layout.setSize(userContext ? "60%" : "100%"); + layout.setResizable(!!userContext); + searchField.setWidth(userContext ? "40%" : "20%"); + } +} diff --git a/packages/odatav4/steps/10/webapp/i18n/i18n.properties b/packages/odatav4/steps/10/webapp/i18n/i18n.properties new file mode 100644 index 000000000..e1b8c4a8c --- /dev/null +++ b/packages/odatav4/steps/10/webapp/i18n/i18n.properties @@ -0,0 +1,100 @@ +# App Descriptor +#XTIT: Application name +appTitle=OData V4 - Step 10: Context#setKeepAlive + +#YDES: Application description +appDescription=OData V4 Tutorial + +#XTIT: Page Title +peoplePageTitle=My Users + +# Toolbar +#XBUT: Button text for save +saveButtonText=Save + +#XBUT: Button text for reset changes +resetChangesButtonText=Restart Tutorial + +#XBUT: Button text for cancel +cancelButtonText=Cancel + +#XTOL: Tooltip for sort +sortButtonText=Sort by Last Name + +#XBUT: Button text for add user +createButtonText=Add User + +#XBUT: Button text for delete user +deleteButtonText=Delete User + +#XTOL: Tooltip for refresh data +refreshButtonText=Refresh Data + +#XTXT: Placeholder text for search field +searchFieldPlaceholder=Type in a last name + +# Table Area +#XFLD: Label for User Name +userNameLabelText=User Name + +#XFLD: Label for First Name +firstNameLabelText=First Name + +#XFLD: Label for Last Name +lastNameLabelText=Last Name + +#XFLD: Label for Age +ageLabelText=Age + +# Messages +#XMSG: Message for user changes sent to the service +changesSentMessage=User data sent to the server + +#XMSG: Message for user deleted +deletionSuccessMessage=User {0} deleted + +#XMSG: Message for user restored (undeleted) +deletionRestoredMessage=User {0} restored + +#XMSG: Message for changes reverted +sourceResetSuccessMessage=All changes reverted back to start + +#XMSG: Message for refresh failed +refreshNotPossibleMessage=Before refreshing, please save or revert your changes + +#XMSG: Message for refresh succeeded +refreshSuccessMessage=Data refreshed + +#MSG: Message for sorting +sortMessage=Users sorted by {0} + +#MSG: Suffix for sorting by LastName, ascending +sortAscending=last name, ascending + +#MSG: Suffix for sorting by LastName, descending +sortDescending=last name, descending + +#MSG: Suffix for no sorting +sortNone=the sequence on the server + +# Detail Area +#XTIT: Title for Address +addressTitleText=Address + +#XFLD: Label for Address +addressLabelText=Address + +#XFLD: Label for City +cityLabelText=City + +#XFLD: Label for Region +regionLabelText=Region + +#XFLD: Label for Country +countryLabelText=Country + +#XTIT: Title for Best Friend +bestFriendTitleText=Best Friend + +#XFLD: Label for Best Friend Name +nameLabelText=Name diff --git a/packages/odatav4/steps/10/webapp/index-cdn.html b/packages/odatav4/steps/10/webapp/index-cdn.html new file mode 100644 index 000000000..5e7e769d6 --- /dev/null +++ b/packages/odatav4/steps/10/webapp/index-cdn.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>OData V4 Tutorial + + + +
+ + diff --git a/packages/odatav4/steps/10/webapp/index.html b/packages/odatav4/steps/10/webapp/index.html new file mode 100644 index 000000000..b1e54667d --- /dev/null +++ b/packages/odatav4/steps/10/webapp/index.html @@ -0,0 +1,22 @@ + + + + + + OData V4 Tutorial + + + +
+ + diff --git a/packages/odatav4/steps/10/webapp/initMockServer.ts b/packages/odatav4/steps/10/webapp/initMockServer.ts new file mode 100644 index 000000000..0150138fe --- /dev/null +++ b/packages/odatav4/steps/10/webapp/initMockServer.ts @@ -0,0 +1,11 @@ +// initMockServer.ts — bootstraps the mock server before the component starts +import MessageBox from "sap/m/MessageBox"; +import mockserver from "./localService/mockserver"; + +// initialize the mock server +mockserver.init().catch((oError: Error) => { + MessageBox.error(oError.message); +}).finally(() => { + // initialize the embedded component on the HTML page + void import("sap/ui/core/ComponentSupport"); +}); diff --git a/packages/odatav4/steps/10/webapp/localService/metadata.xml b/packages/odatav4/steps/10/webapp/localService/metadata.xml new file mode 100644 index 000000000..cd2295653 --- /dev/null +++ b/packages/odatav4/steps/10/webapp/localService/metadata.xml @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/odatav4/steps/10/webapp/localService/mockdata/people.json b/packages/odatav4/steps/10/webapp/localService/mockdata/people.json new file mode 100644 index 000000000..cd9ce4180 --- /dev/null +++ b/packages/odatav4/steps/10/webapp/localService/mockdata/people.json @@ -0,0 +1,399 @@ +{ + "@odata.context": "https://services.odata.org/TripPinRESTierService/(S(id))/$metadata#People(Age,FirstName,LastName,UserName,Friends,BestFriend,HomeAddress)", + "value": [ + { + "Age": 23, + "FirstName": "Angel", + "LastName": "Huffman", + "UserName": "angelhuffman", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "clydeguess", + "HomeAddress": { + "Address": "187 Suffolk Ln.", + "City": { + "Name": "Boise", + "CountryRegion": "United States", + "Region": "ID" + } + } + }, + { + "Age": 44, + "FirstName": "Clyde", + "LastName": "Guess", + "UserName": "clydeguess", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "angelhuffman", + "HomeAddress": { + "Address": "2817 Milton Dr.", + "City": { + "Name": "Albuquerque", + "CountryRegion": "United States", + "Region": "NM" + } + } + }, + { + "Age": 19, + "FirstName": "Elaine", + "LastName": "Stewart", + "UserName": "elainestewart", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "genevievereeves", + "HomeAddress": { + "Address": "308 Negra Arroyo Ln.", + "City": { + "Name": "Albuquerque", + "CountryRegion": "United States", + "Region": "NM" + } + } + }, + { + "Age": 37, + "FirstName": "Genevieve", + "LastName": "Reeves", + "UserName": "genevievereeves", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "elainestewart", + "HomeAddress": { + "Address": "89 Jefferson Way Suite 2", + "City": { + "Name": "Portland", + "CountryRegion": "United States", + "Region": "WA" + } + } + }, + { + "Age": 25, + "FirstName": "Georgina", + "LastName": "Barlow", + "UserName": "georginabarlow", + "Friends": [ + "marshallgaray", + "ursulabright" + ], + "BestFriend": "javieralfred", + "HomeAddress": { + "Address": "31 Spooner Street", + "City": { + "Name": "Quahog", + "CountryRegion": "United States", + "Region": "RI" + } + } + }, + { + "Age": 19, + "FirstName": "Javier", + "LastName": "Alfred", + "UserName": "javieralfred", + "Friends": [ + "marshallgaray", + "ursulabright" + ], + "BestFriend": "georginabarlow", + "HomeAddress": { + "Address": "55 Grizzly Peak Rd.", + "City": { + "Name": "Butte", + "CountryRegion": "United States", + "Region": "MT" + } + } + }, + { + "Age": 26, + "FirstName": "Joni", + "LastName": "Rosales", + "UserName": "jonirosales", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "keithpinckney", + "HomeAddress": { + "Address": "742 Evergreen Terrace", + "City": { + "Name": "Springfield", + "CountryRegion": "United States", + "Region": "OR" + } + } + }, + { + "Age": 41, + "FirstName": "Keith", + "LastName": "Pinckney", + "UserName": "keithpinckney", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "jonirosales", + "HomeAddress": { + "Address": "1600 Pennsylvania Avenue NW", + "City": { + "Name": "Washington", + "CountryRegion": "United States", + "Region": "DC" + } + } + }, + { + "Age": 30, + "FirstName": "Krista", + "LastName": "Kemp", + "UserName": "kristakemp", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "laurelosborn", + "HomeAddress": { + "Address": "Statue of Liberty", + "City": { + "Name": "New York", + "CountryRegion": "United States", + "Region": "NY" + } + } + }, + { + "Age": 29, + "FirstName": "Laurel", + "LastName": "Osborn", + "UserName": "laurelosborn", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "kristakemp", + "HomeAddress": { + "Address": "4059 Mt Lee Dr. Hollywood", + "City": { + "Name": "Los Angelos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 53, + "FirstName": "Marshall", + "LastName": "Garay", + "UserName": "marshallgaray", + "Friends": [ + "georginabarlow", + "ursulabright" + ], + "BestFriend": "ronaldmundy", + "HomeAddress": { + "Address": "87 Polk St. Suite 5", + "City": { + "Name": "San Francisco", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 66, + "FirstName": "Ronald", + "LastName": "Mundy", + "UserName": "ronaldmundy", + "Friends": [ + "georginabarlow", + "ursulabright" + ], + "BestFriend": "marshallgaray", + "HomeAddress": { + "Address": "89 Chiaroscuro Rd.", + "City": { + "Name": "Portland", + "CountryRegion": "United States", + "Region": "OR" + } + } + }, + { + "Age": 51, + "FirstName": "Russell", + "LastName": "Whyte", + "UserName": "russellwhyte", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "ryantheriault", + "HomeAddress": { + "Address": "Tony Stark Mansion, Point Dume", + "City": { + "Name": "Malibu", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 57, + "FirstName": "Ryan", + "LastName": "Theriault", + "UserName": "ryantheriault", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "russellwhyte", + "HomeAddress": { + "Address": "2311 N. Los Robles Ave. Apt 4A", + "City": { + "Name": "Pasadena", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 34, + "FirstName": "Sallie", + "LastName": "Sampson", + "UserName": "salliesampson", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "sandyosborn", + "HomeAddress": { + "Address": "87 Polk St. Suite 5", + "City": { + "Name": "San Francisco", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 18, + "FirstName": "Sandy", + "LastName": "Osborn", + "UserName": "sandyosborn", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "salliesampson", + "HomeAddress": { + "Address": "Grove Street, Ganton", + "City": { + "Name": "Los Santos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 24, + "FirstName": "Scott", + "LastName": "Ketchum", + "UserName": "scottketchum", + "Friends": [ + "georginabarlow", + "marshallgaray" + ], + "BestFriend": "ursulabright", + "HomeAddress": { + "Address": "Portola Drive, Rockford Hills", + "City": { + "Name": "Los Santos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 31, + "FirstName": "Ursula", + "LastName": "Bright", + "UserName": "ursulabright", + "Friends": [ + "georginabarlow", + "marshallgaray" + ], + "BestFriend": "scottketchum", + "HomeAddress": { + "Address": "First St. SE", + "City": { + "Name": "Washington", + "CountryRegion": "United States", + "Region": "DC" + } + } + }, + { + "Age": 40, + "FirstName": "Vincent", + "LastName": "Calabrese", + "UserName": "vincentcalabrese", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "willieashmore", + "HomeAddress": { + "Address": "4 Privet Drive", + "City": { + "Name": "Little Whinging", + "CountryRegion": "Great Britain", + "Region": "SRY" + } + } + }, + { + "Age": 45, + "FirstName": "Willie", + "LastName": "Ashmore", + "UserName": "willieashmore", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "vincentcalabrese", + "HomeAddress": { + "Address": "124 Conch St.", + "City": { + "Name": "Bikini Bottom", + "CountryRegion": "Pacific Ocean", + "Region": "N/D" + } + } + } + ] +} \ No newline at end of file diff --git a/packages/odatav4/steps/10/webapp/localService/mockserver.ts b/packages/odatav4/steps/10/webapp/localService/mockserver.ts new file mode 100644 index 000000000..d6810087d --- /dev/null +++ b/packages/odatav4/steps/10/webapp/localService/mockserver.ts @@ -0,0 +1,782 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any */ +import JSONModel from "sap/ui/model/json/JSONModel"; +import Log from "sap/base/Log"; + +// Pull sinon from the UI5 third-party shim. The shim has no TS typings; +// we treat the imported value as a structural any so the mock implementation +// stays close to the original JavaScript. +// eslint-disable-next-line @typescript-eslint/no-require-imports +declare const sap: any; + +interface MockUser { + UserName: string; + FirstName?: string; + LastName?: string; + Age?: number; + Friends?: string[]; + BestFriend?: string; + [key: string]: unknown; +} + +interface MockXhr { + method: string; + url: string; + requestBody?: string; + respond?: (status: number, headers: Record, body: string | null) => void; +} + +type MockResponse = [number, Record, string | null] | [number, Record]; + +// sinon is provided by the "sap/ui/thirdparty/sinon" module — see the require below +let sinon: any; +let sandbox: any; +let users: MockUser[]; // The array that holds the cached user data +let metadata: string; // The string that holds the cached mock service metadata +const namespace = "ui5/tutorial/odatav4"; +// Component for writing logs into the console +const logComponent = "ui5.tutorial.odatav4.mockserver"; +const rBaseUrl = /services.odata.org\/TripPinRESTierService/; + +/** + * Returns the base URL from a given URL. + * @param sUrl - the complete URL + * @returns the base URL + */ +function getBaseUrl(url: string): string { + const matches = url.match(/http.+\(S\(.+\)\)\//); + + if (!Array.isArray(matches) || matches.length < 1) { + throw new Error("Could not find a base URL in " + url); + } + + return matches[0]; +} + +/** + * Looks for a user with a given user name and returns its index in the user array. + * @param sUserName - the user name to look for. + * @returns index of that user in the array, or -1 if the user was not found. + */ +function findUserIndex(userName: string): number { + for (let i = 0; i < users.length; i++) { + if (users[i].UserName === userName) { + return i; + } + } + return -1; +} + +/** + * Retrieves any user data from a given http request body. + * @param sBody - the http request body. + * @returns the parsed user data. + */ +function getUserDataFromRequestBody(body: string): MockUser { + const matches = body.match(/({.+})/); + + if (!Array.isArray(matches) || matches.length !== 2) { + throw new Error("Could not find any user data in " + body); + } + return JSON.parse(matches[1]) as MockUser; +} + +/** + * Retrieves a user name from a given request URL. + * @param sUrl - the request URL. + * @returns the user name or undefined if no user was found. + */ +function getUserKeyFromUrl(url: string): string | undefined { + const matches = url.match(/People\('(.*)'\)/); + return matches ? matches[1] : undefined; +} + +/** + * Checks if a given UserName is unique or already used + * @param sUserName - the UserName to be checked + * @returns True if the UserName is unique (not used), false otherwise + */ +function isUnique(userName: string): boolean { + return findUserIndex(userName) < 0; +} + +/** + * Returns a proper HTTP response body for "duplicate key" errors + * @param sKey - the duplicate key + * @returns the proper response body + */ +function duplicateKeyError(key: string): string { + return JSON.stringify({ + error: { + code: "409", + message: "There is already a user with user name '" + key + "'.", + target: "UserName" + } + }); +} + +function invalidKeyError(key: string): string { + return JSON.stringify({ + error: { + code: "404", + message: "There is no user with user name '" + key + "'.", + target: "UserName" + } + }); +} + +function getSuccessResponse(responseBody: string): MockResponse { + return [ + 200, + { + "Content-Type": "application/json; odata.metadata=minimal", + "OData-Version": "4.0" + }, + responseBody + ]; +} + +/** + * Reads and caches the fake service metadata and data from their + * respective files. + * @returns a promise that is resolved when the data is loaded + */ +function readData(): Promise { + const metadataPromise = new Promise((resolve, reject) => { + const resourcePath = sap.ui.require.toUrl(namespace + "/localService/metadata.xml"); + const request = new XMLHttpRequest(); + + request.onload = function () { + // 404 is not an error for XMLHttpRequest so we need to handle it here + if (request.status === 404) { + const error = "resource " + resourcePath + " not found"; + + Log.error(error, logComponent); + reject(new Error(error)); + } + metadata = this.responseText; + resolve(); + }; + request.onerror = function () { + const error = "error loading resource '" + resourcePath + "'"; + + Log.error(error, logComponent); + reject(new Error(error)); + }; + request.open("GET", resourcePath); + request.send(); + }); + + const mockDataPromise = new Promise((resolve, reject) => { + const resourcePath = sap.ui.require.toUrl(namespace + "/localService/mockdata/people.json"); + const mockDataModel = new JSONModel(resourcePath); + + mockDataModel.attachRequestCompleted(function (this: JSONModel, event: any) { + // 404 is not an error for JSONModel so we need to handle it here + if (event.getParameter("errorobject") + && event.getParameter("errorobject").statusCode === 404) { + const error = "resource '" + resourcePath + "' not found"; + + Log.error(error, logComponent); + reject(new Error(error)); + } + users = (this.getData() as { value: MockUser[] }).value; + resolve(); + }); + + mockDataModel.attachRequestFailed(() => { + const error = "error loading resource '" + resourcePath + "'"; + + Log.error(error, logComponent); + reject(new Error(error)); + }); + }); + + return Promise.all([metadataPromise, mockDataPromise]); +} + +/** + * Reduces a given result set by applying the OData URL parameters 'skip' and 'top' to it. + * Does NOT change the given result set but returns a new array. + */ +function applySkipTop(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + const reducedUsers = [...resultSet]; + const matches = xhr.url.match(/\$skip=(\d+)&\$top=(\d+)/); + + if (Array.isArray(matches) && matches.length >= 3) { + const skip = parseInt(matches[1], 10); + const top = parseInt(matches[2], 10); + return resultSet.slice(skip, skip + top); + } + + return reducedUsers; +} + +/** + * Sorts a given result set by applying the OData URL parameter 'orderby'. + * Does NOT change the given result set but returns a new array. + */ +function applySort(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + const sortedUsers = [...resultSet]; // work with a copy + const matches = xhr.url.match(/\$orderby=(\w*)(?:%20(\w*))?/); + + if (!Array.isArray(matches) || matches.length < 2) { + return sortedUsers; + } + const fieldName = matches[1]; + const direction = matches[2] || "asc"; + + if (fieldName !== "LastName") { + throw new Error("Filters on field " + fieldName + " are not supported."); + } + + sortedUsers.sort((a, b) => { + const nameA = (a.LastName || "").toUpperCase(); + const nameB = (b.LastName || "").toUpperCase(); + const asc = direction === "asc"; + + if (nameA < nameB) { + return asc ? -1 : 1; + } + if (nameA > nameB) { + return asc ? 1 : -1; + } + return 0; + }); + + return sortedUsers; +} + +/** + * Filters a given result set by applying the OData URL parameter 'filter'. + * Does NOT change the given result set but returns a new array. + */ +function applyFilter(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + let filteredUsers = [...resultSet]; // work with a copy + const matches = xhr.url.match(/\$filter=.*\((.*),'(.*)'\)/); + + // If the request contains a filter command, apply the filter + if (Array.isArray(matches) && matches.length >= 3) { + const fieldName = matches[1]; + const query = matches[2]; + + if (fieldName !== "LastName") { + throw new Error("Filters on field " + fieldName + " are not supported."); + } + + filteredUsers = users.filter((user) => (user.LastName || "").indexOf(query) !== -1); + } + + return filteredUsers; +} + +/** + * Handles GET requests for metadata. + */ +function handleGetMetadataRequests(): MockResponse { + return [ + 200, + { + "Content-Type": "application/xml", + "odata-version": "4.0" + }, metadata + ]; +} + +/** + * Handles GET requests for a pure user count and returns a fitting response. + */ +function handleGetCountRequests(): MockResponse { + return getSuccessResponse(users.length.toString()); +} + +/** + * Handles GET requests for user data and returns a fitting response. + */ +function handleGetUserRequests(xhr: MockXhr, _bCount: boolean): MockResponse { + let count: number; + let expand: RegExpMatchArray | string[] | null; + let expand2: string; + let index: number; + let key: string | undefined; + let response: { "@odata.count"?: number; value: MockUser[] } | MockUser | null; + let responseBody: string; + let result: MockUser[]; + let select: RegExpMatchArray | string[] | null; + let select2: string; + let subSelects: string[][] = []; + let i: number; + + // Get expand parameter + expand = xhr.url.match(/\$expand=([^&]+)/); + + // Sort out expand parameter values + subSelects in brackets + if (expand) { + expand2 = expand[0]; + expand2 = expand2.substring(8); + + // Sort out subselects (e.g. BestFriend($select=Age,UserName),Friend) + const subSelectMatches = expand2.match(/\([^)]*\)/g) || []; + subSelects = subSelectMatches.map((s) => s.replace(/\(\$select=/, "").replace(/\)/, "").split(",")); + expand2 = expand2.replace(/\([^)]*\)/g, ""); + expand = expand2.split(","); + } + + // Get select parameter + select = xhr.url.match(/[^(]\$select=([\w|,]+)/); + + // Sort out select parameter values + if (Array.isArray(select)) { + select2 = select[0]; + select2 = select2.replace(/&/, "").replace(/\?/, "").substring(8); + select = select2.split(","); + } + + // Check if an individual user or a user range is requested + key = getUserKeyFromUrl(xhr.url); + if (key) { + index = findUserIndex(key); + + if (/People\(.+\)\/Friends/.test(xhr.url)) { + // ownRequest for friends + response = { value: createFriendsArray(users[index].Friends, select as string[]) }; + } else { + // specific user was requested + response = getUserObject(index, select as string[], expand as string[], subSelects); + } + + if (index > -1) { + responseBody = JSON.stringify(response); + return getSuccessResponse(responseBody); + } + responseBody = invalidKeyError(key); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; + } + // all users requested + result = applyFilter(xhr, users); + count = result.length; // the total no. of people found, after filtering + result = applySort(xhr, result); + result = applySkipTop(xhr, result); + + // generate sResponse + const finalResponse: { "@odata.count": number; value: MockUser[] } = { "@odata.count": count, value: [] }; + + result.forEach((user) => { + const userIndex = findUserIndex(user.UserName); + + finalResponse.value.push(getUserObject(userIndex, select as string[], expand as string[], subSelects) as MockUser); + }); + + responseBody = JSON.stringify(finalResponse); + + return getSuccessResponse(responseBody); +} + +/** + * Returns a specific user in the aUsers array. + */ +function getUserByIndex(index: number, properties: string[]): MockUser | null { + const helper: MockUser = { UserName: "" }; + const user = users[index]; + + if (user) { + properties.forEach((selectProperty) => { + helper[selectProperty] = user[selectProperty]; + }); + + return helper; + } + return null; +} + +/** + * Returns the user with iIndex in the aUsers array with all its information + */ +function getUserObject(index: number, select: string[], expand: string[] | null | undefined, subSelects: string[][]): MockUser | null { + let bestFriend: string | undefined; + let friendIndex: number; + let friends: string[] | undefined; + let object: MockUser | null; + let user: MockUser; + let i: number; + + object = getUserByIndex(index, select); + if (expand && object) { + user = users[index]; + for (i = 0; i < expand.length; i++) { + switch (expand[i]) { + case "Friends": + friends = user.Friends; + object.Friends = createFriendsArray(friends, subSelects[i]) as unknown as string[]; + break; + case "BestFriend": + bestFriend = user.BestFriend; + friendIndex = findUserIndex(bestFriend || ""); + object.BestFriend = getUserByIndex(friendIndex, subSelects[i]) as unknown as string; + break; + default: + break; + } + } + } + return object; +} + +/** + * creates array of friends for a given user + */ +function createFriendsArray(friends: string[] | undefined, subSelects: string[]): MockUser[] { + let array: (MockUser | null)[] = []; + + if (friends) { + friends.forEach((friend) => { + const friendIndex = findUserIndex(friend); + array.push(getUserByIndex(friendIndex, subSelects)); + }); + + array = array.filter((element) => element !== null); + } + + return array as MockUser[]; +} + +/** + * Handles PATCH requests for users and returns a fitting response. + */ +function handlePatchUserRequests(xhr: MockXhr): MockResponse { + // Get the key of the person to change + const key = getUserKeyFromUrl(xhr.url); + + // Get the list of changes + const changes = getUserDataFromRequestBody(xhr.requestBody || ""); + + // Check if the UserName is changed to a duplicate. + // If the UserName is "changed" to its current value, that is not an error. + if (Object.prototype.hasOwnProperty.call(changes, "UserName") + && changes.UserName !== key + && !isUnique(changes.UserName)) { + // Error + const responseBody = duplicateKeyError(changes.UserName); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; + } + // No error: make the change(s) + const user = users[findUserIndex(key || "")]; + for (const fieldName in changes) { + if (Object.prototype.hasOwnProperty.call(changes, fieldName)) { + user[fieldName] = changes[fieldName]; + } + } + + // The response to PATCH requests is always http 204 (No Content) + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Handles DELETE requests for users and returns a fitting response. + */ +function handleDeleteUserRequests(xhr: MockXhr): MockResponse { + const key = getUserKeyFromUrl(xhr.url); + users.splice(findUserIndex(key || ""), 1); + + // The response to DELETE requests is always http 204 (No Content) + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Handles POST requests for users and returns a fitting response. + */ +function handlePostUserRequests(xhr: MockXhr): MockResponse { + const user = getUserDataFromRequestBody(xhr.requestBody || ""); + + // Check if that user already exists + if (isUnique(user.UserName)) { + users.push(user); + + let responseBody = '{"@odata.context": "' + getBaseUrl(xhr.url) + + '$metadata#People/$entity",'; + responseBody += JSON.stringify(user).slice(1); + + // The response to POST requests is http 201 (Created) + return [ + 201, + { + "Content-Type": "application/json; odata.metadata=minimal", + "OData-Version": "4.0" + }, + responseBody + ]; + } + // Error + const responseBody = duplicateKeyError(user.UserName); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; +} + +/** + * Handles POST requests for resetting the data and returns a fitting response. + */ +function handleResetDataRequest(): MockResponse { + void readData(); + + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Builds a response to direct (= non-batch) requests. + * Supports GET, PATCH, DELETE and POST requests. + */ +function handleDirectRequest(xhr: MockXhr): MockResponse | undefined { + let response2: MockResponse | undefined; + + switch (xhr.method) { + case "GET": + if (/\$metadata/.test(xhr.url)) { + response2 = handleGetMetadataRequests(); + } else if (/\/\$count/.test(xhr.url)) { + response2 = handleGetCountRequests(); + } else if (/People.*\?/.test(xhr.url)) { + response2 = handleGetUserRequests(xhr, /\$count=true/.test(xhr.url)); + } + break; + case "PATCH": + if (/People/.test(xhr.url)) { + response2 = handlePatchUserRequests(xhr); + } + break; + case "POST": + if (/People/.test(xhr.url)) { + response2 = handlePostUserRequests(xhr); + } else if (/ResetDataSource/.test(xhr.url)) { + response2 = handleResetDataRequest(); + } + break; + case "DELETE": + if (/People/.test(xhr.url)) { + response2 = handleDeleteUserRequests(xhr); + } + break; + case "HEAD": + response2 = [204, {}]; + break; + default: + break; + } + + return response2; +} + +/** + * Builds a response to batch requests. + * Unwraps batch request, gets a response for each individual part and + * constructs a fitting batch response. + */ +function handleBatchRequest(xhr: MockXhr): MockResponse { + let responseBody = ""; + const outerBoundary = (xhr.requestBody || "").match(/(.*)/)![1]; // First line of the body + let innerBoundary: string | undefined; + let partBoundary: string; + // The individual requests + const outerParts = (xhr.requestBody || "").split(outerBoundary).slice(1, -1); + let parts: string[]; + let header: string; + + const matches = outerParts[0].match(/multipart\/mixed;boundary=(.+)/); + // If this request has several change sets, then we need to handle the inner and outer + // boundaries (change sets have an additional boundary) + if (matches && matches.length > 0) { + innerBoundary = matches[1]; + parts = outerParts[0].split("--" + innerBoundary).slice(1, -1); + } else { + parts = outerParts; + } + + // If this request has several change sets, then the response must start with the outer + // boundary and content header + if (innerBoundary) { + partBoundary = "--" + innerBoundary; + responseBody += outerBoundary + "\r\n" + + "Content-Type: multipart/mixed; boundary=" + innerBoundary + "\r\n\r\n"; + } else { + partBoundary = outerBoundary; + } + + parts.forEach((part, index) => { + // Construct the batch response body out of the single batch request parts. + const matches0 = part.match(/(GET|DELETE|PATCH|POST) (\S+)(?:.|\r?\n)+\r?\n(.*)\r?\n$/)!; + const partResponse = handleDirectRequest({ + method: matches0[1], + url: getBaseUrl(xhr.url) + matches0[2], + requestBody: matches0[3] + })!; + + responseBody += partBoundary + "\r\n" + + "Content-Type: application/http\r\n"; + // If there are several change sets, we need to add a Content ID header + if (innerBoundary) { + responseBody += "Content-ID:" + index + ".0\r\n"; + } + responseBody += "\r\nHttp/1.1 " + partResponse[0] + "\r\n"; + // Add any headers from the request - unless this response is 204 (no content) + if (partResponse[1] && partResponse[0] !== 204) { + for (header in partResponse[1]) { + if (Object.prototype.hasOwnProperty.call(partResponse[1], header)) { + responseBody += header + ": " + partResponse[1][header] + "\r\n"; + } + } + } + responseBody += "\r\n"; + + if (partResponse[2]) { + responseBody += partResponse[2]; + } + responseBody += "\r\n"; + }); + + // Check if we need to add the inner boundary again at the end + if (innerBoundary) { + responseBody += "--" + innerBoundary + "--\r\n"; + } + // Add a final boundary to the batch response body + responseBody += outerBoundary + "--"; + + // Build the final batch response + return [ + 200, + { + "Content-Type": "multipart/mixed;boundary=" + outerBoundary.slice(2), + "OData-Version": "4.0" + }, + responseBody + ]; +} + +/** + * Handles any type of intercepted request and sends a fake response. + * Logs the request and response to the console. + * Manages batch requests. + */ +function handleAllRequests(xhr: MockXhr): void { + let response2: MockResponse | undefined; + + // Log the request + Log.info( + "Mockserver: Received " + xhr.method + " request to URL " + xhr.url, + (xhr.requestBody ? "Request body is:\n" + xhr.requestBody : "No request body.") + + "\n", + logComponent + ); + + if (xhr.method === "POST" && /\$batch/.test(xhr.url)) { + response2 = handleBatchRequest(xhr); + } else { + response2 = handleDirectRequest(xhr); + } + + if (xhr.respond && response2) { + xhr.respond(response2[0], response2[1], response2[2] || null); + } + + // Log the response + if (response2) { + Log.info( + "Mockserver: Sent response with return code " + response2[0], + ("Response headers: " + JSON.stringify(response2[1]) + "\n\nResponse body:\n" + + (response2[2] || "")) + "\n", + logComponent + ); + } +} + +export default { + + /** + * Creates a Sinon fake service, intercepting all http requests to + * the URL defined in variable rBaseUrl above. + * @returns a promise that is resolved when the mock server is started + */ + init(): Promise { + // Load sinon lazily from the UI5 third-party shim + return new Promise((resolve, reject) => { + sap.ui.require(["sap/ui/thirdparty/sinon"], (sinon: any) => { + sinon = sinon; + sandbox = sinon.sandbox.create(); + + // Read the mock data + readData().then(() => { + // Initialize the sinon fake server + sandbox.useFakeServer(); + // Make sure that requests are responded to automatically. Otherwise we would need + // to do that manually. + sandbox.server.autoRespond = true; + + // Register the requests for which responses should be faked. + sandbox.server.respondWith(rBaseUrl, handleAllRequests); + + // Apply a filter to the fake XmlHttpRequest. + // Otherwise, ALL requests (e.g. for the component, views etc.) would be + // intercepted. + sinon.FakeXMLHttpRequest.useFilters = true; + sinon.FakeXMLHttpRequest.addFilter((_sMethod: string, url: string) => { + // If the filter returns true, the request will NOT be faked. + // We only want to fake requests that go to the intended service. + return !rBaseUrl.test(url); + }); + + // Set the logging level for console entries from the mock server + Log.setLevel(Log.Level.INFO, logComponent); + + Log.info("Running the app with mock data", logComponent); + resolve(undefined); + }, reject); + }); + }); + }, + + /** + * Stops the request interception and deletes the Sinon fake server. + */ + stop(): void { + if (sinon) { + sinon.FakeXMLHttpRequest.filters = []; + sinon.FakeXMLHttpRequest.useFilters = false; + } + if (sandbox) { + sandbox.restore(); + sandbox = null; + } + } +}; diff --git a/packages/odatav4/steps/10/webapp/manifest.json b/packages/odatav4/steps/10/webapp/manifest.json new file mode 100644 index 000000000..ea22bafc9 --- /dev/null +++ b/packages/odatav4/steps/10/webapp/manifest.json @@ -0,0 +1,69 @@ +{ + "_version": "1.60.0", + "sap.app": { + "id": "ui5.tutorial.odatav4", + "type": "application", + "i18n": { + "supportedLocales": [ + "" + ], + "fallbackLocale": "", + "bundleName": "ui5.tutorial.odatav4.i18n.i18n" + }, + "applicationVersion": { + "version": "1.0.0" + }, + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "dataSources": { + "default": { + "uri": "https://services.odata.org/TripPinRESTierService/(S(id))/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + } + }, + "sap.ui": { + "technology": "UI5" + }, + "sap.ui5": { + "rootView": { + "viewName": "ui5.tutorial.odatav4.view.App", + "type": "XML", + "id": "appView" + }, + "dependencies": { + "minUI5Version": "1.132", + "libs": { + "sap.f": {}, + "sap.m": {}, + "sap.ui.core": {}, + "sap.ui.layout": {} + } + }, + "handleValidation": true, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "ui5.tutorial.odatav4.i18n.i18n", + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + } + }, + "": { + "dataSource": "default", + "preload": true, + "settings": { + "autoExpandSelect": true, + "earlyRequests": true, + "operationMode": "Server" + } + } + } + } +} diff --git a/packages/odatav4/steps/10/webapp/model/models.ts b/packages/odatav4/steps/10/webapp/model/models.ts new file mode 100644 index 000000000..5fdcff4a3 --- /dev/null +++ b/packages/odatav4/steps/10/webapp/model/models.ts @@ -0,0 +1,10 @@ +// models.ts — central application models +import JSONModel from "sap/ui/model/json/JSONModel"; +import Device from "sap/ui/Device"; + +export function createDeviceModel(): JSONModel { + const model = new JSONModel(Device); + + model.setDefaultBindingMode("OneWay"); + return model; +} diff --git a/packages/odatav4/steps/10/webapp/view/App.view.xml b/packages/odatav4/steps/10/webapp/view/App.view.xml new file mode 100644 index 000000000..9440b3b50 --- /dev/null +++ b/packages/odatav4/steps/10/webapp/view/App.view.xml @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + </semantic:titleHeading> + <semantic:headerContent> + <FlexBox> + <VBox> + <ObjectAttribute text="{i18n>userNameLabelText}"/> + <ObjectAttribute text="{UserName}"/> + </VBox> + <VBox class="sapUiMediumMarginBegin"> + <ObjectAttribute text="{i18n>ageLabelText}"/> + <ObjectNumber number="{Age}" unit="Years"/> + </VBox> + </FlexBox> + </semantic:headerContent> + <semantic:content> + <VBox> + <FlexBox wrap="Wrap"> + <f:Form editable="false"> + <f:title> + <core:Title text="{i18n>addressTitleText}" /> + </f:title> + <f:layout> + <f:ResponsiveGridLayout + labelSpanXL="3" + labelSpanL="3" + labelSpanM="3" + labelSpanS="12" + adjustLabelSpan="false" + emptySpanXL="4" + emptySpanL="4" + emptySpanM="4" + emptySpanS="0" + columnsXL="1" + columnsL="1" + columnsM="1" + singleContainerFullSize="false" /> + </f:layout> + <f:formContainers> + <f:FormContainer> + <f:formElements> + <f:FormElement label="{i18n>addressLabelText}"> + <f:fields> + <Text text="{HomeAddress/Address}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>cityLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/Name}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>regionLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/Region}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>countryLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/CountryRegion}" /> + </f:fields> + </f:FormElement> + </f:formElements> + </f:FormContainer> + </f:formContainers> + </f:Form> + <f:Form editable="false"> + <f:title> + <core:Title text="{i18n>bestFriendTitleText}" /> + </f:title> + <f:layout> + <f:ResponsiveGridLayout + labelSpanXL="3" + labelSpanL="3" + labelSpanM="3" + labelSpanS="12" + adjustLabelSpan="false" + emptySpanXL="4" + emptySpanL="4" + emptySpanM="4" + emptySpanS="0" + columnsXL="1" + columnsL="1" + columnsM="1" + singleContainerFullSize="false" /> + </f:layout> + <f:formContainers> + <f:FormContainer> + <f:formElements> + <f:FormElement label="{i18n>nameLabelText}"> + <f:fields> + <Text text="{BestFriend/FirstName} {BestFriend/LastName}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>ageLabelText}"> + <f:fields> + <Text text="{BestFriend/Age}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>userNameLabelText}"> + <f:fields> + <Text text="{BestFriend/UserName}" /> + </f:fields> + </f:FormElement> + </f:formElements> + </f:FormContainer> + </f:formContainers> + </f:Form> + </FlexBox> + </VBox> + </semantic:content> + </semantic:SemanticPage> + </l:SplitPane> + </l:PaneContainer> + </l:ResponsiveSplitter> + </content> + <footer> + <Toolbar visible="{appView>/hasUIChanges}"> + <ToolbarSpacer/> + <Button + id="saveButton" + type="Emphasized" + text="{i18n>saveButtonText}" + enabled="{= ${message>/}.length === 0 && ${appView>/usernameEmpty} === false }" + press=".onSave"/> + <Button + id="doneButton" + text="{i18n>cancelButtonText}" + press=".onResetChanges"/> + </Toolbar> + </footer> + </Page> + </pages> + </App> + </Shell> +</mvc:View> \ No newline at end of file diff --git a/packages/odatav4/steps/11/README.md b/packages/odatav4/steps/11/README.md new file mode 100644 index 000000000..650a42906 --- /dev/null +++ b/packages/odatav4/steps/11/README.md @@ -0,0 +1,108 @@ +# Step 11: Add Table with :n Navigation to Detail Area + +<details class="ts-only" markdown="1"> + +You can download the solution for this step here: [📥 Download step 11](https://ui5.github.io/tutorials/odatav4/odatav4-step-11.zip). + +</details> + +<details class="js-only" markdown="1"> + +You can download the solution for this step here: [📥 Download step 11](https://ui5.github.io/tutorials/odatav4/odatav4-step-11-js.zip). + +</details> + +In this step we add a table with additional information to the detail area. + +## Preview + +**A table containing information about friends of the selected user is added** + +![](assets/Tut_OD4_Step_11_45abd62.png "A table containing information about friends of the selected user is added") + +## Coding + +You can view this step live: [🔗 Live Preview of Step 11](https://ui5.github.io/tutorials/odatav4/build/11/index-cdn.html). + +## webapp/view/App.view.xml + +```xml +<mvc:View +... + <VBox> + <FlexBox wrap="Wrap"> + ... + <f:Form editable="false"> + <f:title> + <core:Title text="{i18n>bestFriendTitleText}" /> + </f:title> + ... + <f:formContainers> + <f:FormContainer> + <f:formElements> + ... + </f:formElements> + </f:FormContainer> + </f:formContainers> + </f:Form> + </FlexBox> + <Table + id="friendsTable" + width="auto" + items="{path: 'Friends', + parameters: { + $$ownRequest: true + }}" + noDataText="No Data" + class="sapUiSmallMarginBottom"> + <headerToolbar> + <Toolbar> + <Title + text="Friends" + titleStyle="H3" + level="H3"/> + </Toolbar> + </headerToolbar> + <columns> + <Column> + <Text text="User Name"/> + </Column> + <Column> + <Text text="First Name"/> + </Column> + <Column> + <Text text="Last Name"/> + </Column> + <Column> + <Text text="Age"/> + </Column> + </columns> + <items> + <ColumnListItem> + <cells> + <Text text="{UserName}"/> + </cells> + <cells> + <Text text="{FirstName}"/> + </cells> + <cells> + <Text text="{LastName}"/> + </cells> + <cells> + <Text text="{Age}"/> + </cells> + </ColumnListItem> + </items> + </Table> + </VBox> +... +</mvc:View> +``` + +We extend the detail area of the `appView` by adding a table after the `FlexBox`. To this table we add a data binding for friends. It is important that we set the `$$ownRequest` binding parameter to `true`, so that the table containing all friends of the selected user makes its own OData requests separate from the request for best friend and best friend's address. + +*** + +**Next:** [Step 1: The Initial App](../01/README.md) + +**Previous:** [Step 10: Enable Data Reuse](../10/README.md) diff --git a/packages/odatav4/steps/11/package.json b/packages/odatav4/steps/11/package.json new file mode 100644 index 000000000..ec7537bda --- /dev/null +++ b/packages/odatav4/steps/11/package.json @@ -0,0 +1,19 @@ +{ + "name": "ui5.tutorial.odatav4.step11", + "version": "1.0.0", + "author": "SAP SE", + "description": "OpenUI5 TypeScript Tutorial — OData V4: Step 11 — Add Table with :n Navigation to Detail Area", + "private": true, + "scripts": { + "start": "ui5 serve -o index.html", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@types/openui5": "^1.147.0", + "@ui5/cli": "^4.0.53", + "typescript": "^6.0.3", + "ui5-middleware-livereload": "^3.3.1", + "ui5-middleware-serveframework": "^3.8.1", + "ui5-tooling-transpile": "^3.11.0" + } +} diff --git a/packages/odatav4/steps/11/tsconfig.json b/packages/odatav4/steps/11/tsconfig.json new file mode 100644 index 000000000..1044f76cd --- /dev/null +++ b/packages/odatav4/steps/11/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "es2023", + "types": [ + "node", + "@types/openui5" + ], + "skipLibCheck": true, + "allowJs": true, + "strictPropertyInitialization": false, + "rootDir": "./webapp", + "paths": { + "ui5/tutorial/odatav4/*": [ + "./webapp/*" + ] + }, + "strict": false, + "strictNullChecks": false + }, + "include": [ + "./webapp/**/*" + ] +} diff --git a/packages/odatav4/steps/11/ui5.yaml b/packages/odatav4/steps/11/ui5.yaml new file mode 100644 index 000000000..e1ca8e9c2 --- /dev/null +++ b/packages/odatav4/steps/11/ui5.yaml @@ -0,0 +1,25 @@ +specVersion: '3.0' +metadata: + name: "ui5.tutorial.odatav4" +type: application +framework: + name: OpenUI5 + version: "1.147.1" + libraries: + - name: sap.m + - name: sap.f + - name: sap.ui.layout + - name: sap.ui.core + - name: themelib_sap_horizon +builder: + customTasks: + - name: ui5-tooling-transpile-task + afterTask: replaceVersion +server: + customMiddleware: + - name: ui5-tooling-transpile-middleware + afterMiddleware: compression + - name: ui5-middleware-serveframework + afterMiddleware: compression + - name: ui5-middleware-livereload + afterMiddleware: compression diff --git a/packages/odatav4/steps/11/webapp/Component.ts b/packages/odatav4/steps/11/webapp/Component.ts new file mode 100644 index 000000000..170cbb94c --- /dev/null +++ b/packages/odatav4/steps/11/webapp/Component.ts @@ -0,0 +1,27 @@ +// Component.ts — UI5 OData V4 Tutorial +import UIComponent from "sap/ui/core/UIComponent"; +import { createDeviceModel } from "./model/models"; + +/** + * @namespace ui5.tutorial.odatav4 + */ +export default class Component extends UIComponent { + public static metadata = { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + manifest: "json" + }; + + /** + * The component is initialized by UI5 automatically during the startup of the app and calls + * the init method once. + * @public + * @override + */ + init(): void { + // call the base component's init function + super.init(); + + // set the device model + this.setModel(createDeviceModel(), "device"); + } +} diff --git a/packages/odatav4/steps/11/webapp/controller/App.controller.ts b/packages/odatav4/steps/11/webapp/controller/App.controller.ts new file mode 100644 index 000000000..7722959a3 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/controller/App.controller.ts @@ -0,0 +1,312 @@ +import Messaging from "sap/ui/core/Messaging"; +import Controller from "sap/ui/core/mvc/Controller"; +import MessageToast from "sap/m/MessageToast"; +import MessageBox from "sap/m/MessageBox"; +import Sorter from "sap/ui/model/Sorter"; +import Filter from "sap/ui/model/Filter"; +import FilterOperator from "sap/ui/model/FilterOperator"; +import FilterType from "sap/ui/model/FilterType"; +import JSONModel from "sap/ui/model/json/JSONModel"; +import ResourceModel from "sap/ui/model/resource/ResourceModel"; +import ResourceBundle from "sap/base/i18n/ResourceBundle"; +import Component from "sap/ui/core/Component"; +import List from "sap/m/List"; +import type ColumnListItem from "sap/m/ColumnListItem"; +import type SearchField from "sap/m/SearchField"; +import type ListBinding from "sap/ui/model/ListBinding"; +import type Event from "sap/ui/base/Event"; +import type Input from "sap/m/Input"; +import type Context from "sap/ui/model/odata/v4/Context"; +import type ODataModel from "sap/ui/model/odata/v4/ODataModel"; +import type ODataListBinding from "sap/ui/model/odata/v4/ODataListBinding"; + +/** + * @namespace ui5.tutorial.odatav4.controller + */ +export default class App extends Controller { + + private _bTechnicalErrors = false; + + /** + * Hook for initializing the controller + */ + onInit(): void { + const messageModel = Messaging.getMessageModel(); + const messageModelBinding = messageModel.bindList("/", undefined, [], + new Filter("technical", FilterOperator.EQ, true)); + const viewModel = new JSONModel({ + busy: false, + hasUIChanges: false, + usernameEmpty: false, + order: 0 + }); + + this.getView().setModel(viewModel, "appView"); + this.getView().setModel(messageModel, "message"); + + messageModelBinding.attachChange(this.onMessageBindingChange, this); + this._bTechnicalErrors = false; + } + + /* =========================================================== */ + /* begin: event handlers */ + /* =========================================================== */ + + /** + * Create a new entry. + */ + onCreate(): void { + const list = this.byId("peopleList") as List; + const binding = list.getBinding("items") as ODataListBinding; + // Create a new entry through the table's list binding + const context = binding.create({ Age: "18" }); + + this._setUIChanges(true); + (this.getView().getModel("appView") as JSONModel).setProperty("/usernameEmpty", true); + + // Select and focus the table row that contains the newly created entry + list.getItems().some((item) => { + const columnItem = item as ColumnListItem; + if (columnItem.getBindingContext() === context) { + columnItem.focus(); + columnItem.setSelected(true); + return true; + } + return false; + }); + } + + /** + * Delete an entry. + */ + onDelete(): void { + const peopleList = this.byId("peopleList") as List; + const selected = peopleList.getSelectedItem() as ColumnListItem | null; + + if (selected) { + const context = selected.getBindingContext() as Context; + const userName = context.getProperty("UserName") as string; + void context.delete().then(() => { + MessageToast.show(this._getText("deletionSuccessMessage", [userName])); + }, (error2: Error & { canceled?: boolean }) => { + const currentSelected = peopleList.getSelectedItem() as ColumnListItem | null; + if (currentSelected && context === currentSelected.getBindingContext()) { + this._setDetailArea(context); + } + this._setUIChanges(); + if (error2.canceled) { + MessageToast.show(this._getText("deletionRestoredMessage", [userName])); + return; + } + MessageBox.error(error2.message + ": " + userName); + }); + this._setDetailArea(); + this._setUIChanges(); + } + } + + /** + * Lock UI when changing data in the input controls + */ + onInputChange(evt: Event): void { + if ((evt as unknown as { getParameter(n: string): unknown }).getParameter("escPressed")) { + this._setUIChanges(); + } else { + this._setUIChanges(true); + // Check if the username in the changed table row is empty and set the appView + // property accordingly + const ctx = (evt.getSource() as Input).getParent()?.getBindingContext(); + if (ctx && ctx.getProperty("UserName")) { + (this.getView().getModel("appView") as JSONModel).setProperty("/usernameEmpty", false); + } + } + } + + /** + * Refresh the data. + */ + onRefresh(): void { + const binding = (this.byId("peopleList") as List).getBinding("items") as ODataListBinding; + + if (binding.hasPendingChanges()) { + MessageBox.error(this._getText("refreshNotPossibleMessage")); + return; + } + binding.refresh(); + MessageToast.show(this._getText("refreshSuccessMessage")); + } + + /** + * Reset any unsaved changes. + */ + onResetChanges(): void { + ((this.byId("peopleList") as List).getBinding("items") as ODataListBinding).resetChanges(); + // If there were technical errors, cancelling changes resets them. + this._bTechnicalErrors = false; + this._setUIChanges(false); + } + + /** + * Reset the data source. + */ + onResetDataSource(): void { + const model = this.getView().getModel() as ODataModel; + const operation = model.bindContext("/ResetDataSource(...)"); + + void operation.invoke().then(() => { + model.refresh(); + MessageToast.show(this._getText("sourceResetSuccessMessage")); + }, (error2: Error) => { + MessageBox.error(error2.message); + }); + } + + /** + * Save changes to the source. + */ + onSave(): void { + const success = () => { + this._setBusy(false); + MessageToast.show(this._getText("changesSentMessage")); + this._setUIChanges(false); + }; + const error = (error2: Error) => { + this._setBusy(false); + this._setUIChanges(false); + MessageBox.error(error2.message); + }; + + this._setBusy(true); // Lock UI until submitBatch is resolved. + (this.getView().getModel() as ODataModel).submitBatch("peopleGroup").then(success, error); + // If there were technical errors, a new save resets them. + this._bTechnicalErrors = false; + } + + /** + * Search for the term in the search field. + */ + onSearch(): void { + const view = this.getView(); + const value = (view.byId("searchField") as SearchField).getValue(); + const filter = new Filter("LastName", FilterOperator.Contains, value); + + ((view.byId("peopleList") as List).getBinding("items") as ListBinding).filter(filter, FilterType.Application); + } + + /** + * Sort the table according to the last name. + * Cycles between the three sorting states "none", "ascending" and "descending" + */ + onSort(): void { + const view = this.getView(); + const states: (string | undefined)[] = [undefined, "asc", "desc"]; + const stateTextIds = ["sortNone", "sortAscending", "sortDescending"]; + let order = (view.getModel("appView") as JSONModel).getProperty("/order") as number; + + // Cycle between the states + order = (order + 1) % states.length; + const order2 = states[order]; + + (view.getModel("appView") as JSONModel).setProperty("/order", order); + ((view.byId("peopleList") as List).getBinding("items") as ListBinding) + .sort(order2 ? new Sorter("LastName", order2 === "desc") : []); + + const message = this._getText("sortMessage", [this._getText(stateTextIds[order])]); + MessageToast.show(message); + } + + onMessageBindingChange(event: Event): void { + const contexts = (event.getSource() as ListBinding).getContexts(); + let messageOpen = false; + + if (messageOpen || !contexts.length) { + return; + } + + // Extract and remove the technical messages + const messages = contexts.map((context: Context) => context.getObject()); + Messaging.removeMessages(messages); + + this._setUIChanges(true); + this._bTechnicalErrors = true; + MessageBox.error((messages[0] as { message: string }).message, { + id: "serviceErrorMessageBox", + onClose: () => { + messageOpen = false; + } + }); + + messageOpen = true; + } + + onSelectionChange(event: Event): void { + const listItem = (event as unknown as { getParameter(n: string): unknown }).getParameter("listItem") as ColumnListItem; + this._setDetailArea(listItem.getBindingContext() as Context); + } + + /* =========================================================== */ + /* end: event handlers */ + /* =========================================================== */ + + /** + * Convenience method for retrieving a translatable text. + */ + _getText(textId: string, args?: unknown[]): string { + const bundle = ((this.getOwnerComponent() as Component).getModel("i18n") as ResourceModel).getResourceBundle() as ResourceBundle; + return bundle.getText(textId, args as string[]); + } + + /** + * Set hasUIChanges flag in View Model + * @param bHasUIChanges - set or clear hasUIChanges; if undefined, the hasPendingChanges-function + * of the OdataV4 model determines the result + */ + _setUIChanges(hasUIChanges?: boolean): void { + if (this._bTechnicalErrors) { + // If there is currently a technical error, then force 'true'. + hasUIChanges = true; + } else if (hasUIChanges === undefined) { + hasUIChanges = (this.getView().getModel() as ODataModel).hasPendingChanges(); + } + const model = this.getView().getModel("appView") as JSONModel; + model.setProperty("/hasUIChanges", hasUIChanges); + } + + /** + * Set busy flag in View Model + */ + _setBusy(isBusy: boolean): void { + const model = this.getView().getModel("appView") as JSONModel; + model.setProperty("/busy", isBusy); + } + + /** + * Toggles the visibility of the detail area + * @param oUserContext - the current user context + */ + _setDetailArea(userContext?: Context): void { + const detailArea = this.byId("detailArea"); + const layout = this.byId("defaultLayout") as unknown as { setSize(s: string): void; setResizable(b: boolean): void }; + const searchField = this.byId("searchField") as SearchField; + + if (!detailArea) { + return; // do nothing during view destruction + } + + const oldContext = (detailArea as unknown as { getBindingContext(): Context | null }).getBindingContext(); + if (oldContext && !oldContext.isTransient()) { + oldContext.setKeepAlive(false); + } + if (userContext && !userContext.isTransient()) { + userContext.setKeepAlive(true, + // hide details if kept entity was refreshed but does not exist any more + this._setDetailArea.bind(this)); + } + (detailArea as unknown as { setBindingContext(c: Context | null): void }).setBindingContext(userContext || null); + // resize view + (detailArea as unknown as { setVisible(b: boolean): void }).setVisible(!!userContext); + layout.setSize(userContext ? "60%" : "100%"); + layout.setResizable(!!userContext); + searchField.setWidth(userContext ? "40%" : "20%"); + } +} diff --git a/packages/odatav4/steps/11/webapp/i18n/i18n.properties b/packages/odatav4/steps/11/webapp/i18n/i18n.properties new file mode 100644 index 000000000..a4fa06200 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/i18n/i18n.properties @@ -0,0 +1,100 @@ +# App Descriptor +#XTIT: Application name +appTitle=OData V4 - Step 11: Add table with :n navigation to detail area + +#YDES: Application description +appDescription=OData V4 Tutorial + +#XTIT: Page Title +peoplePageTitle=My Users + +# Toolbar +#XBUT: Button text for save +saveButtonText=Save + +#XBUT: Button text for reset changes +resetChangesButtonText=Restart Tutorial + +#XBUT: Button text for cancel +cancelButtonText=Cancel + +#XTOL: Tooltip for sort +sortButtonText=Sort by Last Name + +#XBUT: Button text for add user +createButtonText=Add User + +#XBUT: Button text for delete user +deleteButtonText=Delete User + +#XTOL: Tooltip for refresh data +refreshButtonText=Refresh Data + +#XTXT: Placeholder text for search field +searchFieldPlaceholder=Type in a last name + +# Table Area +#XFLD: Label for User Name +userNameLabelText=User Name + +#XFLD: Label for First Name +firstNameLabelText=First Name + +#XFLD: Label for Last Name +lastNameLabelText=Last Name + +#XFLD: Label for Age +ageLabelText=Age + +# Messages +#XMSG: Message for user changes sent to the service +changesSentMessage=User data sent to the server + +#XMSG: Message for user deleted +deletionSuccessMessage=User {0} deleted + +#XMSG: Message for user restored (undeleted) +deletionRestoredMessage=User {0} restored + +#XMSG: Message for changes reverted +sourceResetSuccessMessage=All changes reverted back to start + +#XMSG: Message for refresh failed +refreshNotPossibleMessage=Before refreshing, please save or revert your changes + +#XMSG: Message for refresh succeeded +refreshSuccessMessage=Data refreshed + +#MSG: Message for sorting +sortMessage=Users sorted by {0} + +#MSG: Suffix for sorting by LastName, ascending +sortAscending=last name, ascending + +#MSG: Suffix for sorting by LastName, descending +sortDescending=last name, descending + +#MSG: Suffix for no sorting +sortNone=the sequence on the server + +# Detail Area +#XTIT: Title for Address +addressTitleText=Address + +#XFLD: Label for Address +addressLabelText=Address + +#XFLD: Label for City +cityLabelText=City + +#XFLD: Label for Region +regionLabelText=Region + +#XFLD: Label for Country +countryLabelText=Country + +#XTIT: Title for Best Friend +bestFriendTitleText=Best Friend + +#XFLD: Label for Best Friend Name +nameLabelText=Name diff --git a/packages/odatav4/steps/11/webapp/index-cdn.html b/packages/odatav4/steps/11/webapp/index-cdn.html new file mode 100644 index 000000000..5e7e769d6 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/index-cdn.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>OData V4 Tutorial + + + +
+ + diff --git a/packages/odatav4/steps/11/webapp/index.html b/packages/odatav4/steps/11/webapp/index.html new file mode 100644 index 000000000..b1e54667d --- /dev/null +++ b/packages/odatav4/steps/11/webapp/index.html @@ -0,0 +1,22 @@ + + + + + + OData V4 Tutorial + + + +
+ + diff --git a/packages/odatav4/steps/11/webapp/initMockServer.ts b/packages/odatav4/steps/11/webapp/initMockServer.ts new file mode 100644 index 000000000..0150138fe --- /dev/null +++ b/packages/odatav4/steps/11/webapp/initMockServer.ts @@ -0,0 +1,11 @@ +// initMockServer.ts — bootstraps the mock server before the component starts +import MessageBox from "sap/m/MessageBox"; +import mockserver from "./localService/mockserver"; + +// initialize the mock server +mockserver.init().catch((oError: Error) => { + MessageBox.error(oError.message); +}).finally(() => { + // initialize the embedded component on the HTML page + void import("sap/ui/core/ComponentSupport"); +}); diff --git a/packages/odatav4/steps/11/webapp/localService/metadata.xml b/packages/odatav4/steps/11/webapp/localService/metadata.xml new file mode 100644 index 000000000..cd2295653 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/localService/metadata.xml @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/odatav4/steps/11/webapp/localService/mockdata/people.json b/packages/odatav4/steps/11/webapp/localService/mockdata/people.json new file mode 100644 index 000000000..cd9ce4180 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/localService/mockdata/people.json @@ -0,0 +1,399 @@ +{ + "@odata.context": "https://services.odata.org/TripPinRESTierService/(S(id))/$metadata#People(Age,FirstName,LastName,UserName,Friends,BestFriend,HomeAddress)", + "value": [ + { + "Age": 23, + "FirstName": "Angel", + "LastName": "Huffman", + "UserName": "angelhuffman", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "clydeguess", + "HomeAddress": { + "Address": "187 Suffolk Ln.", + "City": { + "Name": "Boise", + "CountryRegion": "United States", + "Region": "ID" + } + } + }, + { + "Age": 44, + "FirstName": "Clyde", + "LastName": "Guess", + "UserName": "clydeguess", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "angelhuffman", + "HomeAddress": { + "Address": "2817 Milton Dr.", + "City": { + "Name": "Albuquerque", + "CountryRegion": "United States", + "Region": "NM" + } + } + }, + { + "Age": 19, + "FirstName": "Elaine", + "LastName": "Stewart", + "UserName": "elainestewart", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "genevievereeves", + "HomeAddress": { + "Address": "308 Negra Arroyo Ln.", + "City": { + "Name": "Albuquerque", + "CountryRegion": "United States", + "Region": "NM" + } + } + }, + { + "Age": 37, + "FirstName": "Genevieve", + "LastName": "Reeves", + "UserName": "genevievereeves", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "elainestewart", + "HomeAddress": { + "Address": "89 Jefferson Way Suite 2", + "City": { + "Name": "Portland", + "CountryRegion": "United States", + "Region": "WA" + } + } + }, + { + "Age": 25, + "FirstName": "Georgina", + "LastName": "Barlow", + "UserName": "georginabarlow", + "Friends": [ + "marshallgaray", + "ursulabright" + ], + "BestFriend": "javieralfred", + "HomeAddress": { + "Address": "31 Spooner Street", + "City": { + "Name": "Quahog", + "CountryRegion": "United States", + "Region": "RI" + } + } + }, + { + "Age": 19, + "FirstName": "Javier", + "LastName": "Alfred", + "UserName": "javieralfred", + "Friends": [ + "marshallgaray", + "ursulabright" + ], + "BestFriend": "georginabarlow", + "HomeAddress": { + "Address": "55 Grizzly Peak Rd.", + "City": { + "Name": "Butte", + "CountryRegion": "United States", + "Region": "MT" + } + } + }, + { + "Age": 26, + "FirstName": "Joni", + "LastName": "Rosales", + "UserName": "jonirosales", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "keithpinckney", + "HomeAddress": { + "Address": "742 Evergreen Terrace", + "City": { + "Name": "Springfield", + "CountryRegion": "United States", + "Region": "OR" + } + } + }, + { + "Age": 41, + "FirstName": "Keith", + "LastName": "Pinckney", + "UserName": "keithpinckney", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "jonirosales", + "HomeAddress": { + "Address": "1600 Pennsylvania Avenue NW", + "City": { + "Name": "Washington", + "CountryRegion": "United States", + "Region": "DC" + } + } + }, + { + "Age": 30, + "FirstName": "Krista", + "LastName": "Kemp", + "UserName": "kristakemp", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "laurelosborn", + "HomeAddress": { + "Address": "Statue of Liberty", + "City": { + "Name": "New York", + "CountryRegion": "United States", + "Region": "NY" + } + } + }, + { + "Age": 29, + "FirstName": "Laurel", + "LastName": "Osborn", + "UserName": "laurelosborn", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "kristakemp", + "HomeAddress": { + "Address": "4059 Mt Lee Dr. Hollywood", + "City": { + "Name": "Los Angelos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 53, + "FirstName": "Marshall", + "LastName": "Garay", + "UserName": "marshallgaray", + "Friends": [ + "georginabarlow", + "ursulabright" + ], + "BestFriend": "ronaldmundy", + "HomeAddress": { + "Address": "87 Polk St. Suite 5", + "City": { + "Name": "San Francisco", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 66, + "FirstName": "Ronald", + "LastName": "Mundy", + "UserName": "ronaldmundy", + "Friends": [ + "georginabarlow", + "ursulabright" + ], + "BestFriend": "marshallgaray", + "HomeAddress": { + "Address": "89 Chiaroscuro Rd.", + "City": { + "Name": "Portland", + "CountryRegion": "United States", + "Region": "OR" + } + } + }, + { + "Age": 51, + "FirstName": "Russell", + "LastName": "Whyte", + "UserName": "russellwhyte", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "ryantheriault", + "HomeAddress": { + "Address": "Tony Stark Mansion, Point Dume", + "City": { + "Name": "Malibu", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 57, + "FirstName": "Ryan", + "LastName": "Theriault", + "UserName": "ryantheriault", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "russellwhyte", + "HomeAddress": { + "Address": "2311 N. Los Robles Ave. Apt 4A", + "City": { + "Name": "Pasadena", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 34, + "FirstName": "Sallie", + "LastName": "Sampson", + "UserName": "salliesampson", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "sandyosborn", + "HomeAddress": { + "Address": "87 Polk St. Suite 5", + "City": { + "Name": "San Francisco", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 18, + "FirstName": "Sandy", + "LastName": "Osborn", + "UserName": "sandyosborn", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "salliesampson", + "HomeAddress": { + "Address": "Grove Street, Ganton", + "City": { + "Name": "Los Santos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 24, + "FirstName": "Scott", + "LastName": "Ketchum", + "UserName": "scottketchum", + "Friends": [ + "georginabarlow", + "marshallgaray" + ], + "BestFriend": "ursulabright", + "HomeAddress": { + "Address": "Portola Drive, Rockford Hills", + "City": { + "Name": "Los Santos", + "CountryRegion": "United States", + "Region": "CA" + } + } + }, + { + "Age": 31, + "FirstName": "Ursula", + "LastName": "Bright", + "UserName": "ursulabright", + "Friends": [ + "georginabarlow", + "marshallgaray" + ], + "BestFriend": "scottketchum", + "HomeAddress": { + "Address": "First St. SE", + "City": { + "Name": "Washington", + "CountryRegion": "United States", + "Region": "DC" + } + } + }, + { + "Age": 40, + "FirstName": "Vincent", + "LastName": "Calabrese", + "UserName": "vincentcalabrese", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "willieashmore", + "HomeAddress": { + "Address": "4 Privet Drive", + "City": { + "Name": "Little Whinging", + "CountryRegion": "Great Britain", + "Region": "SRY" + } + } + }, + { + "Age": 45, + "FirstName": "Willie", + "LastName": "Ashmore", + "UserName": "willieashmore", + "Friends": [ + "georginabarlow", + "marshallgaray", + "ursulabright" + ], + "BestFriend": "vincentcalabrese", + "HomeAddress": { + "Address": "124 Conch St.", + "City": { + "Name": "Bikini Bottom", + "CountryRegion": "Pacific Ocean", + "Region": "N/D" + } + } + } + ] +} \ No newline at end of file diff --git a/packages/odatav4/steps/11/webapp/localService/mockserver.ts b/packages/odatav4/steps/11/webapp/localService/mockserver.ts new file mode 100644 index 000000000..d6810087d --- /dev/null +++ b/packages/odatav4/steps/11/webapp/localService/mockserver.ts @@ -0,0 +1,782 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any */ +import JSONModel from "sap/ui/model/json/JSONModel"; +import Log from "sap/base/Log"; + +// Pull sinon from the UI5 third-party shim. The shim has no TS typings; +// we treat the imported value as a structural any so the mock implementation +// stays close to the original JavaScript. +// eslint-disable-next-line @typescript-eslint/no-require-imports +declare const sap: any; + +interface MockUser { + UserName: string; + FirstName?: string; + LastName?: string; + Age?: number; + Friends?: string[]; + BestFriend?: string; + [key: string]: unknown; +} + +interface MockXhr { + method: string; + url: string; + requestBody?: string; + respond?: (status: number, headers: Record, body: string | null) => void; +} + +type MockResponse = [number, Record, string | null] | [number, Record]; + +// sinon is provided by the "sap/ui/thirdparty/sinon" module — see the require below +let sinon: any; +let sandbox: any; +let users: MockUser[]; // The array that holds the cached user data +let metadata: string; // The string that holds the cached mock service metadata +const namespace = "ui5/tutorial/odatav4"; +// Component for writing logs into the console +const logComponent = "ui5.tutorial.odatav4.mockserver"; +const rBaseUrl = /services.odata.org\/TripPinRESTierService/; + +/** + * Returns the base URL from a given URL. + * @param sUrl - the complete URL + * @returns the base URL + */ +function getBaseUrl(url: string): string { + const matches = url.match(/http.+\(S\(.+\)\)\//); + + if (!Array.isArray(matches) || matches.length < 1) { + throw new Error("Could not find a base URL in " + url); + } + + return matches[0]; +} + +/** + * Looks for a user with a given user name and returns its index in the user array. + * @param sUserName - the user name to look for. + * @returns index of that user in the array, or -1 if the user was not found. + */ +function findUserIndex(userName: string): number { + for (let i = 0; i < users.length; i++) { + if (users[i].UserName === userName) { + return i; + } + } + return -1; +} + +/** + * Retrieves any user data from a given http request body. + * @param sBody - the http request body. + * @returns the parsed user data. + */ +function getUserDataFromRequestBody(body: string): MockUser { + const matches = body.match(/({.+})/); + + if (!Array.isArray(matches) || matches.length !== 2) { + throw new Error("Could not find any user data in " + body); + } + return JSON.parse(matches[1]) as MockUser; +} + +/** + * Retrieves a user name from a given request URL. + * @param sUrl - the request URL. + * @returns the user name or undefined if no user was found. + */ +function getUserKeyFromUrl(url: string): string | undefined { + const matches = url.match(/People\('(.*)'\)/); + return matches ? matches[1] : undefined; +} + +/** + * Checks if a given UserName is unique or already used + * @param sUserName - the UserName to be checked + * @returns True if the UserName is unique (not used), false otherwise + */ +function isUnique(userName: string): boolean { + return findUserIndex(userName) < 0; +} + +/** + * Returns a proper HTTP response body for "duplicate key" errors + * @param sKey - the duplicate key + * @returns the proper response body + */ +function duplicateKeyError(key: string): string { + return JSON.stringify({ + error: { + code: "409", + message: "There is already a user with user name '" + key + "'.", + target: "UserName" + } + }); +} + +function invalidKeyError(key: string): string { + return JSON.stringify({ + error: { + code: "404", + message: "There is no user with user name '" + key + "'.", + target: "UserName" + } + }); +} + +function getSuccessResponse(responseBody: string): MockResponse { + return [ + 200, + { + "Content-Type": "application/json; odata.metadata=minimal", + "OData-Version": "4.0" + }, + responseBody + ]; +} + +/** + * Reads and caches the fake service metadata and data from their + * respective files. + * @returns a promise that is resolved when the data is loaded + */ +function readData(): Promise { + const metadataPromise = new Promise((resolve, reject) => { + const resourcePath = sap.ui.require.toUrl(namespace + "/localService/metadata.xml"); + const request = new XMLHttpRequest(); + + request.onload = function () { + // 404 is not an error for XMLHttpRequest so we need to handle it here + if (request.status === 404) { + const error = "resource " + resourcePath + " not found"; + + Log.error(error, logComponent); + reject(new Error(error)); + } + metadata = this.responseText; + resolve(); + }; + request.onerror = function () { + const error = "error loading resource '" + resourcePath + "'"; + + Log.error(error, logComponent); + reject(new Error(error)); + }; + request.open("GET", resourcePath); + request.send(); + }); + + const mockDataPromise = new Promise((resolve, reject) => { + const resourcePath = sap.ui.require.toUrl(namespace + "/localService/mockdata/people.json"); + const mockDataModel = new JSONModel(resourcePath); + + mockDataModel.attachRequestCompleted(function (this: JSONModel, event: any) { + // 404 is not an error for JSONModel so we need to handle it here + if (event.getParameter("errorobject") + && event.getParameter("errorobject").statusCode === 404) { + const error = "resource '" + resourcePath + "' not found"; + + Log.error(error, logComponent); + reject(new Error(error)); + } + users = (this.getData() as { value: MockUser[] }).value; + resolve(); + }); + + mockDataModel.attachRequestFailed(() => { + const error = "error loading resource '" + resourcePath + "'"; + + Log.error(error, logComponent); + reject(new Error(error)); + }); + }); + + return Promise.all([metadataPromise, mockDataPromise]); +} + +/** + * Reduces a given result set by applying the OData URL parameters 'skip' and 'top' to it. + * Does NOT change the given result set but returns a new array. + */ +function applySkipTop(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + const reducedUsers = [...resultSet]; + const matches = xhr.url.match(/\$skip=(\d+)&\$top=(\d+)/); + + if (Array.isArray(matches) && matches.length >= 3) { + const skip = parseInt(matches[1], 10); + const top = parseInt(matches[2], 10); + return resultSet.slice(skip, skip + top); + } + + return reducedUsers; +} + +/** + * Sorts a given result set by applying the OData URL parameter 'orderby'. + * Does NOT change the given result set but returns a new array. + */ +function applySort(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + const sortedUsers = [...resultSet]; // work with a copy + const matches = xhr.url.match(/\$orderby=(\w*)(?:%20(\w*))?/); + + if (!Array.isArray(matches) || matches.length < 2) { + return sortedUsers; + } + const fieldName = matches[1]; + const direction = matches[2] || "asc"; + + if (fieldName !== "LastName") { + throw new Error("Filters on field " + fieldName + " are not supported."); + } + + sortedUsers.sort((a, b) => { + const nameA = (a.LastName || "").toUpperCase(); + const nameB = (b.LastName || "").toUpperCase(); + const asc = direction === "asc"; + + if (nameA < nameB) { + return asc ? -1 : 1; + } + if (nameA > nameB) { + return asc ? 1 : -1; + } + return 0; + }); + + return sortedUsers; +} + +/** + * Filters a given result set by applying the OData URL parameter 'filter'. + * Does NOT change the given result set but returns a new array. + */ +function applyFilter(xhr: MockXhr, resultSet: MockUser[]): MockUser[] { + let filteredUsers = [...resultSet]; // work with a copy + const matches = xhr.url.match(/\$filter=.*\((.*),'(.*)'\)/); + + // If the request contains a filter command, apply the filter + if (Array.isArray(matches) && matches.length >= 3) { + const fieldName = matches[1]; + const query = matches[2]; + + if (fieldName !== "LastName") { + throw new Error("Filters on field " + fieldName + " are not supported."); + } + + filteredUsers = users.filter((user) => (user.LastName || "").indexOf(query) !== -1); + } + + return filteredUsers; +} + +/** + * Handles GET requests for metadata. + */ +function handleGetMetadataRequests(): MockResponse { + return [ + 200, + { + "Content-Type": "application/xml", + "odata-version": "4.0" + }, metadata + ]; +} + +/** + * Handles GET requests for a pure user count and returns a fitting response. + */ +function handleGetCountRequests(): MockResponse { + return getSuccessResponse(users.length.toString()); +} + +/** + * Handles GET requests for user data and returns a fitting response. + */ +function handleGetUserRequests(xhr: MockXhr, _bCount: boolean): MockResponse { + let count: number; + let expand: RegExpMatchArray | string[] | null; + let expand2: string; + let index: number; + let key: string | undefined; + let response: { "@odata.count"?: number; value: MockUser[] } | MockUser | null; + let responseBody: string; + let result: MockUser[]; + let select: RegExpMatchArray | string[] | null; + let select2: string; + let subSelects: string[][] = []; + let i: number; + + // Get expand parameter + expand = xhr.url.match(/\$expand=([^&]+)/); + + // Sort out expand parameter values + subSelects in brackets + if (expand) { + expand2 = expand[0]; + expand2 = expand2.substring(8); + + // Sort out subselects (e.g. BestFriend($select=Age,UserName),Friend) + const subSelectMatches = expand2.match(/\([^)]*\)/g) || []; + subSelects = subSelectMatches.map((s) => s.replace(/\(\$select=/, "").replace(/\)/, "").split(",")); + expand2 = expand2.replace(/\([^)]*\)/g, ""); + expand = expand2.split(","); + } + + // Get select parameter + select = xhr.url.match(/[^(]\$select=([\w|,]+)/); + + // Sort out select parameter values + if (Array.isArray(select)) { + select2 = select[0]; + select2 = select2.replace(/&/, "").replace(/\?/, "").substring(8); + select = select2.split(","); + } + + // Check if an individual user or a user range is requested + key = getUserKeyFromUrl(xhr.url); + if (key) { + index = findUserIndex(key); + + if (/People\(.+\)\/Friends/.test(xhr.url)) { + // ownRequest for friends + response = { value: createFriendsArray(users[index].Friends, select as string[]) }; + } else { + // specific user was requested + response = getUserObject(index, select as string[], expand as string[], subSelects); + } + + if (index > -1) { + responseBody = JSON.stringify(response); + return getSuccessResponse(responseBody); + } + responseBody = invalidKeyError(key); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; + } + // all users requested + result = applyFilter(xhr, users); + count = result.length; // the total no. of people found, after filtering + result = applySort(xhr, result); + result = applySkipTop(xhr, result); + + // generate sResponse + const finalResponse: { "@odata.count": number; value: MockUser[] } = { "@odata.count": count, value: [] }; + + result.forEach((user) => { + const userIndex = findUserIndex(user.UserName); + + finalResponse.value.push(getUserObject(userIndex, select as string[], expand as string[], subSelects) as MockUser); + }); + + responseBody = JSON.stringify(finalResponse); + + return getSuccessResponse(responseBody); +} + +/** + * Returns a specific user in the aUsers array. + */ +function getUserByIndex(index: number, properties: string[]): MockUser | null { + const helper: MockUser = { UserName: "" }; + const user = users[index]; + + if (user) { + properties.forEach((selectProperty) => { + helper[selectProperty] = user[selectProperty]; + }); + + return helper; + } + return null; +} + +/** + * Returns the user with iIndex in the aUsers array with all its information + */ +function getUserObject(index: number, select: string[], expand: string[] | null | undefined, subSelects: string[][]): MockUser | null { + let bestFriend: string | undefined; + let friendIndex: number; + let friends: string[] | undefined; + let object: MockUser | null; + let user: MockUser; + let i: number; + + object = getUserByIndex(index, select); + if (expand && object) { + user = users[index]; + for (i = 0; i < expand.length; i++) { + switch (expand[i]) { + case "Friends": + friends = user.Friends; + object.Friends = createFriendsArray(friends, subSelects[i]) as unknown as string[]; + break; + case "BestFriend": + bestFriend = user.BestFriend; + friendIndex = findUserIndex(bestFriend || ""); + object.BestFriend = getUserByIndex(friendIndex, subSelects[i]) as unknown as string; + break; + default: + break; + } + } + } + return object; +} + +/** + * creates array of friends for a given user + */ +function createFriendsArray(friends: string[] | undefined, subSelects: string[]): MockUser[] { + let array: (MockUser | null)[] = []; + + if (friends) { + friends.forEach((friend) => { + const friendIndex = findUserIndex(friend); + array.push(getUserByIndex(friendIndex, subSelects)); + }); + + array = array.filter((element) => element !== null); + } + + return array as MockUser[]; +} + +/** + * Handles PATCH requests for users and returns a fitting response. + */ +function handlePatchUserRequests(xhr: MockXhr): MockResponse { + // Get the key of the person to change + const key = getUserKeyFromUrl(xhr.url); + + // Get the list of changes + const changes = getUserDataFromRequestBody(xhr.requestBody || ""); + + // Check if the UserName is changed to a duplicate. + // If the UserName is "changed" to its current value, that is not an error. + if (Object.prototype.hasOwnProperty.call(changes, "UserName") + && changes.UserName !== key + && !isUnique(changes.UserName)) { + // Error + const responseBody = duplicateKeyError(changes.UserName); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; + } + // No error: make the change(s) + const user = users[findUserIndex(key || "")]; + for (const fieldName in changes) { + if (Object.prototype.hasOwnProperty.call(changes, fieldName)) { + user[fieldName] = changes[fieldName]; + } + } + + // The response to PATCH requests is always http 204 (No Content) + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Handles DELETE requests for users and returns a fitting response. + */ +function handleDeleteUserRequests(xhr: MockXhr): MockResponse { + const key = getUserKeyFromUrl(xhr.url); + users.splice(findUserIndex(key || ""), 1); + + // The response to DELETE requests is always http 204 (No Content) + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Handles POST requests for users and returns a fitting response. + */ +function handlePostUserRequests(xhr: MockXhr): MockResponse { + const user = getUserDataFromRequestBody(xhr.requestBody || ""); + + // Check if that user already exists + if (isUnique(user.UserName)) { + users.push(user); + + let responseBody = '{"@odata.context": "' + getBaseUrl(xhr.url) + + '$metadata#People/$entity",'; + responseBody += JSON.stringify(user).slice(1); + + // The response to POST requests is http 201 (Created) + return [ + 201, + { + "Content-Type": "application/json; odata.metadata=minimal", + "OData-Version": "4.0" + }, + responseBody + ]; + } + // Error + const responseBody = duplicateKeyError(user.UserName); + return [ + 400, + { + "Content-Type": "application/json; charset=utf-8" + }, + responseBody + ]; +} + +/** + * Handles POST requests for resetting the data and returns a fitting response. + */ +function handleResetDataRequest(): MockResponse { + void readData(); + + return [ + 204, + { + "OData-Version": "4.0" + }, + null + ]; +} + +/** + * Builds a response to direct (= non-batch) requests. + * Supports GET, PATCH, DELETE and POST requests. + */ +function handleDirectRequest(xhr: MockXhr): MockResponse | undefined { + let response2: MockResponse | undefined; + + switch (xhr.method) { + case "GET": + if (/\$metadata/.test(xhr.url)) { + response2 = handleGetMetadataRequests(); + } else if (/\/\$count/.test(xhr.url)) { + response2 = handleGetCountRequests(); + } else if (/People.*\?/.test(xhr.url)) { + response2 = handleGetUserRequests(xhr, /\$count=true/.test(xhr.url)); + } + break; + case "PATCH": + if (/People/.test(xhr.url)) { + response2 = handlePatchUserRequests(xhr); + } + break; + case "POST": + if (/People/.test(xhr.url)) { + response2 = handlePostUserRequests(xhr); + } else if (/ResetDataSource/.test(xhr.url)) { + response2 = handleResetDataRequest(); + } + break; + case "DELETE": + if (/People/.test(xhr.url)) { + response2 = handleDeleteUserRequests(xhr); + } + break; + case "HEAD": + response2 = [204, {}]; + break; + default: + break; + } + + return response2; +} + +/** + * Builds a response to batch requests. + * Unwraps batch request, gets a response for each individual part and + * constructs a fitting batch response. + */ +function handleBatchRequest(xhr: MockXhr): MockResponse { + let responseBody = ""; + const outerBoundary = (xhr.requestBody || "").match(/(.*)/)![1]; // First line of the body + let innerBoundary: string | undefined; + let partBoundary: string; + // The individual requests + const outerParts = (xhr.requestBody || "").split(outerBoundary).slice(1, -1); + let parts: string[]; + let header: string; + + const matches = outerParts[0].match(/multipart\/mixed;boundary=(.+)/); + // If this request has several change sets, then we need to handle the inner and outer + // boundaries (change sets have an additional boundary) + if (matches && matches.length > 0) { + innerBoundary = matches[1]; + parts = outerParts[0].split("--" + innerBoundary).slice(1, -1); + } else { + parts = outerParts; + } + + // If this request has several change sets, then the response must start with the outer + // boundary and content header + if (innerBoundary) { + partBoundary = "--" + innerBoundary; + responseBody += outerBoundary + "\r\n" + + "Content-Type: multipart/mixed; boundary=" + innerBoundary + "\r\n\r\n"; + } else { + partBoundary = outerBoundary; + } + + parts.forEach((part, index) => { + // Construct the batch response body out of the single batch request parts. + const matches0 = part.match(/(GET|DELETE|PATCH|POST) (\S+)(?:.|\r?\n)+\r?\n(.*)\r?\n$/)!; + const partResponse = handleDirectRequest({ + method: matches0[1], + url: getBaseUrl(xhr.url) + matches0[2], + requestBody: matches0[3] + })!; + + responseBody += partBoundary + "\r\n" + + "Content-Type: application/http\r\n"; + // If there are several change sets, we need to add a Content ID header + if (innerBoundary) { + responseBody += "Content-ID:" + index + ".0\r\n"; + } + responseBody += "\r\nHttp/1.1 " + partResponse[0] + "\r\n"; + // Add any headers from the request - unless this response is 204 (no content) + if (partResponse[1] && partResponse[0] !== 204) { + for (header in partResponse[1]) { + if (Object.prototype.hasOwnProperty.call(partResponse[1], header)) { + responseBody += header + ": " + partResponse[1][header] + "\r\n"; + } + } + } + responseBody += "\r\n"; + + if (partResponse[2]) { + responseBody += partResponse[2]; + } + responseBody += "\r\n"; + }); + + // Check if we need to add the inner boundary again at the end + if (innerBoundary) { + responseBody += "--" + innerBoundary + "--\r\n"; + } + // Add a final boundary to the batch response body + responseBody += outerBoundary + "--"; + + // Build the final batch response + return [ + 200, + { + "Content-Type": "multipart/mixed;boundary=" + outerBoundary.slice(2), + "OData-Version": "4.0" + }, + responseBody + ]; +} + +/** + * Handles any type of intercepted request and sends a fake response. + * Logs the request and response to the console. + * Manages batch requests. + */ +function handleAllRequests(xhr: MockXhr): void { + let response2: MockResponse | undefined; + + // Log the request + Log.info( + "Mockserver: Received " + xhr.method + " request to URL " + xhr.url, + (xhr.requestBody ? "Request body is:\n" + xhr.requestBody : "No request body.") + + "\n", + logComponent + ); + + if (xhr.method === "POST" && /\$batch/.test(xhr.url)) { + response2 = handleBatchRequest(xhr); + } else { + response2 = handleDirectRequest(xhr); + } + + if (xhr.respond && response2) { + xhr.respond(response2[0], response2[1], response2[2] || null); + } + + // Log the response + if (response2) { + Log.info( + "Mockserver: Sent response with return code " + response2[0], + ("Response headers: " + JSON.stringify(response2[1]) + "\n\nResponse body:\n" + + (response2[2] || "")) + "\n", + logComponent + ); + } +} + +export default { + + /** + * Creates a Sinon fake service, intercepting all http requests to + * the URL defined in variable rBaseUrl above. + * @returns a promise that is resolved when the mock server is started + */ + init(): Promise { + // Load sinon lazily from the UI5 third-party shim + return new Promise((resolve, reject) => { + sap.ui.require(["sap/ui/thirdparty/sinon"], (sinon: any) => { + sinon = sinon; + sandbox = sinon.sandbox.create(); + + // Read the mock data + readData().then(() => { + // Initialize the sinon fake server + sandbox.useFakeServer(); + // Make sure that requests are responded to automatically. Otherwise we would need + // to do that manually. + sandbox.server.autoRespond = true; + + // Register the requests for which responses should be faked. + sandbox.server.respondWith(rBaseUrl, handleAllRequests); + + // Apply a filter to the fake XmlHttpRequest. + // Otherwise, ALL requests (e.g. for the component, views etc.) would be + // intercepted. + sinon.FakeXMLHttpRequest.useFilters = true; + sinon.FakeXMLHttpRequest.addFilter((_sMethod: string, url: string) => { + // If the filter returns true, the request will NOT be faked. + // We only want to fake requests that go to the intended service. + return !rBaseUrl.test(url); + }); + + // Set the logging level for console entries from the mock server + Log.setLevel(Log.Level.INFO, logComponent); + + Log.info("Running the app with mock data", logComponent); + resolve(undefined); + }, reject); + }); + }); + }, + + /** + * Stops the request interception and deletes the Sinon fake server. + */ + stop(): void { + if (sinon) { + sinon.FakeXMLHttpRequest.filters = []; + sinon.FakeXMLHttpRequest.useFilters = false; + } + if (sandbox) { + sandbox.restore(); + sandbox = null; + } + } +}; diff --git a/packages/odatav4/steps/11/webapp/manifest.json b/packages/odatav4/steps/11/webapp/manifest.json new file mode 100644 index 000000000..ea22bafc9 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/manifest.json @@ -0,0 +1,69 @@ +{ + "_version": "1.60.0", + "sap.app": { + "id": "ui5.tutorial.odatav4", + "type": "application", + "i18n": { + "supportedLocales": [ + "" + ], + "fallbackLocale": "", + "bundleName": "ui5.tutorial.odatav4.i18n.i18n" + }, + "applicationVersion": { + "version": "1.0.0" + }, + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "dataSources": { + "default": { + "uri": "https://services.odata.org/TripPinRESTierService/(S(id))/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + } + }, + "sap.ui": { + "technology": "UI5" + }, + "sap.ui5": { + "rootView": { + "viewName": "ui5.tutorial.odatav4.view.App", + "type": "XML", + "id": "appView" + }, + "dependencies": { + "minUI5Version": "1.132", + "libs": { + "sap.f": {}, + "sap.m": {}, + "sap.ui.core": {}, + "sap.ui.layout": {} + } + }, + "handleValidation": true, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "ui5.tutorial.odatav4.i18n.i18n", + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + } + }, + "": { + "dataSource": "default", + "preload": true, + "settings": { + "autoExpandSelect": true, + "earlyRequests": true, + "operationMode": "Server" + } + } + } + } +} diff --git a/packages/odatav4/steps/11/webapp/model/models.ts b/packages/odatav4/steps/11/webapp/model/models.ts new file mode 100644 index 000000000..5fdcff4a3 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/model/models.ts @@ -0,0 +1,10 @@ +// models.ts — central application models +import JSONModel from "sap/ui/model/json/JSONModel"; +import Device from "sap/ui/Device"; + +export function createDeviceModel(): JSONModel { + const model = new JSONModel(Device); + + model.setDefaultBindingMode("OneWay"); + return model; +} diff --git a/packages/odatav4/steps/11/webapp/test/integration/AllJourneys.js b/packages/odatav4/steps/11/webapp/test/integration/AllJourneys.js new file mode 100644 index 000000000..c52c9ead3 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/test/integration/AllJourneys.js @@ -0,0 +1,13 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/core/tutorial/odatav4/test/integration/arrangements/Startup", + "sap/ui/core/tutorial/odatav4/test/integration/TutorialJourney" +], function (Opa5, Startup) { + "use strict"; + + Opa5.extendConfig({ + arrangements : new Startup(), + viewNamespace : "sap.ui.core.tutorial.odatav4.view.", + autoWait : true + }); +}); diff --git a/packages/odatav4/steps/11/webapp/test/integration/TutorialJourney.js b/packages/odatav4/steps/11/webapp/test/integration/TutorialJourney.js new file mode 100644 index 000000000..4ba640f71 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/test/integration/TutorialJourney.js @@ -0,0 +1,147 @@ +sap.ui.define([ + "sap/ui/test/opaQunit", + "sap/ui/core/tutorial/odatav4/test/integration/pages/Tutorial" +], function (opaTest) { + "use strict"; + + var iGrowingBy = 10, // Must equal the 'growingThreshold' setting of the table + iTotalUsers = 20; // Must equal the total number of users + + QUnit.module("Posts"); + + opaTest("Should see the paginated table with all users", function (Given, _When, Then) { + // Arrangements + Given.iStartMyApp(); + // Assertions + Then.onTheTutorialPage.theTableShouldHavePagination() + .and.theTableShouldShowUsers(iGrowingBy) + .and.theTableShouldShowTotalUsers(iTotalUsers); + }); + + opaTest("Should be able to load more users", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iPressOnMoreData(); + // Assertions + Then.onTheTutorialPage.theTableShouldShowUsers(iGrowingBy * 2); + }); + + opaTest("Should be able to sort users", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iPressOnSort(); + // Assertions + Then.onTheTutorialPage.theTableShouldStartWith("Alfred"); + }); + + opaTest("Should be able to start adding users", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iPressOnAdd() + .and.iEnterSomeData("a"); + When.onTheTutorialPage.iPressOnAdd() + .and.iEnterSomeData("b"); + // Assertions + Then.onTheTutorialPage.thePageFooterShouldBeVisible(true) + .and.theTableToolbarItemsShouldBeEnabled(false) + .and.theTableShouldShowTotalUsers(iTotalUsers + 2); + }); + + opaTest("Should be able to save the new users", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iPressOnSave(); + // Assertions + Then.onTheTutorialPage.theTableShouldStartWith("b") + .and.theTableShouldShowTotalUsers(iTotalUsers + 2) + .and.theTableToolbarItemsShouldBeEnabled(true) + .and.thePageFooterShouldBeVisible(false); + }); + + opaTest("Should be able to delete/undelete the new users", function (_Given, When, Then) { + // delete and undelete + When.onTheTutorialPage.iSelectUser("b") + .and.iPressOnDelete(); + Then.onTheTutorialPage.theTableShouldStartWith("a") + .and.theTableShouldShowTotalUsers(iTotalUsers + 1); + When.onTheTutorialPage.iSelectUser("a") + .and.iPressOnDelete(); + Then.onTheTutorialPage.theTableShouldStartWith("Alfred") + .and.theTableShouldShowTotalUsers(iTotalUsers); + When.onTheTutorialPage.iPressOnCancel(); + Then.onTheTutorialPage.theMessageToastShouldShow("deletionRestoredMessage", "b") + .and.theMessageToastShouldShow("deletionRestoredMessage", "a") + .and.theTableShouldStartWith("b") + .and.theTableShouldShowTotalUsers(iTotalUsers + 2); + // delete and save + When.onTheTutorialPage.iSelectUser("a") + .and.iPressOnDelete() + .and.iSelectUser("b") + .and.iPressOnDelete() + .and.iPressOnSave(); + Then.onTheTutorialPage.theMessageToastShouldShow("deletionSuccessMessage", "a") + .and.theMessageToastShouldShow("deletionSuccessMessage", "b") + .and.theTableShouldStartWith("Alfred") + .and.theTableShouldShowTotalUsers(iTotalUsers); + }); + + opaTest("Should be able to search for users", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iSearchFor("Mundy"); + // Assertions + Then.onTheTutorialPage.theTableShouldShowUsers(1); + }); + + opaTest("Should be able to reset the search", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iSearchFor(""); + // Assertions + Then.onTheTutorialPage.theTableShouldShowUsers(10); + }); + + opaTest("Should see an error when trying to change a user name to an existing one", + function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iChangeAUserKey("javieralfred", "willieashmore") + .and.iPressOnSave(); + // Assertions + Then.onTheTutorialPage.iShouldSeeAServiceError() + .and.theTableToolbarItemsShouldBeEnabled(false) + .and.thePageFooterShouldBeVisible(true); + } + ); + + opaTest("Should be able to close the error and cancel the change", + function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iCloseTheServiceError() + .and.iPressOnCancel(); + // Assertions + Then.onTheTutorialPage.theTableToolbarItemsShouldBeEnabled(true) + .and.thePageFooterShouldBeVisible(false); + } + ); + + opaTest("Should be able to see the detail area", function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iSelectUser("javieralfred").and.iPressUser(); + //Assertions + Then.onTheTutorialPage.theDetailAreaShouldBeVisible(true); + }); + + opaTest("Should be able to toggle detail area when user is deleted/undeleted", + function (_Given, When, Then) { + //Actions + When.onTheTutorialPage.iSelectUser("javieralfred") + .and.iPressUser() + .and.iPressOnDelete(); + //Assertion + Then.onTheTutorialPage.theDetailAreaShouldBeVisible(false) + .and.theTableShouldShowUsers(iGrowingBy - 1); + //Action + When.onTheTutorialPage.iPressOnCancel(); + //Assertion + Then.onTheTutorialPage.theDetailAreaShouldBeVisible(true) + .and.theMessageToastShouldShow("deletionRestoredMessage", "javieralfred") + .and.theTableShouldShowUsers(iGrowingBy); + //Cleanup + Then.iTeardownMyApp(); + } + ); +}); diff --git a/packages/odatav4/steps/11/webapp/test/integration/arrangements/Startup.js b/packages/odatav4/steps/11/webapp/test/integration/arrangements/Startup.js new file mode 100644 index 000000000..5eb7219a3 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/test/integration/arrangements/Startup.js @@ -0,0 +1,24 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/core/tutorial/odatav4/localService/mockserver" +], function (Opa5, mockserver) { + "use strict"; + + return Opa5.extend("sap.ui.core.tutorial.odatav4.test.integration.arrangements.Startup", { + + iStartMyApp : function () { + // start the mock server + this.iWaitForPromise(mockserver.init()); + + // start the app UI component + this.iStartMyUIComponent({ + componentConfig : { + name : "sap.ui.core.tutorial.odatav4", + async : true + }, + autoWait : true, + timeout : 45 // BCP: 2270085466 + }); + } + }); +}); diff --git a/packages/odatav4/steps/11/webapp/test/integration/opaTests.qunit.html b/packages/odatav4/steps/11/webapp/test/integration/opaTests.qunit.html new file mode 100644 index 000000000..9cdceff2c --- /dev/null +++ b/packages/odatav4/steps/11/webapp/test/integration/opaTests.qunit.html @@ -0,0 +1,27 @@ + + + + Integration tests for OData V4 Tutorial + + + + + + + + + + + + +
+
+ + \ No newline at end of file diff --git a/packages/odatav4/steps/11/webapp/test/integration/opaTests.qunit.js b/packages/odatav4/steps/11/webapp/test/integration/opaTests.qunit.js new file mode 100644 index 000000000..0cc870429 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/test/integration/opaTests.qunit.js @@ -0,0 +1,11 @@ +QUnit.config.autostart = false; + +sap.ui.require([ + "sap/ui/core/Core", + "sap/ui/core/tutorial/odatav4/test/integration/AllJourneys" +], function (Core) { + "use strict"; + Core.ready().then(function () { + QUnit.start(); + }); +}); diff --git a/packages/odatav4/steps/11/webapp/test/integration/pages/Tutorial.js b/packages/odatav4/steps/11/webapp/test/integration/pages/Tutorial.js new file mode 100644 index 000000000..165db29de --- /dev/null +++ b/packages/odatav4/steps/11/webapp/test/integration/pages/Tutorial.js @@ -0,0 +1,330 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/test/matchers/AggregationLengthEquals", + "sap/ui/test/matchers/PropertyStrictEquals", + "sap/ui/test/matchers/BindingPath", + "sap/ui/test/actions/Press", + "sap/ui/test/actions/EnterText" +], function (Opa5, AggregationLengthEquals, PropertyStrictEquals, BindingPath, Press, EnterText) { + "use strict"; + + var sViewName = "App", + sTableId = "peopleList"; + + function getListBinding(oTable) { + return oTable.getBinding("items"); + } + + function getFirstTableEntry(oTable) { + return getListBinding(oTable).getCurrentContexts()[0]; + } + + Opa5.createPageObjects({ + onTheTutorialPage : { + actions : { + iPressOnMoreData : function () { + // Press action hits the "more" trigger on a table + return this.waitFor({ + id : sTableId, + viewName : sViewName, + actions : new Press(), + errorMessage : "Table not found or it does not have a 'See More' trigger" + }); + }, + + iPressOnSort : function () { + return this.waitFor({ + id : "sortUsersButton", + viewName : sViewName, + actions : new Press(), + errorMessage : "Could not find the 'Sort' button" + }); + }, + + iPressOnAdd : function () { + return this.waitFor({ + id : "addUserButton", + viewName : sViewName, + actions : new Press(), + errorMessage : "Could not find the 'Add' button" + }); + }, + + iPressOnDelete : function () { + return this.waitFor({ + id : "deleteUserButton", + viewName : sViewName, + actions : new Press(), + errorMessage : "Could not find the 'Delete' button" + }); + }, + + iPressOnSave : function () { + return this.waitFor({ + id : "saveButton", + viewName : sViewName, + actions : new Press(), + errorMessage : "Could not find the 'Save' button" + }); + }, + + iPressOnCancel : function () { + return this.waitFor({ + id : "doneButton", + viewName : sViewName, + actions : new Press(), + errorMessage : "Could not find the 'Cancel' button" + }); + }, + + iEnterSomeData : function (sValue) { + return this.waitFor({ + controlType : "sap.m.Input", + viewName : sViewName, + matchers : [ + // Find the input fields for the new entry + function (oControl) { + return oControl.getBindingContext().getIndex() === 0; + }, + // Keep only empty input fields + function (oItem) { + return !oItem.getValue(); + } + ], + actions : new EnterText({ + text : sValue + }), + errorMessage : "Could not find Input controls to enter data" + }); + }, + + iSearchFor : function (sSearchString) { + return this.waitFor({ + id : "searchField", + viewName : sViewName, + actions : new EnterText({ + text : sSearchString + }), + errorMessage : "SearchField was not found" + }); + }, + + iSelectUser : function (sKey) { + return this.waitFor({ + controlType : "sap.m.ColumnListItem", + viewName : sViewName, + matchers : new BindingPath({ + path : "/People('" + sKey + "')" + }), + actions : function (oItem) { + oItem.setSelected(true); + }, + errorMessage : "Could not find a user with the key '" + sKey + "'" + }); + }, + + iChangeAUserKey : function (sOldKey, sNewKey) { + return this.waitFor({ + controlType : "sap.m.Input", + viewName : sViewName, + matchers : new PropertyStrictEquals({ + name : "value", + value : sOldKey + }), + actions : new EnterText({ + text : sNewKey + }), + errorMessage : "Could not find a user with the key '" + sOldKey + "'" + }); + }, + + iCloseTheServiceError : function () { + return this.waitFor({ + id : "serviceErrorMessageBox", + success : function () { + this.waitFor({ + controlType : "sap.m.Button", + searchOpenDialogs : true, + // The error MessageBox has only one button, which closes the box + actions : new Press(), + errorMessage : "Cannot find the 'Close' button" + }); + }, + errorMessage : "Could not see the service error dialog" + }); + }, + + iPressUser : function () { + return this.waitFor({ + controlType : "sap.m.Table", + id : sTableId, + viewName : sViewName, + actions : function (oTable) { + oTable.fireSelectionChange({listItem : oTable.getSelectedItem()}); + }, + errorMessage : "Could not press user" + }); + } + }, + assertions : { + theTableShouldHavePagination : function () { + return this.waitFor({ + id : sTableId, + viewName : sViewName, + matchers : new PropertyStrictEquals({ + name : "growing", + value : true + }), + success : function () { + Opa5.assert.ok(true, "The table is paginated"); + }, + errorMessage : "Table not found or it is not paginated" + }); + }, + + theTableShouldShowUsers : function (iNumber) { + return this.waitFor({ + id : sTableId, + viewName : sViewName, + matchers : new AggregationLengthEquals({ + name : "items", + length : iNumber + }), + success : function () { + Opa5.assert.ok(true, "The table has " + + iNumber + " items"); + }, + errorMessage : "Table not found or it does not have " + + iNumber + " entries" + }); + }, + + theTableShouldShowTotalUsers : function (iNumber) { + return this.waitFor({ + id : sTableId, + viewName : sViewName, + matchers : function (oTable) { + var oListBinding = getListBinding(oTable); + + return oListBinding && oListBinding.getLength() === iNumber; + }, + success : function () { + Opa5.assert.ok(true, "The table shows a total of " + iNumber + + " users"); + }, + errorMessage : "Table not found or it does not show " + iNumber + + " total users" + }); + }, + + theTableShouldStartWith : function (sLastName) { + return this.waitFor({ + id : sTableId, + viewName : sViewName, + matchers : function (oTable) { + var oFirstItem = getFirstTableEntry(oTable); + + return oFirstItem && oFirstItem.getProperty("LastName") === sLastName; + }, + success : function () { + Opa5.assert.ok(true, "The table is sorted correctly"); + }, + errorMessage : "Table not found or it is not sorted correctl." + }); + }, + + thePageFooterShouldBeVisible : function (bVisible) { + var sDesiredState = bVisible ? "visible" : "invisible"; + + return this.waitFor({ + controlType : "sap.m.Toolbar", + viewName : sViewName, + visible : false, + matchers : new PropertyStrictEquals({ + name : "visible", + value : bVisible + }), + success : function () { + Opa5.assert.ok(true, "The toolbar is " + sDesiredState); + }, + errorMessage : "Toolbar not found or is not " + sDesiredState + }); + }, + + theTableToolbarItemsShouldBeEnabled : function (bEnabled) { + var sDesiredState = bEnabled ? "enabled" : "disabled"; + + return this.waitFor({ + id : /searchField$|refreshUsersButton$|sortUsersButton$/, + viewName : sViewName, + autoWait : false, // Needed because we want to find disabled controls, too + matchers : new PropertyStrictEquals({ + name : "enabled", + value : bEnabled + }), + check : function (aControls) { + // Validate that ALL controls have the right state + return aControls.length === 3; + }, + success : function () { + Opa5.assert.ok(true, "All controls in the table toolbar are " + + sDesiredState); + }, + errorMessage : "Not all controls in the table toolbar could be found or not" + + " all are " + sDesiredState + }); + }, + + theMessageToastShouldShow : function (sTextId, sArg0) { + return this.waitFor({ + autoWait : false, + id : sTableId, + viewName : sViewName, + check : function (oControl) { + // Locate the message toast using its CSS class name and content + var sText = oControl.getModel("i18n").getResourceBundle() + .getText(sTextId, [sArg0]), + sSelector = ".sapMMessageToast:contains('" + sText + "')"; + + return !!Opa5.getJQuery()(sSelector).length; + }, + success : function () { + Opa5.assert.ok(true, "Could see the MessageToast showing text with ID " + + sTextId); + }, + errorMessage : "Could not see a MessageToast showing text with ID " + + sTextId + }); + }, + + iShouldSeeAServiceError : function () { + return this.waitFor({ + id : "serviceErrorMessageBox", + success : function () { + Opa5.assert.ok(true, "Could see the service error dialog"); + }, + errorMessage : "Could not see the service error dialog" + }); + }, + + theDetailAreaShouldBeVisible : function (bVisible) { + var sDesiredState = bVisible ? "visible" : "invisible"; + + return this.waitFor({ + controlType : "sap.f.semantic.SemanticPage", + viewName : sViewName, + visible : false, + matchers : new PropertyStrictEquals({ + name : "visible", + value : bVisible + }), + success : function () { + Opa5.assert.ok(true, "The detail area is " + sDesiredState); + }, + errorMessage : "Detail area not found or is not " + sDesiredState + }); + } + } + } + }); +}); diff --git a/packages/odatav4/steps/11/webapp/view/App.view.xml b/packages/odatav4/steps/11/webapp/view/App.view.xml new file mode 100644 index 000000000..b97ed71c0 --- /dev/null +++ b/packages/odatav4/steps/11/webapp/view/App.view.xml @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + </semantic:titleHeading> + <semantic:headerContent> + <FlexBox> + <VBox> + <ObjectAttribute text="{i18n>userNameLabelText}"/> + <ObjectAttribute text="{UserName}"/> + </VBox> + <VBox class="sapUiMediumMarginBegin"> + <ObjectAttribute text="{i18n>ageLabelText}"/> + <ObjectNumber number="{Age}" unit="Years"/> + </VBox> + </FlexBox> + </semantic:headerContent> + <semantic:content> + <VBox> + <FlexBox wrap="Wrap"> + <f:Form editable="false"> + <f:title> + <core:Title text="{i18n>addressTitleText}" /> + </f:title> + <f:layout> + <f:ResponsiveGridLayout + labelSpanXL="3" + labelSpanL="3" + labelSpanM="3" + labelSpanS="12" + adjustLabelSpan="false" + emptySpanXL="4" + emptySpanL="4" + emptySpanM="4" + emptySpanS="0" + columnsXL="1" + columnsL="1" + columnsM="1" + singleContainerFullSize="false" /> + </f:layout> + <f:formContainers> + <f:FormContainer> + <f:formElements> + <f:FormElement label="{i18n>addressLabelText}"> + <f:fields> + <Text text="{HomeAddress/Address}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>cityLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/Name}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>regionLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/Region}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>countryLabelText}"> + <f:fields> + <Text text="{HomeAddress/City/CountryRegion}" /> + </f:fields> + </f:FormElement> + </f:formElements> + </f:FormContainer> + </f:formContainers> + </f:Form> + <f:Form editable="false"> + <f:title> + <core:Title text="{i18n>bestFriendTitleText}" /> + </f:title> + <f:layout> + <f:ResponsiveGridLayout + labelSpanXL="3" + labelSpanL="3" + labelSpanM="3" + labelSpanS="12" + adjustLabelSpan="false" + emptySpanXL="4" + emptySpanL="4" + emptySpanM="4" + emptySpanS="0" + columnsXL="1" + columnsL="1" + columnsM="1" + singleContainerFullSize="false" /> + </f:layout> + <f:formContainers> + <f:FormContainer> + <f:formElements> + <f:FormElement label="{i18n>nameLabelText}"> + <f:fields> + <Text text="{BestFriend/FirstName} {BestFriend/LastName}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>ageLabelText}"> + <f:fields> + <Text text="{BestFriend/Age}" /> + </f:fields> + </f:FormElement> + <f:FormElement label="{i18n>userNameLabelText}"> + <f:fields> + <Text text="{BestFriend/UserName}" /> + </f:fields> + </f:FormElement> + </f:formElements> + </f:FormContainer> + </f:formContainers> + </f:Form> + </FlexBox> + <Table + id="friendsTable" + width="auto" + items="{path: 'Friends', + parameters: { + $$ownRequest: true + }}" + noDataText="No Data" + class="sapUiSmallMarginBottom"> + <headerToolbar> + <Toolbar> + <Title + text="Friends" + titleStyle="H3" + level="H3"/> + </Toolbar> + </headerToolbar> + <columns> + <Column> + <Text text="User Name"/> + </Column> + <Column> + <Text text="First Name"/> + </Column> + <Column> + <Text text="Last Name"/> + </Column> + <Column> + <Text text="Age"/> + </Column> + </columns> + <items> + <ColumnListItem> + <cells> + <Text text="{UserName}"/> + </cells> + <cells> + <Text text="{FirstName}"/> + </cells> + <cells> + <Text text="{LastName}"/> + </cells> + <cells> + <Text text="{Age}"/> + </cells> + </ColumnListItem> + </items> + </Table> + </VBox> + </semantic:content> + </semantic:SemanticPage> + </l:SplitPane> + </l:PaneContainer> + </l:ResponsiveSplitter> + </content> + <footer> + <Toolbar visible="{appView>/hasUIChanges}"> + <ToolbarSpacer/> + <Button + id="saveButton" + type="Emphasized" + text="{i18n>saveButtonText}" + enabled="{= ${message>/}.length === 0 && ${appView>/usernameEmpty} === false }" + press=".onSave"/> + <Button + id="doneButton" + text="{i18n>cancelButtonText}" + press=".onResetChanges"/> + </Toolbar> + </footer> + </Page> + </pages> + </App> + </Shell> +</mvc:View> \ No newline at end of file diff --git a/packages/quickstart/README.md b/packages/quickstart/README.md index 49823416b..4b4c339d6 100644 --- a/packages/quickstart/README.md +++ b/packages/quickstart/README.md @@ -10,7 +10,7 @@ We first introduce you to the basic development paradigms like *Model-View-Contr ![Preview of the OpenUI5 application that is going to be built in this tutorial. Contains a Hello World upper part with buttons and a text input. The lower part shows list of invoices with details, grouped by vendor names.](steps/03/assets/loio79e1157d948c488c9717ef840fa9b396_LowRes.png). -> 💡 **Tip:** <br> +> :tip: > You don't have to do all tutorial steps sequentially, you can also jump directly to any step you want. Just download the code from the previous step and make sure that the application runs as intended. > > You can view the samples for all steps here in this repository. @@ -26,4 +26,4 @@ The tutorial consists of the following steps. To start, just open the first link ## License -Copyright (c) 2025 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](../../LICENSE) file. +Copyright (c) 2026 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](../../LICENSE) file. diff --git a/packages/quickstart/steps/01/README.md b/packages/quickstart/steps/01/README.md index 53f9b750a..b311a3329 100644 --- a/packages/quickstart/steps/01/README.md +++ b/packages/quickstart/steps/01/README.md @@ -58,9 +58,9 @@ In our webapp folder, we create a new HTML file named `index.html` and copy the data-sap-ui-libs="sap.m" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/quickstart/index" + data-sap-ui-on-init="module:ui5/tutorial/quickstart/index" data-sap-ui-resource-roots='{ - "ui5.quickstart": "./" + "ui5.tutorial.quickstart": "./" }'> </script> </head> @@ -117,12 +117,12 @@ Create a new file named `manifest.json` in the webapp folder; it's also known as { "_version": "1.60.0", "sap.app": { - "id": "ui5.quickstart" + "id": "ui5.tutorial.quickstart" } } ``` -> 📝 **Note:** <br> +> :note: > In this tutorial step, we focus on adding the absolute minimum configuration to the app descriptor file. In certain development environments you might encounter validation errors due to missing settings. However, for the purposes of this tutorial you can safely ignore these errors. In [Step 10: Descriptor for Applications](../10/README.md) we'll examine the purpose of the file in detail and configure some further options. *** @@ -141,7 +141,7 @@ Enter the following content: ```json { - "name": "ui5.quickstart", + "name": "ui5.tutorial.quickstart", "version": "1.0.0", "description": "The UI5 quickstart tutorial", "scripts": { @@ -185,7 +185,7 @@ We specify the compiler options as follow: "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/quickstart/*": [ + "ui5/tutorial/quickstart/*": [ "./webapp/*" ] } @@ -212,7 +212,7 @@ Let's go through the compiler options specified in the file: - `"rootDir": "./webapp"`: The `rootDir` parameter specifies the root directory of the TypeScript source files. The compiler considers this directory as the starting point for resolving file paths. We set it to our `webapp` folder. -- `"paths": { "ui5/quickstart/*": ["./webapp/**/*"] }`: The `path` paramter specifies path mappings for module resolution. It allows you to define custom module paths that map to specific directories or files. In this case, it maps the module path `ui5/quickstart/*`. +- `"paths": { "ui5/tutorial/quickstart/*": ["./webapp/**/*"] }`: The `path` paramter specifies path mappings for module resolution. It allows you to define custom module paths that map to specific directories or files. In this case, it maps the module path `ui5/tutorial/quickstart/*`. - `"include": [ "./webapp/**/*" ]`: Specifies an array of filenames or patterns to include in TypeScript compilation. @@ -292,7 +292,7 @@ Next, we have to configure the tooling extension we installed from npm to our U - All our custom middleware extensions will be called after the `compression` middleware. -> 📌 **Important:** <br> +> :info: > Middleware configurations are applied in the order in which they are defined. <details class="ts-only" markdown="1"> @@ -330,7 +330,7 @@ Now you can benefit from live reload on changes and built framework resources at </details> <br> -> 📝 **Note:**<br> +> :note: > During its initial run, the `ui5-middleware-serveframework` middleware will build the framework, which can take a while. In all following steps, the build will not happen again and the framework is served from the built resources.   diff --git a/packages/quickstart/steps/01/package.json b/packages/quickstart/steps/01/package.json index 6594f755e..3df759ed5 100644 --- a/packages/quickstart/steps/01/package.json +++ b/packages/quickstart/steps/01/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.quickstart.step01", + "name": "ui5.tutorial.quickstart.step01", "private": true, "version": "1.0.0", "author": "SAP SE", diff --git a/packages/quickstart/steps/01/tsconfig.json b/packages/quickstart/steps/01/tsconfig.json index ddc228fd3..b5fa604d9 100644 --- a/packages/quickstart/steps/01/tsconfig.json +++ b/packages/quickstart/steps/01/tsconfig.json @@ -10,7 +10,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/quickstart/*": [ + "ui5/tutorial/quickstart/*": [ "./webapp/*" ] } diff --git a/packages/quickstart/steps/01/ui5.yaml b/packages/quickstart/steps/01/ui5.yaml index 851e823d5..66eb4ac67 100644 --- a/packages/quickstart/steps/01/ui5.yaml +++ b/packages/quickstart/steps/01/ui5.yaml @@ -1,6 +1,6 @@ specVersion: "4.0" metadata: - name: quickstart-tutorial + name: ui5.tutorial.quickstart type: application framework: name: OpenUI5 diff --git a/packages/quickstart/steps/01/webapp/index-cdn.html b/packages/quickstart/steps/01/webapp/index-cdn.html index f6d5be806..684556751 100644 --- a/packages/quickstart/steps/01/webapp/index-cdn.html +++ b/packages/quickstart/steps/01/webapp/index-cdn.html @@ -8,9 +8,9 @@ data-sap-ui-libs="sap.m" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/quickstart/index" + data-sap-ui-on-init="module:ui5/tutorial/quickstart/index" data-sap-ui-resource-roots='{ - "ui5.quickstart": "./" + "ui5.tutorial.quickstart": "./" }'> </script> </head> diff --git a/packages/quickstart/steps/01/webapp/index.html b/packages/quickstart/steps/01/webapp/index.html index b5e19abc9..35f40a726 100644 --- a/packages/quickstart/steps/01/webapp/index.html +++ b/packages/quickstart/steps/01/webapp/index.html @@ -8,9 +8,9 @@ data-sap-ui-libs="sap.m" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/quickstart/index" + data-sap-ui-on-init="module:ui5/tutorial/quickstart/index" data-sap-ui-resource-roots='{ - "ui5.quickstart": "./" + "ui5.tutorial.quickstart": "./" }'> </script> </head> diff --git a/packages/quickstart/steps/01/webapp/manifest.json b/packages/quickstart/steps/01/webapp/manifest.json index bc55cb8e8..749dd7d61 100644 --- a/packages/quickstart/steps/01/webapp/manifest.json +++ b/packages/quickstart/steps/01/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.quickstart", + "id": "ui5.tutorial.quickstart", "type": "application", "title": "OpenUI5 Quickstart", "applicationVersion": { diff --git a/packages/quickstart/steps/02/README.md b/packages/quickstart/steps/02/README.md index 6b5e1b952..d0213de2f 100644 --- a/packages/quickstart/steps/02/README.md +++ b/packages/quickstart/steps/02/README.md @@ -35,7 +35,7 @@ You can download the solution for this step here: [📥 Download step 2](https:/ ### webapp/index.?s -Now we replace most of the code in this file: We remove the inline button from the previous step, and introduce a proper XML view to separate the presentation from the controller logic. We prefix the view name `ui5.quickstart.App` with our newly defined namespace. The view is loaded asynchronously. +Now we replace most of the code in this file: We remove the inline button from the previous step, and introduce a proper XML view to separate the presentation from the controller logic. We prefix the view name `ui5.tutorial.quickstart.App` with our newly defined namespace. The view is loaded asynchronously. Similar to the step before, the view is placed in the element with the `content` ID after it has finished loading. @@ -43,7 +43,7 @@ Similar to the step before, the view is placed in the element with the `content` import XMLView from "sap/ui/core/mvc/XMLView"; XMLView.create({ - viewName: "ui5.quickstart.App" + viewName: "ui5.tutorial.quickstart.App" }).then((oView) => oView.placeAt("content")); ``` ```js @@ -53,7 +53,7 @@ sap.ui.define([ "use strict"; XMLView.create({ - viewName: "ui5.quickstart.App" + viewName: "ui5.tutorial.quickstart.App" }).then((oView) => oView.placeAt("content")); }); ``` @@ -68,7 +68,7 @@ We outsource the controller logic to an app controller. The `.onPress` event now ```xml <mvc:View - controllerName="ui5.quickstart.App" + controllerName="ui5.tutorial.quickstart.App" displayBlock="true" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> @@ -105,7 +105,7 @@ sap.ui.define([ ], (Controller, MessageToast) => { "use strict"; - return Controller.extend("ui5.quickstart.App", { + return Controller.extend("ui5.tutorial.quickstart.App", { onPress() { MessageToast.show("Hello App!"); } diff --git a/packages/quickstart/steps/02/package.json b/packages/quickstart/steps/02/package.json index a085d7c8f..4c3b307b2 100644 --- a/packages/quickstart/steps/02/package.json +++ b/packages/quickstart/steps/02/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.quickstart.step02", + "name": "ui5.tutorial.quickstart.step02", "private": true, "version": "1.0.0", "author": "SAP SE", diff --git a/packages/quickstart/steps/02/tsconfig.json b/packages/quickstart/steps/02/tsconfig.json index ddc228fd3..b5fa604d9 100644 --- a/packages/quickstart/steps/02/tsconfig.json +++ b/packages/quickstart/steps/02/tsconfig.json @@ -10,7 +10,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/quickstart/*": [ + "ui5/tutorial/quickstart/*": [ "./webapp/*" ] } diff --git a/packages/quickstart/steps/02/ui5.yaml b/packages/quickstart/steps/02/ui5.yaml index 851e823d5..66eb4ac67 100644 --- a/packages/quickstart/steps/02/ui5.yaml +++ b/packages/quickstart/steps/02/ui5.yaml @@ -1,6 +1,6 @@ specVersion: "4.0" metadata: - name: quickstart-tutorial + name: ui5.tutorial.quickstart type: application framework: name: OpenUI5 diff --git a/packages/quickstart/steps/02/webapp/App.controller.ts b/packages/quickstart/steps/02/webapp/App.controller.ts index d595a07e4..ed1ee48a9 100644 --- a/packages/quickstart/steps/02/webapp/App.controller.ts +++ b/packages/quickstart/steps/02/webapp/App.controller.ts @@ -2,7 +2,7 @@ import Controller from "sap/ui/core/mvc/Controller"; import MessageToast from "sap/m/MessageToast"; /** - * @namespace ui5.quickstart + * @namespace ui5.tutorial.quickstart */ export default class App extends Controller { onPress(): void { diff --git a/packages/quickstart/steps/02/webapp/App.view.xml b/packages/quickstart/steps/02/webapp/App.view.xml index c977e2ed8..7f47b5ea2 100644 --- a/packages/quickstart/steps/02/webapp/App.view.xml +++ b/packages/quickstart/steps/02/webapp/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.quickstart.App" + controllerName="ui5.tutorial.quickstart.App" displayBlock="true" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> diff --git a/packages/quickstart/steps/02/webapp/index-cdn.html b/packages/quickstart/steps/02/webapp/index-cdn.html index f6d5be806..684556751 100644 --- a/packages/quickstart/steps/02/webapp/index-cdn.html +++ b/packages/quickstart/steps/02/webapp/index-cdn.html @@ -8,9 +8,9 @@ data-sap-ui-libs="sap.m" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/quickstart/index" + data-sap-ui-on-init="module:ui5/tutorial/quickstart/index" data-sap-ui-resource-roots='{ - "ui5.quickstart": "./" + "ui5.tutorial.quickstart": "./" }'> </script> </head> diff --git a/packages/quickstart/steps/02/webapp/index.html b/packages/quickstart/steps/02/webapp/index.html index b5e19abc9..35f40a726 100644 --- a/packages/quickstart/steps/02/webapp/index.html +++ b/packages/quickstart/steps/02/webapp/index.html @@ -8,9 +8,9 @@ data-sap-ui-libs="sap.m" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/quickstart/index" + data-sap-ui-on-init="module:ui5/tutorial/quickstart/index" data-sap-ui-resource-roots='{ - "ui5.quickstart": "./" + "ui5.tutorial.quickstart": "./" }'> </script> </head> diff --git a/packages/quickstart/steps/02/webapp/index.ts b/packages/quickstart/steps/02/webapp/index.ts index 2c58de3bb..e8932dcb2 100644 --- a/packages/quickstart/steps/02/webapp/index.ts +++ b/packages/quickstart/steps/02/webapp/index.ts @@ -1,5 +1,5 @@ import XMLView from "sap/ui/core/mvc/XMLView"; XMLView.create({ - viewName: "ui5.quickstart.App" + viewName: "ui5.tutorial.quickstart.App" }).then((oView) => oView.placeAt("content")); diff --git a/packages/quickstart/steps/02/webapp/manifest.json b/packages/quickstart/steps/02/webapp/manifest.json index bc55cb8e8..749dd7d61 100644 --- a/packages/quickstart/steps/02/webapp/manifest.json +++ b/packages/quickstart/steps/02/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.quickstart", + "id": "ui5.tutorial.quickstart", "type": "application", "title": "OpenUI5 Quickstart", "applicationVersion": { diff --git a/packages/quickstart/steps/03/README.md b/packages/quickstart/steps/03/README.md index fcc48fbd6..fc6129f05 100644 --- a/packages/quickstart/steps/03/README.md +++ b/packages/quickstart/steps/03/README.md @@ -48,9 +48,9 @@ Let's spice up our app by adding some more UI controls. We add two more librarie data-sap-ui-libs="sap.m, sap.ui.layout, sap.tnt" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/quickstart/index" + data-sap-ui-on-init="module:ui5/tutorial/quickstart/index" data-sap-ui-resource-roots='{ - "ui5.quickstart": "./" + "ui5.tutorial.quickstart": "./" }'> </script> </head> @@ -58,7 +58,7 @@ Let's spice up our app by adding some more UI controls. We add two more librarie </html> ``` -> 💡 **Tip:** <br> +> :tip: > To browse all available controls and libraries, see the [Samples](https://sdk.openui5.org/#/controls). ### webapp/App.view.xml @@ -73,7 +73,7 @@ Don't worry too much about the details, we will explain them in the next tutoria ```xml <mvc:View - controllerName="ui5.quickstart.App" + controllerName="ui5.tutorial.quickstart.App" displayBlock="true" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" @@ -176,7 +176,7 @@ sap.ui.define([ ], (Controller, MessageToast, JSONModel) => { "use strict"; - return Controller.extend("ui5.quickstart.App", { + return Controller.extend("ui5.tutorial.quickstart.App", { onPress() { MessageToast.show("Hello UI5!"); this.byId("app").to(this.byId("intro")); diff --git a/packages/quickstart/steps/03/package.json b/packages/quickstart/steps/03/package.json index a316d56f0..d59124e2b 100644 --- a/packages/quickstart/steps/03/package.json +++ b/packages/quickstart/steps/03/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.quickstart.step03", + "name": "ui5.tutorial.quickstart.step03", "private": true, "version": "1.0.0", "author": "SAP SE", diff --git a/packages/quickstart/steps/03/tsconfig.json b/packages/quickstart/steps/03/tsconfig.json index ddc228fd3..b5fa604d9 100644 --- a/packages/quickstart/steps/03/tsconfig.json +++ b/packages/quickstart/steps/03/tsconfig.json @@ -10,7 +10,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/quickstart/*": [ + "ui5/tutorial/quickstart/*": [ "./webapp/*" ] } diff --git a/packages/quickstart/steps/03/ui5.yaml b/packages/quickstart/steps/03/ui5.yaml index 851e823d5..66eb4ac67 100644 --- a/packages/quickstart/steps/03/ui5.yaml +++ b/packages/quickstart/steps/03/ui5.yaml @@ -1,6 +1,6 @@ specVersion: "4.0" metadata: - name: quickstart-tutorial + name: ui5.tutorial.quickstart type: application framework: name: OpenUI5 diff --git a/packages/quickstart/steps/03/webapp/App.controller.ts b/packages/quickstart/steps/03/webapp/App.controller.ts index 0cc3cd46d..dcd0609f7 100644 --- a/packages/quickstart/steps/03/webapp/App.controller.ts +++ b/packages/quickstart/steps/03/webapp/App.controller.ts @@ -6,7 +6,7 @@ import HorizontalLayout from "sap/ui/layout/HorizontalLayout"; import { Switch$ChangeEvent } from "sap/m/Switch"; /** - * @namespace ui5.quickstart + * @namespace ui5.tutorial.quickstart */ export default class AppController extends Controller { onPress(): void { diff --git a/packages/quickstart/steps/03/webapp/App.view.xml b/packages/quickstart/steps/03/webapp/App.view.xml index fba9707f4..a865752ee 100644 --- a/packages/quickstart/steps/03/webapp/App.view.xml +++ b/packages/quickstart/steps/03/webapp/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.quickstart.App" + controllerName="ui5.tutorial.quickstart.App" displayBlock="true" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" diff --git a/packages/quickstart/steps/03/webapp/index-cdn.html b/packages/quickstart/steps/03/webapp/index-cdn.html index f6d5be806..684556751 100644 --- a/packages/quickstart/steps/03/webapp/index-cdn.html +++ b/packages/quickstart/steps/03/webapp/index-cdn.html @@ -8,9 +8,9 @@ data-sap-ui-libs="sap.m" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/quickstart/index" + data-sap-ui-on-init="module:ui5/tutorial/quickstart/index" data-sap-ui-resource-roots='{ - "ui5.quickstart": "./" + "ui5.tutorial.quickstart": "./" }'> </script> </head> diff --git a/packages/quickstart/steps/03/webapp/index.html b/packages/quickstart/steps/03/webapp/index.html index 930dc632d..ff2f0e466 100644 --- a/packages/quickstart/steps/03/webapp/index.html +++ b/packages/quickstart/steps/03/webapp/index.html @@ -8,9 +8,9 @@ data-sap-ui-libs="sap.m, sap.ui.layout, sap.tnt" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/quickstart/index" + data-sap-ui-on-init="module:ui5/tutorial/quickstart/index" data-sap-ui-resource-roots='{ - "ui5.quickstart": "./" + "ui5.tutorial.quickstart": "./" }'> </script> </head> diff --git a/packages/quickstart/steps/03/webapp/index.ts b/packages/quickstart/steps/03/webapp/index.ts index 2c58de3bb..e8932dcb2 100644 --- a/packages/quickstart/steps/03/webapp/index.ts +++ b/packages/quickstart/steps/03/webapp/index.ts @@ -1,5 +1,5 @@ import XMLView from "sap/ui/core/mvc/XMLView"; XMLView.create({ - viewName: "ui5.quickstart.App" + viewName: "ui5.tutorial.quickstart.App" }).then((oView) => oView.placeAt("content")); diff --git a/packages/quickstart/steps/03/webapp/manifest.json b/packages/quickstart/steps/03/webapp/manifest.json index bc55cb8e8..749dd7d61 100644 --- a/packages/quickstart/steps/03/webapp/manifest.json +++ b/packages/quickstart/steps/03/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.quickstart", + "id": "ui5.tutorial.quickstart", "type": "application", "title": "OpenUI5 Quickstart", "applicationVersion": { diff --git a/packages/walkthrough/README.md b/packages/walkthrough/README.md index 86b7968c1..63a7ec7f5 100644 --- a/packages/walkthrough/README.md +++ b/packages/walkthrough/README.md @@ -10,7 +10,7 @@ We first introduce you to the basic development paradigms like *Model-View-Contr ![Preview of the OpenUI5 application that is going to be built in this tutorial. Contains a Hello World upper part with buttons and a text input. The lower part shows list of invoices with details, grouped by vendor names.](steps/38/assets/loiofb12cea5ac9b45bb9007aac5a1a8689f_LowRes.png) -> 💡 **Tip:** <br> +> :tip: > You don't have to do all tutorial steps sequentially, you can also jump directly to any step you want. Just download the code from the previous step and make sure that the application runs as intended. > > You can view the samples for all steps here in this repository. @@ -46,8 +46,8 @@ The tutorial consists of the following steps. To start, just open the first link - **[Step 24: Sorting and Grouping](steps/24/README.md "To make our list of invoices even more user-friendly, we sort it alphabetically instead of just showing the order from the data model. Additionally, we introduce groups and add the company that ships the products so that the data is easier to consume.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/walkthrough/build/24/index-cdn.html) \| <details class="ts-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-24.zip) </details><details class="js-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-24-js.zip)</details>) - **[Step 25: Remote OData Service](steps/25/README.md "So far we have worked with local JSON data, but now we will access a real OData service to visualize remote data.")** (🔗 Live Preview *unfeasible* \| <details class="ts-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-25.zip) </details><details class="js-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-25-js.zip)</details>) - **[Step 26: Mock Server Configuration](steps/26/README.md "We just ran our app against a real service, but for developing and testing our app we do not want to rely on the availability of the “real” service or put additional load on the system where the data service is located.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/walkthrough/build/26/test/mockServer-cdn.html) \| <details class="ts-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-26.zip) </details><details class="js-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-26-js.zip)</details>) -- **[Step 27: Unit Test with QUnit](steps/27/README.md "Now that we have a test folder in the app, we can start to increase our test coverage. ")** ([🔗 Live Preview](https://ui5.github.io/tutorials/walkthrough/build/27/test/Test.cdn.qunit.html?testsuite=test-resources/ui5/walkthrough/testsuite.cdn.qunit&test=unit/unitTests) \| <details class="ts-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-27.zip) </details><details class="js-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-27-js.zip)</details>) -- **[Step 28: Integration Test with OPA](steps/28/README.md "If we want to test interaction patterns or more visual features of our app, we can also write an integration test. ")** ([🔗 Live Preview](https://ui5.github.io/tutorials/walkthrough/build/28/test/Test.cdn.qunit.html?testsuite=test-resources/ui5/walkthrough/testsuite.cdn.qunit&test=integration/opaTests) \| <details class="ts-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-28.zip) </details><details class="js-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-28-js.zip)</details>) +- **[Step 27: Unit Test with QUnit](steps/27/README.md "Now that we have a test folder in the app, we can start to increase our test coverage. ")** ([🔗 Live Preview](https://ui5.github.io/tutorials/walkthrough/build/27/test/Test.cdn.qunit.html?testsuite=test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit&test=unit/unitTests) \| <details class="ts-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-27.zip) </details><details class="js-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-27-js.zip)</details>) +- **[Step 28: Integration Test with OPA](steps/28/README.md "If we want to test interaction patterns or more visual features of our app, we can also write an integration test. ")** ([🔗 Live Preview](https://ui5.github.io/tutorials/walkthrough/build/28/test/Test.cdn.qunit.html?testsuite=test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit&test=integration/opaTests) \| <details class="ts-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-28.zip) </details><details class="js-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-28-js.zip)</details>) - **[Step 29: Debugging Tools](steps/29/README.md "Even though we have added a basic test coverage in the previous steps, it seems like we accidentally broke our app, because it does not display prices to our invoices anymore. We need to debug the issue and fix it before someone finds out.")** (*code remains unchanged from the previous step*) - **[Step 30: Routing and Navigation](steps/30/README.md "So far, we have put all app content on one single page. As we add more and more features, we want to split the content and put it on separate pages.")** ([🔗 Live Preview](https://ui5.github.io/tutorials/walkthrough/build/30/test/mockServer-cdn.html) \| <details class="ts-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-30.zip) </details><details class="js-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-30-js.zip)</details>) - **[Step 31: Routing with Parameters](steps/31/README.md "We can now navigate between the overview and the detail page, but the actual item that we selected in the overview is not displayed on the detail page yet. A typical use case for our app is to show additional information for the selected item on the detail page. ")** ([🔗 Live Preview](https://ui5.github.io/tutorials/walkthrough/build/31/test/mockServer-cdn.html) \| <details class="ts-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-31.zip) </details><details class="js-only" markdown="1"> [📥 Download Solution](https://ui5.github.io/tutorials/walkthrough/walkthrough-step-31-js.zip)</details>) @@ -61,4 +61,4 @@ The tutorial consists of the following steps. To start, just open the first link ## License -Copyright (c) 2025 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](../../LICENSE) file. +Copyright (c) 2026 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](../../LICENSE) file. diff --git a/packages/walkthrough/steps/01/README.md b/packages/walkthrough/steps/01/README.md index abea777ca..b173dd055 100644 --- a/packages/walkthrough/steps/01/README.md +++ b/packages/walkthrough/steps/01/README.md @@ -57,7 +57,7 @@ In our webapp folder, we create a new HTML file named `index.html` and copy the </html> ``` -> 📝 **Note:** <br> +> :note: > An HTML document consists basically of two sections: head and body. The head part will be used by the browser to process the document. > > Using meta tags, we can influence the behavior of the browser. In this case, we tell the browser to use `UTF-8` as the document character set. @@ -76,7 +76,7 @@ Let's start by creating a new file named `manifest.json` in the webapp folder an Since we want our app to support not only the latest OpenUI5 version but rather the latest long-term maintenance version, which is OpenUI5 1.120, we set the format version to `1.60.0`. - > 📝 **Note:** <br> + > :note: > The manifest version should not necessarily align directly with the OpenUI5 version being used. Instead, choose the descriptor version that matches the requirements or supports the features you intend to use in your application. To find the appropriate `_version` for each OpenUI5 release, refer to [Descriptor for Applications, Components, and Libraries \(manifest.json\)](https://sdk.openui5.org/topic/be0cf40f61184b358b5faedaec98b2da.html) or the [mapping.json](https://github.com/SAP/ui5-manifest/blob/main/mapping.json) file of the [ui5-manifest](https://github.com/SAP/ui5-manifest/) project. @@ -89,7 +89,7 @@ Since we want our app to support not only the latest OpenUI5 version but rather - `title`: This defines the title of the application, which appears in application management tools like the SAP Fiori launchpad. - > 📝 **Note:** <br> + > :note: > It is advisable to make the title language-dependent. We'll cover implementing language-dependent titles in [Step 10: Manifest (Descriptor for Applications)](../10/README.md), but for now we'll use a static title. - `applicationVersion`: This is used to denote the version of the application using semantic versioning principles. It's typically used for tracking and managing changes to the application over time. @@ -98,7 +98,7 @@ Since we want our app to support not only the latest OpenUI5 version but rather { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "title": "OpenUI5 TypeScript Walkthrough", "applicationVersion": { @@ -108,7 +108,7 @@ Since we want our app to support not only the latest OpenUI5 version but rather } ``` -> 📝 **Note:** <br> +> :note: > In this tutorial step, we focus on adding the absolute minimum configuration to the app descriptor file. In certain development environments you might encounter validation errors due to missing settings. However, for the purposes of this tutorial you can safely ignore these errors. In [Step 10: Descriptor for Applications](../10/README.md) we'll examine the purpose of the file in detail and configure some further options. *** @@ -127,7 +127,7 @@ Enter the following content: ```json { - "name": "ui5.walkthrough", + "name": "ui5.tutorial.walkthrough", "version": "1.0.0", "description": "OpenUI5 TypeScript Walkthrough", "private": true, diff --git a/packages/walkthrough/steps/01/package.json b/packages/walkthrough/steps/01/package.json index b18a0bf03..b89092327 100644 --- a/packages/walkthrough/steps/01/package.json +++ b/packages/walkthrough/steps/01/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step01", + "name": "ui5.tutorial.walkthrough.step01", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 1 - Hello World!", diff --git a/packages/walkthrough/steps/01/ui5.yaml b/packages/walkthrough/steps/01/ui5.yaml index 2eab71877..ea8c87387 100644 --- a/packages/walkthrough/steps/01/ui5.yaml +++ b/packages/walkthrough/steps/01/ui5.yaml @@ -1,4 +1,4 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application diff --git a/packages/walkthrough/steps/01/webapp/manifest.json b/packages/walkthrough/steps/01/webapp/manifest.json index 90f0f71b7..287380556 100644 --- a/packages/walkthrough/steps/01/webapp/manifest.json +++ b/packages/walkthrough/steps/01/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "title": "OpenUI5 TypeScript Walkthrough", "applicationVersion": { diff --git a/packages/walkthrough/steps/02/README.md b/packages/walkthrough/steps/02/README.md index e0aebe2b6..30b2475e4 100644 --- a/packages/walkthrough/steps/02/README.md +++ b/packages/walkthrough/steps/02/README.md @@ -81,7 +81,7 @@ We specify the compiler options as follow: "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] @@ -102,7 +102,7 @@ Let's go through the compiler options specified in the file: - `"rootDir": "./webapp"`: The `rootDir` parameter specifies the root directory of the TypeScript source files. The compiler considers this directory as the starting point for resolving file paths. We set it to our `webapp` folder. -- `"paths": { "ui5/walkthrough/*": ["./webapp/*"] }`: The `path` paramter specifies path mappings for module resolution. It allows you to define custom module paths that map to specific directories or files. In this case, it maps the module path `ui5/walkthrough/*`. +- `"paths": { "ui5/tutorial/walkthrough/*": ["./webapp/*"] }`: The `path` paramter specifies path mappings for module resolution. It allows you to define custom module paths that map to specific directories or files. In this case, it maps the module path `ui5/tutorial/walkthrough/*`. - `"include": [ "./webapp/**/*" ]`: Specifies an array of filenames or patterns to include in TypeScript compilation. @@ -136,7 +136,7 @@ We initialize the core modules with the following configuration options: - The `data-sap-ui-on-init` attribute is used in OpenUI5 to specify the name of a module that should be executed when the framework is fully loaded and initialized. This approach provides a way to avoid directly including executable JavaScript code in the HTML file, which improves the security of our application. To specify the name of the module, you need to provide the module name as the value of the `data-sap-ui-on-init` attribute. The module name should be in the format of a module path, which is a dot-separated string that represents the location of the module within the application's folder structure. When specifying the path to a module within the current project, it's important to include the namespace (explained below) and omit the file extension. We specify the `index.ts` script to the `data-sap-ui-on-init` attribute. -- The `data-sap-ui-resource-roots` attribute lets you map a namespace to a specific path. We define the `ui5.walkthrough` namespace and map it relative to the location of `index.html`. This way, we tell OpenUI5 core that resources in the `ui5.walkthrough` namespace are located in the same folder as `index.html`. +- The `data-sap-ui-resource-roots` attribute lets you map a namespace to a specific path. We define the `ui5.tutorial.walkthrough` namespace and map it relative to the location of `index.html`. This way, we tell OpenUI5 core that resources in the `ui5.tutorial.walkthrough` namespace are located in the same folder as `index.html`. ```html <!DOCTYPE html> @@ -150,9 +150,9 @@ We initialize the core modules with the following configuration options: data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> @@ -162,7 +162,7 @@ We initialize the core modules with the following configuration options: </html> ``` -> 📝 **Note:**<br> +> :note: > The namespace is a unique identifier for your application file. It helps prevent naming conflicts with other modules or libraries. *** @@ -212,7 +212,7 @@ Next, we have to configure the tooling extension we installed from npm to our U - All our custom middleware extensions will be called after the `compression` middleware. -> 📌 **Important:** <br> +> :info: > Middleware configurations are applied in the order in which they are defined. <details class="ts-only" markdown="1"> @@ -250,7 +250,7 @@ Now you can benefit from live reload on changes and built framework resources at </details> <br> -> 📝 **Note:**<br> +> :note: > During its initial run, the `ui5-middleware-serveframework` middleware will build the framework, which can take a while. In all following steps, the build will not happen again and the framework is served from the built resources.   diff --git a/packages/walkthrough/steps/02/package.json b/packages/walkthrough/steps/02/package.json index 278760a16..fb2ab5758 100644 --- a/packages/walkthrough/steps/02/package.json +++ b/packages/walkthrough/steps/02/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step02", + "name": "ui5.tutorial.walkthrough.step02", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 2 - Bootstrap", diff --git a/packages/walkthrough/steps/02/tsconfig.json b/packages/walkthrough/steps/02/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/02/tsconfig.json +++ b/packages/walkthrough/steps/02/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/02/ui5.yaml b/packages/walkthrough/steps/02/ui5.yaml index 6df34f44d..994cbcbad 100644 --- a/packages/walkthrough/steps/02/ui5.yaml +++ b/packages/walkthrough/steps/02/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/02/webapp/index-cdn.html b/packages/walkthrough/steps/02/webapp/index-cdn.html index d5a8a3937..04c50fe38 100644 --- a/packages/walkthrough/steps/02/webapp/index-cdn.html +++ b/packages/walkthrough/steps/02/webapp/index-cdn.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/02/webapp/index.html b/packages/walkthrough/steps/02/webapp/index.html index f827464d2..1c585ad3e 100644 --- a/packages/walkthrough/steps/02/webapp/index.html +++ b/packages/walkthrough/steps/02/webapp/index.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/02/webapp/manifest.json b/packages/walkthrough/steps/02/webapp/manifest.json index 90f0f71b7..287380556 100644 --- a/packages/walkthrough/steps/02/webapp/manifest.json +++ b/packages/walkthrough/steps/02/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "title": "OpenUI5 TypeScript Walkthrough", "applicationVersion": { diff --git a/packages/walkthrough/steps/03/README.md b/packages/walkthrough/steps/03/README.md index 104820fb9..edce90f8a 100644 --- a/packages/walkthrough/steps/03/README.md +++ b/packages/walkthrough/steps/03/README.md @@ -64,7 +64,7 @@ To place the text control to our HTML document, we chain the constructor call of <details class="js-only" markdown="1"> -> 📌 **Important:** <br> +> :info: > It is best practice to use of Anynchronous Module Loading (AMD) style for defining modules and their dependencies. This ensures better performance, proper dependency tracking between modules and helps avoid issues related to loading order. </details> @@ -89,7 +89,7 @@ sap.ui.define(["sap/m/Text"], function (Text) { All controls of OpenUI5 have a fixed set of properties, aggregations, and associations for configuration. You can find their descriptions in the Demo Kit. In addition, each control comes with a set of public functions that you can look up in the API reference. -> 📌 **Important:** <br> +> :info: > Only instances of `sap.ui.core.Control` or their subclasses can be rendered stand-alone and have a `placeAt` function. Each control extends `sap.ui.core.Element` that can only be rendered inside controls. Check the API reference to learn more about the inheritance hierarchy of controls. The API documentation of each control refers to the directly known subclasses. *** @@ -112,9 +112,9 @@ We also add the `sapUiBody` class, which provides additional theme-dependent sty data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/03/package.json b/packages/walkthrough/steps/03/package.json index 63662332e..94f67fd35 100644 --- a/packages/walkthrough/steps/03/package.json +++ b/packages/walkthrough/steps/03/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step03", + "name": "ui5.tutorial.walkthrough.step03", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 3 - Controls", diff --git a/packages/walkthrough/steps/03/tsconfig.json b/packages/walkthrough/steps/03/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/03/tsconfig.json +++ b/packages/walkthrough/steps/03/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/03/ui5.yaml b/packages/walkthrough/steps/03/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/03/ui5.yaml +++ b/packages/walkthrough/steps/03/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/03/webapp/index-cdn.html b/packages/walkthrough/steps/03/webapp/index-cdn.html index b4cdba0d7..801914ab6 100644 --- a/packages/walkthrough/steps/03/webapp/index-cdn.html +++ b/packages/walkthrough/steps/03/webapp/index-cdn.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/03/webapp/index.html b/packages/walkthrough/steps/03/webapp/index.html index 8a71c5c8b..d4895803c 100644 --- a/packages/walkthrough/steps/03/webapp/index.html +++ b/packages/walkthrough/steps/03/webapp/index.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/03/webapp/manifest.json b/packages/walkthrough/steps/03/webapp/manifest.json index 90f0f71b7..287380556 100644 --- a/packages/walkthrough/steps/03/webapp/manifest.json +++ b/packages/walkthrough/steps/03/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "title": "OpenUI5 TypeScript Walkthrough", "applicationVersion": { diff --git a/packages/walkthrough/steps/04/README.md b/packages/walkthrough/steps/04/README.md index 15da0c628..8ece8d6e8 100644 --- a/packages/walkthrough/steps/04/README.md +++ b/packages/walkthrough/steps/04/README.md @@ -49,10 +49,10 @@ Inside the `<mvc:View>` tag, we add the `<Text>` tag from the default XML namesp We have created an XML view that displays a text control with the text "Hello World". -> 💡 **Tip:** <br> +> :tip: > XML tags are mapped to UI controls, and attributes are mapped to the properties of the control. In this case, the `<Text>` tag represents the `Text` control in the sap.m library, and the `text` attribute sets the `text` property of the control. -> 📝 **Note:** <br> +> :note: > The namespace identifies all resources of the project and has to be unique. If you develop your own application code or library, you cannot use the namespace prefix `sap`, because this namespace is reserved for SAP resources. Instead, simply define your own unique namespace \(for example, `myCompany.myApp`\). *** @@ -65,7 +65,7 @@ As a next step, we are going to replace the `sap/m/Text` control in our `index.? import XMLView from "sap/ui/core/mvc/XMLView"; XMLView.create({ - viewName: "ui5.walkthrough.view.App", + viewName: "ui5.tutorial.walkthrough.view.App", id: "app" }).then(function (view) { view.placeAt("content"); @@ -78,7 +78,7 @@ sap.ui.define(["sap/ui/core/mvc/XMLView"], function (XMLView) { "use strict"; XMLView.create({ - viewName: "ui5.walkthrough.view.App", + viewName: "ui5.tutorial.walkthrough.view.App", id: "app" }).then(function (view) { view.placeAt("content"); @@ -89,7 +89,7 @@ sap.ui.define(["sap/ui/core/mvc/XMLView"], function (XMLView) { We have now embed our app view to the body of the HTML document. -> 💡 **Tip:** <br> +> :tip: >Although setting an ID is not mandatory, it greatly improves the maintainability and flexibility of your code. With a stable ID, you can easily locate and update specific parts of your application. *** diff --git a/packages/walkthrough/steps/04/package.json b/packages/walkthrough/steps/04/package.json index 9c064b599..849b9ddcc 100644 --- a/packages/walkthrough/steps/04/package.json +++ b/packages/walkthrough/steps/04/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step04", + "name": "ui5.tutorial.walkthrough.step04", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 4: XML Views", diff --git a/packages/walkthrough/steps/04/tsconfig.json b/packages/walkthrough/steps/04/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/04/tsconfig.json +++ b/packages/walkthrough/steps/04/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/04/ui5.yaml b/packages/walkthrough/steps/04/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/04/ui5.yaml +++ b/packages/walkthrough/steps/04/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/04/webapp/index-cdn.html b/packages/walkthrough/steps/04/webapp/index-cdn.html index b4cdba0d7..801914ab6 100644 --- a/packages/walkthrough/steps/04/webapp/index-cdn.html +++ b/packages/walkthrough/steps/04/webapp/index-cdn.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/04/webapp/index.html b/packages/walkthrough/steps/04/webapp/index.html index 8a71c5c8b..d4895803c 100644 --- a/packages/walkthrough/steps/04/webapp/index.html +++ b/packages/walkthrough/steps/04/webapp/index.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/04/webapp/index.ts b/packages/walkthrough/steps/04/webapp/index.ts index 1d9ef897d..d0fa02cc8 100644 --- a/packages/walkthrough/steps/04/webapp/index.ts +++ b/packages/walkthrough/steps/04/webapp/index.ts @@ -1,7 +1,7 @@ import XMLView from "sap/ui/core/mvc/XMLView"; XMLView.create({ - viewName: "ui5.walkthrough.view.App", + viewName: "ui5.tutorial.walkthrough.view.App", id: "app" }).then(function (view) { view.placeAt("content"); diff --git a/packages/walkthrough/steps/04/webapp/manifest.json b/packages/walkthrough/steps/04/webapp/manifest.json index 90f0f71b7..287380556 100644 --- a/packages/walkthrough/steps/04/webapp/manifest.json +++ b/packages/walkthrough/steps/04/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "title": "OpenUI5 TypeScript Walkthrough", "applicationVersion": { diff --git a/packages/walkthrough/steps/05/README.md b/packages/walkthrough/steps/05/README.md index f230c82a9..6eab26517 100644 --- a/packages/walkthrough/steps/05/README.md +++ b/packages/walkthrough/steps/05/README.md @@ -42,7 +42,7 @@ We create a new folder called `controller` inside the `webapp` folder. This fold import Controller from "sap/ui/core/mvc/Controller"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onShowHello(): void { @@ -57,7 +57,7 @@ export default class AppController extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller"], function (Controller) { "use strict"; - const AppController = Controller.extend("ui5.walkthrough.controller.App", { + const AppController = Controller.extend("ui5.tutorial.walkthrough.controller.App", { onShowHello() { // show a native JavaScript alert alert("Hello World"); @@ -70,8 +70,8 @@ sap.ui.define(["sap/ui/core/mvc/Controller"], function (Controller) { ``` <details class="ts-only" markdown="1"> -> 📝 **Note:** <br> -> The comment `@name ui5.walkthrough.controller.App` is a JSDoc comment that names this controller. It can be used by documentation generators and IDEs to provide more information about this class. +> :note: +> The comment `@name ui5.tutorial.walkthrough.controller.App` is a JSDoc comment that names this controller. It can be used by documentation generators and IDEs to provide more information about this class. </details> *** @@ -84,7 +84,7 @@ In addition, we replace the `<text>` tag with a `<button>` tag. We set the `text ```xml <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Button diff --git a/packages/walkthrough/steps/05/package.json b/packages/walkthrough/steps/05/package.json index 3f1db1589..e5af85460 100644 --- a/packages/walkthrough/steps/05/package.json +++ b/packages/walkthrough/steps/05/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step05", + "name": "ui5.tutorial.walkthrough.step05", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 5: Controllers", diff --git a/packages/walkthrough/steps/05/tsconfig.json b/packages/walkthrough/steps/05/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/05/tsconfig.json +++ b/packages/walkthrough/steps/05/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/05/ui5.yaml b/packages/walkthrough/steps/05/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/05/ui5.yaml +++ b/packages/walkthrough/steps/05/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/05/webapp/controller/App.controller.ts b/packages/walkthrough/steps/05/webapp/controller/App.controller.ts index 4cd4c3fa7..e60c0aaa7 100644 --- a/packages/walkthrough/steps/05/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/05/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onShowHello(): void { diff --git a/packages/walkthrough/steps/05/webapp/index-cdn.html b/packages/walkthrough/steps/05/webapp/index-cdn.html index b4cdba0d7..801914ab6 100644 --- a/packages/walkthrough/steps/05/webapp/index-cdn.html +++ b/packages/walkthrough/steps/05/webapp/index-cdn.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/05/webapp/index.html b/packages/walkthrough/steps/05/webapp/index.html index 8a71c5c8b..d4895803c 100644 --- a/packages/walkthrough/steps/05/webapp/index.html +++ b/packages/walkthrough/steps/05/webapp/index.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/05/webapp/index.ts b/packages/walkthrough/steps/05/webapp/index.ts index 1d9ef897d..d0fa02cc8 100644 --- a/packages/walkthrough/steps/05/webapp/index.ts +++ b/packages/walkthrough/steps/05/webapp/index.ts @@ -1,7 +1,7 @@ import XMLView from "sap/ui/core/mvc/XMLView"; XMLView.create({ - viewName: "ui5.walkthrough.view.App", + viewName: "ui5.tutorial.walkthrough.view.App", id: "app" }).then(function (view) { view.placeAt("content"); diff --git a/packages/walkthrough/steps/05/webapp/manifest.json b/packages/walkthrough/steps/05/webapp/manifest.json index 90f0f71b7..287380556 100644 --- a/packages/walkthrough/steps/05/webapp/manifest.json +++ b/packages/walkthrough/steps/05/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "title": "OpenUI5 TypeScript Walkthrough", "applicationVersion": { diff --git a/packages/walkthrough/steps/05/webapp/view/App.view.xml b/packages/walkthrough/steps/05/webapp/view/App.view.xml index 6c80fdd82..5231c7bae 100644 --- a/packages/walkthrough/steps/05/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/05/webapp/view/App.view.xml @@ -1,4 +1,4 @@ -<mvc:View controllerName="ui5.walkthrough.controller.App" +<mvc:View controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Button diff --git a/packages/walkthrough/steps/06/README.md b/packages/walkthrough/steps/06/README.md index 82442b1b0..a889f5713 100644 --- a/packages/walkthrough/steps/06/README.md +++ b/packages/walkthrough/steps/06/README.md @@ -41,7 +41,7 @@ import MessageToast from "sap/m/MessageToast"; import Controller from "sap/ui/core/mvc/Controller"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onShowHello(): void { @@ -56,9 +56,9 @@ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/mvc/Controller"], function (Me "use strict"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ - const AppController = Controller.extend("ui5.walkthrough.controller.App", { + const AppController = Controller.extend("ui5.tutorial.walkthrough.controller.App", { onShowHello() { MessageToast.show("Hello World"); } diff --git a/packages/walkthrough/steps/06/package.json b/packages/walkthrough/steps/06/package.json index 08f862fee..fd973ce28 100644 --- a/packages/walkthrough/steps/06/package.json +++ b/packages/walkthrough/steps/06/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step06", + "name": "ui5.tutorial.walkthrough.step06", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 6: Modules", diff --git a/packages/walkthrough/steps/06/tsconfig.json b/packages/walkthrough/steps/06/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/06/tsconfig.json +++ b/packages/walkthrough/steps/06/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/06/ui5.yaml b/packages/walkthrough/steps/06/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/06/ui5.yaml +++ b/packages/walkthrough/steps/06/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/06/webapp/controller/App.controller.ts b/packages/walkthrough/steps/06/webapp/controller/App.controller.ts index 4a5b8f96c..e244eb73d 100644 --- a/packages/walkthrough/steps/06/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/06/webapp/controller/App.controller.ts @@ -2,7 +2,7 @@ import MessageToast from "sap/m/MessageToast"; import Controller from "sap/ui/core/mvc/Controller"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onShowHello(): void { diff --git a/packages/walkthrough/steps/06/webapp/index-cdn.html b/packages/walkthrough/steps/06/webapp/index-cdn.html index b4cdba0d7..801914ab6 100644 --- a/packages/walkthrough/steps/06/webapp/index-cdn.html +++ b/packages/walkthrough/steps/06/webapp/index-cdn.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/06/webapp/index.html b/packages/walkthrough/steps/06/webapp/index.html index 8a71c5c8b..d4895803c 100644 --- a/packages/walkthrough/steps/06/webapp/index.html +++ b/packages/walkthrough/steps/06/webapp/index.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/06/webapp/index.ts b/packages/walkthrough/steps/06/webapp/index.ts index 1d9ef897d..d0fa02cc8 100644 --- a/packages/walkthrough/steps/06/webapp/index.ts +++ b/packages/walkthrough/steps/06/webapp/index.ts @@ -1,7 +1,7 @@ import XMLView from "sap/ui/core/mvc/XMLView"; XMLView.create({ - viewName: "ui5.walkthrough.view.App", + viewName: "ui5.tutorial.walkthrough.view.App", id: "app" }).then(function (view) { view.placeAt("content"); diff --git a/packages/walkthrough/steps/06/webapp/manifest.json b/packages/walkthrough/steps/06/webapp/manifest.json index 90f0f71b7..287380556 100644 --- a/packages/walkthrough/steps/06/webapp/manifest.json +++ b/packages/walkthrough/steps/06/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "title": "OpenUI5 TypeScript Walkthrough", "applicationVersion": { diff --git a/packages/walkthrough/steps/06/webapp/view/App.view.xml b/packages/walkthrough/steps/06/webapp/view/App.view.xml index 6c80fdd82..5231c7bae 100644 --- a/packages/walkthrough/steps/06/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/06/webapp/view/App.view.xml @@ -1,4 +1,4 @@ -<mvc:View controllerName="ui5.walkthrough.controller.App" +<mvc:View controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Button diff --git a/packages/walkthrough/steps/07/README.md b/packages/walkthrough/steps/07/README.md index f5ad1bc47..6c57de3b7 100644 --- a/packages/walkthrough/steps/07/README.md +++ b/packages/walkthrough/steps/07/README.md @@ -48,7 +48,7 @@ import Controller from "sap/ui/core/mvc/Controller"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onInit(): void { @@ -73,7 +73,7 @@ export default class AppController extends Controller { sap.ui.define(["sap/m/MessageToast", "sap/ui/core/mvc/Controller", "sap/ui/model/json/JSONModel"], function (MessageToast, Controller, JSONModel) { "use strict"; - const AppController = Controller.extend("ui5.walkthrough.controller.App", { + const AppController = Controller.extend("ui5.tutorial.walkthrough.controller.App", { onInit() { // set data model on view const data = { @@ -106,7 +106,7 @@ We add an `sap/m/Input` control to our view, allowing the user to enter a name f To make this work, we connect, or 'bind', the value of the input control to the `name` attribute of the 'recipient' object in our JSON data model. We do this using a simple binding syntax, which is a straightforward way to link data between the model and the view. -> 📌 **Important:** <br> +> :info: > To bind a control property to your view model data you need to specify a [`sap.ui.base.ManagedObject.PropertyBindingInfo`](https://sdk.openui5.org/api/sap.ui.base.ManagedObject.PropertyBindingInfo) for the property. A binding info is always initiated by enclosing it in curly brackets `{…}`, and the properties defined in the BindingInfos API are placed within the brackets. > > You can omit all properties of the binding info and just provide the binding path as a simple string. A binding path consists of path segments separated by a slash (`/`) which point to a property in the model that you want to bind to. This applies all OpenUI5 provided models. @@ -116,7 +116,7 @@ To make this work, we connect, or 'bind', the value of the input control to the In addition to this, we create a greeting message. We combine the static text "Hello" with the `name` attribute from our data model, and assign it to the `description` property of the input field. This means that the greeting message will dynamically update with whatever name the user enters. To ensure that the greeting message updates in real time as the user types, we set the `valueLiveUpdate` attribute of the input control to "true". ```xml -<mvc:View controllerName="ui5.walkthrough.controller.App" +<mvc:View controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Button diff --git a/packages/walkthrough/steps/07/package.json b/packages/walkthrough/steps/07/package.json index 5fed1c39b..0f83154dc 100644 --- a/packages/walkthrough/steps/07/package.json +++ b/packages/walkthrough/steps/07/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step07", + "name": "ui5.tutorial.walkthrough.step07", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 7: JSON Model", diff --git a/packages/walkthrough/steps/07/tsconfig.json b/packages/walkthrough/steps/07/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/07/tsconfig.json +++ b/packages/walkthrough/steps/07/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/07/ui5.yaml b/packages/walkthrough/steps/07/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/07/ui5.yaml +++ b/packages/walkthrough/steps/07/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/07/webapp/controller/App.controller.ts b/packages/walkthrough/steps/07/webapp/controller/App.controller.ts index 46582538c..7e51a39cd 100644 --- a/packages/walkthrough/steps/07/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/07/webapp/controller/App.controller.ts @@ -3,7 +3,7 @@ import Controller from "sap/ui/core/mvc/Controller"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/07/webapp/index-cdn.html b/packages/walkthrough/steps/07/webapp/index-cdn.html index b4cdba0d7..801914ab6 100644 --- a/packages/walkthrough/steps/07/webapp/index-cdn.html +++ b/packages/walkthrough/steps/07/webapp/index-cdn.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/07/webapp/index.html b/packages/walkthrough/steps/07/webapp/index.html index 8a71c5c8b..d4895803c 100644 --- a/packages/walkthrough/steps/07/webapp/index.html +++ b/packages/walkthrough/steps/07/webapp/index.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/07/webapp/index.ts b/packages/walkthrough/steps/07/webapp/index.ts index 1d9ef897d..d0fa02cc8 100644 --- a/packages/walkthrough/steps/07/webapp/index.ts +++ b/packages/walkthrough/steps/07/webapp/index.ts @@ -1,7 +1,7 @@ import XMLView from "sap/ui/core/mvc/XMLView"; XMLView.create({ - viewName: "ui5.walkthrough.view.App", + viewName: "ui5.tutorial.walkthrough.view.App", id: "app" }).then(function (view) { view.placeAt("content"); diff --git a/packages/walkthrough/steps/07/webapp/manifest.json b/packages/walkthrough/steps/07/webapp/manifest.json index 90f0f71b7..287380556 100644 --- a/packages/walkthrough/steps/07/webapp/manifest.json +++ b/packages/walkthrough/steps/07/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "title": "OpenUI5 TypeScript Walkthrough", "applicationVersion": { diff --git a/packages/walkthrough/steps/07/webapp/view/App.view.xml b/packages/walkthrough/steps/07/webapp/view/App.view.xml index cdf8a6158..fb84e6d14 100644 --- a/packages/walkthrough/steps/07/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/07/webapp/view/App.view.xml @@ -1,4 +1,4 @@ -<mvc:View controllerName="ui5.walkthrough.controller.App" +<mvc:View controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Button diff --git a/packages/walkthrough/steps/08/README.md b/packages/walkthrough/steps/08/README.md index dee76b8dc..43d05a20d 100644 --- a/packages/walkthrough/steps/08/README.md +++ b/packages/walkthrough/steps/08/README.md @@ -64,7 +64,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import ResourceBundle from "sap/base/i18n/ResourceBundle"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onInit(): void { @@ -79,7 +79,7 @@ export default class AppController extends Controller { // set i18n model on view const i18nModel = new ResourceModel({ - bundleName: "ui5.walkthrough.i18n.i18n" + bundleName: "ui5.tutorial.walkthrough.i18n.i18n" }); this.getView()?.setModel(i18nModel, "i18n"); } @@ -100,7 +100,7 @@ export default class AppController extends Controller { sap.ui.define(["sap/m/MessageToast", "sap/ui/core/mvc/Controller", "sap/ui/model/json/JSONModel", "sap/ui/model/resource/ResourceModel"], function (MessageToast, Controller, JSONModel, ResourceModel) { "use strict"; - const AppController = Controller.extend("ui5.walkthrough.controller.App", { + const AppController = Controller.extend("ui5.tutorial.walkthrough.controller.App", { onInit() { // set data model on view const data = { @@ -113,7 +113,7 @@ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/mvc/Controller", "sap/ui/model // set i18n model on view const i18nModel = new ResourceModel({ - bundleName: "ui5.walkthrough.i18n.i18n" + bundleName: "ui5.tutorial.walkthrough.i18n.i18n" }); this.getView()?.setModel(i18nModel, "i18n"); }, @@ -132,7 +132,7 @@ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/mvc/Controller", "sap/ui/model ``` -The bundle name \(`ui5.walkthrough.i18n.i18n`\) consists of the application namespace `ui5.walkthrough` \(the application root as defined in the `index.html`\), the folder name `i18n`, and finally the base file name `i18n` without extension. The OpenUI5 runtime calculates the correct path to the resource, to which `.properties` is then appended. +The bundle name \(`ui5.tutorial.walkthrough.i18n.i18n`\) consists of the application namespace `ui5.tutorial.walkthrough` \(the application root as defined in the `index.html`\), the folder name `i18n`, and finally the base file name `i18n` without extension. The OpenUI5 runtime calculates the correct path to the resource, to which `.properties` is then appended. During runtime, OpenUI5 tries to load the correct`i18n_*.properties` file based on your browser settings and your locale. In our case we have only created the base `i18n.properties` file to make it simple. However, you can see in the network traffic of your browser’s developer tools that OpenUI5 tries to load one or more `i18n_*.properties` files before falling back to the default `i18n.properties` file. @@ -147,7 +147,7 @@ To correctly reference the model, the binding path should start with the model n A resource bundle is a flat structure, therefore the preceding slash \(/\) can be omitted for the path to the text. ```xml -<mvc:View controllerName="ui5.walkthrough.controller.App" +<mvc:View controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Button @@ -161,7 +161,7 @@ A resource bundle is a flat structure, therefore the preceding slash \(/\) can b </mvc:View> ``` -> 📝 **Note:** <br> +> :note: > The description text is not completely localized in this example for illustration purposes. To be on the safe side, we would have to use a similar mechanism as in the controller to use a string from the resource bundle and replace parts of it. This can be done with the `sap/base/strings/formatMessage` formatter. > > Furthermore, `i18n` files only impact client-side application texts. Texts that are loaded from back-end systems can appear in all languages that are supported by the back-end system. diff --git a/packages/walkthrough/steps/08/package.json b/packages/walkthrough/steps/08/package.json index 3bea3bdf4..79c72df0b 100644 --- a/packages/walkthrough/steps/08/package.json +++ b/packages/walkthrough/steps/08/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step08", + "name": "ui5.tutorial.walkthrough.step08", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 8: Translatable Texts", diff --git a/packages/walkthrough/steps/08/tsconfig.json b/packages/walkthrough/steps/08/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/08/tsconfig.json +++ b/packages/walkthrough/steps/08/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/08/ui5.yaml b/packages/walkthrough/steps/08/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/08/ui5.yaml +++ b/packages/walkthrough/steps/08/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/08/webapp/controller/App.controller.ts b/packages/walkthrough/steps/08/webapp/controller/App.controller.ts index 1b72b85c3..a62c9e89e 100644 --- a/packages/walkthrough/steps/08/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/08/webapp/controller/App.controller.ts @@ -5,7 +5,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import ResourceBundle from "sap/base/i18n/ResourceBundle"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onInit(): void { @@ -21,7 +21,7 @@ export default class AppController extends Controller { // set i18n model on view const i18nModel = new ResourceModel({ - bundleName: "ui5.walkthrough.i18n.i18n" + bundleName: "ui5.tutorial.walkthrough.i18n.i18n" }); this.getView()?.setModel(i18nModel, "i18n"); } diff --git a/packages/walkthrough/steps/08/webapp/index-cdn.html b/packages/walkthrough/steps/08/webapp/index-cdn.html index b4cdba0d7..801914ab6 100644 --- a/packages/walkthrough/steps/08/webapp/index-cdn.html +++ b/packages/walkthrough/steps/08/webapp/index-cdn.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/08/webapp/index.html b/packages/walkthrough/steps/08/webapp/index.html index 8a71c5c8b..d4895803c 100644 --- a/packages/walkthrough/steps/08/webapp/index.html +++ b/packages/walkthrough/steps/08/webapp/index.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/08/webapp/index.ts b/packages/walkthrough/steps/08/webapp/index.ts index 1d9ef897d..d0fa02cc8 100644 --- a/packages/walkthrough/steps/08/webapp/index.ts +++ b/packages/walkthrough/steps/08/webapp/index.ts @@ -1,7 +1,7 @@ import XMLView from "sap/ui/core/mvc/XMLView"; XMLView.create({ - viewName: "ui5.walkthrough.view.App", + viewName: "ui5.tutorial.walkthrough.view.App", id: "app" }).then(function (view) { view.placeAt("content"); diff --git a/packages/walkthrough/steps/08/webapp/manifest.json b/packages/walkthrough/steps/08/webapp/manifest.json index 90f0f71b7..287380556 100644 --- a/packages/walkthrough/steps/08/webapp/manifest.json +++ b/packages/walkthrough/steps/08/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "title": "OpenUI5 TypeScript Walkthrough", "applicationVersion": { diff --git a/packages/walkthrough/steps/08/webapp/view/App.view.xml b/packages/walkthrough/steps/08/webapp/view/App.view.xml index 68931368f..3822a4b5b 100644 --- a/packages/walkthrough/steps/08/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/08/webapp/view/App.view.xml @@ -1,4 +1,4 @@ -<mvc:View controllerName="ui5.walkthrough.controller.App" +<mvc:View controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Button diff --git a/packages/walkthrough/steps/09/README.md b/packages/walkthrough/steps/09/README.md index b2493a7b5..0d6932f34 100644 --- a/packages/walkthrough/steps/09/README.md +++ b/packages/walkthrough/steps/09/README.md @@ -59,7 +59,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { @@ -79,7 +79,7 @@ export default class Component extends UIComponent { // set i18n model const i18nModel = new ResourceModel({ - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [""], "fallbackLocale": "" }); @@ -87,7 +87,7 @@ export default class Component extends UIComponent { }; createContent(): Control | Promise<Control | null> | null { return XMLView.create({ - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "id": "app" }); }; @@ -99,7 +99,7 @@ export default class Component extends UIComponent { sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/core/mvc/XMLView", "sap/ui/model/json/JSONModel", "sap/ui/model/resource/ResourceModel"], function (UIComponent, XMLView, JSONModel, ResourceModel) { "use strict"; - const Component = UIComponent.extend("ui5.walkthrough.Component", { + const Component = UIComponent.extend("ui5.tutorial.walkthrough.Component", { metadata: { "interfaces": ["sap.ui.core.IAsyncContentCreation"] }, @@ -117,7 +117,7 @@ sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/core/mvc/XMLView", "sap/ui/mod // set i18n model const i18nModel = new ResourceModel({ - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [""], "fallbackLocale": "" }); @@ -125,7 +125,7 @@ sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/core/mvc/XMLView", "sap/ui/mod }, createContent() { return XMLView.create({ - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "id": "app" }); } @@ -151,7 +151,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import ResourceBundle from "sap/base/i18n/ResourceBundle"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onShowHello(): void { @@ -171,9 +171,9 @@ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/mvc/Controller"], function (Me "use strict"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ - const AppController = Controller.extend("ui5.walkthrough.controller.App", { + const AppController = Controller.extend("ui5.tutorial.walkthrough.controller.App", { onShowHello() { // read msg from i18n model // functions with generic return values require casting @@ -212,7 +212,7 @@ import ComponentContainer from "sap/ui/core/ComponentContainer"; new ComponentContainer({ id: "container", - name: "ui5.walkthrough", + name: "ui5.tutorial.walkthrough", settings: { id: "walkthrough" }, @@ -228,7 +228,7 @@ sap.ui.define(["sap/ui/core/ComponentContainer"], function (ComponentContainer) new ComponentContainer({ id: "container", - name: "ui5.walkthrough", + name: "ui5.tutorial.walkthrough", settings: { id: "walkthrough" }, diff --git a/packages/walkthrough/steps/09/package.json b/packages/walkthrough/steps/09/package.json index 0a03897fe..2d25406ce 100644 --- a/packages/walkthrough/steps/09/package.json +++ b/packages/walkthrough/steps/09/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step09", + "name": "ui5.tutorial.walkthrough.step09", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 9 - Component Configuration", diff --git a/packages/walkthrough/steps/09/tsconfig.json b/packages/walkthrough/steps/09/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/09/tsconfig.json +++ b/packages/walkthrough/steps/09/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/09/ui5.yaml b/packages/walkthrough/steps/09/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/09/ui5.yaml +++ b/packages/walkthrough/steps/09/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/09/webapp/Component.ts b/packages/walkthrough/steps/09/webapp/Component.ts index ae01986cc..fcbc94d3e 100644 --- a/packages/walkthrough/steps/09/webapp/Component.ts +++ b/packages/walkthrough/steps/09/webapp/Component.ts @@ -5,7 +5,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import ResourceModel from "sap/ui/model/resource/ResourceModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { @@ -25,7 +25,7 @@ export default class Component extends UIComponent { // set i18n model const i18nModel = new ResourceModel({ - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [""], "fallbackLocale": "" }); @@ -33,7 +33,7 @@ export default class Component extends UIComponent { }; createContent(): Control | Promise<Control | null> | null { return XMLView.create({ - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "id": "app" }); }; diff --git a/packages/walkthrough/steps/09/webapp/controller/App.controller.ts b/packages/walkthrough/steps/09/webapp/controller/App.controller.ts index 29058d442..a2aea7ec4 100644 --- a/packages/walkthrough/steps/09/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/09/webapp/controller/App.controller.ts @@ -5,7 +5,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import ResourceBundle from "sap/base/i18n/ResourceBundle"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onShowHello() : void { diff --git a/packages/walkthrough/steps/09/webapp/index-cdn.html b/packages/walkthrough/steps/09/webapp/index-cdn.html index b4cdba0d7..801914ab6 100644 --- a/packages/walkthrough/steps/09/webapp/index-cdn.html +++ b/packages/walkthrough/steps/09/webapp/index-cdn.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/09/webapp/index.html b/packages/walkthrough/steps/09/webapp/index.html index 8a71c5c8b..d4895803c 100644 --- a/packages/walkthrough/steps/09/webapp/index.html +++ b/packages/walkthrough/steps/09/webapp/index.html @@ -9,9 +9,9 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/index" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/index" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> diff --git a/packages/walkthrough/steps/09/webapp/index.ts b/packages/walkthrough/steps/09/webapp/index.ts index 004d014ca..b123c7bb0 100644 --- a/packages/walkthrough/steps/09/webapp/index.ts +++ b/packages/walkthrough/steps/09/webapp/index.ts @@ -2,7 +2,7 @@ import ComponentContainer from "sap/ui/core/ComponentContainer"; new ComponentContainer({ id: "container", - name: "ui5.walkthrough", + name: "ui5.tutorial.walkthrough", settings: { id: "walkthrough" }, diff --git a/packages/walkthrough/steps/09/webapp/manifest.json b/packages/walkthrough/steps/09/webapp/manifest.json index 90f0f71b7..287380556 100644 --- a/packages/walkthrough/steps/09/webapp/manifest.json +++ b/packages/walkthrough/steps/09/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "title": "OpenUI5 TypeScript Walkthrough", "applicationVersion": { diff --git a/packages/walkthrough/steps/09/webapp/view/App.view.xml b/packages/walkthrough/steps/09/webapp/view/App.view.xml index 68931368f..3822a4b5b 100644 --- a/packages/walkthrough/steps/09/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/09/webapp/view/App.view.xml @@ -1,4 +1,4 @@ -<mvc:View controllerName="ui5.walkthrough.controller.App" +<mvc:View controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Button diff --git a/packages/walkthrough/steps/10/README.md b/packages/walkthrough/steps/10/README.md index 75bd401db..ab9510b91 100644 --- a/packages/walkthrough/steps/10/README.md +++ b/packages/walkthrough/steps/10/README.md @@ -77,7 +77,7 @@ The **`sap.ui`** namespace is used for UI-specific attributes and comes with the - `deviceTypes` \(mandatory\): This property defines the supported device types for the application. It is an object that contains three boolean properties: `desktop`, `tablet`, and `phone`. Each property indicates whether the application is designed to be used on that particular device type. We define all three device types as "true", which means that our application is intended to be used on desktops, tablets, and phones. -> 📝 **Note:** <br> +> :note: > By configuring the `deviceTypes` property, developers can ensure that the application's user interface is optimized for different device types, providing a consistent and responsive experience across various devices. The **`sap.ui5`** namespace adds OpenUI5-specific configuration parameters that are automatically processed by OpenUI5. The following parameters are important: @@ -90,7 +90,7 @@ The **`sap.ui5`** namespace adds OpenUI5-specific configuration parameters that In our component we currenetly only use the `sap.ui.core` and `sap.m` liibraries. The `sap.ui.core` library provides the basic framework functionality and is required for any OpenUI5 application.<br> By default, loading of libraries is set to `"lazy": false`, which means they are loaded immediately when the component initializes. For libraries that are essential for your app to function from the start, like `sap.ui.core` and in our case also `sap.m` (since it is used in the root view), we can keep the default setting of `"lazy": false`. - > 📌 **Important:** <br> + > :info: > It is crucial to be mindful of the lazy loading configuration for libraries. Only libraries that are absolutely necessary for your component to start should be declared with `"lazy": false`. For libraries that are not required immediately, it is recommended to override the default setting and set `"lazy": true`. This approach allows for better performance and faster initial loading of the component by deferring the loading of non-essential libraries until they are actually needed. > For more information on loading libraries, refer to the [sap.ui.core.Lib.load](https://sdk.openui5.org/api/sap.ui.core.Lib#methods/sap.ui.core.Lib.load) API reference. > If your component requires a minimum version of the library, you need to specify the `minVersion` for information purposes. @@ -104,10 +104,10 @@ In our current scenario, we only have one model called `i18n`, which is a resour { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -136,7 +136,7 @@ In our current scenario, we only have one model called `i18n`, which is a resour } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -144,7 +144,7 @@ In our current scenario, we only have one model called `i18n`, which is a resour "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -156,7 +156,7 @@ In our current scenario, we only have one model called `i18n`, which is a resour } ``` -> 📝 **Note:** <br> +> :note: > In this tutorial, we only introduce the most important settings and parameters of the manifest. In some development environments you may get validation errors because some settings are missing - you can ignore those in this context. *** @@ -172,7 +172,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { @@ -200,7 +200,7 @@ export default class Component extends UIComponent { sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/model/json/JSONModel"], function (UIComponent, JSONModel) { "use strict"; - const Component = UIComponent.extend("ui5.walkthrough.Component", { + const Component = UIComponent.extend("ui5.tutorial.walkthrough.Component", { metadata: { "interfaces": ["sap.ui.core.IAsyncContentCreation"], "manifest": "json" @@ -231,7 +231,7 @@ sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/model/json/JSONModel"], functi Let's explore how we can create a component in a simple and straightforward way directly in the HTML markup of our `index.html` file. To do this, we need to make a few changes in our HTML document. -First, we need to remove the reference to the `ui5/walkthrough/index` module from the `data-sap-ui-on-init` attribute. Instead, we set it to the `sap/ui/core/ComponentSupport` module. Next, we add a `div` tag to the body of our HTML file. Inside this `div` tag, we add a special data attribute called `data-sap-ui-component`. This attribute is important because the `sap/ui/core/ComponentSupport` module scans the HTML elements with this attribute. Any element marked with this attribute will be considered a container element into which a `sap/ui/core/ComponentContainer` is inserted. We can also use additional data attributes to define the constructor arguments for the `ComponentContainer` instance. We transfer the arguments used to configure the `CompontentContainer `instance in the `index.ts` file to data attributes on our `div` tag. +First, we need to remove the reference to the `ui5/tutorial/walkthrough/index` module from the `data-sap-ui-on-init` attribute. Instead, we set it to the `sap/ui/core/ComponentSupport` module. Next, we add a `div` tag to the body of our HTML file. Inside this `div` tag, we add a special data attribute called `data-sap-ui-component`. This attribute is important because the `sap/ui/core/ComponentSupport` module scans the HTML elements with this attribute. Any element marked with this attribute will be considered a container element into which a `sap/ui/core/ComponentContainer` is inserted. We can also use additional data attributes to define the constructor arguments for the `ComponentContainer` instance. We transfer the arguments used to configure the `CompontentContainer `instance in the `index.ts` file to data attributes on our `div` tag. It's worth noting that the `ComponentSupport` module enforces asynchronous loading of the respective component, so we don't need to set the `async` attribute to "true" in this case. It also sets the `autoPrefixId` property to "true" by default, so we don't need to set this attribute here either. @@ -249,12 +249,12 @@ It's worth noting that the `ComponentSupport` module enforces asynchronous loadi data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> ``` diff --git a/packages/walkthrough/steps/10/package.json b/packages/walkthrough/steps/10/package.json index 4b043511e..83635145c 100644 --- a/packages/walkthrough/steps/10/package.json +++ b/packages/walkthrough/steps/10/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step10", + "name": "ui5.tutorial.walkthrough.step10", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 10 - Descriptor for Applications", diff --git a/packages/walkthrough/steps/10/tsconfig.json b/packages/walkthrough/steps/10/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/10/tsconfig.json +++ b/packages/walkthrough/steps/10/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/10/ui5.yaml b/packages/walkthrough/steps/10/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/10/ui5.yaml +++ b/packages/walkthrough/steps/10/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/10/webapp/Component.ts b/packages/walkthrough/steps/10/webapp/Component.ts index 1826f88c8..b840ec7ba 100644 --- a/packages/walkthrough/steps/10/webapp/Component.ts +++ b/packages/walkthrough/steps/10/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/10/webapp/controller/App.controller.ts b/packages/walkthrough/steps/10/webapp/controller/App.controller.ts index 6b3072be1..83a566bdf 100644 --- a/packages/walkthrough/steps/10/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/10/webapp/controller/App.controller.ts @@ -5,7 +5,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import ResourceBundle from "sap/base/i18n/ResourceBundle"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onShowHello() : void { diff --git a/packages/walkthrough/steps/10/webapp/index-cdn.html b/packages/walkthrough/steps/10/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/10/webapp/index-cdn.html +++ b/packages/walkthrough/steps/10/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/10/webapp/index.html b/packages/walkthrough/steps/10/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/10/webapp/index.html +++ b/packages/walkthrough/steps/10/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/10/webapp/manifest.json b/packages/walkthrough/steps/10/webapp/manifest.json index 678c256d7..6e7aeac1c 100644 --- a/packages/walkthrough/steps/10/webapp/manifest.json +++ b/packages/walkthrough/steps/10/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/10/webapp/view/App.view.xml b/packages/walkthrough/steps/10/webapp/view/App.view.xml index 68931368f..3822a4b5b 100644 --- a/packages/walkthrough/steps/10/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/10/webapp/view/App.view.xml @@ -1,4 +1,4 @@ -<mvc:View controllerName="ui5.walkthrough.controller.App" +<mvc:View controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Button diff --git a/packages/walkthrough/steps/11/README.md b/packages/walkthrough/steps/11/README.md index e91465be2..a500ae83c 100644 --- a/packages/walkthrough/steps/11/README.md +++ b/packages/walkthrough/steps/11/README.md @@ -57,7 +57,7 @@ In order to make the fullscreen height of the view work properly, we add the `di ```xml <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -90,7 +90,7 @@ The `App` control does the following important things for us: - It writes a bunch of properties into the header of the `index.html` that are necessary for proper display on mobile devices. - It offers functionality to navigate between pages with animations. We will use this soon. -> 📝 **Note:** <br> +> :note: > The `sap/m/Page` control used here is one of the most popular view-level containers in OpenUI5. However, OpenUI5 applications are used in different environments: they can be embedded within shells that come with their own header (like e.g. SAP Build Work Zone or the SAP Fiori launchpad). Or they are displayed stand-alone without such a shell around them. This has implications on how the header area of a OpenUI5 application should look: > - A stand-alone OpenUI5 application could use a `sap/m/Page` control as root control of its views. This Page control provides a visually distinguished header bar with a title and has a built-in "back" button using which the user can navigate back to the previous page. (This back button can be enabled by setting the Page’s `showNavButton` property to `true`.) > - When, on the other hand, a containing shell already comes with a header that has a "back" button and a title, then using `sap/m/Page` controls will lead to duplicate headers (and possibly even duplicate back buttons). The `sap/f/DynamicPage` control would be a preferred alternative in such a scenario, as it comes without a header bar and back button, but still offers the option to configure a title if needed – and many other features on top of a plain `sap/m/Page`. Further alternatives are `sap/f/semantic/SemanticPage` and `sap/uxap/ObjectPageLayout`, depending on the use-case. Note that they are part of other control libraries than sap.m, so you might need to add the respective library to your application setup. For some scenarios, the `sap/tnt/ToolPage` may be another alternative. But also the `sap/m/Page` can be configured to have its header hidden. diff --git a/packages/walkthrough/steps/11/package.json b/packages/walkthrough/steps/11/package.json index ee5d9e5cc..e89fa97c8 100644 --- a/packages/walkthrough/steps/11/package.json +++ b/packages/walkthrough/steps/11/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step11", + "name": "ui5.tutorial.walkthrough.step11", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 11 - Pages and Panels", diff --git a/packages/walkthrough/steps/11/tsconfig.json b/packages/walkthrough/steps/11/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/11/tsconfig.json +++ b/packages/walkthrough/steps/11/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/11/ui5.yaml b/packages/walkthrough/steps/11/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/11/ui5.yaml +++ b/packages/walkthrough/steps/11/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/11/webapp/Component.ts b/packages/walkthrough/steps/11/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/11/webapp/Component.ts +++ b/packages/walkthrough/steps/11/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/11/webapp/controller/App.controller.ts b/packages/walkthrough/steps/11/webapp/controller/App.controller.ts index 6b3072be1..83a566bdf 100644 --- a/packages/walkthrough/steps/11/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/11/webapp/controller/App.controller.ts @@ -5,7 +5,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import ResourceBundle from "sap/base/i18n/ResourceBundle"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onShowHello() : void { diff --git a/packages/walkthrough/steps/11/webapp/index-cdn.html b/packages/walkthrough/steps/11/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/11/webapp/index-cdn.html +++ b/packages/walkthrough/steps/11/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/11/webapp/index.html b/packages/walkthrough/steps/11/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/11/webapp/index.html +++ b/packages/walkthrough/steps/11/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/11/webapp/manifest.json b/packages/walkthrough/steps/11/webapp/manifest.json index 678c256d7..6e7aeac1c 100644 --- a/packages/walkthrough/steps/11/webapp/manifest.json +++ b/packages/walkthrough/steps/11/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/11/webapp/view/App.view.xml b/packages/walkthrough/steps/11/webapp/view/App.view.xml index aa9f05fd2..98742275b 100644 --- a/packages/walkthrough/steps/11/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/11/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/12/README.md b/packages/walkthrough/steps/12/README.md index aa9529644..77e065c65 100644 --- a/packages/walkthrough/steps/12/README.md +++ b/packages/walkthrough/steps/12/README.md @@ -37,7 +37,7 @@ In your App view, we put the `App` control inside a `sap/m/Shell` control. ```xml <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/12/package.json b/packages/walkthrough/steps/12/package.json index 8c7fa274f..67fb251ef 100644 --- a/packages/walkthrough/steps/12/package.json +++ b/packages/walkthrough/steps/12/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step12", + "name": "ui5.tutorial.walkthrough.step12", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 12 - Shell Control as Container", diff --git a/packages/walkthrough/steps/12/tsconfig.json b/packages/walkthrough/steps/12/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/12/tsconfig.json +++ b/packages/walkthrough/steps/12/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/12/ui5.yaml b/packages/walkthrough/steps/12/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/12/ui5.yaml +++ b/packages/walkthrough/steps/12/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/12/webapp/Component.ts b/packages/walkthrough/steps/12/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/12/webapp/Component.ts +++ b/packages/walkthrough/steps/12/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/12/webapp/controller/App.controller.ts b/packages/walkthrough/steps/12/webapp/controller/App.controller.ts index 6b3072be1..83a566bdf 100644 --- a/packages/walkthrough/steps/12/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/12/webapp/controller/App.controller.ts @@ -5,7 +5,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import ResourceBundle from "sap/base/i18n/ResourceBundle"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onShowHello() : void { diff --git a/packages/walkthrough/steps/12/webapp/index-cdn.html b/packages/walkthrough/steps/12/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/12/webapp/index-cdn.html +++ b/packages/walkthrough/steps/12/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/12/webapp/index.html b/packages/walkthrough/steps/12/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/12/webapp/index.html +++ b/packages/walkthrough/steps/12/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/12/webapp/manifest.json b/packages/walkthrough/steps/12/webapp/manifest.json index 678c256d7..6e7aeac1c 100644 --- a/packages/walkthrough/steps/12/webapp/manifest.json +++ b/packages/walkthrough/steps/12/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/12/webapp/view/App.view.xml b/packages/walkthrough/steps/12/webapp/view/App.view.xml index c46a21fe7..c86c7d739 100644 --- a/packages/walkthrough/steps/12/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/12/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/13/README.md b/packages/walkthrough/steps/13/README.md index 43cc38db3..1b47cb688 100644 --- a/packages/walkthrough/steps/13/README.md +++ b/packages/walkthrough/steps/13/README.md @@ -45,7 +45,7 @@ To format the output text individually, we remove the description from the input ```xml <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/13/package.json b/packages/walkthrough/steps/13/package.json index 2c47154ba..ca0e58219 100644 --- a/packages/walkthrough/steps/13/package.json +++ b/packages/walkthrough/steps/13/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step13", + "name": "ui5.tutorial.walkthrough.step13", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 13 - Margins and Paddings", diff --git a/packages/walkthrough/steps/13/tsconfig.json b/packages/walkthrough/steps/13/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/13/tsconfig.json +++ b/packages/walkthrough/steps/13/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/13/ui5.yaml b/packages/walkthrough/steps/13/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/13/ui5.yaml +++ b/packages/walkthrough/steps/13/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/13/webapp/Component.ts b/packages/walkthrough/steps/13/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/13/webapp/Component.ts +++ b/packages/walkthrough/steps/13/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/13/webapp/controller/App.controller.ts b/packages/walkthrough/steps/13/webapp/controller/App.controller.ts index 6b3072be1..83a566bdf 100644 --- a/packages/walkthrough/steps/13/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/13/webapp/controller/App.controller.ts @@ -5,7 +5,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import ResourceBundle from "sap/base/i18n/ResourceBundle"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onShowHello() : void { diff --git a/packages/walkthrough/steps/13/webapp/index-cdn.html b/packages/walkthrough/steps/13/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/13/webapp/index-cdn.html +++ b/packages/walkthrough/steps/13/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/13/webapp/index.html b/packages/walkthrough/steps/13/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/13/webapp/index.html +++ b/packages/walkthrough/steps/13/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/13/webapp/manifest.json b/packages/walkthrough/steps/13/webapp/manifest.json index 678c256d7..6e7aeac1c 100644 --- a/packages/walkthrough/steps/13/webapp/manifest.json +++ b/packages/walkthrough/steps/13/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/13/webapp/view/App.view.xml b/packages/walkthrough/steps/13/webapp/view/App.view.xml index 37c4e675e..1b39d220d 100644 --- a/packages/walkthrough/steps/13/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/13/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/14/README.md b/packages/walkthrough/steps/14/README.md index 5ede85b0c..3f806716f 100644 --- a/packages/walkthrough/steps/14/README.md +++ b/packages/walkthrough/steps/14/README.md @@ -93,7 +93,7 @@ To highlight the output text, we replace the text control by a `FormattedText` c ```xml <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/14/package.json b/packages/walkthrough/steps/14/package.json index 7214205d0..db61d9feb 100644 --- a/packages/walkthrough/steps/14/package.json +++ b/packages/walkthrough/steps/14/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step14", + "name": "ui5.tutorial.walkthrough.step14", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 14 - Custom CSS and Theme Colors", diff --git a/packages/walkthrough/steps/14/tsconfig.json b/packages/walkthrough/steps/14/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/14/tsconfig.json +++ b/packages/walkthrough/steps/14/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/14/ui5.yaml b/packages/walkthrough/steps/14/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/14/ui5.yaml +++ b/packages/walkthrough/steps/14/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/14/webapp/Component.ts b/packages/walkthrough/steps/14/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/14/webapp/Component.ts +++ b/packages/walkthrough/steps/14/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/14/webapp/controller/App.controller.ts b/packages/walkthrough/steps/14/webapp/controller/App.controller.ts index 6b3072be1..83a566bdf 100644 --- a/packages/walkthrough/steps/14/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/14/webapp/controller/App.controller.ts @@ -5,7 +5,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import ResourceBundle from "sap/base/i18n/ResourceBundle"; /** - * @name ui5.walkthrough.controller.App + * @name ui5.tutorial.walkthrough.controller.App */ export default class AppController extends Controller { onShowHello() : void { diff --git a/packages/walkthrough/steps/14/webapp/index-cdn.html b/packages/walkthrough/steps/14/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/14/webapp/index-cdn.html +++ b/packages/walkthrough/steps/14/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/14/webapp/index.html b/packages/walkthrough/steps/14/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/14/webapp/index.html +++ b/packages/walkthrough/steps/14/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/14/webapp/manifest.json b/packages/walkthrough/steps/14/webapp/manifest.json index 1fd1b03f5..646b0b666 100644 --- a/packages/walkthrough/steps/14/webapp/manifest.json +++ b/packages/walkthrough/steps/14/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/14/webapp/view/App.view.xml b/packages/walkthrough/steps/14/webapp/view/App.view.xml index 7123cbd76..1cb890d9c 100644 --- a/packages/walkthrough/steps/14/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/14/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/15/README.md b/packages/walkthrough/steps/15/README.md index 278d6c059..04e7e94a5 100644 --- a/packages/walkthrough/steps/15/README.md +++ b/packages/walkthrough/steps/15/README.md @@ -44,7 +44,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import ResourceBundle from "sap/base/i18n/ResourceBundle"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { @@ -65,7 +65,7 @@ export default class HelloPanel extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller", "sap/m/MessageToast"], function (Controller, MessageToast) { "use strict"; - const HelloPanel = Controller.extend("ui5.walkthrough.controller.HelloPanel", { + const HelloPanel = Controller.extend("ui5.tutorial.walkthrough.controller.HelloPanel", { onShowHello() { // read msg from i18n model const recipient = this.getView()?.getModel()?.getProperty("/recipient/name"); @@ -87,7 +87,7 @@ We create a new `HelloPanel.view.xml` file in folder `webapp/view` and move the ```xml <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel @@ -113,11 +113,11 @@ We create a new `HelloPanel.view.xml` file in folder `webapp/view` and move the ### webapp/view/App.view.xml -In the App view, we remove the panel control and its content and put the `XMLView` control to the content of the page instead. We add the `viewName` attribute with the value `ui5.walkthrough.view.HelloPanel` to reference the new view that now contains the panel. +In the App view, we remove the panel control and its content and put the `XMLView` control to the content of the page instead. We add the `viewName` attribute with the value `ui5.tutorial.walkthrough.view.HelloPanel` to reference the new view that now contains the panel. ```xml <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -126,7 +126,7 @@ In the App view, we remove the panel control and its content and put the `XMLVie <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> </content> </Page> </pages> @@ -142,7 +142,7 @@ We remove the `onShowHello` method from the App controller, as this is not neede ```ts import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { @@ -154,7 +154,7 @@ export default class App extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller"], function (Controller) { "use strict"; - const App = Controller.extend("ui5.walkthrough.controller.App", {}); + const App = Controller.extend("ui5.tutorial.walkthrough.controller.App", {}); ; return App; }); diff --git a/packages/walkthrough/steps/15/package.json b/packages/walkthrough/steps/15/package.json index 882a766b4..c68cff6a8 100644 --- a/packages/walkthrough/steps/15/package.json +++ b/packages/walkthrough/steps/15/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step15", + "name": "ui5.tutorial.walkthrough.step15", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 15 - Nested Views", diff --git a/packages/walkthrough/steps/15/tsconfig.json b/packages/walkthrough/steps/15/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/15/tsconfig.json +++ b/packages/walkthrough/steps/15/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/15/ui5.yaml b/packages/walkthrough/steps/15/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/15/ui5.yaml +++ b/packages/walkthrough/steps/15/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/15/webapp/Component.ts b/packages/walkthrough/steps/15/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/15/webapp/Component.ts +++ b/packages/walkthrough/steps/15/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/15/webapp/controller/App.controller.ts b/packages/walkthrough/steps/15/webapp/controller/App.controller.ts index 58a03ef8f..a79c1a2eb 100644 --- a/packages/walkthrough/steps/15/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/15/webapp/controller/App.controller.ts @@ -1,6 +1,6 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/15/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/15/webapp/controller/HelloPanel.controller.ts index 9e6a761f5..333e571e4 100644 --- a/packages/walkthrough/steps/15/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/15/webapp/controller/HelloPanel.controller.ts @@ -5,7 +5,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import ResourceBundle from "sap/base/i18n/ResourceBundle"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { diff --git a/packages/walkthrough/steps/15/webapp/index-cdn.html b/packages/walkthrough/steps/15/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/15/webapp/index-cdn.html +++ b/packages/walkthrough/steps/15/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/15/webapp/index.html b/packages/walkthrough/steps/15/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/15/webapp/index.html +++ b/packages/walkthrough/steps/15/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/15/webapp/manifest.json b/packages/walkthrough/steps/15/webapp/manifest.json index 1fd1b03f5..646b0b666 100644 --- a/packages/walkthrough/steps/15/webapp/manifest.json +++ b/packages/walkthrough/steps/15/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/15/webapp/view/App.view.xml b/packages/walkthrough/steps/15/webapp/view/App.view.xml index 5c73ab7be..c2c368c56 100644 --- a/packages/walkthrough/steps/15/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/15/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,7 +8,7 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/15/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/15/webapp/view/HelloPanel.view.xml index c8a76e8f6..4a81c7fae 100644 --- a/packages/walkthrough/steps/15/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/15/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/16/README.md b/packages/walkthrough/steps/16/README.md index da18b7175..8b5241326 100644 --- a/packages/walkthrough/steps/16/README.md +++ b/packages/walkthrough/steps/16/README.md @@ -71,7 +71,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog : Dialog; @@ -81,7 +81,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } @@ -92,13 +92,13 @@ export default class HelloPanel extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller", "sap/m/MessageToast"], function (Controller, MessageToast) { "use strict"; - const HelloPanel = Controller.extend("ui5.walkthrough.controller.HelloPanel", { + const HelloPanel = Controller.extend("ui5.tutorial.walkthrough.controller.HelloPanel", { onShowHello() { ... }, async onOpenDialog() { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }); this.dialog.open(); } @@ -109,8 +109,8 @@ sap.ui.define(["sap/ui/core/mvc/Controller", "sap/m/MessageToast"], function (Co ```   -> 💡 **Tip:** <br> -> To reuse the dialog opening and closing functionality in other controllers, you might create a new file `ui5.walkthrough.controller.controller.BaseController`, which extends `sap.ui.core.mvc.Controller`, and put all your dialog-related coding into this controller. Now, all the other controllers can extend from `ui5.walkthrough.controller.BaseController` instead of `sap.ui.core.mvc.Controller`. +> :tip: +> To reuse the dialog opening and closing functionality in other controllers, you might create a new file `ui5.tutorial.walkthrough.controller.controller.BaseController`, which extends `sap.ui.core.mvc.Controller`, and put all your dialog-related coding into this controller. Now, all the other controllers can extend from `ui5.tutorial.walkthrough.controller.BaseController` instead of `sap.ui.core.mvc.Controller`. ### webapp/i18n/i18n.properties @@ -133,7 +133,7 @@ We add a new button to the view to open the dialog and assign an unique `id`to i ```xml <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/16/package.json b/packages/walkthrough/steps/16/package.json index 32097b73c..511ef9b53 100644 --- a/packages/walkthrough/steps/16/package.json +++ b/packages/walkthrough/steps/16/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step16", + "name": "ui5.tutorial.walkthrough.step16", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 16 - Dialogs and Fragments", diff --git a/packages/walkthrough/steps/16/tsconfig.json b/packages/walkthrough/steps/16/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/16/tsconfig.json +++ b/packages/walkthrough/steps/16/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/16/ui5.yaml b/packages/walkthrough/steps/16/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/16/ui5.yaml +++ b/packages/walkthrough/steps/16/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/16/webapp/Component.ts b/packages/walkthrough/steps/16/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/16/webapp/Component.ts +++ b/packages/walkthrough/steps/16/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/16/webapp/controller/App.controller.ts b/packages/walkthrough/steps/16/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/16/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/16/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/16/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/16/webapp/controller/HelloPanel.controller.ts index 007293a1e..daa187704 100644 --- a/packages/walkthrough/steps/16/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/16/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog : Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/16/webapp/index-cdn.html b/packages/walkthrough/steps/16/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/16/webapp/index-cdn.html +++ b/packages/walkthrough/steps/16/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/16/webapp/index.html b/packages/walkthrough/steps/16/webapp/index.html index 1ede072c6..a6fb18645 100644 --- a/packages/walkthrough/steps/16/webapp/index.html +++ b/packages/walkthrough/steps/16/webapp/index.html @@ -12,11 +12,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/16/webapp/manifest.json b/packages/walkthrough/steps/16/webapp/manifest.json index 1fd1b03f5..646b0b666 100644 --- a/packages/walkthrough/steps/16/webapp/manifest.json +++ b/packages/walkthrough/steps/16/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/16/webapp/view/App.view.xml b/packages/walkthrough/steps/16/webapp/view/App.view.xml index 5c73ab7be..c2c368c56 100644 --- a/packages/walkthrough/steps/16/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/16/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,7 +8,7 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/16/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/16/webapp/view/HelloPanel.view.xml index 127490824..86d3d24ec 100644 --- a/packages/walkthrough/steps/16/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/16/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/17/README.md b/packages/walkthrough/steps/17/README.md index 2c5d32a28..c76b84e39 100644 --- a/packages/walkthrough/steps/17/README.md +++ b/packages/walkthrough/steps/17/README.md @@ -43,7 +43,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -57,7 +57,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } @@ -72,7 +72,7 @@ export default class HelloPanel extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller", "sap/m/MessageToast"], function (Controller, MessageToast) { "use strict"; - const HelloPanel = Controller.extend("ui5.walkthrough.controller.HelloPanel", { + const HelloPanel = Controller.extend("ui5.tutorial.walkthrough.controller.HelloPanel", { onShowHello() { // read msg from i18n model const recipient = this.getView()?.getModel()?.getProperty("/recipient/name"); @@ -83,7 +83,7 @@ sap.ui.define(["sap/ui/core/mvc/Controller", "sap/m/MessageToast"], function (Co }, async onOpenDialog() { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }); this.dialog.open(); }, diff --git a/packages/walkthrough/steps/17/package.json b/packages/walkthrough/steps/17/package.json index b5cb44bff..64d50ba67 100644 --- a/packages/walkthrough/steps/17/package.json +++ b/packages/walkthrough/steps/17/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step17", + "name": "ui5.tutorial.walkthrough.step17", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 17 - Fragment Callbacks", diff --git a/packages/walkthrough/steps/17/tsconfig.json b/packages/walkthrough/steps/17/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/17/tsconfig.json +++ b/packages/walkthrough/steps/17/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/17/ui5.yaml b/packages/walkthrough/steps/17/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/17/ui5.yaml +++ b/packages/walkthrough/steps/17/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/17/webapp/Component.ts b/packages/walkthrough/steps/17/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/17/webapp/Component.ts +++ b/packages/walkthrough/steps/17/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/17/webapp/controller/App.controller.ts b/packages/walkthrough/steps/17/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/17/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/17/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/17/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/17/webapp/controller/HelloPanel.controller.ts index 2ff9e8c94..9481ca6b6 100644 --- a/packages/walkthrough/steps/17/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/17/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/17/webapp/index-cdn.html b/packages/walkthrough/steps/17/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/17/webapp/index-cdn.html +++ b/packages/walkthrough/steps/17/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/17/webapp/index.html b/packages/walkthrough/steps/17/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/17/webapp/index.html +++ b/packages/walkthrough/steps/17/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/17/webapp/manifest.json b/packages/walkthrough/steps/17/webapp/manifest.json index 1fd1b03f5..646b0b666 100644 --- a/packages/walkthrough/steps/17/webapp/manifest.json +++ b/packages/walkthrough/steps/17/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/17/webapp/view/App.view.xml b/packages/walkthrough/steps/17/webapp/view/App.view.xml index 5c73ab7be..c2c368c56 100644 --- a/packages/walkthrough/steps/17/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/17/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,7 +8,7 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/17/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/17/webapp/view/HelloPanel.view.xml index 127490824..86d3d24ec 100644 --- a/packages/walkthrough/steps/17/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/17/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/18/README.md b/packages/walkthrough/steps/18/README.md index 6776cd2d7..2b9b7d6a8 100644 --- a/packages/walkthrough/steps/18/README.md +++ b/packages/walkthrough/steps/18/README.md @@ -36,7 +36,7 @@ We add an icon to the button that opens the dialog. The `sap-icon://` protocol i ```xml <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel @@ -66,7 +66,7 @@ We add an icon to the button that opens the dialog. The `sap-icon://` protocol i </mvc:View> ```   ->💡 **Tip:** <br> +> :tip: > You can look up other icons using the [Icon Explorer tool](https://sdk.openui5.org/test-resources/sap/m/demokit/iconExplorer/webapp/index.html). > To call any icon, use its name as listed in the *Icon Explorer* in <code>sap-icon://<i><iconname></i></code>. diff --git a/packages/walkthrough/steps/18/package.json b/packages/walkthrough/steps/18/package.json index 1aedd970f..aac6683c0 100644 --- a/packages/walkthrough/steps/18/package.json +++ b/packages/walkthrough/steps/18/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step18", + "name": "ui5.tutorial.walkthrough.step18", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 18 - Icons", diff --git a/packages/walkthrough/steps/18/tsconfig.json b/packages/walkthrough/steps/18/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/18/tsconfig.json +++ b/packages/walkthrough/steps/18/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/18/ui5.yaml b/packages/walkthrough/steps/18/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/18/ui5.yaml +++ b/packages/walkthrough/steps/18/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/18/webapp/Component.ts b/packages/walkthrough/steps/18/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/18/webapp/Component.ts +++ b/packages/walkthrough/steps/18/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/18/webapp/controller/App.controller.ts b/packages/walkthrough/steps/18/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/18/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/18/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/18/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/18/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/18/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/18/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/18/webapp/index-cdn.html b/packages/walkthrough/steps/18/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/18/webapp/index-cdn.html +++ b/packages/walkthrough/steps/18/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/18/webapp/index.html b/packages/walkthrough/steps/18/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/18/webapp/index.html +++ b/packages/walkthrough/steps/18/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/18/webapp/manifest.json b/packages/walkthrough/steps/18/webapp/manifest.json index 1fd1b03f5..646b0b666 100644 --- a/packages/walkthrough/steps/18/webapp/manifest.json +++ b/packages/walkthrough/steps/18/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/18/webapp/view/App.view.xml b/packages/walkthrough/steps/18/webapp/view/App.view.xml index 5c73ab7be..c2c368c56 100644 --- a/packages/walkthrough/steps/18/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/18/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,7 +8,7 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/18/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/18/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/18/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/18/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/19/README.md b/packages/walkthrough/steps/19/README.md index a2fc836cb..fd3f3bd18 100644 --- a/packages/walkthrough/steps/19/README.md +++ b/packages/walkthrough/steps/19/README.md @@ -96,7 +96,7 @@ We add a new named model `invoice` to the `sap.ui5` section of the descriptor. T "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -171,7 +171,7 @@ In the app view we add a second view and assign it to our newly created InvoiceL ```xml <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -180,8 +180,8 @@ In the app view we add a second view and assign it to our newly created InvoiceL <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/19/package.json b/packages/walkthrough/steps/19/package.json index 55ae99c9e..6d4864518 100644 --- a/packages/walkthrough/steps/19/package.json +++ b/packages/walkthrough/steps/19/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step19", + "name": "ui5.tutorial.walkthrough.step19", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 19 - Aggregation Binding", diff --git a/packages/walkthrough/steps/19/tsconfig.json b/packages/walkthrough/steps/19/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/19/tsconfig.json +++ b/packages/walkthrough/steps/19/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/19/ui5.yaml b/packages/walkthrough/steps/19/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/19/ui5.yaml +++ b/packages/walkthrough/steps/19/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/19/webapp/Component.ts b/packages/walkthrough/steps/19/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/19/webapp/Component.ts +++ b/packages/walkthrough/steps/19/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/19/webapp/controller/App.controller.ts b/packages/walkthrough/steps/19/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/19/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/19/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/19/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/19/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/19/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/19/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/19/webapp/index-cdn.html b/packages/walkthrough/steps/19/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/19/webapp/index-cdn.html +++ b/packages/walkthrough/steps/19/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/19/webapp/index.html b/packages/walkthrough/steps/19/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/19/webapp/index.html +++ b/packages/walkthrough/steps/19/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/19/webapp/manifest.json b/packages/walkthrough/steps/19/webapp/manifest.json index b255418b7..55e9a6881 100644 --- a/packages/walkthrough/steps/19/webapp/manifest.json +++ b/packages/walkthrough/steps/19/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/19/webapp/view/App.view.xml b/packages/walkthrough/steps/19/webapp/view/App.view.xml index 21bb07fd7..9a34e5ed0 100644 --- a/packages/walkthrough/steps/19/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/19/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,8 +8,8 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/19/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/19/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/19/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/19/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/20/README.md b/packages/walkthrough/steps/20/README.md index a6ffaa9bb..12725fd9a 100644 --- a/packages/walkthrough/steps/20/README.md +++ b/packages/walkthrough/steps/20/README.md @@ -41,7 +41,7 @@ import Controller from "sap/ui/core/mvc/Controller"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { @@ -59,7 +59,7 @@ export default class App extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller", "sap/ui/model/json/JSONModel"], function (Controller, JSONModel) { "use strict"; - const App = Controller.extend("ui5.walkthrough.controller.App", { + const App = Controller.extend("ui5.tutorial.walkthrough.controller.App", { onInit() { const viewModel = new JSONModel({ currency: "EUR" @@ -83,7 +83,7 @@ Additionally, we set the formatting option `showMeasure` to `false`. This hides ```xml <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> diff --git a/packages/walkthrough/steps/20/package.json b/packages/walkthrough/steps/20/package.json index ff73ca999..e4ebf0287 100644 --- a/packages/walkthrough/steps/20/package.json +++ b/packages/walkthrough/steps/20/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step20", + "name": "ui5.tutorial.walkthrough.step20", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 20 - Data Types", diff --git a/packages/walkthrough/steps/20/tsconfig.json b/packages/walkthrough/steps/20/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/20/tsconfig.json +++ b/packages/walkthrough/steps/20/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/20/ui5.yaml b/packages/walkthrough/steps/20/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/20/ui5.yaml +++ b/packages/walkthrough/steps/20/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/20/webapp/Component.ts b/packages/walkthrough/steps/20/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/20/webapp/Component.ts +++ b/packages/walkthrough/steps/20/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/20/webapp/controller/App.controller.ts b/packages/walkthrough/steps/20/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/20/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/20/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/20/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/20/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/20/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/20/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/20/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/20/webapp/controller/InvoiceList.controller.ts index 7213980ee..f68a0aa1a 100644 --- a/packages/walkthrough/steps/20/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/20/webapp/controller/InvoiceList.controller.ts @@ -2,7 +2,7 @@ import Controller from "sap/ui/core/mvc/Controller"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/20/webapp/index-cdn.html b/packages/walkthrough/steps/20/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/20/webapp/index-cdn.html +++ b/packages/walkthrough/steps/20/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/20/webapp/index.html b/packages/walkthrough/steps/20/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/20/webapp/index.html +++ b/packages/walkthrough/steps/20/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/20/webapp/manifest.json b/packages/walkthrough/steps/20/webapp/manifest.json index b255418b7..55e9a6881 100644 --- a/packages/walkthrough/steps/20/webapp/manifest.json +++ b/packages/walkthrough/steps/20/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/20/webapp/view/App.view.xml b/packages/walkthrough/steps/20/webapp/view/App.view.xml index 21bb07fd7..9a34e5ed0 100644 --- a/packages/walkthrough/steps/20/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/20/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,8 +8,8 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/20/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/20/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/20/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/20/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/20/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/20/webapp/view/InvoiceList.view.xml index c9f5529bf..56aa01311 100644 --- a/packages/walkthrough/steps/20/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/20/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> diff --git a/packages/walkthrough/steps/21/README.md b/packages/walkthrough/steps/21/README.md index c01ce1e5e..88668940a 100644 --- a/packages/walkthrough/steps/21/README.md +++ b/packages/walkthrough/steps/21/README.md @@ -37,7 +37,7 @@ We add the `numberState` attribute to the `ObjectListItem` control in our invoic ```xml <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> diff --git a/packages/walkthrough/steps/21/package.json b/packages/walkthrough/steps/21/package.json index 25264a172..b98ea50a8 100644 --- a/packages/walkthrough/steps/21/package.json +++ b/packages/walkthrough/steps/21/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step21", + "name": "ui5.tutorial.walkthrough.step21", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 21 - Expression Binding", diff --git a/packages/walkthrough/steps/21/tsconfig.json b/packages/walkthrough/steps/21/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/21/tsconfig.json +++ b/packages/walkthrough/steps/21/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/21/ui5.yaml b/packages/walkthrough/steps/21/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/21/ui5.yaml +++ b/packages/walkthrough/steps/21/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/21/webapp/Component.ts b/packages/walkthrough/steps/21/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/21/webapp/Component.ts +++ b/packages/walkthrough/steps/21/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/21/webapp/controller/App.controller.ts b/packages/walkthrough/steps/21/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/21/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/21/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/21/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/21/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/21/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/21/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/21/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/21/webapp/controller/InvoiceList.controller.ts index 98e950724..5223e6955 100644 --- a/packages/walkthrough/steps/21/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/21/webapp/controller/InvoiceList.controller.ts @@ -2,7 +2,7 @@ import Controller from "sap/ui/core/mvc/Controller"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/21/webapp/index-cdn.html b/packages/walkthrough/steps/21/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/21/webapp/index-cdn.html +++ b/packages/walkthrough/steps/21/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/21/webapp/index.html b/packages/walkthrough/steps/21/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/21/webapp/index.html +++ b/packages/walkthrough/steps/21/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/21/webapp/manifest.json b/packages/walkthrough/steps/21/webapp/manifest.json index b255418b7..55e9a6881 100644 --- a/packages/walkthrough/steps/21/webapp/manifest.json +++ b/packages/walkthrough/steps/21/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/21/webapp/view/App.view.xml b/packages/walkthrough/steps/21/webapp/view/App.view.xml index bb1576d28..08658b594 100644 --- a/packages/walkthrough/steps/21/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/21/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,8 +8,8 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/21/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/21/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/21/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/21/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/21/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/21/webapp/view/InvoiceList.view.xml index 47298708d..15757bc7b 100644 --- a/packages/walkthrough/steps/21/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/21/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> diff --git a/packages/walkthrough/steps/22/README.md b/packages/walkthrough/steps/22/README.md index 171c5384f..524943aa2 100644 --- a/packages/walkthrough/steps/22/README.md +++ b/packages/walkthrough/steps/22/README.md @@ -105,7 +105,7 @@ The new `formatter` file is placed in the model folder of the app, because forma   ->📌 **Important:** <br> +> :info: > In the above example, `this` refers to the controller instance as soon as the formatter gets called. We access the resource bundle via the component using `this.getOwnerComponent().getModel()` instead of using `this.getView().getModel()`. The latter call might return `undefined`, because the view might not have been attached to the component yet, and thus the view can't inherit a model from the component. **Additional Information:** @@ -119,7 +119,7 @@ We add the `ObjectStatus` control to our `ObjectListItem` using the `firstStatus ```xml <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -149,7 +149,7 @@ We add the `ObjectStatus` control to our `ObjectListItem` using the `firstStatus <firstStatus> <ObjectStatus core:require="{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/22/package.json b/packages/walkthrough/steps/22/package.json index 9a1162863..4fc7d07d9 100644 --- a/packages/walkthrough/steps/22/package.json +++ b/packages/walkthrough/steps/22/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step22", + "name": "ui5.tutorial.walkthrough.step22", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 22 - Custom Formatters", diff --git a/packages/walkthrough/steps/22/tsconfig.json b/packages/walkthrough/steps/22/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/22/tsconfig.json +++ b/packages/walkthrough/steps/22/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/22/ui5.yaml b/packages/walkthrough/steps/22/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/22/ui5.yaml +++ b/packages/walkthrough/steps/22/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/22/webapp/Component.ts b/packages/walkthrough/steps/22/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/22/webapp/Component.ts +++ b/packages/walkthrough/steps/22/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/22/webapp/controller/App.controller.ts b/packages/walkthrough/steps/22/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/22/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/22/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/22/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/22/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/22/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/22/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/22/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/22/webapp/controller/InvoiceList.controller.ts index 999d3e812..39ca336d8 100644 --- a/packages/walkthrough/steps/22/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/22/webapp/controller/InvoiceList.controller.ts @@ -2,7 +2,7 @@ import Controller from "sap/ui/core/mvc/Controller"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/22/webapp/index-cdn.html b/packages/walkthrough/steps/22/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/22/webapp/index-cdn.html +++ b/packages/walkthrough/steps/22/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/22/webapp/index.html b/packages/walkthrough/steps/22/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/22/webapp/index.html +++ b/packages/walkthrough/steps/22/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/22/webapp/manifest.json b/packages/walkthrough/steps/22/webapp/manifest.json index b255418b7..55e9a6881 100644 --- a/packages/walkthrough/steps/22/webapp/manifest.json +++ b/packages/walkthrough/steps/22/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/22/webapp/view/App.view.xml b/packages/walkthrough/steps/22/webapp/view/App.view.xml index 21bb07fd7..9a34e5ed0 100644 --- a/packages/walkthrough/steps/22/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/22/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,8 +8,8 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/22/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/22/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/22/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/22/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/22/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/22/webapp/view/InvoiceList.view.xml index 4a7f3e31d..c804c3cda 100644 --- a/packages/walkthrough/steps/22/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/22/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -29,7 +29,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/23/README.md b/packages/walkthrough/steps/23/README.md index 6c70e2525..de86c7695 100644 --- a/packages/walkthrough/steps/23/README.md +++ b/packages/walkthrough/steps/23/README.md @@ -50,7 +50,7 @@ import FilterOperator from "sap/ui/model/FilterOperator"; import ListBinding from "sap/ui/model/ListBinding"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { @@ -81,7 +81,7 @@ export default class App extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller", "sap/ui/model/json/JSONModel", "sap/ui/model/Filter", "sap/ui/model/FilterOperator"], function (Controller, JSONModel, Filter, FilterOperator) { "use strict"; - const App = Controller.extend("ui5.walkthrough.controller.App", { + const App = Controller.extend("ui5.tutorial.walkthrough.controller.App", { onInit() { const viewModel = new JSONModel({ currency: "EUR" @@ -131,7 +131,7 @@ In addition, we remove the `headerText` property in the list control and use `he ```xml <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> diff --git a/packages/walkthrough/steps/23/package.json b/packages/walkthrough/steps/23/package.json index a815bcc8a..136be005d 100644 --- a/packages/walkthrough/steps/23/package.json +++ b/packages/walkthrough/steps/23/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step23", + "name": "ui5.tutorial.walkthrough.step23", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 23 - Filtering", diff --git a/packages/walkthrough/steps/23/tsconfig.json b/packages/walkthrough/steps/23/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/23/tsconfig.json +++ b/packages/walkthrough/steps/23/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/23/ui5.yaml b/packages/walkthrough/steps/23/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/23/ui5.yaml +++ b/packages/walkthrough/steps/23/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/23/webapp/Component.ts b/packages/walkthrough/steps/23/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/23/webapp/Component.ts +++ b/packages/walkthrough/steps/23/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/23/webapp/controller/App.controller.ts b/packages/walkthrough/steps/23/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/23/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/23/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/23/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/23/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/23/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/23/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/23/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/23/webapp/controller/InvoiceList.controller.ts index cbf952e98..705ee3476 100644 --- a/packages/walkthrough/steps/23/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/23/webapp/controller/InvoiceList.controller.ts @@ -6,7 +6,7 @@ import FilterOperator from "sap/ui/model/FilterOperator"; import ListBinding from "sap/ui/model/ListBinding"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/23/webapp/index-cdn.html b/packages/walkthrough/steps/23/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/23/webapp/index-cdn.html +++ b/packages/walkthrough/steps/23/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/23/webapp/index.html b/packages/walkthrough/steps/23/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/23/webapp/index.html +++ b/packages/walkthrough/steps/23/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/23/webapp/manifest.json b/packages/walkthrough/steps/23/webapp/manifest.json index b255418b7..55e9a6881 100644 --- a/packages/walkthrough/steps/23/webapp/manifest.json +++ b/packages/walkthrough/steps/23/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/23/webapp/view/App.view.xml b/packages/walkthrough/steps/23/webapp/view/App.view.xml index 21bb07fd7..9a34e5ed0 100644 --- a/packages/walkthrough/steps/23/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/23/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,8 +8,8 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/23/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/23/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/23/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/23/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/23/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/23/webapp/view/InvoiceList.view.xml index d05caf260..b4027d9f6 100644 --- a/packages/walkthrough/steps/23/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/23/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -36,7 +36,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/24/README.md b/packages/walkthrough/steps/24/README.md index 76ea9d6de..10b896498 100644 --- a/packages/walkthrough/steps/24/README.md +++ b/packages/walkthrough/steps/24/README.md @@ -38,7 +38,7 @@ We add a declarative sorter to the binding syntax of the list control. Therefore ```xml <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -68,7 +68,7 @@ As with the sorter, no further action is required. The list and the data binding ```xml <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> diff --git a/packages/walkthrough/steps/24/package.json b/packages/walkthrough/steps/24/package.json index a91ee146f..7b57b8049 100644 --- a/packages/walkthrough/steps/24/package.json +++ b/packages/walkthrough/steps/24/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step24", + "name": "ui5.tutorial.walkthrough.step24", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 24 - Sorting and Grouping", diff --git a/packages/walkthrough/steps/24/tsconfig.json b/packages/walkthrough/steps/24/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/24/tsconfig.json +++ b/packages/walkthrough/steps/24/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/24/ui5.yaml b/packages/walkthrough/steps/24/ui5.yaml index 3de94066d..b71e0b6ad 100644 --- a/packages/walkthrough/steps/24/ui5.yaml +++ b/packages/walkthrough/steps/24/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/24/webapp/Component.ts b/packages/walkthrough/steps/24/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/24/webapp/Component.ts +++ b/packages/walkthrough/steps/24/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/24/webapp/controller/App.controller.ts b/packages/walkthrough/steps/24/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/24/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/24/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/24/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/24/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/24/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/24/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/24/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/24/webapp/controller/InvoiceList.controller.ts index cbf952e98..705ee3476 100644 --- a/packages/walkthrough/steps/24/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/24/webapp/controller/InvoiceList.controller.ts @@ -6,7 +6,7 @@ import FilterOperator from "sap/ui/model/FilterOperator"; import ListBinding from "sap/ui/model/ListBinding"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/24/webapp/index-cdn.html b/packages/walkthrough/steps/24/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/24/webapp/index-cdn.html +++ b/packages/walkthrough/steps/24/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/24/webapp/index.html b/packages/walkthrough/steps/24/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/24/webapp/index.html +++ b/packages/walkthrough/steps/24/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/24/webapp/manifest.json b/packages/walkthrough/steps/24/webapp/manifest.json index b255418b7..55e9a6881 100644 --- a/packages/walkthrough/steps/24/webapp/manifest.json +++ b/packages/walkthrough/steps/24/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -33,7 +33,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -41,7 +41,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/24/webapp/view/App.view.xml b/packages/walkthrough/steps/24/webapp/view/App.view.xml index 21bb07fd7..9a34e5ed0 100644 --- a/packages/walkthrough/steps/24/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/24/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,8 +8,8 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/24/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/24/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/24/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/24/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/24/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/24/webapp/view/InvoiceList.view.xml index 4c480790b..b5af26f26 100644 --- a/packages/walkthrough/steps/24/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/24/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -42,7 +42,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/25/README.md b/packages/walkthrough/steps/25/README.md index 9812adc8f..d77b31298 100644 --- a/packages/walkthrough/steps/25/README.md +++ b/packages/walkthrough/steps/25/README.md @@ -125,7 +125,7 @@ In the `models` section, we replace the content of the `invoice` model. This key Our component now automatically creates an instance of `sap.ui.model.odata.v2.ODataModel` according to the settings we specified above, and makes it available as a model named `invoice`. When you use the `invoiceRemote` data source, the `ODataModel` fetches the data from the real Northwind OData service. The invoices we receive from the Northwind OData service have identical properties as the JSON data we used previously \(except for the `status` property, which is not available in the Northwind OData service\). -> 📝 **Note:** <br> +> :note: > If you want to have a default model on the component, you can change the name of the model to an empty string in the descriptor file. > > Automatically instantiated models can be retrieved by calling `this.getModel` in the component. In the controllers of component-based apps you can call `this.getView().getModel()` to get the automatically instantiated model. For retrieving a named model you have to pass on the model name defined in the descriptor file to `getModel`, that is, in the component you would call `this.getModel("invoice")` to get our automatically generated `invoice` model that we defined in the descriptor. diff --git a/packages/walkthrough/steps/25/package.json b/packages/walkthrough/steps/25/package.json index 7d30568fd..3d415deba 100644 --- a/packages/walkthrough/steps/25/package.json +++ b/packages/walkthrough/steps/25/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step25", + "name": "ui5.tutorial.walkthrough.step25", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 25 - Remote OData Service", diff --git a/packages/walkthrough/steps/25/tsconfig.json b/packages/walkthrough/steps/25/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/25/tsconfig.json +++ b/packages/walkthrough/steps/25/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/25/ui5.yaml b/packages/walkthrough/steps/25/ui5.yaml index 4583b4bca..686c27abf 100644 --- a/packages/walkthrough/steps/25/ui5.yaml +++ b/packages/walkthrough/steps/25/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/25/webapp/Component.ts b/packages/walkthrough/steps/25/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/25/webapp/Component.ts +++ b/packages/walkthrough/steps/25/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/25/webapp/controller/App.controller.ts b/packages/walkthrough/steps/25/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/25/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/25/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/25/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/25/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/25/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/25/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/25/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/25/webapp/controller/InvoiceList.controller.ts index cbf952e98..705ee3476 100644 --- a/packages/walkthrough/steps/25/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/25/webapp/controller/InvoiceList.controller.ts @@ -6,7 +6,7 @@ import FilterOperator from "sap/ui/model/FilterOperator"; import ListBinding from "sap/ui/model/ListBinding"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/25/webapp/index-cdn.html b/packages/walkthrough/steps/25/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/25/webapp/index-cdn.html +++ b/packages/walkthrough/steps/25/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/25/webapp/index.html b/packages/walkthrough/steps/25/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/25/webapp/index.html +++ b/packages/walkthrough/steps/25/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/25/webapp/manifest.json b/packages/walkthrough/steps/25/webapp/manifest.json index d1436c472..4462da884 100644 --- a/packages/walkthrough/steps/25/webapp/manifest.json +++ b/packages/walkthrough/steps/25/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -42,7 +42,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -50,7 +50,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/25/webapp/view/App.view.xml b/packages/walkthrough/steps/25/webapp/view/App.view.xml index ee99451f9..7f6133cdf 100644 --- a/packages/walkthrough/steps/25/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/25/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,8 +8,8 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/25/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/25/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/25/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/25/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/25/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/25/webapp/view/InvoiceList.view.xml index 4c480790b..b5af26f26 100644 --- a/packages/walkthrough/steps/25/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/25/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -42,7 +42,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/26/README.md b/packages/walkthrough/steps/26/README.md index 846082dcf..999fe470b 100644 --- a/packages/walkthrough/steps/26/README.md +++ b/packages/walkthrough/steps/26/README.md @@ -156,7 +156,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -168,7 +168,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start @@ -186,7 +186,7 @@ sap.ui.define(["sap/ui/core/util/MockServer"], function (MockServer) { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -197,7 +197,7 @@ sap.ui.define(["sap/ui/core/util/MockServer"], function (MockServer) { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start @@ -258,15 +258,15 @@ Instead the app component, we define that the `initMockServer` is initialized fr data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> ``` @@ -287,7 +287,7 @@ In case you prefer to continue with the local data, you should adjust the `start ```json { - "name": "ui5.walkthrough", + "name": "ui5.tutorial.walkthrough", "version": "1.0.0", "description": "OpenUI5 TypeScript Walkthrough", "private": true, diff --git a/packages/walkthrough/steps/26/package.json b/packages/walkthrough/steps/26/package.json index 4465edb1d..da8b0c01f 100644 --- a/packages/walkthrough/steps/26/package.json +++ b/packages/walkthrough/steps/26/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step26", + "name": "ui5.tutorial.walkthrough.step26", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 26 - Mock Server Configuration", diff --git a/packages/walkthrough/steps/26/tsconfig.json b/packages/walkthrough/steps/26/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/26/tsconfig.json +++ b/packages/walkthrough/steps/26/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/26/ui5.yaml b/packages/walkthrough/steps/26/ui5.yaml index 4583b4bca..686c27abf 100644 --- a/packages/walkthrough/steps/26/ui5.yaml +++ b/packages/walkthrough/steps/26/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '3.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/26/webapp/Component.ts b/packages/walkthrough/steps/26/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/26/webapp/Component.ts +++ b/packages/walkthrough/steps/26/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/26/webapp/controller/App.controller.ts b/packages/walkthrough/steps/26/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/26/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/26/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/26/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/26/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/26/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/26/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/26/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/26/webapp/controller/InvoiceList.controller.ts index cbf952e98..705ee3476 100644 --- a/packages/walkthrough/steps/26/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/26/webapp/controller/InvoiceList.controller.ts @@ -6,7 +6,7 @@ import FilterOperator from "sap/ui/model/FilterOperator"; import ListBinding from "sap/ui/model/ListBinding"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/26/webapp/index-cdn.html b/packages/walkthrough/steps/26/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/26/webapp/index-cdn.html +++ b/packages/walkthrough/steps/26/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/26/webapp/index.html b/packages/walkthrough/steps/26/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/26/webapp/index.html +++ b/packages/walkthrough/steps/26/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/26/webapp/localService/mockserver.ts b/packages/walkthrough/steps/26/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/26/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/26/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/26/webapp/manifest.json b/packages/walkthrough/steps/26/webapp/manifest.json index d1436c472..4462da884 100644 --- a/packages/walkthrough/steps/26/webapp/manifest.json +++ b/packages/walkthrough/steps/26/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -42,7 +42,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -50,7 +50,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/26/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/26/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/26/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/26/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/26/webapp/test/mockServer.html b/packages/walkthrough/steps/26/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/26/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/26/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/26/webapp/view/App.view.xml b/packages/walkthrough/steps/26/webapp/view/App.view.xml index 5cab811e8..ee2b7bd84 100644 --- a/packages/walkthrough/steps/26/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/26/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,8 +8,8 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/26/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/26/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/26/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/26/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/26/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/26/webapp/view/InvoiceList.view.xml index 4c480790b..b5af26f26 100644 --- a/packages/walkthrough/steps/26/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/26/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -42,7 +42,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/27/README.md b/packages/walkthrough/steps/27/README.md index 9e70dfc2b..15ce1c33d 100644 --- a/packages/walkthrough/steps/27/README.md +++ b/packages/walkthrough/steps/27/README.md @@ -4,7 +4,7 @@ Now that we have a test folder in the app, we can start to increase our test cov Actually, every feature that we added to the app so far, would require a separate test case. We have totally neglected this so far, so let’s add a simple unit test for our custom formatter function from Step 23. We will test if the long text for our status is correct by comparing it with the texts from our resource bundle. -> 📝 **Note:** <br> +> :note: > In this tutorial, we focus on a simple use case for the test implementation. If you want to learn more about QUnit tests, have a look at the [Testing Tutorial](https://sdk.openui5.org/topic/291c9121e6044ab381e0b51716f97f52.html) tutorial, especially [Step 2: A First Unit Test](https://sdk.openui5.org/topic/b81736e0fcb246efb3b0cf0ca422f8fd.html).   @@ -22,7 +22,7 @@ We add a new folder `unit` under the `test` folder and a `model` subfolder where ![](assets/loio1b5613ac3ab94757af2c7823039222a9_LowRes.png "Folder Structure for this Step") <sup>*Folder Structure for this Step*</sup> -You can access the live preview by clicking on this link: [🔗 Live Preview of Step 27](https://ui5.github.io/tutorials/walkthrough/build/27/test/Test.cdn.qunit.html?testsuite=test-resources/ui5/walkthrough/testsuite.cdn.qunit&test=unit/unitTests). +You can access the live preview by clicking on this link: [🔗 Live Preview of Step 27](https://ui5.github.io/tutorials/walkthrough/build/27/test/Test.cdn.qunit.html?testsuite=test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit&test=unit/unitTests). *** @@ -49,19 +49,19 @@ The new formatter file just contains one QUnit module for our formatter function Finally, we perform our assertions. We check each branch of the formatter logic by invoking the isolated formatter function with the values that we expect in the data model \(`A`, `B`, `C`, and everything else\). We strictly compare the result of the formatter function with the hard-coded strings that we expect from the resource bundle and give a meaningful error message if the test should fail. -> 📝 **Note:** <br> -> Test code needs to import the modules under test (i.e. productive code) using their full namespace (in our case `ui5/walkthrough/`), rather than using relative paths. This is because the test code uses a different namespace (`test-resources/ui5/walkthrough/`). +> :note: +> Test code needs to import the modules under test (i.e. productive code) using their full namespace (in our case `ui5/tutorial/walkthrough/`), rather than using relative paths. This is because the test code uses a different namespace (`test-resources/ui5/tutorial/walkthrough/`). ```ts import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], @@ -91,13 +91,13 @@ QUnit.test("Should return the translated texts", (assert) => { ``` ```js -sap.ui.define(["sap/ui/model/resource/ResourceModel", "ui5/walkthrough/model/formatter"], function (ResourceModel, formatter) { +sap.ui.define(["sap/ui/model/resource/ResourceModel", "ui5/tutorial/walkthrough/model/formatter"], function (ResourceModel, formatter) { "use strict"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", assert => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [""], fallbackLocale: "" }); @@ -161,7 +161,7 @@ The page will be referenced in the test suite that we will create next. <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> @@ -191,7 +191,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -200,7 +200,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, @@ -220,7 +220,7 @@ sap.ui.define([], function () { return { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -229,7 +229,7 @@ sap.ui.define([], function () { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, @@ -258,9 +258,9 @@ It registers a resource root mapping for the test resources of our project and r <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/27/package.json b/packages/walkthrough/steps/27/package.json index 2f889926a..c0974345c 100644 --- a/packages/walkthrough/steps/27/package.json +++ b/packages/walkthrough/steps/27/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step27", + "name": "ui5.tutorial.walkthrough.step27", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 27 - Unit Test with QUnit", diff --git a/packages/walkthrough/steps/27/tsconfig.json b/packages/walkthrough/steps/27/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/27/tsconfig.json +++ b/packages/walkthrough/steps/27/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/27/ui5.yaml b/packages/walkthrough/steps/27/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/27/ui5.yaml +++ b/packages/walkthrough/steps/27/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/27/webapp/Component.ts b/packages/walkthrough/steps/27/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/27/webapp/Component.ts +++ b/packages/walkthrough/steps/27/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/27/webapp/controller/App.controller.ts b/packages/walkthrough/steps/27/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/27/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/27/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/27/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/27/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/27/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/27/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/27/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/27/webapp/controller/InvoiceList.controller.ts index cbf952e98..705ee3476 100644 --- a/packages/walkthrough/steps/27/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/27/webapp/controller/InvoiceList.controller.ts @@ -6,7 +6,7 @@ import FilterOperator from "sap/ui/model/FilterOperator"; import ListBinding from "sap/ui/model/ListBinding"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/27/webapp/index-cdn.html b/packages/walkthrough/steps/27/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/27/webapp/index-cdn.html +++ b/packages/walkthrough/steps/27/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/27/webapp/index.html b/packages/walkthrough/steps/27/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/27/webapp/index.html +++ b/packages/walkthrough/steps/27/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/27/webapp/localService/mockserver.ts b/packages/walkthrough/steps/27/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/27/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/27/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/27/webapp/manifest.json b/packages/walkthrough/steps/27/webapp/manifest.json index d1436c472..4462da884 100644 --- a/packages/walkthrough/steps/27/webapp/manifest.json +++ b/packages/walkthrough/steps/27/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -42,7 +42,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -50,7 +50,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/27/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/27/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/27/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/27/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/27/webapp/test/Test.qunit.html b/packages/walkthrough/steps/27/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/27/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/27/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/27/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/27/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/27/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/27/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/27/webapp/test/mockServer.html b/packages/walkthrough/steps/27/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/27/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/27/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/27/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/27/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/27/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/27/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/27/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/27/webapp/test/testsuite.cdn.qunit.ts index 18b9cb9e7..f0eb044b6 100644 --- a/packages/walkthrough/steps/27/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/27/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/27/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/27/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/27/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/27/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/27/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/27/webapp/test/testsuite.qunit.ts index a2f133280..92a411ef1 100644 --- a/packages/walkthrough/steps/27/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/27/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/27/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/27/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/27/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/27/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/27/webapp/view/App.view.xml b/packages/walkthrough/steps/27/webapp/view/App.view.xml index 5cab811e8..ee2b7bd84 100644 --- a/packages/walkthrough/steps/27/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/27/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,8 +8,8 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/27/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/27/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/27/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/27/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/27/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/27/webapp/view/InvoiceList.view.xml index 4c480790b..b5af26f26 100644 --- a/packages/walkthrough/steps/27/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/27/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -42,7 +42,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/28/README.md b/packages/walkthrough/steps/28/README.md index f9d75ebf1..b32f6007f 100644 --- a/packages/walkthrough/steps/28/README.md +++ b/packages/walkthrough/steps/28/README.md @@ -4,7 +4,7 @@ If we want to test interaction patterns or more visual features of our app, we c We haven’t thought about testing our interaction with the app yet, so in this step we will check if the dialog actually opens when we click the “Say Hello with Dialog” button. We can easily do this with OPA5, a feature of OpenUI5 that is easy to set up and is based on JavaScript and QUnit. Using integration and unit tests and running them consistently in a continuous integration \(CI\) environment, we can make sure that we don’t accidentally break our app or introduce logical errors in existing code.   -> 📝 **Note:** +> :note: > In this tutorial, we focus on a simple use case for the test implementation. If you want to learn more about OPA tests, have a look at our [Testing Tutorial](https://sdk.openui5.org/topic/291c9121e6044ab381e0b51716f97f52.html) tutorial, especially [Step 6: A First OPA Test](https://sdk.openui5.org/topic/1b47457cbe4941ee926317d827517acb.html).   @@ -22,7 +22,7 @@ We add a new folder `integration` below the `test` folder, where we put our new ![](assets/loio27e84d5bd72a485498564b92894869b5_LowRes.png "Folder Structure for this Step") <sup>*Folder Structure for this Step*</sup> -You can access the live preview by clicking on this link: [🔗 Live Preview of Step 28](https://ui5.github.io/tutorials/walkthrough/build/28/test/Test.cdn.qunit.html?testsuite=test-resources/ui5/walkthrough/testsuite.cdn.qunit&test=integration/opaTests). +You can access the live preview by clicking on this link: [🔗 Live Preview of Step 28](https://ui5.github.io/tutorials/walkthrough/build/28/test/Test.cdn.qunit.html?testsuite=test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit&test=integration/opaTests). *** @@ -56,7 +56,7 @@ In the assertions section we define a `waitFor` statement that checks if a `sap. import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions @@ -88,7 +88,7 @@ export default class HelloPanelPage extends Opa5 { sap.ui.define(["sap/ui/test/Opa5", "sap/ui/test/actions/Press"], function (Opa5, Press) { "use strict"; - const viewName = "ui5.walkthrough.view.HelloPanel"; + const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; class HelloPanelPage extends Opa5 { // Actions iPressTheSayHelloWithDialogButton() { @@ -150,7 +150,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); @@ -176,7 +176,7 @@ sap.ui.define(["sap/ui/test/opaQunit", "./pages/HelloPanelPage"], function (opaT // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/28/package.json b/packages/walkthrough/steps/28/package.json index 541ff5628..5c7676026 100644 --- a/packages/walkthrough/steps/28/package.json +++ b/packages/walkthrough/steps/28/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step28", + "name": "ui5.tutorial.walkthrough.step28", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 28 - Integration Test with OPA", diff --git a/packages/walkthrough/steps/28/tsconfig.json b/packages/walkthrough/steps/28/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/28/tsconfig.json +++ b/packages/walkthrough/steps/28/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/28/ui5.yaml b/packages/walkthrough/steps/28/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/28/ui5.yaml +++ b/packages/walkthrough/steps/28/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/28/webapp/Component.ts b/packages/walkthrough/steps/28/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/28/webapp/Component.ts +++ b/packages/walkthrough/steps/28/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/28/webapp/controller/App.controller.ts b/packages/walkthrough/steps/28/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/28/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/28/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/28/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/28/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/28/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/28/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/28/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/28/webapp/controller/InvoiceList.controller.ts index cbf952e98..705ee3476 100644 --- a/packages/walkthrough/steps/28/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/28/webapp/controller/InvoiceList.controller.ts @@ -6,7 +6,7 @@ import FilterOperator from "sap/ui/model/FilterOperator"; import ListBinding from "sap/ui/model/ListBinding"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/28/webapp/index-cdn.html b/packages/walkthrough/steps/28/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/28/webapp/index-cdn.html +++ b/packages/walkthrough/steps/28/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/28/webapp/index.html b/packages/walkthrough/steps/28/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/28/webapp/index.html +++ b/packages/walkthrough/steps/28/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/28/webapp/localService/mockserver.ts b/packages/walkthrough/steps/28/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/28/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/28/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/28/webapp/manifest.json b/packages/walkthrough/steps/28/webapp/manifest.json index d1436c472..4462da884 100644 --- a/packages/walkthrough/steps/28/webapp/manifest.json +++ b/packages/walkthrough/steps/28/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -42,7 +42,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -50,7 +50,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/28/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/28/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/28/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/28/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/28/webapp/test/Test.qunit.html b/packages/walkthrough/steps/28/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/28/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/28/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/28/webapp/test/integration/NavigationJourney.ts b/packages/walkthrough/steps/28/webapp/test/integration/NavigationJourney.ts index 2c5a3c942..b3b7de6c5 100644 --- a/packages/walkthrough/steps/28/webapp/test/integration/NavigationJourney.ts +++ b/packages/walkthrough/steps/28/webapp/test/integration/NavigationJourney.ts @@ -10,7 +10,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/28/webapp/test/integration/pages/HelloPanelPage.ts b/packages/walkthrough/steps/28/webapp/test/integration/pages/HelloPanelPage.ts index 83e59dde1..da73c14de 100644 --- a/packages/walkthrough/steps/28/webapp/test/integration/pages/HelloPanelPage.ts +++ b/packages/walkthrough/steps/28/webapp/test/integration/pages/HelloPanelPage.ts @@ -1,7 +1,7 @@ import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions diff --git a/packages/walkthrough/steps/28/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/28/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/28/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/28/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/28/webapp/test/mockServer.html b/packages/walkthrough/steps/28/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/28/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/28/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/28/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/28/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/28/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/28/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/28/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/28/webapp/test/testsuite.cdn.qunit.ts index e158902a7..3f57245ab 100644 --- a/packages/walkthrough/steps/28/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/28/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/28/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/28/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/28/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/28/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/28/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/28/webapp/test/testsuite.qunit.ts index be9cab085..78cb8dd37 100644 --- a/packages/walkthrough/steps/28/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/28/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/28/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/28/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/28/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/28/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/28/webapp/view/App.view.xml b/packages/walkthrough/steps/28/webapp/view/App.view.xml index 5cab811e8..ee2b7bd84 100644 --- a/packages/walkthrough/steps/28/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/28/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,8 +8,8 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/28/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/28/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/28/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/28/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/28/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/28/webapp/view/InvoiceList.view.xml index 4c480790b..b5af26f26 100644 --- a/packages/walkthrough/steps/28/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/28/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -42,7 +42,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/29/README.md b/packages/walkthrough/steps/29/README.md index 1c6e252b1..4f3255b39 100644 --- a/packages/walkthrough/steps/29/README.md +++ b/packages/walkthrough/steps/29/README.md @@ -41,7 +41,7 @@ We introduced a typo in the binding of the number attribute to simulate a freque ```xml <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -96,7 +96,7 @@ We introduced a typo in the binding of the number attribute to simulate a freque   Now we call the app and notice that the price is actually missing. By entering the [shortcut](https://sdk.openui5.org/topic/154844c3ac2a4675a37aeb6259a5e034.html) [Ctrl\] + [Shift\] + [Alt\] /[Option\] + [S\] we open the OpenUI5 support diagnostics tool and check the app. -> 📝 **Note:** +> :note: > > If you use the Google Chrome browser, you can install the *UI5 Inspector* plugin. With this plugin, you can easily debug your OpenUI5- or OpenUI5-based apps. For more information, see [UI5 Inspector](https://sdk.openui5.org/topic/b24e72443eb34d0fb7bf6940f2d697eb.html). @@ -106,7 +106,7 @@ A hierarchical tree of OpenUI5 controls is shown on the left and the properties Sometimes errors are not as easy to spot and you actually need to debug the JavaScript code with the tools of the browser. -> 📝 **Note:** <br> +> :note: > When debugging UI5 applications that use built resources, the OpenUI5 files are minified, which means that variable names are shortened and comments are removed. > > This makes debugging harder, because the code is a lot less readable. You can load the debug sources by adding the URL parameter `sap-ui-debug=true` or by pressing [Ctrl\] + [Shift\] + [Alt\] /[Option\] + [P\] and selecting *Use Debug Sources* in the dialog box that is displayed. After reloading the page, you can see in the *Network* tab of the browser’s developer tools that now a lot of files are loaded that have a `–dbg` suffix. These are the source code files that include comments and the uncompressed code of the app and the OpenUI5 artifacts. diff --git a/packages/walkthrough/steps/29/package.json b/packages/walkthrough/steps/29/package.json index 9e188f2b6..538e7a045 100644 --- a/packages/walkthrough/steps/29/package.json +++ b/packages/walkthrough/steps/29/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step29", + "name": "ui5.tutorial.walkthrough.step29", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 29 - Debugging Tools", diff --git a/packages/walkthrough/steps/29/tsconfig.json b/packages/walkthrough/steps/29/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/29/tsconfig.json +++ b/packages/walkthrough/steps/29/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/29/ui5.yaml b/packages/walkthrough/steps/29/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/29/ui5.yaml +++ b/packages/walkthrough/steps/29/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/29/webapp/Component.ts b/packages/walkthrough/steps/29/webapp/Component.ts index b1ca2b4f6..6aabcd1c5 100644 --- a/packages/walkthrough/steps/29/webapp/Component.ts +++ b/packages/walkthrough/steps/29/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/29/webapp/controller/App.controller.ts b/packages/walkthrough/steps/29/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/29/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/29/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/29/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/29/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/29/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/29/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/29/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/29/webapp/controller/InvoiceList.controller.ts index cbf952e98..705ee3476 100644 --- a/packages/walkthrough/steps/29/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/29/webapp/controller/InvoiceList.controller.ts @@ -6,7 +6,7 @@ import FilterOperator from "sap/ui/model/FilterOperator"; import ListBinding from "sap/ui/model/ListBinding"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/29/webapp/index-cdn.html b/packages/walkthrough/steps/29/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/29/webapp/index-cdn.html +++ b/packages/walkthrough/steps/29/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/29/webapp/index.html b/packages/walkthrough/steps/29/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/29/webapp/index.html +++ b/packages/walkthrough/steps/29/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/29/webapp/localService/mockserver.ts b/packages/walkthrough/steps/29/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/29/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/29/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/29/webapp/manifest.json b/packages/walkthrough/steps/29/webapp/manifest.json index d1436c472..4462da884 100644 --- a/packages/walkthrough/steps/29/webapp/manifest.json +++ b/packages/walkthrough/steps/29/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -42,7 +42,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -50,7 +50,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], diff --git a/packages/walkthrough/steps/29/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/29/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/29/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/29/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/29/webapp/test/Test.qunit.html b/packages/walkthrough/steps/29/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/29/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/29/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/29/webapp/test/integration/NavigationJourney.ts b/packages/walkthrough/steps/29/webapp/test/integration/NavigationJourney.ts index 2c5a3c942..b3b7de6c5 100644 --- a/packages/walkthrough/steps/29/webapp/test/integration/NavigationJourney.ts +++ b/packages/walkthrough/steps/29/webapp/test/integration/NavigationJourney.ts @@ -10,7 +10,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/29/webapp/test/integration/pages/HelloPanelPage.ts b/packages/walkthrough/steps/29/webapp/test/integration/pages/HelloPanelPage.ts index 83e59dde1..da73c14de 100644 --- a/packages/walkthrough/steps/29/webapp/test/integration/pages/HelloPanelPage.ts +++ b/packages/walkthrough/steps/29/webapp/test/integration/pages/HelloPanelPage.ts @@ -1,7 +1,7 @@ import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions diff --git a/packages/walkthrough/steps/29/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/29/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/29/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/29/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/29/webapp/test/mockServer.html b/packages/walkthrough/steps/29/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/29/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/29/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/29/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/29/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/29/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/29/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/29/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/29/webapp/test/testsuite.cdn.qunit.ts index e158902a7..3f57245ab 100644 --- a/packages/walkthrough/steps/29/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/29/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/29/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/29/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/29/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/29/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/29/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/29/webapp/test/testsuite.qunit.ts index be9cab085..78cb8dd37 100644 --- a/packages/walkthrough/steps/29/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/29/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/29/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/29/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/29/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/29/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/29/webapp/view/App.view.xml b/packages/walkthrough/steps/29/webapp/view/App.view.xml index 5cab811e8..ee2b7bd84 100644 --- a/packages/walkthrough/steps/29/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/29/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -8,8 +8,8 @@ <pages> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </pages> diff --git a/packages/walkthrough/steps/29/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/29/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/29/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/29/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/29/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/29/webapp/view/InvoiceList.view.xml index 4c480790b..b5af26f26 100644 --- a/packages/walkthrough/steps/29/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/29/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -42,7 +42,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/30/README.md b/packages/walkthrough/steps/30/README.md index 4981ba9b1..3a412f735 100644 --- a/packages/walkthrough/steps/30/README.md +++ b/packages/walkthrough/steps/30/README.md @@ -71,24 +71,24 @@ Now we add the new `Detail.view.xml` file to our view folder. Beside of the the Next, we create another view in the view folder, called `Overview.view.xml`. We add the root node of the XML structure including the required namespaces to it. Then we copy and paste from the app view everything between and including the `Page` control to our new view. -For simplicity, we reuse the controller `ui5.walkthrough.controller.App` for our new view as it only contains our helper method to open the dialog. +For simplicity, we reuse the controller `ui5.tutorial.walkthrough.controller.App` for our new view as it only contains our helper method to open the dialog. ```xml <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel" /> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList" /> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel" /> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList" /> </content> </Page> </mvc:View> ```   -As we reuse the controller `ui5.walkthrough.controller.App` for two different views \(for the new overview and for the app view\), two instances of that controller are instantiated at runtime. In general, one instance of a controller is instantiated for each view that references the controller. +As we reuse the controller `ui5.tutorial.walkthrough.controller.App` for two different views \(for the new overview and for the app view\), two instances of that controller are instantiated at runtime. In general, one instance of a controller is instantiated for each view that references the controller. ### webapp/view/App.view.xml @@ -96,7 +96,7 @@ In the app view, we now remove everything and between the control aggregation `p ```xml <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -117,7 +117,7 @@ We add a new “routing" section to the `sap.ui5` part of the descriptor. There - `config` This section contains the global router configuration and default values that apply for all routes and targets. The property routerClass is special as it determines the router implementation. The default value is `sap.ui.core.routing.Router`. Here, we set the `routerClass` to `sap.m.routing.Router`, because our app is based on `sap.m`. All other properties in config are given to the router instance. For example, we define in `path` where our views are located in the app. As we want to specify view to view navigation and we only use XML views in our app we preset also the paramter `type` and `viewType`. To load and display views automatically, we also specify the `controlId` of the control that will contain the views and the aggregation (`controlAggregation`) of the control where the views will be added. Here we specify that the views are loaded into the `pages` aggregation of the control with the id we provided in the app view. - > 📌 **Important:** + > :info: > The possible values for `routerClass` are `sap.ui.core.routing.Router`, `sap.m.routing.Router`, or any other subclasses of `sap.ui.core.routing.Router`. Compared to `sap.ui.core.routing.Router` the `sap.m.routing.Router` is optimized for mobile apps and adds the properties `level`, `transition` and `transitionParameters` which can be specified for each route or target created by the `sap.m.routing.Router`. - `routes` @@ -143,7 +143,7 @@ We add a new “routing" section to the `sap.ui5` part of the descriptor. There "routerClass": "sap.m.routing.Router", "type": "View", "viewType": "XML", - "path": "ui5.walkthrough.view", + "path": "ui5.tutorial.walkthrough.view", "controlId": "app", "controlAggregation": "pages" }, @@ -178,7 +178,7 @@ The router will automatically add the view that corresponds to the current URL i The overview view is always shown when the hash is empty. The detail view is shown when the hash matches the pattern `detail`. -> 📌 **Important:** <br> +> :info: > The sequence of the routes in the routes definition is important. As soon as a pattern is matched, the following patterns are ignored. To prevent this for a specific route, you use the `greedy` parameter. If set to `true`, the route is always taken into account. ### webapp/Component.?s @@ -190,7 +190,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { @@ -221,7 +221,7 @@ export default class Component extends UIComponent { sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/model/json/JSONModel"], function (UIComponent, JSONModel) { "use strict"; - const Component = UIComponent.extend("ui5.walkthrough.Component", { + const Component = UIComponent.extend("ui5.tutorial.walkthrough.Component", { metadata: { "interfaces": ["sap.ui.core.IAsyncContentCreation"], "manifest": "json" @@ -269,7 +269,7 @@ import ListBinding from "sap/ui/model/ListBinding"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { @@ -286,7 +286,7 @@ export default class App extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller", "sap/ui/model/json/JSONModel", "sap/ui/model/Filter", "sap/ui/model/FilterOperator", "sap/ui/core/UIComponent"], function (Controller, JSONModel, Filter, FilterOperator, UIComponent) { "use strict"; - const App = Controller.extend("ui5.walkthrough.controller.App", { + const App = Controller.extend("ui5.tutorial.walkthrough.controller.App", { //... @@ -307,7 +307,7 @@ In the invoice list view we finally add the press event to the list item we just ```xml <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> diff --git a/packages/walkthrough/steps/30/package.json b/packages/walkthrough/steps/30/package.json index 2ffa6616c..07daa41d0 100644 --- a/packages/walkthrough/steps/30/package.json +++ b/packages/walkthrough/steps/30/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step30", + "name": "ui5.tutorial.walkthrough.step30", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 30 - Routing and Navigation", diff --git a/packages/walkthrough/steps/30/tsconfig.json b/packages/walkthrough/steps/30/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/30/tsconfig.json +++ b/packages/walkthrough/steps/30/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/30/ui5.yaml b/packages/walkthrough/steps/30/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/30/ui5.yaml +++ b/packages/walkthrough/steps/30/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/30/webapp/Component.ts b/packages/walkthrough/steps/30/webapp/Component.ts index ee2eae016..3e347464b 100644 --- a/packages/walkthrough/steps/30/webapp/Component.ts +++ b/packages/walkthrough/steps/30/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/30/webapp/controller/App.controller.ts b/packages/walkthrough/steps/30/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/30/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/30/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/30/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/30/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/30/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/30/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/30/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/30/webapp/controller/InvoiceList.controller.ts index cab2191fe..1ebafe5c1 100644 --- a/packages/walkthrough/steps/30/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/30/webapp/controller/InvoiceList.controller.ts @@ -7,7 +7,7 @@ import ListBinding from "sap/ui/model/ListBinding"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/30/webapp/index-cdn.html b/packages/walkthrough/steps/30/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/30/webapp/index-cdn.html +++ b/packages/walkthrough/steps/30/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/30/webapp/index.html b/packages/walkthrough/steps/30/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/30/webapp/index.html +++ b/packages/walkthrough/steps/30/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/30/webapp/localService/mockserver.ts b/packages/walkthrough/steps/30/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/30/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/30/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/30/webapp/manifest.json b/packages/walkthrough/steps/30/webapp/manifest.json index cea286b7f..ae7abfc57 100644 --- a/packages/walkthrough/steps/30/webapp/manifest.json +++ b/packages/walkthrough/steps/30/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -42,7 +42,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -50,7 +50,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -73,7 +73,7 @@ "routerClass": "sap.m.routing.Router", "type": "View", "viewType": "XML", - "path": "ui5.walkthrough.view", + "path": "ui5.tutorial.walkthrough.view", "controlId": "app", "controlAggregation": "pages" }, diff --git a/packages/walkthrough/steps/30/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/30/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/30/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/30/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/30/webapp/test/Test.qunit.html b/packages/walkthrough/steps/30/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/30/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/30/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/30/webapp/test/integration/NavigationJourney.ts b/packages/walkthrough/steps/30/webapp/test/integration/NavigationJourney.ts index 2c5a3c942..b3b7de6c5 100644 --- a/packages/walkthrough/steps/30/webapp/test/integration/NavigationJourney.ts +++ b/packages/walkthrough/steps/30/webapp/test/integration/NavigationJourney.ts @@ -10,7 +10,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/30/webapp/test/integration/pages/HelloPanelPage.ts b/packages/walkthrough/steps/30/webapp/test/integration/pages/HelloPanelPage.ts index 83e59dde1..da73c14de 100644 --- a/packages/walkthrough/steps/30/webapp/test/integration/pages/HelloPanelPage.ts +++ b/packages/walkthrough/steps/30/webapp/test/integration/pages/HelloPanelPage.ts @@ -1,7 +1,7 @@ import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions diff --git a/packages/walkthrough/steps/30/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/30/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/30/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/30/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/30/webapp/test/mockServer.html b/packages/walkthrough/steps/30/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/30/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/30/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/30/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/30/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/30/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/30/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/30/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/30/webapp/test/testsuite.cdn.qunit.ts index e158902a7..3f57245ab 100644 --- a/packages/walkthrough/steps/30/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/30/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/30/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/30/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/30/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/30/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/30/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/30/webapp/test/testsuite.qunit.ts index be9cab085..78cb8dd37 100644 --- a/packages/walkthrough/steps/30/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/30/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/30/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/30/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/30/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/30/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/30/webapp/view/App.view.xml b/packages/walkthrough/steps/30/webapp/view/App.view.xml index 11d955a8b..19804995f 100644 --- a/packages/walkthrough/steps/30/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/30/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/30/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/30/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/30/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/30/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/30/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/30/webapp/view/InvoiceList.view.xml index a458ffcb2..aa485b948 100644 --- a/packages/walkthrough/steps/30/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/30/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -44,7 +44,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/30/webapp/view/Overview.view.xml b/packages/walkthrough/steps/30/webapp/view/Overview.view.xml index d278a7c41..07c835e92 100644 --- a/packages/walkthrough/steps/30/webapp/view/Overview.view.xml +++ b/packages/walkthrough/steps/30/webapp/view/Overview.view.xml @@ -1,12 +1,12 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </mvc:View> \ No newline at end of file diff --git a/packages/walkthrough/steps/31/README.md b/packages/walkthrough/steps/31/README.md index a832dbddb..5cbcdb91b 100644 --- a/packages/walkthrough/steps/31/README.md +++ b/packages/walkthrough/steps/31/README.md @@ -39,7 +39,7 @@ You can download the solution for this step here: [📥 Download step 31](https: We want to hand over the information for the selected item when navigating to the detail view. To achieve that, we add the navigation parameter `invoicePath` to the detail route in the app descriptor. There, we add a navigation parameter `invoicePath` to the detail route so that we can hand over the information for the selected item to the detail page. -> 📝 **Note:** <br> +> :note: > Mandatory navigation parameters are defined with curly brackets. ```json @@ -52,7 +52,7 @@ We want to hand over the information for the selected item when navigating to th "routerClass": "sap.m.routing.Router", "type": "View", "viewType": "XML", - "path": "ui5.walkthrough.view", + "path": "ui5.tutorial.walkthrough.view", "controlId": "app", "controlAggregation": "pages" }, @@ -107,7 +107,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import Context from "sap/ui/model/Context"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { @@ -128,7 +128,7 @@ export default class App extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller", "sap/ui/model/json/JSONModel", "sap/ui/model/Filter", "sap/ui/model/FilterOperator", "sap/ui/core/UIComponent"], function (Controller, JSONModel, Filter, FilterOperator, UIComponent) { "use strict"; - const App = Controller.extend("ui5.walkthrough.controller.App", { + const App = Controller.extend("ui5.tutorial.walkthrough.controller.App", { //... @@ -165,7 +165,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import Route, { Route$PatternMatchedEvent } from "sap/ui/core/routing/Route"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { @@ -188,7 +188,7 @@ export default class Detail extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller", "sap/ui/core/UIComponent"], function (Controller, UIComponent) { "use strict"; - const Detail = Controller.extend("ui5.walkthrough.controller.Detail", { + const Detail = Controller.extend("ui5.tutorial.walkthrough.controller.Detail", { onInit() { const router = UIComponent.getRouterFor(this); router.getRoute("detail").attachPatternMatched(this.onObjectMatched, this); @@ -211,7 +211,7 @@ Our last piece to fit the puzzle together is the detail view. We replace the app ```xml <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Page diff --git a/packages/walkthrough/steps/31/package.json b/packages/walkthrough/steps/31/package.json index 085d5112b..95596308b 100644 --- a/packages/walkthrough/steps/31/package.json +++ b/packages/walkthrough/steps/31/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step31", + "name": "ui5.tutorial.walkthrough.step31", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 31 - Routing with Parameters", diff --git a/packages/walkthrough/steps/31/tsconfig.json b/packages/walkthrough/steps/31/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/31/tsconfig.json +++ b/packages/walkthrough/steps/31/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/31/ui5.yaml b/packages/walkthrough/steps/31/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/31/ui5.yaml +++ b/packages/walkthrough/steps/31/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/31/webapp/Component.ts b/packages/walkthrough/steps/31/webapp/Component.ts index ee2eae016..3e347464b 100644 --- a/packages/walkthrough/steps/31/webapp/Component.ts +++ b/packages/walkthrough/steps/31/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/31/webapp/controller/App.controller.ts b/packages/walkthrough/steps/31/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/31/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/31/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/31/webapp/controller/Detail.controller.ts b/packages/walkthrough/steps/31/webapp/controller/Detail.controller.ts index b4c211ffa..1bba1f50b 100644 --- a/packages/walkthrough/steps/31/webapp/controller/Detail.controller.ts +++ b/packages/walkthrough/steps/31/webapp/controller/Detail.controller.ts @@ -3,7 +3,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import Route, { Route$PatternMatchedEvent } from "sap/ui/core/routing/Route"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { diff --git a/packages/walkthrough/steps/31/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/31/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/31/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/31/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/31/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/31/webapp/controller/InvoiceList.controller.ts index f571980c4..862825a09 100644 --- a/packages/walkthrough/steps/31/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/31/webapp/controller/InvoiceList.controller.ts @@ -10,7 +10,7 @@ import ObjectListItem from "sap/m/ObjectListItem"; import Context from "sap/ui/model/Context"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/31/webapp/index-cdn.html b/packages/walkthrough/steps/31/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/31/webapp/index-cdn.html +++ b/packages/walkthrough/steps/31/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/31/webapp/index.html b/packages/walkthrough/steps/31/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/31/webapp/index.html +++ b/packages/walkthrough/steps/31/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/31/webapp/localService/mockserver.ts b/packages/walkthrough/steps/31/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/31/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/31/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/31/webapp/manifest.json b/packages/walkthrough/steps/31/webapp/manifest.json index 3d46db0e6..7c3bbf8a2 100644 --- a/packages/walkthrough/steps/31/webapp/manifest.json +++ b/packages/walkthrough/steps/31/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -42,7 +42,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -50,7 +50,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -73,7 +73,7 @@ "routerClass": "sap.m.routing.Router", "type": "View", "viewType": "XML", - "path": "ui5.walkthrough.view", + "path": "ui5.tutorial.walkthrough.view", "controlId": "app", "controlAggregation": "pages" }, diff --git a/packages/walkthrough/steps/31/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/31/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/31/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/31/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/31/webapp/test/Test.qunit.html b/packages/walkthrough/steps/31/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/31/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/31/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/31/webapp/test/integration/NavigationJourney.ts b/packages/walkthrough/steps/31/webapp/test/integration/NavigationJourney.ts index 2c5a3c942..b3b7de6c5 100644 --- a/packages/walkthrough/steps/31/webapp/test/integration/NavigationJourney.ts +++ b/packages/walkthrough/steps/31/webapp/test/integration/NavigationJourney.ts @@ -10,7 +10,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/31/webapp/test/integration/pages/HelloPanelPage.ts b/packages/walkthrough/steps/31/webapp/test/integration/pages/HelloPanelPage.ts index 83e59dde1..da73c14de 100644 --- a/packages/walkthrough/steps/31/webapp/test/integration/pages/HelloPanelPage.ts +++ b/packages/walkthrough/steps/31/webapp/test/integration/pages/HelloPanelPage.ts @@ -1,7 +1,7 @@ import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions diff --git a/packages/walkthrough/steps/31/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/31/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/31/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/31/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/31/webapp/test/mockServer.html b/packages/walkthrough/steps/31/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/31/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/31/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/31/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/31/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/31/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/31/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/31/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/31/webapp/test/testsuite.cdn.qunit.ts index e158902a7..3f57245ab 100644 --- a/packages/walkthrough/steps/31/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/31/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/31/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/31/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/31/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/31/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/31/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/31/webapp/test/testsuite.qunit.ts index be9cab085..78cb8dd37 100644 --- a/packages/walkthrough/steps/31/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/31/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/31/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/31/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/31/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/31/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/31/webapp/view/App.view.xml b/packages/walkthrough/steps/31/webapp/view/App.view.xml index 11d955a8b..19804995f 100644 --- a/packages/walkthrough/steps/31/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/31/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/31/webapp/view/Detail.view.xml b/packages/walkthrough/steps/31/webapp/view/Detail.view.xml index 7040ea92d..80f7616fe 100644 --- a/packages/walkthrough/steps/31/webapp/view/Detail.view.xml +++ b/packages/walkthrough/steps/31/webapp/view/Detail.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Page diff --git a/packages/walkthrough/steps/31/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/31/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/31/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/31/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/31/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/31/webapp/view/InvoiceList.view.xml index a458ffcb2..aa485b948 100644 --- a/packages/walkthrough/steps/31/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/31/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -44,7 +44,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/31/webapp/view/Overview.view.xml b/packages/walkthrough/steps/31/webapp/view/Overview.view.xml index d278a7c41..07c835e92 100644 --- a/packages/walkthrough/steps/31/webapp/view/Overview.view.xml +++ b/packages/walkthrough/steps/31/webapp/view/Overview.view.xml @@ -1,12 +1,12 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </mvc:View> \ No newline at end of file diff --git a/packages/walkthrough/steps/32/README.md b/packages/walkthrough/steps/32/README.md index edc6bb0a5..0630152de 100644 --- a/packages/walkthrough/steps/32/README.md +++ b/packages/walkthrough/steps/32/README.md @@ -49,7 +49,7 @@ import History from "sap/ui/core/routing/History"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { @@ -74,7 +74,7 @@ export default class Detail extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller", "sap/ui/core/routing/History", "sap/ui/core/UIComponent"], function (Controller, History, UIComponent) { "use strict"; - const Detail = Controller.extend("ui5.walkthrough.controller.Detail", { + const Detail = Controller.extend("ui5.tutorial.walkthrough.controller.Detail", { //... onNavBack() { const history = History.getInstance(); @@ -100,7 +100,7 @@ Now only the back button is missing on the detail page. We do this by telling th ```xml <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Page diff --git a/packages/walkthrough/steps/32/package.json b/packages/walkthrough/steps/32/package.json index 9847acc0e..fc1650639 100644 --- a/packages/walkthrough/steps/32/package.json +++ b/packages/walkthrough/steps/32/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step32", + "name": "ui5.tutorial.walkthrough.step32", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 32 - Routing Back and History", diff --git a/packages/walkthrough/steps/32/tsconfig.json b/packages/walkthrough/steps/32/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/32/tsconfig.json +++ b/packages/walkthrough/steps/32/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/32/ui5.yaml b/packages/walkthrough/steps/32/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/32/ui5.yaml +++ b/packages/walkthrough/steps/32/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/32/webapp/Component.ts b/packages/walkthrough/steps/32/webapp/Component.ts index ee2eae016..3e347464b 100644 --- a/packages/walkthrough/steps/32/webapp/Component.ts +++ b/packages/walkthrough/steps/32/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/32/webapp/controller/App.controller.ts b/packages/walkthrough/steps/32/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/32/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/32/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/32/webapp/controller/Detail.controller.ts b/packages/walkthrough/steps/32/webapp/controller/Detail.controller.ts index 6373e005a..cb7d570a2 100644 --- a/packages/walkthrough/steps/32/webapp/controller/Detail.controller.ts +++ b/packages/walkthrough/steps/32/webapp/controller/Detail.controller.ts @@ -4,7 +4,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import Route, { Route$PatternMatchedEvent } from "sap/ui/core/routing/Route"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { diff --git a/packages/walkthrough/steps/32/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/32/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/32/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/32/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/32/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/32/webapp/controller/InvoiceList.controller.ts index a0b8a86a7..64f9d0cc0 100644 --- a/packages/walkthrough/steps/32/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/32/webapp/controller/InvoiceList.controller.ts @@ -10,7 +10,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import Context from "sap/ui/model/Context"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/32/webapp/index-cdn.html b/packages/walkthrough/steps/32/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/32/webapp/index-cdn.html +++ b/packages/walkthrough/steps/32/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/32/webapp/index.html b/packages/walkthrough/steps/32/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/32/webapp/index.html +++ b/packages/walkthrough/steps/32/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/32/webapp/localService/mockserver.ts b/packages/walkthrough/steps/32/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/32/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/32/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/32/webapp/manifest.json b/packages/walkthrough/steps/32/webapp/manifest.json index 2ab83e865..013e191d5 100644 --- a/packages/walkthrough/steps/32/webapp/manifest.json +++ b/packages/walkthrough/steps/32/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -42,7 +42,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -50,7 +50,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -73,7 +73,7 @@ "routerClass": "sap.m.routing.Router", "type": "View", "viewType": "XML", - "path": "ui5.walkthrough.view", + "path": "ui5.tutorial.walkthrough.view", "controlId": "app", "controlAggregation": "pages" }, diff --git a/packages/walkthrough/steps/32/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/32/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/32/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/32/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/32/webapp/test/Test.qunit.html b/packages/walkthrough/steps/32/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/32/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/32/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/32/webapp/test/integration/NavigationJourney.ts b/packages/walkthrough/steps/32/webapp/test/integration/NavigationJourney.ts index 2c5a3c942..b3b7de6c5 100644 --- a/packages/walkthrough/steps/32/webapp/test/integration/NavigationJourney.ts +++ b/packages/walkthrough/steps/32/webapp/test/integration/NavigationJourney.ts @@ -10,7 +10,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/32/webapp/test/integration/pages/HelloPanelPage.ts b/packages/walkthrough/steps/32/webapp/test/integration/pages/HelloPanelPage.ts index 83e59dde1..da73c14de 100644 --- a/packages/walkthrough/steps/32/webapp/test/integration/pages/HelloPanelPage.ts +++ b/packages/walkthrough/steps/32/webapp/test/integration/pages/HelloPanelPage.ts @@ -1,7 +1,7 @@ import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions diff --git a/packages/walkthrough/steps/32/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/32/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/32/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/32/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/32/webapp/test/mockServer.html b/packages/walkthrough/steps/32/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/32/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/32/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/32/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/32/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/32/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/32/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/32/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/32/webapp/test/testsuite.cdn.qunit.ts index e158902a7..3f57245ab 100644 --- a/packages/walkthrough/steps/32/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/32/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/32/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/32/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/32/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/32/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/32/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/32/webapp/test/testsuite.qunit.ts index be9cab085..78cb8dd37 100644 --- a/packages/walkthrough/steps/32/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/32/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/32/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/32/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/32/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/32/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/32/webapp/view/App.view.xml b/packages/walkthrough/steps/32/webapp/view/App.view.xml index 11d955a8b..19804995f 100644 --- a/packages/walkthrough/steps/32/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/32/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/32/webapp/view/Detail.view.xml b/packages/walkthrough/steps/32/webapp/view/Detail.view.xml index abab995fa..66c0300b4 100644 --- a/packages/walkthrough/steps/32/webapp/view/Detail.view.xml +++ b/packages/walkthrough/steps/32/webapp/view/Detail.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Page diff --git a/packages/walkthrough/steps/32/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/32/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/32/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/32/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/32/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/32/webapp/view/InvoiceList.view.xml index a458ffcb2..aa485b948 100644 --- a/packages/walkthrough/steps/32/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/32/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -44,7 +44,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/32/webapp/view/Overview.view.xml b/packages/walkthrough/steps/32/webapp/view/Overview.view.xml index d278a7c41..07c835e92 100644 --- a/packages/walkthrough/steps/32/webapp/view/Overview.view.xml +++ b/packages/walkthrough/steps/32/webapp/view/Overview.view.xml @@ -1,12 +1,12 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </mvc:View> \ No newline at end of file diff --git a/packages/walkthrough/steps/33/README.md b/packages/walkthrough/steps/33/README.md index 2420fe53c..472cd3ccb 100644 --- a/packages/walkthrough/steps/33/README.md +++ b/packages/walkthrough/steps/33/README.md @@ -87,7 +87,7 @@ The `init` function is a lifecycle function that is automatically called by the The static `renderer` property expects an object that defines how the control is rendered. It is invoked initially by the OpenUI5 framework and each time a property of the control is changed. The `renderer` object has two properties: `apiVersion` and `render`. The `apiVersion` property specifies the API version of the RenderManager that is used in this renderer. The `render` property is a method that takes two parameters: a `RenderManager` object and the control instance itself. We'll delve into the implementation of our control's rendering within this method at a later stage. -> 📝 **Note:** <br> +> :note: > The RenderManager is an important component in OpenUI5 that is responsible for converting abstract representations of controls into actual HTML elements that can be displayed in the browser. There are different versions of the RenderManager API, each representing an evolution of the RenderManager with specific sets of APIs and rendering techniques. These different API versions are important to ensure compatibility between different versions of OpenUI5. > > The latest version of the RenderManager API is version 4, which introduces new features and improvements compared to previous versions. It also includes performance enhancements, making your applications run faster and more efficiently. For example, version 4 avoids re-rendering of child controls unless they are invalidated, which can save processing time. @@ -99,7 +99,7 @@ import Control from "sap/ui/core/Control"; import RenderManager from "sap/ui/core/RenderManager"; /** - * @namespace ui5.walkthrough.control + * @namespace ui5.tutorial.walkthrough.control */ export default class ProductRating extends Control { @@ -123,7 +123,7 @@ export default class ProductRating extends Control { sap.ui.define(["sap/ui/core/Control"], function (Control) { "use strict"; - const ProductRating = Control.extend("ui5.walkthrough.control.ProductRating", { + const ProductRating = Control.extend("ui5.tutorial.walkthrough.control.ProductRating", { renderer: { apiVersion: 4, render: (rm, control) => { } @@ -137,7 +137,7 @@ sap.ui.define(["sap/ui/core/Control"], function (Control) { ```   -> 📌 **Remember:** <br> +> :info: > Controls always extend `sap.ui.core.Control` and render themselves. You could also extend `sap.ui.core.Element` or `sap.ui.base.ManagedObject` directly if you want to reuse life cycle features of OpenUI5 including data binding for objects that are not rendered. Please refer to the API reference to learn more about the inheritance hierarchy of controls. We now enhance our new custom control with the custom functionality that we need. In our case we want to create an interactive product rating feature. We utilize three controls provided by the sap.m library to compose our custom control: A `RatingIndicator` control to collect user input on a product, a `Label` control to display additional information, and a `Button` control that allows users to submit their rating. @@ -152,7 +152,7 @@ In the `metadata` section we therefore define several properties that we make us As described in the first paragraph, we need three internal controls to realize our rating functionality. We therefore create three “hidden aggregations” by setting the `visibility` attribute to `hidden`. This way, we can use the models that are set on the view also in the inner controls and OpenUI5 will take care of the lifecycle management and destroy the controls when they are not needed anymore. Aggregations can also be used to hold arrays of controls but we just want a single control in each of the aggregations so we need to adjust the cardinality by setting the attribute `multiple` to `false`. - > 📝 **Note:** <br> + > :note: > You can define `aggregations` and `associations` > > - An **`aggregation`** is a strong relation that also manages the lifecycle of the related control, for example, when the parent is destroyed, the related control is also destroyed. Also, a control can only be assigned to one single aggregation, if it is assigned to a second aggregation, it is removed from the previous aggregation automatically. @@ -167,7 +167,7 @@ In the `init` function we instantiate the three controls and store them in the i Let’s ignore the other internal helper functions and event handlers for now and define our renderer. By using the APIs of the RenderManager and the control instance that are passed as references, we can describe the necessary HTML for our control. To open a new HTML tag we use the `openStart` method and pass `"div"` as the HTML element to be created. We also pass our control instance (ProductRating) to be associated with the HTML tag. The RenderManager will automatically generate the properties for the control and assign it to the `div` tag. After calling `openStart`, we can chain additional methods to set attributes or styles for the element. To set our custom CSS class `myAppDemoWTProductRating` for the `div` element, we use the `class` method. If a `tooltip` exists, we call the `attr` method to set the `title` attribute with the value of the tooltip for the div element. Finally, we close the surrounding `div` tag by calling `openEnd`. -> 📌 **Remember:** <br> +> :info: > Since our custom control extends the `sap.ui.core.Control` class, it also inherits its properties and aggregations from it. In this case, the `tooltip` property is defined in the `sap.ui.core.Element` class, which is inherited by the `sap.ui.core.Control` class. Therefore, your custom control also inherits this aggregation. However, controls must explicitly support tooltips as they have to render them. Next, we render the three child controls we defined in the aggregation of our ProductRating control. We retrieve the child controls using the `getAggregation` method with the aggregation name as the parameter. The `renderControl` method is then called on each child control to render them. Finally, we close the element by calling the `close` method on the RenderManager and passing the `"div"` element name as argument. This completes the rendering of the custom control. @@ -191,7 +191,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import ResourceModel from "sap/ui/model/resource/ResourceModel"; /** - * @namespace ui5.walkthrough.control + * @namespace ui5.tutorial.walkthrough.control */ export default class ProductRating extends Control { // The following three lines were generated and should remain as-is to make TypeScript aware of the constructor signatures @@ -308,7 +308,7 @@ export default class ProductRating extends Control { sap.ui.define(["sap/ui/core/Control", "sap/m/Label", "sap/m/Button", "sap/m/RatingIndicator"], function (Control, Label, Button, RatingIndicator) { "use strict"; - const ProductRating = Control.extend("ui5.walkthrough.control.ProductRating", { + const ProductRating = Control.extend("ui5.tutorial.walkthrough.control.ProductRating", { renderer: { apiVersion: 4, render: (rm, control) => { @@ -448,7 +448,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { @@ -492,7 +492,7 @@ export default class Detail extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller", "sap/ui/core/routing/History", "sap/m/MessageToast", "sap/ui/core/UIComponent"], function (Controller, History, MessageToast, UIComponent) { "use strict"; - const Detail = Controller.extend("ui5.walkthrough.controller.Detail", { + const Detail = Controller.extend("ui5.tutorial.walkthrough.controller.Detail", { onInit() { const router = UIComponent.getRouterFor(this); router.getRoute("detail").attachPatternMatched(this.onObjectMatched, this); @@ -531,10 +531,10 @@ All we need now is to add our new control to the detail view. To do so we must a ```xml <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" - xmlns:wt="ui5.walkthrough.control"> + xmlns:wt="ui5.tutorial.walkthrough.control"> <Page title="{i18n>detailPageTitle}" showNavButton="true" @@ -584,7 +584,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import ResourceModel from "sap/ui/model/resource/ResourceModel"; /** - * @namespace ui5.walkthrough.control + * @namespace ui5.tutorial.walkthrough.control */ export default class ProductRating extends Control { // The following three lines were generated and should remain as-is to make TypeScript aware of the constructor signatures diff --git a/packages/walkthrough/steps/33/package.json b/packages/walkthrough/steps/33/package.json index 19cab2cfd..cd6ae0cfa 100644 --- a/packages/walkthrough/steps/33/package.json +++ b/packages/walkthrough/steps/33/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step33", + "name": "ui5.tutorial.walkthrough.step33", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 33 - Custom Controls", diff --git a/packages/walkthrough/steps/33/tsconfig.json b/packages/walkthrough/steps/33/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/33/tsconfig.json +++ b/packages/walkthrough/steps/33/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/33/ui5.yaml b/packages/walkthrough/steps/33/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/33/ui5.yaml +++ b/packages/walkthrough/steps/33/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/33/webapp/Component.ts b/packages/walkthrough/steps/33/webapp/Component.ts index ee2eae016..3e347464b 100644 --- a/packages/walkthrough/steps/33/webapp/Component.ts +++ b/packages/walkthrough/steps/33/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/33/webapp/control/ProductRating.ts b/packages/walkthrough/steps/33/webapp/control/ProductRating.ts index 0c209935f..9fd3f3a55 100644 --- a/packages/walkthrough/steps/33/webapp/control/ProductRating.ts +++ b/packages/walkthrough/steps/33/webapp/control/ProductRating.ts @@ -8,7 +8,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import ResourceModel from "sap/ui/model/resource/ResourceModel"; /** - * @namespace ui5.walkthrough.control + * @namespace ui5.tutorial.walkthrough.control */ export default class ProductRating extends Control { // The following three lines were generated and should remain as-is to make TypeScript aware of the constructor signatures diff --git a/packages/walkthrough/steps/33/webapp/controller/App.controller.ts b/packages/walkthrough/steps/33/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/33/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/33/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/33/webapp/controller/Detail.controller.ts b/packages/walkthrough/steps/33/webapp/controller/Detail.controller.ts index cf895c407..5eb485b26 100644 --- a/packages/walkthrough/steps/33/webapp/controller/Detail.controller.ts +++ b/packages/walkthrough/steps/33/webapp/controller/Detail.controller.ts @@ -8,7 +8,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { diff --git a/packages/walkthrough/steps/33/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/33/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/33/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/33/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/33/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/33/webapp/controller/InvoiceList.controller.ts index a0b8a86a7..64f9d0cc0 100644 --- a/packages/walkthrough/steps/33/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/33/webapp/controller/InvoiceList.controller.ts @@ -10,7 +10,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import Context from "sap/ui/model/Context"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/33/webapp/index-cdn.html b/packages/walkthrough/steps/33/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/33/webapp/index-cdn.html +++ b/packages/walkthrough/steps/33/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/33/webapp/index.html b/packages/walkthrough/steps/33/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/33/webapp/index.html +++ b/packages/walkthrough/steps/33/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/33/webapp/localService/mockserver.ts b/packages/walkthrough/steps/33/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/33/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/33/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/33/webapp/manifest.json b/packages/walkthrough/steps/33/webapp/manifest.json index 3d46db0e6..7c3bbf8a2 100644 --- a/packages/walkthrough/steps/33/webapp/manifest.json +++ b/packages/walkthrough/steps/33/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -42,7 +42,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -50,7 +50,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -73,7 +73,7 @@ "routerClass": "sap.m.routing.Router", "type": "View", "viewType": "XML", - "path": "ui5.walkthrough.view", + "path": "ui5.tutorial.walkthrough.view", "controlId": "app", "controlAggregation": "pages" }, diff --git a/packages/walkthrough/steps/33/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/33/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/33/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/33/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/33/webapp/test/Test.qunit.html b/packages/walkthrough/steps/33/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/33/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/33/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/33/webapp/test/integration/NavigationJourney.ts b/packages/walkthrough/steps/33/webapp/test/integration/NavigationJourney.ts index 2c5a3c942..b3b7de6c5 100644 --- a/packages/walkthrough/steps/33/webapp/test/integration/NavigationJourney.ts +++ b/packages/walkthrough/steps/33/webapp/test/integration/NavigationJourney.ts @@ -10,7 +10,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/33/webapp/test/integration/pages/HelloPanelPage.ts b/packages/walkthrough/steps/33/webapp/test/integration/pages/HelloPanelPage.ts index 83e59dde1..da73c14de 100644 --- a/packages/walkthrough/steps/33/webapp/test/integration/pages/HelloPanelPage.ts +++ b/packages/walkthrough/steps/33/webapp/test/integration/pages/HelloPanelPage.ts @@ -1,7 +1,7 @@ import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions diff --git a/packages/walkthrough/steps/33/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/33/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/33/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/33/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/33/webapp/test/mockServer.html b/packages/walkthrough/steps/33/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/33/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/33/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/33/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/33/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/33/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/33/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/33/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/33/webapp/test/testsuite.cdn.qunit.ts index e158902a7..3f57245ab 100644 --- a/packages/walkthrough/steps/33/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/33/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/33/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/33/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/33/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/33/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/33/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/33/webapp/test/testsuite.qunit.ts index be9cab085..78cb8dd37 100644 --- a/packages/walkthrough/steps/33/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/33/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/33/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/33/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/33/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/33/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/33/webapp/view/App.view.xml b/packages/walkthrough/steps/33/webapp/view/App.view.xml index 11d955a8b..19804995f 100644 --- a/packages/walkthrough/steps/33/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/33/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/33/webapp/view/Detail.view.xml b/packages/walkthrough/steps/33/webapp/view/Detail.view.xml index 8ee825d0f..41b2222a4 100644 --- a/packages/walkthrough/steps/33/webapp/view/Detail.view.xml +++ b/packages/walkthrough/steps/33/webapp/view/Detail.view.xml @@ -1,8 +1,8 @@ <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" - xmlns:wt="ui5.walkthrough.control"> + xmlns:wt="ui5.tutorial.walkthrough.control"> <Page title="{i18n>detailPageTitle}" showNavButton="true" diff --git a/packages/walkthrough/steps/33/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/33/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/33/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/33/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/33/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/33/webapp/view/InvoiceList.view.xml index a458ffcb2..aa485b948 100644 --- a/packages/walkthrough/steps/33/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/33/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -44,7 +44,7 @@ <firstStatus> <ObjectStatus core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/33/webapp/view/Overview.view.xml b/packages/walkthrough/steps/33/webapp/view/Overview.view.xml index d278a7c41..07c835e92 100644 --- a/packages/walkthrough/steps/33/webapp/view/Overview.view.xml +++ b/packages/walkthrough/steps/33/webapp/view/Overview.view.xml @@ -1,12 +1,12 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </mvc:View> \ No newline at end of file diff --git a/packages/walkthrough/steps/34/README.md b/packages/walkthrough/steps/34/README.md index 75e9beac7..58c41d904 100644 --- a/packages/walkthrough/steps/34/README.md +++ b/packages/walkthrough/steps/34/README.md @@ -102,7 +102,7 @@ Instead of the `ObjectListItem` that we had before, we will now split the inform ```xml <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -194,7 +194,7 @@ Now we have defined our table responsively and can see the results when we decre We can see the results when we decrease the browser's screen size or open the app on a small device. -> 💡 **Tip:** <br> +> :tip: > You can test the device specific features of your app with the developer tools of your browser. For example in Google Chrome, you can emulate a tablet or a phone easily and see the effects. Some responsive options of OpenUI5 are only set initially when loading the app, so you might have to reload your page to see the results. *** diff --git a/packages/walkthrough/steps/34/package.json b/packages/walkthrough/steps/34/package.json index 8d967eb09..2967e4085 100644 --- a/packages/walkthrough/steps/34/package.json +++ b/packages/walkthrough/steps/34/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step34", + "name": "ui5.tutorial.walkthrough.step34", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 34 - Responsiveness", diff --git a/packages/walkthrough/steps/34/tsconfig.json b/packages/walkthrough/steps/34/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/34/tsconfig.json +++ b/packages/walkthrough/steps/34/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/34/ui5.yaml b/packages/walkthrough/steps/34/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/34/ui5.yaml +++ b/packages/walkthrough/steps/34/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/34/webapp/Component.ts b/packages/walkthrough/steps/34/webapp/Component.ts index ee2eae016..3e347464b 100644 --- a/packages/walkthrough/steps/34/webapp/Component.ts +++ b/packages/walkthrough/steps/34/webapp/Component.ts @@ -2,7 +2,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import JSONModel from "sap/ui/model/json/JSONModel"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/34/webapp/control/ProductRating.ts b/packages/walkthrough/steps/34/webapp/control/ProductRating.ts index 0c209935f..9fd3f3a55 100644 --- a/packages/walkthrough/steps/34/webapp/control/ProductRating.ts +++ b/packages/walkthrough/steps/34/webapp/control/ProductRating.ts @@ -8,7 +8,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import ResourceModel from "sap/ui/model/resource/ResourceModel"; /** - * @namespace ui5.walkthrough.control + * @namespace ui5.tutorial.walkthrough.control */ export default class ProductRating extends Control { // The following three lines were generated and should remain as-is to make TypeScript aware of the constructor signatures diff --git a/packages/walkthrough/steps/34/webapp/controller/App.controller.ts b/packages/walkthrough/steps/34/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/34/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/34/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/34/webapp/controller/Detail.controller.ts b/packages/walkthrough/steps/34/webapp/controller/Detail.controller.ts index cf895c407..5eb485b26 100644 --- a/packages/walkthrough/steps/34/webapp/controller/Detail.controller.ts +++ b/packages/walkthrough/steps/34/webapp/controller/Detail.controller.ts @@ -8,7 +8,7 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { diff --git a/packages/walkthrough/steps/34/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/34/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/34/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/34/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/34/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/34/webapp/controller/InvoiceList.controller.ts index a0b8a86a7..64f9d0cc0 100644 --- a/packages/walkthrough/steps/34/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/34/webapp/controller/InvoiceList.controller.ts @@ -10,7 +10,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import Context from "sap/ui/model/Context"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/34/webapp/index-cdn.html b/packages/walkthrough/steps/34/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/34/webapp/index-cdn.html +++ b/packages/walkthrough/steps/34/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/34/webapp/index.html b/packages/walkthrough/steps/34/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/34/webapp/index.html +++ b/packages/walkthrough/steps/34/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/34/webapp/localService/mockserver.ts b/packages/walkthrough/steps/34/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/34/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/34/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/34/webapp/manifest.json b/packages/walkthrough/steps/34/webapp/manifest.json index 3d46db0e6..7c3bbf8a2 100644 --- a/packages/walkthrough/steps/34/webapp/manifest.json +++ b/packages/walkthrough/steps/34/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -42,7 +42,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -50,7 +50,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -73,7 +73,7 @@ "routerClass": "sap.m.routing.Router", "type": "View", "viewType": "XML", - "path": "ui5.walkthrough.view", + "path": "ui5.tutorial.walkthrough.view", "controlId": "app", "controlAggregation": "pages" }, diff --git a/packages/walkthrough/steps/34/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/34/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/34/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/34/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/34/webapp/test/Test.qunit.html b/packages/walkthrough/steps/34/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/34/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/34/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/34/webapp/test/integration/NavigationJourney.ts b/packages/walkthrough/steps/34/webapp/test/integration/NavigationJourney.ts index 2c5a3c942..b3b7de6c5 100644 --- a/packages/walkthrough/steps/34/webapp/test/integration/NavigationJourney.ts +++ b/packages/walkthrough/steps/34/webapp/test/integration/NavigationJourney.ts @@ -10,7 +10,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/34/webapp/test/integration/pages/HelloPanelPage.ts b/packages/walkthrough/steps/34/webapp/test/integration/pages/HelloPanelPage.ts index 83e59dde1..da73c14de 100644 --- a/packages/walkthrough/steps/34/webapp/test/integration/pages/HelloPanelPage.ts +++ b/packages/walkthrough/steps/34/webapp/test/integration/pages/HelloPanelPage.ts @@ -1,7 +1,7 @@ import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions diff --git a/packages/walkthrough/steps/34/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/34/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/34/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/34/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/34/webapp/test/mockServer.html b/packages/walkthrough/steps/34/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/34/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/34/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/34/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/34/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/34/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/34/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/34/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/34/webapp/test/testsuite.cdn.qunit.ts index e158902a7..3f57245ab 100644 --- a/packages/walkthrough/steps/34/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/34/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/34/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/34/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/34/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/34/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/34/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/34/webapp/test/testsuite.qunit.ts index be9cab085..78cb8dd37 100644 --- a/packages/walkthrough/steps/34/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/34/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/34/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/34/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/34/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/34/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/34/webapp/view/App.view.xml b/packages/walkthrough/steps/34/webapp/view/App.view.xml index 11d955a8b..19804995f 100644 --- a/packages/walkthrough/steps/34/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/34/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/34/webapp/view/Detail.view.xml b/packages/walkthrough/steps/34/webapp/view/Detail.view.xml index 8ee825d0f..41b2222a4 100644 --- a/packages/walkthrough/steps/34/webapp/view/Detail.view.xml +++ b/packages/walkthrough/steps/34/webapp/view/Detail.view.xml @@ -1,8 +1,8 @@ <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" - xmlns:wt="ui5.walkthrough.control"> + xmlns:wt="ui5.tutorial.walkthrough.control"> <Page title="{i18n>detailPageTitle}" showNavButton="true" diff --git a/packages/walkthrough/steps/34/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/34/webapp/view/HelloPanel.view.xml index 161d6074d..531ffdae0 100644 --- a/packages/walkthrough/steps/34/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/34/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/34/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/34/webapp/view/InvoiceList.view.xml index c08ca3d36..0e517a5a6 100644 --- a/packages/walkthrough/steps/34/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/34/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -58,7 +58,7 @@ title="{invoice>ProductName}"/> <Text core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/34/webapp/view/Overview.view.xml b/packages/walkthrough/steps/34/webapp/view/Overview.view.xml index d278a7c41..07c835e92 100644 --- a/packages/walkthrough/steps/34/webapp/view/Overview.view.xml +++ b/packages/walkthrough/steps/34/webapp/view/Overview.view.xml @@ -1,12 +1,12 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </mvc:View> \ No newline at end of file diff --git a/packages/walkthrough/steps/35/README.md b/packages/walkthrough/steps/35/README.md index 5ec13799c..27f19d937 100644 --- a/packages/walkthrough/steps/35/README.md +++ b/packages/walkthrough/steps/35/README.md @@ -34,7 +34,7 @@ You can download the solution for this step here: [📥 Download step 35](https: In the `app` component we import the `Device` module from the `sap.ui` namespace and initialize the device model in the `init` method. We can simply pass the loaded dependency `Device` to the constructor function of the JSONModel. This will make most properties of the OpenUI5 device API available as a JSON model. The model is then set on the component as a named model so that we can reference it in data binding. -> 📌 **Important:** <br> +> :info: > We have to set the binding mode to `OneWay` as the device model is read-only and we want to avoid changing the model accidentally when we bind properties of a control to it. By default, models in OpenUI5 are bidirectional \(`TwoWay`\). When the property changes, the bound model value is updated as well. ```ts @@ -43,7 +43,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import Device from "sap/ui/Device"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { @@ -79,7 +79,7 @@ export default class Component extends UIComponent { sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/model/json/JSONModel", "sap/ui/Device"], function (UIComponent, JSONModel, Device) { "use strict"; - const Component = UIComponent.extend("ui5.walkthrough.Component", { + const Component = UIComponent.extend("ui5.tutorial.walkthrough.Component", { metadata: { "interfaces": ["sap.ui.core.IAsyncContentCreation"], "manifest": "json" @@ -120,7 +120,7 @@ We can also hide single controls by device type when we set a CSS class like `sa ```xml <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel @@ -154,7 +154,7 @@ We can also hide single controls by device type when we set a CSS class like `sa   The device API of OpenUI5 offers more functionality to detect various device-specific settings, please have a look at the [documentation](https://sdk.openui5.org/api/sap.ui.Device) for more details. -> 📌 **Important:** <br> +> :info: > The `sap.ui.Device` API detects the device type \(Phone, Tablet, Desktop\) based on the user agent and many other properties of the device. Therefore simply reducing the screen size will not change the device type. To test this feature, you will have to enable device emulation in your browser or open it on a real device. ### webapp/controller/Detail.controller.?s @@ -173,7 +173,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { @@ -195,7 +195,7 @@ export default class Detail extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller", "sap/ui/core/routing/History", "sap/m/MessageToast", "sap/ui/model/json/JSONModel", "sap/ui/core/UIComponent"], function (Controller, History, MessageToast, JSONModel, UIComponent) { "use strict"; - const Detail = Controller.extend("ui5.walkthrough.controller.Detail", { + const Detail = Controller.extend("ui5.tutorial.walkthrough.controller.Detail", { onInit() { const viewModel = new JSONModel({ currency: "EUR" @@ -231,11 +231,11 @@ We add the `number` and `numberUnit` field from the list of the previous steps a ```xml <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" - xmlns:wt="ui5.walkthrough.control"> + xmlns:wt="ui5.tutorial.walkthrough.control"> <Page title="{i18n>detailPageTitle}" showNavButton="true" @@ -290,7 +290,7 @@ We add the `number` and `numberUnit` field from the list of the previous steps a We can see the results when we decrease the browser's screen size or open the app on a small device. -> 📝 **Note:** <br> +> :note: > You can test the device specific features of your app with the developer tools of your browser. For example in Google Chrome, you can emulate a tablet or a phone easily and see the effects. Some responsive options of OpenUI5 are only set initially when loading the app, so you might have to reload your page to see the results. *** diff --git a/packages/walkthrough/steps/35/package.json b/packages/walkthrough/steps/35/package.json index a477f12ad..8a50fcc7d 100644 --- a/packages/walkthrough/steps/35/package.json +++ b/packages/walkthrough/steps/35/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step35", + "name": "ui5.tutorial.walkthrough.step35", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 35 - Device Adaptation", diff --git a/packages/walkthrough/steps/35/tsconfig.json b/packages/walkthrough/steps/35/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/35/tsconfig.json +++ b/packages/walkthrough/steps/35/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/35/ui5.yaml b/packages/walkthrough/steps/35/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/35/ui5.yaml +++ b/packages/walkthrough/steps/35/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/35/webapp/Component.ts b/packages/walkthrough/steps/35/webapp/Component.ts index d128a0575..d294bc3fb 100644 --- a/packages/walkthrough/steps/35/webapp/Component.ts +++ b/packages/walkthrough/steps/35/webapp/Component.ts @@ -3,7 +3,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import Device from "sap/ui/Device"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/35/webapp/control/ProductRating.ts b/packages/walkthrough/steps/35/webapp/control/ProductRating.ts index 0c209935f..9fd3f3a55 100644 --- a/packages/walkthrough/steps/35/webapp/control/ProductRating.ts +++ b/packages/walkthrough/steps/35/webapp/control/ProductRating.ts @@ -8,7 +8,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import ResourceModel from "sap/ui/model/resource/ResourceModel"; /** - * @namespace ui5.walkthrough.control + * @namespace ui5.tutorial.walkthrough.control */ export default class ProductRating extends Control { // The following three lines were generated and should remain as-is to make TypeScript aware of the constructor signatures diff --git a/packages/walkthrough/steps/35/webapp/controller/App.controller.ts b/packages/walkthrough/steps/35/webapp/controller/App.controller.ts index 784f02a7f..f1e84f6cb 100644 --- a/packages/walkthrough/steps/35/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/35/webapp/controller/App.controller.ts @@ -1,7 +1,7 @@ import Controller from "sap/ui/core/mvc/Controller"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { diff --git a/packages/walkthrough/steps/35/webapp/controller/Detail.controller.ts b/packages/walkthrough/steps/35/webapp/controller/Detail.controller.ts index e829892ce..5200e6595 100644 --- a/packages/walkthrough/steps/35/webapp/controller/Detail.controller.ts +++ b/packages/walkthrough/steps/35/webapp/controller/Detail.controller.ts @@ -9,7 +9,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { diff --git a/packages/walkthrough/steps/35/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/35/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/35/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/35/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/35/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/35/webapp/controller/InvoiceList.controller.ts index a0b8a86a7..64f9d0cc0 100644 --- a/packages/walkthrough/steps/35/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/35/webapp/controller/InvoiceList.controller.ts @@ -10,7 +10,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import Context from "sap/ui/model/Context"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/35/webapp/index-cdn.html b/packages/walkthrough/steps/35/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/35/webapp/index-cdn.html +++ b/packages/walkthrough/steps/35/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/35/webapp/index.html b/packages/walkthrough/steps/35/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/35/webapp/index.html +++ b/packages/walkthrough/steps/35/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/35/webapp/localService/mockserver.ts b/packages/walkthrough/steps/35/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/35/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/35/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/35/webapp/manifest.json b/packages/walkthrough/steps/35/webapp/manifest.json index 3d46db0e6..7c3bbf8a2 100644 --- a/packages/walkthrough/steps/35/webapp/manifest.json +++ b/packages/walkthrough/steps/35/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -42,7 +42,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -50,7 +50,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -73,7 +73,7 @@ "routerClass": "sap.m.routing.Router", "type": "View", "viewType": "XML", - "path": "ui5.walkthrough.view", + "path": "ui5.tutorial.walkthrough.view", "controlId": "app", "controlAggregation": "pages" }, diff --git a/packages/walkthrough/steps/35/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/35/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/35/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/35/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/35/webapp/test/Test.qunit.html b/packages/walkthrough/steps/35/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/35/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/35/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/35/webapp/test/integration/NavigationJourney.ts b/packages/walkthrough/steps/35/webapp/test/integration/NavigationJourney.ts index 2c5a3c942..b3b7de6c5 100644 --- a/packages/walkthrough/steps/35/webapp/test/integration/NavigationJourney.ts +++ b/packages/walkthrough/steps/35/webapp/test/integration/NavigationJourney.ts @@ -10,7 +10,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/35/webapp/test/integration/pages/HelloPanelPage.ts b/packages/walkthrough/steps/35/webapp/test/integration/pages/HelloPanelPage.ts index 83e59dde1..da73c14de 100644 --- a/packages/walkthrough/steps/35/webapp/test/integration/pages/HelloPanelPage.ts +++ b/packages/walkthrough/steps/35/webapp/test/integration/pages/HelloPanelPage.ts @@ -1,7 +1,7 @@ import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions diff --git a/packages/walkthrough/steps/35/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/35/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/35/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/35/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/35/webapp/test/mockServer.html b/packages/walkthrough/steps/35/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/35/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/35/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/35/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/35/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/35/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/35/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/35/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/35/webapp/test/testsuite.cdn.qunit.ts index e158902a7..3f57245ab 100644 --- a/packages/walkthrough/steps/35/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/35/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/35/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/35/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/35/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/35/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/35/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/35/webapp/test/testsuite.qunit.ts index be9cab085..78cb8dd37 100644 --- a/packages/walkthrough/steps/35/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/35/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/35/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/35/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/35/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/35/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/35/webapp/view/App.view.xml b/packages/walkthrough/steps/35/webapp/view/App.view.xml index 11d955a8b..19804995f 100644 --- a/packages/walkthrough/steps/35/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/35/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/35/webapp/view/Detail.view.xml b/packages/walkthrough/steps/35/webapp/view/Detail.view.xml index 172befcbd..559cff076 100644 --- a/packages/walkthrough/steps/35/webapp/view/Detail.view.xml +++ b/packages/walkthrough/steps/35/webapp/view/Detail.view.xml @@ -1,9 +1,9 @@ <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" - xmlns:wt="ui5.walkthrough.control"> + xmlns:wt="ui5.tutorial.walkthrough.control"> <Page title="{i18n>detailPageTitle}" showNavButton="true" diff --git a/packages/walkthrough/steps/35/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/35/webapp/view/HelloPanel.view.xml index 6ad4df9cd..0618bd177 100644 --- a/packages/walkthrough/steps/35/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/35/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/35/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/35/webapp/view/InvoiceList.view.xml index 268e28b72..bbc918a55 100644 --- a/packages/walkthrough/steps/35/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/35/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -58,7 +58,7 @@ title="{invoice>ProductName}"/> <Text core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/35/webapp/view/Overview.view.xml b/packages/walkthrough/steps/35/webapp/view/Overview.view.xml index d278a7c41..07c835e92 100644 --- a/packages/walkthrough/steps/35/webapp/view/Overview.view.xml +++ b/packages/walkthrough/steps/35/webapp/view/Overview.view.xml @@ -1,12 +1,12 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </mvc:View> \ No newline at end of file diff --git a/packages/walkthrough/steps/36/README.md b/packages/walkthrough/steps/36/README.md index 1c801c4fb..276d2cc5a 100644 --- a/packages/walkthrough/steps/36/README.md +++ b/packages/walkthrough/steps/36/README.md @@ -42,7 +42,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import Device from "sap/ui/Device"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { @@ -65,7 +65,7 @@ export default class Component extends UIComponent { sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/model/json/JSONModel", "sap/ui/Device"], function (UIComponent, JSONModel, Device) { "use strict"; - const Component = UIComponent.extend("ui5.walkthrough.Component", { + const Component = UIComponent.extend("ui5.tutorial.walkthrough.Component", { metadata: { "interfaces": ["sap.ui.core.IAsyncContentCreation"], "manifest": "json" @@ -93,7 +93,7 @@ import Controller from "sap/ui/core/mvc/Controller"; import Component from "../Component"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { @@ -107,7 +107,7 @@ export default class App extends Controller { sap.ui.define(["sap/ui/core/mvc/Controller"], function (Controller) { "use strict"; - const App = Controller.extend("ui5.walkthrough.controller.App", { + const App = Controller.extend("ui5.tutorial.walkthrough.controller.App", { onInit() { this.getView().addStyleClass(this.getOwnerComponent().getContentDensityClass()); } diff --git a/packages/walkthrough/steps/36/package.json b/packages/walkthrough/steps/36/package.json index 66fb108a6..fb293d148 100644 --- a/packages/walkthrough/steps/36/package.json +++ b/packages/walkthrough/steps/36/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step36", + "name": "ui5.tutorial.walkthrough.step36", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 36 - Content Density", diff --git a/packages/walkthrough/steps/36/tsconfig.json b/packages/walkthrough/steps/36/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/36/tsconfig.json +++ b/packages/walkthrough/steps/36/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/36/ui5.yaml b/packages/walkthrough/steps/36/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/36/ui5.yaml +++ b/packages/walkthrough/steps/36/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/36/webapp/Component.ts b/packages/walkthrough/steps/36/webapp/Component.ts index 16c6384be..0de22e3df 100644 --- a/packages/walkthrough/steps/36/webapp/Component.ts +++ b/packages/walkthrough/steps/36/webapp/Component.ts @@ -3,7 +3,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import Device from "sap/ui/Device"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/36/webapp/control/ProductRating.ts b/packages/walkthrough/steps/36/webapp/control/ProductRating.ts index 0c209935f..9fd3f3a55 100644 --- a/packages/walkthrough/steps/36/webapp/control/ProductRating.ts +++ b/packages/walkthrough/steps/36/webapp/control/ProductRating.ts @@ -8,7 +8,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import ResourceModel from "sap/ui/model/resource/ResourceModel"; /** - * @namespace ui5.walkthrough.control + * @namespace ui5.tutorial.walkthrough.control */ export default class ProductRating extends Control { // The following three lines were generated and should remain as-is to make TypeScript aware of the constructor signatures diff --git a/packages/walkthrough/steps/36/webapp/controller/App.controller.ts b/packages/walkthrough/steps/36/webapp/controller/App.controller.ts index 01b9915b8..3fcbe0779 100644 --- a/packages/walkthrough/steps/36/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/36/webapp/controller/App.controller.ts @@ -2,7 +2,7 @@ import Controller from "sap/ui/core/mvc/Controller"; import Component from "../Component"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/36/webapp/controller/Detail.controller.ts b/packages/walkthrough/steps/36/webapp/controller/Detail.controller.ts index e829892ce..5200e6595 100644 --- a/packages/walkthrough/steps/36/webapp/controller/Detail.controller.ts +++ b/packages/walkthrough/steps/36/webapp/controller/Detail.controller.ts @@ -9,7 +9,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { diff --git a/packages/walkthrough/steps/36/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/36/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/36/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/36/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/36/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/36/webapp/controller/InvoiceList.controller.ts index a0b8a86a7..64f9d0cc0 100644 --- a/packages/walkthrough/steps/36/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/36/webapp/controller/InvoiceList.controller.ts @@ -10,7 +10,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import Context from "sap/ui/model/Context"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/36/webapp/index-cdn.html b/packages/walkthrough/steps/36/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/36/webapp/index-cdn.html +++ b/packages/walkthrough/steps/36/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/36/webapp/index.html b/packages/walkthrough/steps/36/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/36/webapp/index.html +++ b/packages/walkthrough/steps/36/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/36/webapp/localService/mockserver.ts b/packages/walkthrough/steps/36/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/36/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/36/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/36/webapp/manifest.json b/packages/walkthrough/steps/36/webapp/manifest.json index 3cbe542ba..753471a41 100644 --- a/packages/walkthrough/steps/36/webapp/manifest.json +++ b/packages/walkthrough/steps/36/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -46,7 +46,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -54,7 +54,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -77,7 +77,7 @@ "routerClass": "sap.m.routing.Router", "type": "View", "viewType": "XML", - "path": "ui5.walkthrough.view", + "path": "ui5.tutorial.walkthrough.view", "controlId": "app", "controlAggregation": "pages" }, diff --git a/packages/walkthrough/steps/36/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/36/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/36/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/36/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/36/webapp/test/Test.qunit.html b/packages/walkthrough/steps/36/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/36/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/36/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/36/webapp/test/integration/NavigationJourney.ts b/packages/walkthrough/steps/36/webapp/test/integration/NavigationJourney.ts index 2c5a3c942..b3b7de6c5 100644 --- a/packages/walkthrough/steps/36/webapp/test/integration/NavigationJourney.ts +++ b/packages/walkthrough/steps/36/webapp/test/integration/NavigationJourney.ts @@ -10,7 +10,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/36/webapp/test/integration/pages/HelloPanelPage.ts b/packages/walkthrough/steps/36/webapp/test/integration/pages/HelloPanelPage.ts index 83e59dde1..da73c14de 100644 --- a/packages/walkthrough/steps/36/webapp/test/integration/pages/HelloPanelPage.ts +++ b/packages/walkthrough/steps/36/webapp/test/integration/pages/HelloPanelPage.ts @@ -1,7 +1,7 @@ import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions diff --git a/packages/walkthrough/steps/36/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/36/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/36/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/36/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/36/webapp/test/mockServer.html b/packages/walkthrough/steps/36/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/36/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/36/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/36/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/36/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/36/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/36/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/36/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/36/webapp/test/testsuite.cdn.qunit.ts index e158902a7..3f57245ab 100644 --- a/packages/walkthrough/steps/36/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/36/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/36/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/36/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/36/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/36/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/36/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/36/webapp/test/testsuite.qunit.ts index be9cab085..78cb8dd37 100644 --- a/packages/walkthrough/steps/36/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/36/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/36/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/36/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/36/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/36/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/36/webapp/view/App.view.xml b/packages/walkthrough/steps/36/webapp/view/App.view.xml index 11d955a8b..19804995f 100644 --- a/packages/walkthrough/steps/36/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/36/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/36/webapp/view/Detail.view.xml b/packages/walkthrough/steps/36/webapp/view/Detail.view.xml index 172befcbd..559cff076 100644 --- a/packages/walkthrough/steps/36/webapp/view/Detail.view.xml +++ b/packages/walkthrough/steps/36/webapp/view/Detail.view.xml @@ -1,9 +1,9 @@ <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" - xmlns:wt="ui5.walkthrough.control"> + xmlns:wt="ui5.tutorial.walkthrough.control"> <Page title="{i18n>detailPageTitle}" showNavButton="true" diff --git a/packages/walkthrough/steps/36/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/36/webapp/view/HelloPanel.view.xml index 6ad4df9cd..0618bd177 100644 --- a/packages/walkthrough/steps/36/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/36/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/36/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/36/webapp/view/InvoiceList.view.xml index 268e28b72..bbc918a55 100644 --- a/packages/walkthrough/steps/36/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/36/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -58,7 +58,7 @@ title="{invoice>ProductName}"/> <Text core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/36/webapp/view/Overview.view.xml b/packages/walkthrough/steps/36/webapp/view/Overview.view.xml index d278a7c41..07c835e92 100644 --- a/packages/walkthrough/steps/36/webapp/view/Overview.view.xml +++ b/packages/walkthrough/steps/36/webapp/view/Overview.view.xml @@ -1,12 +1,12 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> <Page title="{i18n>homePageTitle}"> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </mvc:View> \ No newline at end of file diff --git a/packages/walkthrough/steps/37/README.md b/packages/walkthrough/steps/37/README.md index fbd90f7b7..4b60ffb6a 100644 --- a/packages/walkthrough/steps/37/README.md +++ b/packages/walkthrough/steps/37/README.md @@ -6,7 +6,7 @@ To achieve this, we will add ARIA attributes. ARIA attributes are used by screen One part of the ARIA attribute set are the so-called landmarks. You can compare landmarks to maps in that they help the user navigate through an app. For this step, we will use Google Chrome with a free [landmark navigation extension](https://chrome.google.com/webstore/detail/landmark-navigation-via-k/ddpokpbjopmeeiiolheejjpkonlkklgp) We will now add meaningful landmarks to our code. -> 💡 **Tip:** <br> +> :tip: > ARIA is short for **Accessible Rich Internet Applications**. It is a set of attributes that enable us to make apps more accessible by assigning semantic characteristics to certain elements. For more information, see [Accessible Rich Internet Applications \(ARIA\) – Part 1: Introduction](https://blogs.sap.com/2015/06/01/accessible-rich-internet-applications-aria-part-1-introduction/).   @@ -64,7 +64,7 @@ For more information, see the [API Reference: `sap.m.PageAccessibleLandmarkInfo` ```xml <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -79,8 +79,8 @@ For more information, see the [API Reference: `sap.m.PageAccessibleLandmarkInfo` headerLabel="{i18n>Overview_headerLabel}"/> </landmarkInfo> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </mvc:View> @@ -92,7 +92,7 @@ We add an `sap.m.Panel` around the invoice list and move the toolbar from the ta ```xml <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -129,7 +129,7 @@ In the `HelloPanel` view, we already have a panel, so we just add the `accessibl ```xml <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/37/package.json b/packages/walkthrough/steps/37/package.json index 0d870c1c4..aafadc62e 100644 --- a/packages/walkthrough/steps/37/package.json +++ b/packages/walkthrough/steps/37/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step37", + "name": "ui5.tutorial.walkthrough.step37", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 37 - Accessibility", diff --git a/packages/walkthrough/steps/37/tsconfig.json b/packages/walkthrough/steps/37/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/37/tsconfig.json +++ b/packages/walkthrough/steps/37/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/37/ui5.yaml b/packages/walkthrough/steps/37/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/37/ui5.yaml +++ b/packages/walkthrough/steps/37/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/37/webapp/Component.ts b/packages/walkthrough/steps/37/webapp/Component.ts index ed07cdb7c..422917681 100644 --- a/packages/walkthrough/steps/37/webapp/Component.ts +++ b/packages/walkthrough/steps/37/webapp/Component.ts @@ -3,7 +3,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import Device from "sap/ui/Device"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/37/webapp/control/ProductRating.ts b/packages/walkthrough/steps/37/webapp/control/ProductRating.ts index 0c209935f..9fd3f3a55 100644 --- a/packages/walkthrough/steps/37/webapp/control/ProductRating.ts +++ b/packages/walkthrough/steps/37/webapp/control/ProductRating.ts @@ -8,7 +8,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import ResourceModel from "sap/ui/model/resource/ResourceModel"; /** - * @namespace ui5.walkthrough.control + * @namespace ui5.tutorial.walkthrough.control */ export default class ProductRating extends Control { // The following three lines were generated and should remain as-is to make TypeScript aware of the constructor signatures diff --git a/packages/walkthrough/steps/37/webapp/controller/App.controller.ts b/packages/walkthrough/steps/37/webapp/controller/App.controller.ts index ff42e58cf..c75cc0028 100644 --- a/packages/walkthrough/steps/37/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/37/webapp/controller/App.controller.ts @@ -3,7 +3,7 @@ import Component from "../Component"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/37/webapp/controller/Detail.controller.ts b/packages/walkthrough/steps/37/webapp/controller/Detail.controller.ts index e829892ce..5200e6595 100644 --- a/packages/walkthrough/steps/37/webapp/controller/Detail.controller.ts +++ b/packages/walkthrough/steps/37/webapp/controller/Detail.controller.ts @@ -9,7 +9,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { diff --git a/packages/walkthrough/steps/37/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/37/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/37/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/37/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/37/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/37/webapp/controller/InvoiceList.controller.ts index a0b8a86a7..64f9d0cc0 100644 --- a/packages/walkthrough/steps/37/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/37/webapp/controller/InvoiceList.controller.ts @@ -10,7 +10,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import Context from "sap/ui/model/Context"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/37/webapp/index-cdn.html b/packages/walkthrough/steps/37/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/37/webapp/index-cdn.html +++ b/packages/walkthrough/steps/37/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/37/webapp/index.html b/packages/walkthrough/steps/37/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/37/webapp/index.html +++ b/packages/walkthrough/steps/37/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/37/webapp/localService/mockserver.ts b/packages/walkthrough/steps/37/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/37/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/37/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/37/webapp/manifest.json b/packages/walkthrough/steps/37/webapp/manifest.json index 7680a67e0..b03e03fe8 100644 --- a/packages/walkthrough/steps/37/webapp/manifest.json +++ b/packages/walkthrough/steps/37/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -46,7 +46,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -54,7 +54,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -77,7 +77,7 @@ "routerClass": "sap.m.routing.Router", "type": "View", "viewType": "XML", - "path": "ui5.walkthrough.view", + "path": "ui5.tutorial.walkthrough.view", "controlId": "app", "controlAggregation": "pages" }, diff --git a/packages/walkthrough/steps/37/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/37/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/37/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/37/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/37/webapp/test/Test.qunit.html b/packages/walkthrough/steps/37/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/37/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/37/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/37/webapp/test/integration/NavigationJourney.ts b/packages/walkthrough/steps/37/webapp/test/integration/NavigationJourney.ts index 2c5a3c942..b3b7de6c5 100644 --- a/packages/walkthrough/steps/37/webapp/test/integration/NavigationJourney.ts +++ b/packages/walkthrough/steps/37/webapp/test/integration/NavigationJourney.ts @@ -10,7 +10,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/37/webapp/test/integration/pages/HelloPanelPage.ts b/packages/walkthrough/steps/37/webapp/test/integration/pages/HelloPanelPage.ts index 83e59dde1..da73c14de 100644 --- a/packages/walkthrough/steps/37/webapp/test/integration/pages/HelloPanelPage.ts +++ b/packages/walkthrough/steps/37/webapp/test/integration/pages/HelloPanelPage.ts @@ -1,7 +1,7 @@ import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions diff --git a/packages/walkthrough/steps/37/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/37/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/37/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/37/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/37/webapp/test/mockServer.html b/packages/walkthrough/steps/37/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/37/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/37/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/37/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/37/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/37/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/37/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/37/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/37/webapp/test/testsuite.cdn.qunit.ts index e158902a7..3f57245ab 100644 --- a/packages/walkthrough/steps/37/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/37/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/37/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/37/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/37/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/37/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/37/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/37/webapp/test/testsuite.qunit.ts index be9cab085..78cb8dd37 100644 --- a/packages/walkthrough/steps/37/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/37/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/37/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/37/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/37/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/37/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/37/webapp/view/App.view.xml b/packages/walkthrough/steps/37/webapp/view/App.view.xml index 11d955a8b..19804995f 100644 --- a/packages/walkthrough/steps/37/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/37/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/37/webapp/view/Detail.view.xml b/packages/walkthrough/steps/37/webapp/view/Detail.view.xml index 172befcbd..559cff076 100644 --- a/packages/walkthrough/steps/37/webapp/view/Detail.view.xml +++ b/packages/walkthrough/steps/37/webapp/view/Detail.view.xml @@ -1,9 +1,9 @@ <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" - xmlns:wt="ui5.walkthrough.control"> + xmlns:wt="ui5.tutorial.walkthrough.control"> <Page title="{i18n>detailPageTitle}" showNavButton="true" diff --git a/packages/walkthrough/steps/37/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/37/webapp/view/HelloPanel.view.xml index 39256d9fa..f127330d1 100644 --- a/packages/walkthrough/steps/37/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/37/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/37/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/37/webapp/view/InvoiceList.view.xml index aec957bd9..368c702c1 100644 --- a/packages/walkthrough/steps/37/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/37/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -61,7 +61,7 @@ title="{invoice>ProductName}"/> <Text core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/37/webapp/view/Overview.view.xml b/packages/walkthrough/steps/37/webapp/view/Overview.view.xml index 577e70b47..3e468460a 100644 --- a/packages/walkthrough/steps/37/webapp/view/Overview.view.xml +++ b/packages/walkthrough/steps/37/webapp/view/Overview.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -14,8 +14,8 @@ headerLabel="{i18n>Overview_headerLabel}"/> </landmarkInfo> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </mvc:View> \ No newline at end of file diff --git a/packages/walkthrough/steps/38/README.md b/packages/walkthrough/steps/38/README.md index b6755e6ca..2c6437d38 100644 --- a/packages/walkthrough/steps/38/README.md +++ b/packages/walkthrough/steps/38/README.md @@ -35,7 +35,7 @@ Now we create a production-ready version of our OpenUI5 application that can be ```json { - "name": "ui5.walkthrough", + "name": "ui5.tutorial.walkthrough", "version": "1.0.0", "description": "OpenUI5 TypeScript Walkthrough", "private": true, @@ -67,7 +67,7 @@ To actually use the newly added web server, we have to add a new script to our ` ```json { - "name": "ui5.walkthrough", + "name": "ui5.tutorial.walkthrough", "version": "1.0.0", "description": "OpenUI5 TypeScript Walkthrough", "private": true, diff --git a/packages/walkthrough/steps/38/package.json b/packages/walkthrough/steps/38/package.json index 8a32dfb67..d2dc1b174 100644 --- a/packages/walkthrough/steps/38/package.json +++ b/packages/walkthrough/steps/38/package.json @@ -1,5 +1,5 @@ { - "name": "ui5.walkthrough.step38", + "name": "ui5.tutorial.walkthrough.step38", "version": "1.0.0", "author": "SAP SE", "description": "OpenUI5 TypeScript Walkthrough: Step 38 - Build Your Application", diff --git a/packages/walkthrough/steps/38/tsconfig.json b/packages/walkthrough/steps/38/tsconfig.json index dbbd22fc4..3b70ce1e6 100644 --- a/packages/walkthrough/steps/38/tsconfig.json +++ b/packages/walkthrough/steps/38/tsconfig.json @@ -7,7 +7,7 @@ "strictPropertyInitialization": false, "rootDir": "./webapp", "paths": { - "ui5/walkthrough/*": ["./webapp/*"] + "ui5/tutorial/walkthrough/*": ["./webapp/*"] } }, "include": ["./webapp/**/*"] diff --git a/packages/walkthrough/steps/38/ui5.yaml b/packages/walkthrough/steps/38/ui5.yaml index c847b688d..a151da62c 100644 --- a/packages/walkthrough/steps/38/ui5.yaml +++ b/packages/walkthrough/steps/38/ui5.yaml @@ -1,6 +1,6 @@ specVersion: '4.0' metadata: - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" type: application framework: name: OpenUI5 diff --git a/packages/walkthrough/steps/38/webapp/Component.ts b/packages/walkthrough/steps/38/webapp/Component.ts index ed07cdb7c..422917681 100644 --- a/packages/walkthrough/steps/38/webapp/Component.ts +++ b/packages/walkthrough/steps/38/webapp/Component.ts @@ -3,7 +3,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import Device from "sap/ui/Device"; /** - * @namespace ui5.walkthrough + * @namespace ui5.tutorial.walkthrough */ export default class Component extends UIComponent { public static metadata = { diff --git a/packages/walkthrough/steps/38/webapp/control/ProductRating.ts b/packages/walkthrough/steps/38/webapp/control/ProductRating.ts index 0c209935f..9fd3f3a55 100644 --- a/packages/walkthrough/steps/38/webapp/control/ProductRating.ts +++ b/packages/walkthrough/steps/38/webapp/control/ProductRating.ts @@ -8,7 +8,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import ResourceModel from "sap/ui/model/resource/ResourceModel"; /** - * @namespace ui5.walkthrough.control + * @namespace ui5.tutorial.walkthrough.control */ export default class ProductRating extends Control { // The following three lines were generated and should remain as-is to make TypeScript aware of the constructor signatures diff --git a/packages/walkthrough/steps/38/webapp/controller/App.controller.ts b/packages/walkthrough/steps/38/webapp/controller/App.controller.ts index 01b9915b8..3fcbe0779 100644 --- a/packages/walkthrough/steps/38/webapp/controller/App.controller.ts +++ b/packages/walkthrough/steps/38/webapp/controller/App.controller.ts @@ -2,7 +2,7 @@ import Controller from "sap/ui/core/mvc/Controller"; import Component from "../Component"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/38/webapp/controller/Detail.controller.ts b/packages/walkthrough/steps/38/webapp/controller/Detail.controller.ts index e829892ce..5200e6595 100644 --- a/packages/walkthrough/steps/38/webapp/controller/Detail.controller.ts +++ b/packages/walkthrough/steps/38/webapp/controller/Detail.controller.ts @@ -9,7 +9,7 @@ import JSONModel from "sap/ui/model/json/JSONModel"; import UIComponent from "sap/ui/core/UIComponent"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class Detail extends Controller { diff --git a/packages/walkthrough/steps/38/webapp/controller/HelloPanel.controller.ts b/packages/walkthrough/steps/38/webapp/controller/HelloPanel.controller.ts index 333931030..3be88a8e5 100644 --- a/packages/walkthrough/steps/38/webapp/controller/HelloPanel.controller.ts +++ b/packages/walkthrough/steps/38/webapp/controller/HelloPanel.controller.ts @@ -6,7 +6,7 @@ import ResourceBundle from "sap/base/i18n/ResourceBundle"; import Dialog from "sap/m/Dialog"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class HelloPanel extends Controller { private dialog: Dialog; @@ -20,7 +20,7 @@ export default class HelloPanel extends Controller { } async onOpenDialog(): Promise<void> { this.dialog ??= await this.loadFragment({ - name: "ui5.walkthrough.view.HelloDialog" + name: "ui5.tutorial.walkthrough.view.HelloDialog" }) as Dialog; this.dialog.open(); } diff --git a/packages/walkthrough/steps/38/webapp/controller/InvoiceList.controller.ts b/packages/walkthrough/steps/38/webapp/controller/InvoiceList.controller.ts index a0b8a86a7..64f9d0cc0 100644 --- a/packages/walkthrough/steps/38/webapp/controller/InvoiceList.controller.ts +++ b/packages/walkthrough/steps/38/webapp/controller/InvoiceList.controller.ts @@ -10,7 +10,7 @@ import UIComponent from "sap/ui/core/UIComponent"; import Context from "sap/ui/model/Context"; /** - * @namespace ui5.walkthrough.controller + * @namespace ui5.tutorial.walkthrough.controller */ export default class App extends Controller { onInit(): void { diff --git a/packages/walkthrough/steps/38/webapp/index-cdn.html b/packages/walkthrough/steps/38/webapp/index-cdn.html index b3b27659a..32b0e78d1 100644 --- a/packages/walkthrough/steps/38/webapp/index-cdn.html +++ b/packages/walkthrough/steps/38/webapp/index-cdn.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/38/webapp/index.html b/packages/walkthrough/steps/38/webapp/index.html index c30b76fbf..9ee5171b0 100644 --- a/packages/walkthrough/steps/38/webapp/index.html +++ b/packages/walkthrough/steps/38/webapp/index.html @@ -11,11 +11,11 @@ data-sap-ui-async="true" data-sap-ui-on-init="module:sap/ui/core/ComponentSupport" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "./" + "ui5.tutorial.walkthrough": "./" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/38/webapp/index.ts b/packages/walkthrough/steps/38/webapp/index.ts index 8e8eaee0c..7f2ec4364 100644 --- a/packages/walkthrough/steps/38/webapp/index.ts +++ b/packages/walkthrough/steps/38/webapp/index.ts @@ -1,7 +1,7 @@ import ComponentContainer from "sap/ui/core/ComponentContainer"; new ComponentContainer({ - name: "ui5.walkthrough", + name: "ui5.tutorial.walkthrough", settings : { id : "walkthroughts" }, diff --git a/packages/walkthrough/steps/38/webapp/localService/mockserver.ts b/packages/walkthrough/steps/38/webapp/localService/mockserver.ts index 2284538c8..9493ee8f5 100644 --- a/packages/walkthrough/steps/38/webapp/localService/mockserver.ts +++ b/packages/walkthrough/steps/38/webapp/localService/mockserver.ts @@ -4,7 +4,7 @@ export default { init: function () { // create const mockServer = new MockServer({ - rootUri: sap.ui.require.toUrl("ui5/walkthrough/V2/Northwind/Northwind.svc/") + rootUri: sap.ui.require.toUrl("ui5/tutorial/walkthrough/V2/Northwind/Northwind.svc/") }); const urlParams = new URLSearchParams(window.location.search); @@ -16,7 +16,7 @@ export default { }); // simulate - const path = sap.ui.require.toUrl("ui5/walkthrough/localService"); + const path = sap.ui.require.toUrl("ui5/tutorial/walkthrough/localService"); mockServer.simulate(path + "/metadata.xml", path + "/mockdata"); // start diff --git a/packages/walkthrough/steps/38/webapp/manifest.json b/packages/walkthrough/steps/38/webapp/manifest.json index 7680a67e0..b03e03fe8 100644 --- a/packages/walkthrough/steps/38/webapp/manifest.json +++ b/packages/walkthrough/steps/38/webapp/manifest.json @@ -1,10 +1,10 @@ { "_version": "1.60.0", "sap.app": { - "id": "ui5.walkthrough", + "id": "ui5.tutorial.walkthrough", "type": "application", "i18n": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -46,7 +46,7 @@ } }, "rootView": { - "viewName": "ui5.walkthrough.view.App", + "viewName": "ui5.tutorial.walkthrough.view.App", "type": "XML", "id": "app" }, @@ -54,7 +54,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "ui5.walkthrough.i18n.i18n", + "bundleName": "ui5.tutorial.walkthrough.i18n.i18n", "supportedLocales": [ "" ], @@ -77,7 +77,7 @@ "routerClass": "sap.m.routing.Router", "type": "View", "viewType": "XML", - "path": "ui5.walkthrough.view", + "path": "ui5.tutorial.walkthrough.view", "controlId": "app", "controlAggregation": "pages" }, diff --git a/packages/walkthrough/steps/38/webapp/test/Test.cdn.qunit.html b/packages/walkthrough/steps/38/webapp/test/Test.cdn.qunit.html index e9ad7711a..38bf3f0a4 100644 --- a/packages/walkthrough/steps/38/webapp/test/Test.cdn.qunit.html +++ b/packages/walkthrough/steps/38/webapp/test/Test.cdn.qunit.html @@ -5,7 +5,7 @@ <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/38/webapp/test/Test.qunit.html b/packages/walkthrough/steps/38/webapp/test/Test.qunit.html index 5e3880e7b..46f3efdb4 100644 --- a/packages/walkthrough/steps/38/webapp/test/Test.qunit.html +++ b/packages/walkthrough/steps/38/webapp/test/Test.qunit.html @@ -5,7 +5,7 @@ <script src="../resources/sap/ui/test/starter/runTest.js" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/38/webapp/test/integration/NavigationJourney.ts b/packages/walkthrough/steps/38/webapp/test/integration/NavigationJourney.ts index 2c5a3c942..b3b7de6c5 100644 --- a/packages/walkthrough/steps/38/webapp/test/integration/NavigationJourney.ts +++ b/packages/walkthrough/steps/38/webapp/test/integration/NavigationJourney.ts @@ -10,7 +10,7 @@ opaTest("Should open the Hello dialog", function () { // Arrangements onTheHelloPanelPage.iStartMyUIComponent({ componentConfig: { - name: "ui5.walkthrough" + name: "ui5.tutorial.walkthrough" } }); diff --git a/packages/walkthrough/steps/38/webapp/test/integration/pages/HelloPanelPage.ts b/packages/walkthrough/steps/38/webapp/test/integration/pages/HelloPanelPage.ts index 83e59dde1..da73c14de 100644 --- a/packages/walkthrough/steps/38/webapp/test/integration/pages/HelloPanelPage.ts +++ b/packages/walkthrough/steps/38/webapp/test/integration/pages/HelloPanelPage.ts @@ -1,7 +1,7 @@ import Opa5 from "sap/ui/test/Opa5"; import Press from "sap/ui/test/actions/Press"; -const viewName = "ui5.walkthrough.view.HelloPanel"; +const viewName = "ui5.tutorial.walkthrough.view.HelloPanel"; export default class HelloPanelPage extends Opa5 { // Actions diff --git a/packages/walkthrough/steps/38/webapp/test/mockServer-cdn.html b/packages/walkthrough/steps/38/webapp/test/mockServer-cdn.html index 658c58748..937c8b604 100644 --- a/packages/walkthrough/steps/38/webapp/test/mockServer-cdn.html +++ b/packages/walkthrough/steps/38/webapp/test/mockServer-cdn.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/38/webapp/test/mockServer.html b/packages/walkthrough/steps/38/webapp/test/mockServer.html index 1ce73671b..bb5bc4e89 100644 --- a/packages/walkthrough/steps/38/webapp/test/mockServer.html +++ b/packages/walkthrough/steps/38/webapp/test/mockServer.html @@ -9,14 +9,14 @@ data-sap-ui-theme="sap_horizon" data-sap-ui-compat-version="edge" data-sap-ui-async="true" - data-sap-ui-on-init="module:ui5/walkthrough/test/initMockServer" + data-sap-ui-on-init="module:ui5/tutorial/walkthrough/test/initMockServer" data-sap-ui-resource-roots='{ - "ui5.walkthrough": "../" + "ui5.tutorial.walkthrough": "../" }'> </script> </head> <body class="sapUiBody" id="content"> - <div data-sap-ui-component data-name="ui5.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> + <div data-sap-ui-component data-name="ui5.tutorial.walkthrough" data-id="container" data-settings='{"id" : "walkthrough"}'></div> </body> </html> diff --git a/packages/walkthrough/steps/38/webapp/test/testsuite.cdn.qunit.html b/packages/walkthrough/steps/38/webapp/test/testsuite.cdn.qunit.html index e2399f165..acef5d20f 100644 --- a/packages/walkthrough/steps/38/webapp/test/testsuite.cdn.qunit.html +++ b/packages/walkthrough/steps/38/webapp/test/testsuite.cdn.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="https://sdk.openui5.org/1.147.1/resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.cdn.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/38/webapp/test/testsuite.cdn.qunit.ts b/packages/walkthrough/steps/38/webapp/test/testsuite.cdn.qunit.ts index e158902a7..3f57245ab 100644 --- a/packages/walkthrough/steps/38/webapp/test/testsuite.cdn.qunit.ts +++ b/packages/walkthrough/steps/38/webapp/test/testsuite.cdn.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.cdn.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/38/webapp/test/testsuite.qunit.html b/packages/walkthrough/steps/38/webapp/test/testsuite.qunit.html index 1fdae6328..90da984c9 100644 --- a/packages/walkthrough/steps/38/webapp/test/testsuite.qunit.html +++ b/packages/walkthrough/steps/38/webapp/test/testsuite.qunit.html @@ -4,9 +4,9 @@ <meta charset="utf-8"> <script src="../resources/sap/ui/test/starter/createSuite.js" - data-sap-ui-testsuite="test-resources/ui5/walkthrough/testsuite.qunit" + data-sap-ui-testsuite="test-resources/ui5/tutorial/walkthrough/testsuite.qunit" data-sap-ui-resource-roots='{ - "test-resources.ui5.walkthrough": "./" + "test-resources.ui5.tutorial.walkthrough": "./" }' ></script> </head> diff --git a/packages/walkthrough/steps/38/webapp/test/testsuite.qunit.ts b/packages/walkthrough/steps/38/webapp/test/testsuite.qunit.ts index be9cab085..78cb8dd37 100644 --- a/packages/walkthrough/steps/38/webapp/test/testsuite.qunit.ts +++ b/packages/walkthrough/steps/38/webapp/test/testsuite.qunit.ts @@ -2,7 +2,7 @@ import type {SuiteConfiguration} from "sap/ui/test/starter/config"; export default { name: "QUnit test suite for UI5 TypeScript Walkthrough", defaults: { - page: "ui5://test-resources/ui5/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", + page: "ui5://test-resources/ui5/tutorial/walkthrough/Test.qunit.html?testsuite={suite}&test={name}", qunit: { version: 2 }, @@ -11,7 +11,7 @@ export default { }, loader: { paths: { - "ui5/walkthrough": "../" + "ui5/tutorial/walkthrough": "../" } } }, diff --git a/packages/walkthrough/steps/38/webapp/test/unit/model/formatter.ts b/packages/walkthrough/steps/38/webapp/test/unit/model/formatter.ts index a7c40d393..bb4f8acfc 100644 --- a/packages/walkthrough/steps/38/webapp/test/unit/model/formatter.ts +++ b/packages/walkthrough/steps/38/webapp/test/unit/model/formatter.ts @@ -1,12 +1,12 @@ import ResourceModel from "sap/ui/model/resource/ResourceModel"; import Controller from "sap/ui/core/mvc/Controller"; -import formatter from "ui5/walkthrough/model/formatter"; +import formatter from "ui5/tutorial/walkthrough/model/formatter"; QUnit.module("Formatting function", {}); QUnit.test("Should return the translated texts", (assert) => { const resourceModel = new ResourceModel({ - bundleUrl: sap.ui.require.toUrl("ui5/walkthrough/i18n/i18n.properties"), + bundleUrl: sap.ui.require.toUrl("ui5/tutorial/walkthrough/i18n/i18n.properties"), supportedLocales: [ "" ], diff --git a/packages/walkthrough/steps/38/webapp/view/App.view.xml b/packages/walkthrough/steps/38/webapp/view/App.view.xml index 11d955a8b..19804995f 100644 --- a/packages/walkthrough/steps/38/webapp/view/App.view.xml +++ b/packages/walkthrough/steps/38/webapp/view/App.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> diff --git a/packages/walkthrough/steps/38/webapp/view/Detail.view.xml b/packages/walkthrough/steps/38/webapp/view/Detail.view.xml index 172befcbd..559cff076 100644 --- a/packages/walkthrough/steps/38/webapp/view/Detail.view.xml +++ b/packages/walkthrough/steps/38/webapp/view/Detail.view.xml @@ -1,9 +1,9 @@ <mvc:View - controllerName="ui5.walkthrough.controller.Detail" + controllerName="ui5.tutorial.walkthrough.controller.Detail" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" - xmlns:wt="ui5.walkthrough.control"> + xmlns:wt="ui5.tutorial.walkthrough.control"> <Page title="{i18n>detailPageTitle}" showNavButton="true" diff --git a/packages/walkthrough/steps/38/webapp/view/HelloPanel.view.xml b/packages/walkthrough/steps/38/webapp/view/HelloPanel.view.xml index 39256d9fa..f127330d1 100644 --- a/packages/walkthrough/steps/38/webapp/view/HelloPanel.view.xml +++ b/packages/walkthrough/steps/38/webapp/view/HelloPanel.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.HelloPanel" + controllerName="ui5.tutorial.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel diff --git a/packages/walkthrough/steps/38/webapp/view/InvoiceList.view.xml b/packages/walkthrough/steps/38/webapp/view/InvoiceList.view.xml index aec957bd9..368c702c1 100644 --- a/packages/walkthrough/steps/38/webapp/view/InvoiceList.view.xml +++ b/packages/walkthrough/steps/38/webapp/view/InvoiceList.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.InvoiceList" + controllerName="ui5.tutorial.walkthrough.controller.InvoiceList" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> @@ -61,7 +61,7 @@ title="{invoice>ProductName}"/> <Text core:require= "{ - Formatter: 'ui5/walkthrough/model/formatter' + Formatter: 'ui5/tutorial/walkthrough/model/formatter' }" text="{ path: 'invoice>Status', diff --git a/packages/walkthrough/steps/38/webapp/view/Overview.view.xml b/packages/walkthrough/steps/38/webapp/view/Overview.view.xml index 577e70b47..3e468460a 100644 --- a/packages/walkthrough/steps/38/webapp/view/Overview.view.xml +++ b/packages/walkthrough/steps/38/webapp/view/Overview.view.xml @@ -1,5 +1,5 @@ <mvc:View - controllerName="ui5.walkthrough.controller.App" + controllerName="ui5.tutorial.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> @@ -14,8 +14,8 @@ headerLabel="{i18n>Overview_headerLabel}"/> </landmarkInfo> <content> - <mvc:XMLView viewName="ui5.walkthrough.view.HelloPanel"/> - <mvc:XMLView viewName="ui5.walkthrough.view.InvoiceList"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.HelloPanel"/> + <mvc:XMLView viewName="ui5.tutorial.walkthrough.view.InvoiceList"/> </content> </Page> </mvc:View> \ No newline at end of file diff --git a/tools/dev-server/server.js b/tools/dev-server/server.js index c548242b4..56d73b056 100644 --- a/tools/dev-server/server.js +++ b/tools/dev-server/server.js @@ -15,6 +15,11 @@ const port = 1337; const cwd = process.cwd(); +// Known tutorial slugs we link from the rendered overview READMEs. The dev +// server rewrites the GH Pages URLs (used in the published markdown) so they +// resolve against the local `dist/` folder instead of the live site. +const TUTORIAL_SLUGS = ["walkthrough", "quickstart", "navigation", "odatav4"]; + async function convertMarkdown(md) { const converter = new showdown.Converter({ ghCompatibleHeaderId: true, @@ -31,6 +36,27 @@ async function convertMarkdown(md) { return converter.makeHtml(md); } +/** + * Rewrites the absolute GH Pages URLs that the published markdown uses for + * Live Preview links, README cross-links and ZIP downloads so they resolve + * against the locally-built `dist/` tree. Restricted to the four known + * tutorial slugs to avoid accidentally rewriting unrelated URLs. + */ +function rewriteGhPagesUrls(html) { + const slugAlt = TUTORIAL_SLUGS.join("|"); + // build pages (apps + READMEs): /tutorial/build/NN/anything + html = html.replace( + new RegExp(`https://ui5\\.github\\.io/tutorials/(${slugAlt})/build/`, "g"), + "/dist/$1/build/" + ); + // ZIP downloads: /tutorial/tutorial-step-NN(-js).zip + html = html.replace( + new RegExp(`https://ui5\\.github\\.io/tutorials/(${slugAlt})/(\\1-step-\\d+(?:-js)?\\.zip)`, "g"), + "/dist/$1/$2" + ); + return html; +} + async function getTemplate() { const headContent = readFileSync(join(cwd, "_includes/head-custom.html"), { encoding: "utf-8" }); let template = readFileSync(join(__dirname, "ghpage-template.hbs"), { encoding: "utf-8" }); @@ -40,6 +66,31 @@ async function getTemplate() { return templateFn; } +/** + * Express middleware that serves built tutorial artifacts (built apps, READMEs, + * downloadable ZIPs) out of `dist/<tutorial>/...`. If the requested path doesn't + * exist (e.g. `npm run build` was never run), return a friendly hint page + * instead of a bare 404. + */ +app.get(/^\/dist\//, (req, res, next) => { + const reqPath = req.path; // already starts with /dist/ + const full = join(cwd, reqPath); + if (existsSync(full) && statSync(full).isFile()) { + return res.sendFile(full); + } + // Allow directory requests to fall through to the standard index resolution below. + if (existsSync(full) && statSync(full).isDirectory()) { + return next(); + } + // Friendlier failure: dist is missing or the artifact wasn't produced yet + res.status(404).type("html").send(`<!DOCTYPE html> +<html><body style="font-family: system-ui, sans-serif; padding: 2rem; max-width: 720px;"> +<h1>Build artifact not found</h1> +<p><code>${reqPath}</code> was not found under <code>dist/</code>.</p> +<p>Run <code>npm run build</code> in the repository root to produce the per-tutorial build artifacts (built apps, ZIP downloads, rendered step READMEs).</p> +</body></html>`); +}); + app.use("/node_modules", express.static(join(cwd, "node_modules"))); app.use(async (req, res, next) => { @@ -63,7 +114,8 @@ app.use(async (req, res, next) => { } if (file && file.endsWith(".md")) { const md = readFileSync(file, { encoding: "utf-8" }); - const bodyContent = await convertMarkdown(md); + let bodyContent = await convertMarkdown(md); + bodyContent = rewriteGhPagesUrls(bodyContent); const templateFn = await getTemplate(); // get title as first line in the md file which starts with hashes, which indicates it is a title of some kind const title = md.match(/^##* (.+)$/m)?.[1] || reqUrlWithoutParams; From 9b4f266606b7ab09048c7a2a3fbdfca61e6a1406 Mon Sep 17 00:00:00 2001 From: Peter Muessig <peter.muessig@sap.com> Date: Tue, 30 Jun 2026 18:47:08 +0200 Subject: [PATCH 2/8] chore: align tutorials to UI5 1.148 LTS and normalize conventions Versions - Bump framework to OpenUI5 1.148.1 (latest LTS patch) in every step ui5.yaml and CDN bootstrap URL. - Bump manifest _version to 2.8.0 and minUI5Version to 1.148 across all 69 manifests (mapping per UI5/manifest v2/mapping.json). - specVersion: "4.0" for every ui5.yaml. - @types/openui5 ^1.148.0 in every step package.json. - Sync README narrative and inline manifest snippets that referenced OpenUI5 1.120 / _version 1.60.0 / 1.38.0 to the new values. Reviewer findings (PR #295, @flovogt) - Manifest v2 (_version 2.8.0). - specVersion '4.0'. - Ensure trailing newline on every webapp source file. Cross-tutorial inconsistency cleanup - Quickstart Component.ts: @namespace sap.m.tutorial.quickstart.NN -> ui5.tutorial.quickstart, switch to public static metadata and add interfaces: ["sap.ui.core.IAsyncContentCreation"]. - Strip residual Hungarian-notation in quickstart controllers/index.ts (oEvent/bState/oView) and the named identifiers in odatav4 OPA tests (iGrowingBy/sViewName/oListBinding). - Add explicit "strict": false, "strictNullChecks": false to walkthrough and quickstart tsconfig.json files (match navigation/odatav4). - Drop redundant data-sap-ui-libs from quickstart steps 02 and 03 index.html (Component manifest already declares the libs). - Add data-sap-ui-theme="sap_horizon" to quickstart and navigation bootstrap script tags so the theme is explicit and consistent with walkthrough/odatav4. Indentation normalization per .editorconfig - JSON / XML / YAML / .properties -> 2 spaces. - TS / JS / HTML -> tabs. - Re-indent fenced code blocks inside step README.md files to match the same conventions so doc snippets mirror the actual source files. Verified: npm run typecheck and npm run build both exit 0; ui5-linter clean on sampled steps; manifest validation clean. --- packages/navigation/steps/01/package.json | 2 +- packages/navigation/steps/01/ui5.yaml | 4 +- .../navigation/steps/01/webapp/index-cdn.html | 5 +- .../navigation/steps/01/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/01/webapp/manifest.json | 148 ++-- packages/navigation/steps/02/README.md | 168 ++-- packages/navigation/steps/02/package.json | 2 +- packages/navigation/steps/02/ui5.yaml | 4 +- .../navigation/steps/02/webapp/index-cdn.html | 5 +- .../navigation/steps/02/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/02/webapp/manifest.json | 196 ++--- packages/navigation/steps/03/README.md | 108 +-- packages/navigation/steps/03/package.json | 2 +- packages/navigation/steps/03/ui5.yaml | 4 +- .../navigation/steps/03/webapp/index-cdn.html | 5 +- .../navigation/steps/03/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/03/webapp/manifest.json | 212 ++--- packages/navigation/steps/04/README.md | 126 +-- packages/navigation/steps/04/package.json | 2 +- packages/navigation/steps/04/ui5.yaml | 4 +- .../navigation/steps/04/webapp/index-cdn.html | 5 +- .../navigation/steps/04/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/04/webapp/manifest.json | 212 ++--- packages/navigation/steps/05/README.md | 172 ++-- packages/navigation/steps/05/package.json | 2 +- packages/navigation/steps/05/ui5.yaml | 4 +- .../navigation/steps/05/webapp/index-cdn.html | 5 +- .../navigation/steps/05/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/05/webapp/manifest.json | 212 ++--- packages/navigation/steps/06/README.md | 218 ++--- packages/navigation/steps/06/package.json | 2 +- packages/navigation/steps/06/ui5.yaml | 4 +- .../navigation/steps/06/webapp/index-cdn.html | 5 +- .../navigation/steps/06/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/06/webapp/manifest.json | 233 ++--- packages/navigation/steps/07/README.md | 420 ++++----- packages/navigation/steps/07/package.json | 2 +- packages/navigation/steps/07/ui5.yaml | 4 +- .../navigation/steps/07/webapp/index-cdn.html | 5 +- .../navigation/steps/07/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/07/webapp/manifest.json | 254 +++--- packages/navigation/steps/08/README.md | 492 +++++------ packages/navigation/steps/08/package.json | 2 +- packages/navigation/steps/08/ui5.yaml | 4 +- .../navigation/steps/08/webapp/index-cdn.html | 5 +- .../navigation/steps/08/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/08/webapp/manifest.json | 277 +++--- packages/navigation/steps/09/README.md | 390 ++++----- packages/navigation/steps/09/package.json | 2 +- packages/navigation/steps/09/ui5.yaml | 4 +- .../navigation/steps/09/webapp/index-cdn.html | 5 +- .../navigation/steps/09/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/09/webapp/manifest.json | 277 +++--- packages/navigation/steps/10/README.md | 382 ++++----- packages/navigation/steps/10/package.json | 2 +- packages/navigation/steps/10/ui5.yaml | 4 +- .../navigation/steps/10/webapp/index-cdn.html | 5 +- .../navigation/steps/10/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/10/webapp/manifest.json | 309 +++---- packages/navigation/steps/11/README.md | 786 ++++++++--------- packages/navigation/steps/11/package.json | 2 +- packages/navigation/steps/11/ui5.yaml | 4 +- .../navigation/steps/11/webapp/index-cdn.html | 5 +- .../navigation/steps/11/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/11/webapp/manifest.json | 365 ++++---- packages/navigation/steps/12/README.md | 428 +++++----- packages/navigation/steps/12/package.json | 2 +- packages/navigation/steps/12/ui5.yaml | 4 +- .../navigation/steps/12/webapp/index-cdn.html | 5 +- .../navigation/steps/12/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/12/webapp/manifest.json | 365 ++++---- packages/navigation/steps/13/README.md | 332 ++++---- packages/navigation/steps/13/package.json | 2 +- packages/navigation/steps/13/ui5.yaml | 4 +- .../navigation/steps/13/webapp/index-cdn.html | 5 +- .../navigation/steps/13/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/13/webapp/manifest.json | 365 ++++---- packages/navigation/steps/14/README.md | 388 ++++----- packages/navigation/steps/14/package.json | 2 +- packages/navigation/steps/14/ui5.yaml | 4 +- .../navigation/steps/14/webapp/index-cdn.html | 5 +- .../navigation/steps/14/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/14/webapp/manifest.json | 365 ++++---- packages/navigation/steps/15/README.md | 382 ++++----- packages/navigation/steps/15/package.json | 2 +- packages/navigation/steps/15/ui5.yaml | 4 +- .../navigation/steps/15/webapp/index-cdn.html | 5 +- .../navigation/steps/15/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/15/webapp/manifest.json | 365 ++++---- packages/navigation/steps/16/README.md | 74 +- packages/navigation/steps/16/package.json | 2 +- packages/navigation/steps/16/ui5.yaml | 4 +- .../navigation/steps/16/webapp/index-cdn.html | 5 +- .../navigation/steps/16/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/16/webapp/manifest.json | 365 ++++---- packages/navigation/steps/17/README.md | 102 +-- packages/navigation/steps/17/package.json | 2 +- packages/navigation/steps/17/ui5.yaml | 4 +- .../navigation/steps/17/webapp/index-cdn.html | 5 +- .../navigation/steps/17/webapp/index.html | 3 +- .../localService/mockdata/Employees.json | 310 +++---- .../webapp/localService/mockdata/Resumes.json | 130 +-- .../navigation/steps/17/webapp/manifest.json | 365 ++++---- packages/odatav4/steps/01/README.md | 14 +- packages/odatav4/steps/01/package.json | 2 +- packages/odatav4/steps/01/ui5.yaml | 4 +- .../steps/01/webapp/i18n/i18n.properties | 2 +- .../odatav4/steps/01/webapp/index-cdn.html | 2 +- .../steps/01/webapp/localService/metadata.xml | 382 ++++----- .../webapp/localService/mockdata/people.json | 796 +++++++++--------- .../odatav4/steps/01/webapp/manifest.json | 134 +-- .../odatav4/steps/01/webapp/view/App.view.xml | 106 +-- packages/odatav4/steps/02/README.md | 120 +-- packages/odatav4/steps/02/package.json | 2 +- packages/odatav4/steps/02/ui5.yaml | 4 +- .../steps/02/webapp/i18n/i18n.properties | 2 +- .../odatav4/steps/02/webapp/index-cdn.html | 2 +- .../steps/02/webapp/localService/metadata.xml | 382 ++++----- .../webapp/localService/mockdata/people.json | 796 +++++++++--------- .../odatav4/steps/02/webapp/manifest.json | 128 +-- .../odatav4/steps/02/webapp/view/App.view.xml | 130 +-- packages/odatav4/steps/03/README.md | 74 +- packages/odatav4/steps/03/package.json | 2 +- packages/odatav4/steps/03/ui5.yaml | 4 +- .../steps/03/webapp/i18n/i18n.properties | 2 +- .../odatav4/steps/03/webapp/index-cdn.html | 2 +- .../steps/03/webapp/localService/metadata.xml | 382 ++++----- .../webapp/localService/mockdata/people.json | 796 +++++++++--------- .../odatav4/steps/03/webapp/manifest.json | 130 +-- .../odatav4/steps/03/webapp/view/App.view.xml | 130 +-- packages/odatav4/steps/04/README.md | 154 ++-- packages/odatav4/steps/04/package.json | 2 +- packages/odatav4/steps/04/ui5.yaml | 4 +- .../steps/04/webapp/i18n/i18n.properties | 2 +- .../odatav4/steps/04/webapp/index-cdn.html | 2 +- .../steps/04/webapp/localService/metadata.xml | 382 ++++----- .../webapp/localService/mockdata/people.json | 796 +++++++++--------- .../odatav4/steps/04/webapp/manifest.json | 130 +-- .../odatav4/steps/04/webapp/view/App.view.xml | 156 ++-- packages/odatav4/steps/05/README.md | 14 +- packages/odatav4/steps/05/package.json | 2 +- packages/odatav4/steps/05/ui5.yaml | 4 +- .../steps/05/webapp/i18n/i18n.properties | 2 +- .../odatav4/steps/05/webapp/index-cdn.html | 2 +- .../steps/05/webapp/localService/metadata.xml | 382 ++++----- .../webapp/localService/mockdata/people.json | 796 +++++++++--------- .../odatav4/steps/05/webapp/manifest.json | 130 +-- .../odatav4/steps/05/webapp/view/App.view.xml | 156 ++-- packages/odatav4/steps/06/README.md | 236 +++--- packages/odatav4/steps/06/package.json | 2 +- packages/odatav4/steps/06/ui5.yaml | 4 +- .../steps/06/webapp/i18n/i18n.properties | 2 +- .../odatav4/steps/06/webapp/index-cdn.html | 2 +- .../steps/06/webapp/localService/metadata.xml | 382 ++++----- .../webapp/localService/mockdata/people.json | 796 +++++++++--------- .../odatav4/steps/06/webapp/manifest.json | 130 +-- .../odatav4/steps/06/webapp/view/App.view.xml | 232 ++--- packages/odatav4/steps/07/package.json | 2 +- packages/odatav4/steps/07/ui5.yaml | 4 +- .../steps/07/webapp/i18n/i18n.properties | 2 +- .../odatav4/steps/07/webapp/index-cdn.html | 2 +- .../steps/07/webapp/localService/metadata.xml | 382 ++++----- .../webapp/localService/mockdata/people.json | 796 +++++++++--------- .../odatav4/steps/07/webapp/manifest.json | 130 +-- .../odatav4/steps/07/webapp/view/App.view.xml | 252 +++--- packages/odatav4/steps/08/README.md | 34 +- packages/odatav4/steps/08/package.json | 2 +- packages/odatav4/steps/08/ui5.yaml | 4 +- .../steps/08/webapp/i18n/i18n.properties | 2 +- .../odatav4/steps/08/webapp/index-cdn.html | 2 +- .../steps/08/webapp/localService/metadata.xml | 382 ++++----- .../webapp/localService/mockdata/people.json | 796 +++++++++--------- .../odatav4/steps/08/webapp/manifest.json | 130 +-- .../test/integration/opaTests.qunit.html | 2 +- .../odatav4/steps/08/webapp/view/App.view.xml | 270 +++--- packages/odatav4/steps/09/README.md | 504 +++++------ packages/odatav4/steps/09/package.json | 2 +- packages/odatav4/steps/09/ui5.yaml | 4 +- .../odatav4/steps/09/webapp/index-cdn.html | 2 +- .../steps/09/webapp/localService/metadata.xml | 382 ++++----- .../webapp/localService/mockdata/people.json | 796 +++++++++--------- .../odatav4/steps/09/webapp/manifest.json | 134 +-- .../odatav4/steps/09/webapp/view/App.view.xml | 538 ++++++------ packages/odatav4/steps/10/README.md | 136 +-- packages/odatav4/steps/10/package.json | 2 +- packages/odatav4/steps/10/ui5.yaml | 4 +- .../odatav4/steps/10/webapp/index-cdn.html | 2 +- .../steps/10/webapp/localService/metadata.xml | 382 ++++----- .../webapp/localService/mockdata/people.json | 796 +++++++++--------- .../odatav4/steps/10/webapp/manifest.json | 134 +-- .../odatav4/steps/10/webapp/view/App.view.xml | 538 ++++++------ packages/odatav4/steps/11/README.md | 132 +-- packages/odatav4/steps/11/package.json | 2 +- packages/odatav4/steps/11/ui5.yaml | 4 +- .../odatav4/steps/11/webapp/index-cdn.html | 2 +- .../steps/11/webapp/localService/metadata.xml | 382 ++++----- .../webapp/localService/mockdata/people.json | 796 +++++++++--------- .../odatav4/steps/11/webapp/manifest.json | 134 +-- .../test/integration/TutorialJourney.js | 10 +- .../test/integration/opaTests.qunit.html | 2 +- .../webapp/test/integration/pages/Tutorial.js | 44 +- .../odatav4/steps/11/webapp/view/App.view.xml | 634 +++++++------- packages/quickstart/steps/01/Component.ts | 5 +- packages/quickstart/steps/01/README.md | 100 +-- packages/quickstart/steps/01/package.json | 2 +- packages/quickstart/steps/01/tsconfig.json | 4 +- packages/quickstart/steps/01/ui5.yaml | 2 +- .../quickstart/steps/01/webapp/index-cdn.html | 1 + .../quickstart/steps/01/webapp/index.html | 3 +- .../quickstart/steps/01/webapp/manifest.json | 2 +- packages/quickstart/steps/02/Component.ts | 5 +- packages/quickstart/steps/02/README.md | 26 +- packages/quickstart/steps/02/package.json | 2 +- packages/quickstart/steps/02/tsconfig.json | 4 +- packages/quickstart/steps/02/ui5.yaml | 2 +- .../quickstart/steps/02/webapp/App.view.xml | 28 +- .../quickstart/steps/02/webapp/index-cdn.html | 2 +- .../quickstart/steps/02/webapp/index.html | 4 +- packages/quickstart/steps/02/webapp/index.ts | 2 +- .../quickstart/steps/02/webapp/manifest.json | 2 +- packages/quickstart/steps/03/Component.ts | 5 +- packages/quickstart/steps/03/README.md | 94 +-- packages/quickstart/steps/03/package.json | 2 +- packages/quickstart/steps/03/tsconfig.json | 4 +- packages/quickstart/steps/03/ui5.yaml | 2 +- .../steps/03/webapp/App.controller.ts | 6 +- .../quickstart/steps/03/webapp/App.view.xml | 92 +- .../quickstart/steps/03/webapp/index-cdn.html | 2 +- .../quickstart/steps/03/webapp/index.html | 4 +- packages/quickstart/steps/03/webapp/index.ts | 2 +- .../quickstart/steps/03/webapp/manifest.json | 2 +- packages/walkthrough/steps/01/README.md | 24 +- packages/walkthrough/steps/01/ui5.yaml | 2 +- .../walkthrough/steps/01/webapp/index.html | 2 +- .../walkthrough/steps/01/webapp/manifest.json | 16 +- packages/walkthrough/steps/02/tsconfig.json | 33 +- packages/walkthrough/steps/02/ui5.yaml | 4 +- .../steps/02/webapp/index-cdn.html | 2 +- .../walkthrough/steps/02/webapp/manifest.json | 16 +- packages/walkthrough/steps/03/README.md | 10 +- packages/walkthrough/steps/03/package.json | 2 +- packages/walkthrough/steps/03/tsconfig.json | 33 +- packages/walkthrough/steps/03/ui5.yaml | 4 +- .../steps/03/webapp/index-cdn.html | 2 +- packages/walkthrough/steps/03/webapp/index.ts | 2 +- .../walkthrough/steps/03/webapp/manifest.json | 16 +- packages/walkthrough/steps/04/README.md | 22 +- packages/walkthrough/steps/04/package.json | 2 +- packages/walkthrough/steps/04/tsconfig.json | 33 +- packages/walkthrough/steps/04/ui5.yaml | 4 +- .../steps/04/webapp/index-cdn.html | 2 +- packages/walkthrough/steps/04/webapp/index.ts | 8 +- .../walkthrough/steps/04/webapp/manifest.json | 16 +- .../steps/04/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/05/README.md | 28 +- packages/walkthrough/steps/05/package.json | 2 +- packages/walkthrough/steps/05/tsconfig.json | 33 +- packages/walkthrough/steps/05/ui5.yaml | 4 +- .../05/webapp/controller/App.controller.ts | 8 +- .../steps/05/webapp/index-cdn.html | 2 +- packages/walkthrough/steps/05/webapp/index.ts | 8 +- .../walkthrough/steps/05/webapp/manifest.json | 16 +- .../steps/05/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/06/README.md | 30 +- packages/walkthrough/steps/06/package.json | 2 +- packages/walkthrough/steps/06/tsconfig.json | 33 +- packages/walkthrough/steps/06/ui5.yaml | 4 +- .../06/webapp/controller/App.controller.ts | 6 +- .../steps/06/webapp/index-cdn.html | 2 +- packages/walkthrough/steps/06/webapp/index.ts | 8 +- .../walkthrough/steps/06/webapp/manifest.json | 16 +- .../steps/06/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/07/README.md | 64 +- packages/walkthrough/steps/07/package.json | 2 +- packages/walkthrough/steps/07/tsconfig.json | 33 +- packages/walkthrough/steps/07/ui5.yaml | 4 +- .../07/webapp/controller/App.controller.ts | 26 +- .../steps/07/webapp/index-cdn.html | 2 +- packages/walkthrough/steps/07/webapp/index.ts | 8 +- .../walkthrough/steps/07/webapp/manifest.json | 16 +- .../steps/07/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/08/README.md | 110 +-- packages/walkthrough/steps/08/package.json | 2 +- packages/walkthrough/steps/08/tsconfig.json | 33 +- packages/walkthrough/steps/08/ui5.yaml | 4 +- .../08/webapp/controller/App.controller.ts | 46 +- .../steps/08/webapp/i18n/i18n.properties | 2 +- .../steps/08/webapp/index-cdn.html | 2 +- packages/walkthrough/steps/08/webapp/index.ts | 8 +- .../walkthrough/steps/08/webapp/manifest.json | 16 +- .../steps/08/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/09/README.md | 208 ++--- packages/walkthrough/steps/09/package.json | 2 +- packages/walkthrough/steps/09/tsconfig.json | 33 +- packages/walkthrough/steps/09/ui5.yaml | 4 +- .../walkthrough/steps/09/webapp/Component.ts | 58 +- .../09/webapp/controller/App.controller.ts | 18 +- .../steps/09/webapp/i18n/i18n.properties | 2 +- .../steps/09/webapp/index-cdn.html | 2 +- packages/walkthrough/steps/09/webapp/index.ts | 16 +- .../walkthrough/steps/09/webapp/manifest.json | 16 +- .../steps/09/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/10/README.md | 176 ++-- packages/walkthrough/steps/10/package.json | 2 +- packages/walkthrough/steps/10/tsconfig.json | 33 +- packages/walkthrough/steps/10/ui5.yaml | 4 +- .../walkthrough/steps/10/webapp/Component.ts | 36 +- .../10/webapp/controller/App.controller.ts | 16 +- .../steps/10/webapp/i18n/i18n.properties | 2 +- .../steps/10/webapp/index-cdn.html | 2 +- .../walkthrough/steps/10/webapp/manifest.json | 94 +-- .../steps/10/webapp/view/App.view.xml | 2 +- packages/walkthrough/steps/11/README.md | 38 +- packages/walkthrough/steps/11/package.json | 2 +- packages/walkthrough/steps/11/tsconfig.json | 33 +- packages/walkthrough/steps/11/ui5.yaml | 4 +- .../walkthrough/steps/11/webapp/Component.ts | 36 +- .../11/webapp/controller/App.controller.ts | 16 +- .../steps/11/webapp/i18n/i18n.properties | 2 +- .../steps/11/webapp/index-cdn.html | 2 +- .../walkthrough/steps/11/webapp/manifest.json | 94 +-- .../steps/11/webapp/view/App.view.xml | 38 +- packages/walkthrough/steps/12/README.md | 54 +- packages/walkthrough/steps/12/package.json | 2 +- packages/walkthrough/steps/12/tsconfig.json | 33 +- packages/walkthrough/steps/12/ui5.yaml | 4 +- .../walkthrough/steps/12/webapp/Component.ts | 36 +- .../12/webapp/controller/App.controller.ts | 16 +- .../steps/12/webapp/i18n/i18n.properties | 2 +- .../steps/12/webapp/index-cdn.html | 2 +- .../walkthrough/steps/12/webapp/manifest.json | 94 +-- .../steps/12/webapp/view/App.view.xml | 54 +- packages/walkthrough/steps/13/README.md | 64 +- packages/walkthrough/steps/13/package.json | 2 +- packages/walkthrough/steps/13/tsconfig.json | 33 +- packages/walkthrough/steps/13/ui5.yaml | 4 +- .../walkthrough/steps/13/webapp/Component.ts | 36 +- .../13/webapp/controller/App.controller.ts | 16 +- .../steps/13/webapp/i18n/i18n.properties | 2 +- .../steps/13/webapp/index-cdn.html | 2 +- .../walkthrough/steps/13/webapp/manifest.json | 94 +-- .../steps/13/webapp/view/App.view.xml | 64 +- packages/walkthrough/steps/14/README.md | 90 +- packages/walkthrough/steps/14/package.json | 2 +- packages/walkthrough/steps/14/tsconfig.json | 33 +- packages/walkthrough/steps/14/ui5.yaml | 4 +- .../walkthrough/steps/14/webapp/Component.ts | 36 +- .../14/webapp/controller/App.controller.ts | 16 +- .../walkthrough/steps/14/webapp/css/style.css | 2 +- .../steps/14/webapp/i18n/i18n.properties | 2 +- .../steps/14/webapp/index-cdn.html | 2 +- .../walkthrough/steps/14/webapp/manifest.json | 106 +-- .../steps/14/webapp/view/App.view.xml | 64 +- packages/walkthrough/steps/15/README.md | 118 +-- packages/walkthrough/steps/15/package.json | 2 +- packages/walkthrough/steps/15/tsconfig.json | 33 +- packages/walkthrough/steps/15/ui5.yaml | 4 +- .../walkthrough/steps/15/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 16 +- .../walkthrough/steps/15/webapp/css/style.css | 2 +- .../steps/15/webapp/i18n/i18n.properties | 2 +- .../steps/15/webapp/index-cdn.html | 2 +- .../walkthrough/steps/15/webapp/manifest.json | 106 +-- .../steps/15/webapp/view/App.view.xml | 30 +- .../steps/15/webapp/view/HelloPanel.view.xml | 34 +- packages/walkthrough/steps/16/README.md | 94 +-- packages/walkthrough/steps/16/package.json | 2 +- packages/walkthrough/steps/16/tsconfig.json | 33 +- packages/walkthrough/steps/16/ui5.yaml | 4 +- .../walkthrough/steps/16/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 30 +- .../walkthrough/steps/16/webapp/css/style.css | 2 +- .../steps/16/webapp/i18n/i18n.properties | 2 +- .../steps/16/webapp/index-cdn.html | 2 +- .../walkthrough/steps/16/webapp/manifest.json | 106 +-- .../steps/16/webapp/view/App.view.xml | 30 +- .../16/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/16/webapp/view/HelloPanel.view.xml | 44 +- packages/walkthrough/steps/17/README.md | 82 +- packages/walkthrough/steps/17/package.json | 2 +- packages/walkthrough/steps/17/tsconfig.json | 33 +- packages/walkthrough/steps/17/ui5.yaml | 4 +- .../walkthrough/steps/17/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 36 +- .../walkthrough/steps/17/webapp/css/style.css | 2 +- .../steps/17/webapp/i18n/i18n.properties | 2 +- .../steps/17/webapp/index-cdn.html | 2 +- .../walkthrough/steps/17/webapp/manifest.json | 106 +-- .../steps/17/webapp/view/App.view.xml | 30 +- .../17/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/17/webapp/view/HelloPanel.view.xml | 44 +- packages/walkthrough/steps/18/README.md | 44 +- packages/walkthrough/steps/18/package.json | 2 +- packages/walkthrough/steps/18/tsconfig.json | 33 +- packages/walkthrough/steps/18/ui5.yaml | 4 +- .../walkthrough/steps/18/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../walkthrough/steps/18/webapp/css/style.css | 2 +- .../steps/18/webapp/i18n/i18n.properties | 2 +- .../steps/18/webapp/index-cdn.html | 2 +- .../walkthrough/steps/18/webapp/manifest.json | 106 +-- .../steps/18/webapp/view/App.view.xml | 30 +- .../18/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/18/webapp/view/HelloPanel.view.xml | 46 +- packages/walkthrough/steps/19/README.md | 32 +- packages/walkthrough/steps/19/package.json | 2 +- packages/walkthrough/steps/19/tsconfig.json | 33 +- packages/walkthrough/steps/19/ui5.yaml | 4 +- .../walkthrough/steps/19/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../walkthrough/steps/19/webapp/css/style.css | 2 +- .../steps/19/webapp/i18n/i18n.properties | 2 +- .../steps/19/webapp/index-cdn.html | 2 +- .../walkthrough/steps/19/webapp/manifest.json | 114 +-- .../steps/19/webapp/model/localInvoices.json | 2 +- .../steps/19/webapp/view/App.view.xml | 32 +- .../19/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/19/webapp/view/HelloPanel.view.xml | 46 +- .../steps/19/webapp/view/InvoiceList.view.xml | 2 +- packages/walkthrough/steps/20/README.md | 38 +- packages/walkthrough/steps/20/package.json | 2 +- packages/walkthrough/steps/20/tsconfig.json | 33 +- packages/walkthrough/steps/20/ui5.yaml | 4 +- .../walkthrough/steps/20/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 16 +- .../walkthrough/steps/20/webapp/css/style.css | 2 +- .../steps/20/webapp/i18n/i18n.properties | 2 +- .../steps/20/webapp/index-cdn.html | 2 +- .../walkthrough/steps/20/webapp/manifest.json | 114 +-- .../steps/20/webapp/model/localInvoices.json | 2 +- .../steps/20/webapp/view/App.view.xml | 32 +- .../20/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/20/webapp/view/HelloPanel.view.xml | 46 +- packages/walkthrough/steps/21/package.json | 2 +- packages/walkthrough/steps/21/tsconfig.json | 33 +- packages/walkthrough/steps/21/ui5.yaml | 4 +- .../walkthrough/steps/21/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 14 +- .../walkthrough/steps/21/webapp/css/style.css | 2 +- .../steps/21/webapp/i18n/i18n.properties | 2 +- .../steps/21/webapp/index-cdn.html | 2 +- .../walkthrough/steps/21/webapp/manifest.json | 114 +-- .../steps/21/webapp/model/localInvoices.json | 2 +- .../steps/21/webapp/view/App.view.xml | 32 +- .../21/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/21/webapp/view/HelloPanel.view.xml | 46 +- packages/walkthrough/steps/22/README.md | 60 +- packages/walkthrough/steps/22/package.json | 2 +- packages/walkthrough/steps/22/tsconfig.json | 33 +- packages/walkthrough/steps/22/ui5.yaml | 4 +- .../walkthrough/steps/22/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 12 +- .../walkthrough/steps/22/webapp/css/style.css | 2 +- .../steps/22/webapp/i18n/i18n.properties | 2 +- .../steps/22/webapp/index-cdn.html | 2 +- .../walkthrough/steps/22/webapp/manifest.json | 114 +-- .../steps/22/webapp/model/formatter.ts | 26 +- .../steps/22/webapp/model/localInvoices.json | 2 +- .../steps/22/webapp/view/App.view.xml | 32 +- .../22/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/22/webapp/view/HelloPanel.view.xml | 46 +- packages/walkthrough/steps/23/README.md | 90 +- packages/walkthrough/steps/23/package.json | 2 +- packages/walkthrough/steps/23/tsconfig.json | 33 +- packages/walkthrough/steps/23/ui5.yaml | 4 +- .../walkthrough/steps/23/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 36 +- .../walkthrough/steps/23/webapp/css/style.css | 2 +- .../steps/23/webapp/i18n/i18n.properties | 2 +- .../steps/23/webapp/index-cdn.html | 2 +- .../walkthrough/steps/23/webapp/manifest.json | 114 +-- .../steps/23/webapp/model/formatter.ts | 26 +- .../steps/23/webapp/model/localInvoices.json | 2 +- .../steps/23/webapp/view/App.view.xml | 32 +- .../23/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/23/webapp/view/HelloPanel.view.xml | 46 +- packages/walkthrough/steps/24/package.json | 2 +- packages/walkthrough/steps/24/tsconfig.json | 33 +- packages/walkthrough/steps/24/ui5.yaml | 4 +- .../walkthrough/steps/24/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 36 +- .../walkthrough/steps/24/webapp/css/style.css | 2 +- .../steps/24/webapp/i18n/i18n.properties | 2 +- .../steps/24/webapp/index-cdn.html | 2 +- .../walkthrough/steps/24/webapp/manifest.json | 114 +-- .../steps/24/webapp/model/formatter.ts | 26 +- .../steps/24/webapp/model/localInvoices.json | 2 +- .../steps/24/webapp/view/App.view.xml | 32 +- .../24/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/24/webapp/view/HelloPanel.view.xml | 46 +- packages/walkthrough/steps/25/README.md | 42 +- packages/walkthrough/steps/25/package.json | 2 +- packages/walkthrough/steps/25/tsconfig.json | 33 +- packages/walkthrough/steps/25/ui5.yaml | 4 +- .../walkthrough/steps/25/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 36 +- .../walkthrough/steps/25/webapp/css/style.css | 2 +- .../steps/25/webapp/i18n/i18n.properties | 2 +- .../steps/25/webapp/index-cdn.html | 2 +- .../walkthrough/steps/25/webapp/manifest.json | 128 +-- .../steps/25/webapp/model/formatter.ts | 26 +- .../steps/25/webapp/view/App.view.xml | 32 +- .../25/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/25/webapp/view/HelloPanel.view.xml | 46 +- packages/walkthrough/steps/26/README.md | 212 ++--- packages/walkthrough/steps/26/package.json | 2 +- packages/walkthrough/steps/26/tsconfig.json | 33 +- packages/walkthrough/steps/26/ui5.yaml | 4 +- .../walkthrough/steps/26/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 36 +- .../walkthrough/steps/26/webapp/css/style.css | 2 +- .../steps/26/webapp/i18n/i18n.properties | 2 +- .../steps/26/webapp/index-cdn.html | 2 +- .../steps/26/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../26/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/26/webapp/manifest.json | 128 +-- .../steps/26/webapp/model/formatter.ts | 26 +- .../steps/26/webapp/test/mockServer-cdn.html | 2 +- .../steps/26/webapp/view/App.view.xml | 32 +- .../26/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/26/webapp/view/HelloPanel.view.xml | 46 +- packages/walkthrough/steps/27/README.md | 148 ++-- packages/walkthrough/steps/27/package.json | 2 +- packages/walkthrough/steps/27/tsconfig.json | 33 +- packages/walkthrough/steps/27/ui5.yaml | 4 +- .../walkthrough/steps/27/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 36 +- .../walkthrough/steps/27/webapp/css/style.css | 2 +- .../steps/27/webapp/i18n/i18n.properties | 2 +- .../steps/27/webapp/index-cdn.html | 2 +- .../steps/27/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../27/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/27/webapp/manifest.json | 128 +-- .../steps/27/webapp/model/formatter.ts | 26 +- .../steps/27/webapp/test/Test.cdn.qunit.html | 2 +- .../steps/27/webapp/test/mockServer-cdn.html | 2 +- .../27/webapp/test/testsuite.cdn.qunit.html | 2 +- .../27/webapp/test/unit/model/formatter.ts | 46 +- .../steps/27/webapp/view/App.view.xml | 32 +- .../27/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/27/webapp/view/HelloPanel.view.xml | 46 +- packages/walkthrough/steps/28/README.md | 88 +- packages/walkthrough/steps/28/package.json | 2 +- packages/walkthrough/steps/28/tsconfig.json | 33 +- packages/walkthrough/steps/28/ui5.yaml | 4 +- .../walkthrough/steps/28/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 36 +- .../walkthrough/steps/28/webapp/css/style.css | 2 +- .../steps/28/webapp/i18n/i18n.properties | 2 +- .../steps/28/webapp/index-cdn.html | 2 +- .../steps/28/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../28/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/28/webapp/manifest.json | 128 +-- .../steps/28/webapp/model/formatter.ts | 26 +- .../steps/28/webapp/test/Test.cdn.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/28/webapp/test/mockServer-cdn.html | 2 +- .../28/webapp/test/testsuite.cdn.qunit.html | 2 +- .../28/webapp/test/unit/model/formatter.ts | 46 +- .../steps/28/webapp/view/App.view.xml | 32 +- .../28/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/28/webapp/view/HelloPanel.view.xml | 46 +- packages/walkthrough/steps/29/README.md | 84 +- packages/walkthrough/steps/29/package.json | 2 +- packages/walkthrough/steps/29/tsconfig.json | 33 +- packages/walkthrough/steps/29/ui5.yaml | 4 +- .../walkthrough/steps/29/webapp/Component.ts | 36 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 36 +- .../walkthrough/steps/29/webapp/css/style.css | 2 +- .../steps/29/webapp/i18n/i18n.properties | 2 +- .../steps/29/webapp/index-cdn.html | 2 +- .../steps/29/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../29/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/29/webapp/manifest.json | 128 +-- .../steps/29/webapp/model/formatter.ts | 26 +- .../steps/29/webapp/test/Test.cdn.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/29/webapp/test/mockServer-cdn.html | 2 +- .../29/webapp/test/testsuite.cdn.qunit.html | 2 +- .../29/webapp/test/unit/model/formatter.ts | 46 +- .../steps/29/webapp/view/App.view.xml | 32 +- .../29/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/29/webapp/view/HelloPanel.view.xml | 46 +- packages/walkthrough/steps/30/README.md | 330 ++++---- packages/walkthrough/steps/30/package.json | 2 +- packages/walkthrough/steps/30/tsconfig.json | 33 +- packages/walkthrough/steps/30/ui5.yaml | 4 +- .../walkthrough/steps/30/webapp/Component.ts | 40 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 44 +- .../walkthrough/steps/30/webapp/css/style.css | 2 +- .../steps/30/webapp/i18n/i18n.properties | 2 +- .../steps/30/webapp/index-cdn.html | 2 +- .../steps/30/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../30/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/30/webapp/manifest.json | 188 ++--- .../steps/30/webapp/model/formatter.ts | 26 +- .../steps/30/webapp/test/Test.cdn.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/30/webapp/test/mockServer-cdn.html | 2 +- .../30/webapp/test/testsuite.cdn.qunit.html | 2 +- .../30/webapp/test/unit/model/formatter.ts | 46 +- .../steps/30/webapp/view/App.view.xml | 20 +- .../steps/30/webapp/view/Detail.view.xml | 16 +- .../30/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/30/webapp/view/HelloPanel.view.xml | 46 +- .../steps/30/webapp/view/InvoiceList.view.xml | 98 +-- .../steps/30/webapp/view/Overview.view.xml | 22 +- packages/walkthrough/steps/31/README.md | 186 ++-- packages/walkthrough/steps/31/package.json | 2 +- packages/walkthrough/steps/31/tsconfig.json | 33 +- packages/walkthrough/steps/31/ui5.yaml | 4 +- .../walkthrough/steps/31/webapp/Component.ts | 40 +- .../31/webapp/controller/Detail.controller.ts | 20 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 50 +- .../walkthrough/steps/31/webapp/css/style.css | 2 +- .../steps/31/webapp/i18n/i18n.properties | 2 +- .../steps/31/webapp/index-cdn.html | 2 +- .../steps/31/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../31/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/31/webapp/manifest.json | 188 ++--- .../steps/31/webapp/model/formatter.ts | 26 +- .../steps/31/webapp/test/Test.cdn.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/31/webapp/test/mockServer-cdn.html | 2 +- .../31/webapp/test/testsuite.cdn.qunit.html | 2 +- .../31/webapp/test/unit/model/formatter.ts | 46 +- .../steps/31/webapp/view/App.view.xml | 20 +- .../steps/31/webapp/view/Detail.view.xml | 20 +- .../31/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/31/webapp/view/HelloPanel.view.xml | 46 +- .../steps/31/webapp/view/InvoiceList.view.xml | 98 +-- .../steps/31/webapp/view/Overview.view.xml | 22 +- packages/walkthrough/steps/32/README.md | 82 +- packages/walkthrough/steps/32/package.json | 2 +- packages/walkthrough/steps/32/tsconfig.json | 33 +- packages/walkthrough/steps/32/ui5.yaml | 4 +- .../walkthrough/steps/32/webapp/Component.ts | 40 +- .../32/webapp/controller/Detail.controller.ts | 40 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 50 +- .../walkthrough/steps/32/webapp/css/style.css | 2 +- .../steps/32/webapp/i18n/i18n.properties | 2 +- .../steps/32/webapp/index-cdn.html | 2 +- .../steps/32/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../32/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/32/webapp/manifest.json | 188 ++--- .../steps/32/webapp/model/formatter.ts | 26 +- .../steps/32/webapp/test/Test.cdn.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/32/webapp/test/mockServer-cdn.html | 2 +- .../32/webapp/test/testsuite.cdn.qunit.html | 2 +- .../32/webapp/test/unit/model/formatter.ts | 46 +- .../steps/32/webapp/view/App.view.xml | 20 +- .../steps/32/webapp/view/Detail.view.xml | 24 +- .../32/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/32/webapp/view/HelloPanel.view.xml | 46 +- .../steps/32/webapp/view/InvoiceList.view.xml | 98 +-- .../steps/32/webapp/view/Overview.view.xml | 22 +- packages/walkthrough/steps/33/README.md | 380 ++++----- packages/walkthrough/steps/33/package.json | 2 +- packages/walkthrough/steps/33/tsconfig.json | 33 +- packages/walkthrough/steps/33/ui5.yaml | 4 +- .../walkthrough/steps/33/webapp/Component.ts | 40 +- .../33/webapp/control/ProductRating.gen.d.ts | 54 +- .../33/webapp/controller/Detail.controller.ts | 64 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 50 +- .../walkthrough/steps/33/webapp/css/style.css | 2 +- .../steps/33/webapp/i18n/i18n.properties | 2 +- .../steps/33/webapp/index-cdn.html | 2 +- .../steps/33/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../33/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/33/webapp/manifest.json | 188 ++--- .../steps/33/webapp/model/formatter.ts | 26 +- .../steps/33/webapp/test/Test.cdn.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/33/webapp/test/mockServer-cdn.html | 2 +- .../33/webapp/test/testsuite.cdn.qunit.html | 2 +- .../33/webapp/test/unit/model/formatter.ts | 46 +- .../steps/33/webapp/view/App.view.xml | 20 +- .../steps/33/webapp/view/Detail.view.xml | 36 +- .../33/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/33/webapp/view/HelloPanel.view.xml | 46 +- .../steps/33/webapp/view/InvoiceList.view.xml | 98 +-- .../steps/33/webapp/view/Overview.view.xml | 22 +- packages/walkthrough/steps/34/README.md | 168 ++-- packages/walkthrough/steps/34/package.json | 2 +- packages/walkthrough/steps/34/tsconfig.json | 33 +- packages/walkthrough/steps/34/ui5.yaml | 4 +- .../walkthrough/steps/34/webapp/Component.ts | 40 +- .../34/webapp/control/ProductRating.gen.d.ts | 54 +- .../34/webapp/controller/Detail.controller.ts | 64 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 50 +- .../walkthrough/steps/34/webapp/css/style.css | 2 +- .../steps/34/webapp/i18n/i18n.properties | 2 +- .../steps/34/webapp/index-cdn.html | 2 +- .../steps/34/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../34/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/34/webapp/manifest.json | 188 ++--- .../steps/34/webapp/model/formatter.ts | 26 +- .../steps/34/webapp/test/Test.cdn.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/34/webapp/test/mockServer-cdn.html | 2 +- .../34/webapp/test/testsuite.cdn.qunit.html | 2 +- .../34/webapp/test/unit/model/formatter.ts | 46 +- .../steps/34/webapp/view/App.view.xml | 20 +- .../steps/34/webapp/view/Detail.view.xml | 36 +- .../34/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/34/webapp/view/HelloPanel.view.xml | 46 +- .../steps/34/webapp/view/InvoiceList.view.xml | 174 ++-- .../steps/34/webapp/view/Overview.view.xml | 22 +- packages/walkthrough/steps/35/README.md | 320 +++---- packages/walkthrough/steps/35/package.json | 2 +- packages/walkthrough/steps/35/tsconfig.json | 33 +- packages/walkthrough/steps/35/ui5.yaml | 4 +- .../walkthrough/steps/35/webapp/Component.ts | 48 +- .../35/webapp/control/ProductRating.gen.d.ts | 54 +- .../35/webapp/controller/Detail.controller.ts | 74 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 50 +- .../walkthrough/steps/35/webapp/css/style.css | 2 +- .../steps/35/webapp/i18n/i18n.properties | 2 +- .../steps/35/webapp/index-cdn.html | 2 +- .../steps/35/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../35/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/35/webapp/manifest.json | 188 ++--- .../steps/35/webapp/model/formatter.ts | 26 +- .../steps/35/webapp/test/Test.cdn.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/35/webapp/test/mockServer-cdn.html | 2 +- .../35/webapp/test/testsuite.cdn.qunit.html | 2 +- .../35/webapp/test/unit/model/formatter.ts | 46 +- .../steps/35/webapp/view/App.view.xml | 20 +- .../35/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/35/webapp/view/HelloPanel.view.xml | 48 +- .../steps/35/webapp/view/InvoiceList.view.xml | 174 ++-- .../steps/35/webapp/view/Overview.view.xml | 22 +- packages/walkthrough/steps/36/README.md | 100 +-- packages/walkthrough/steps/36/package.json | 2 +- packages/walkthrough/steps/36/tsconfig.json | 33 +- packages/walkthrough/steps/36/ui5.yaml | 4 +- .../walkthrough/steps/36/webapp/Component.ts | 56 +- .../36/webapp/control/ProductRating.gen.d.ts | 54 +- .../36/webapp/controller/App.controller.ts | 4 +- .../36/webapp/controller/Detail.controller.ts | 74 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 50 +- .../walkthrough/steps/36/webapp/css/style.css | 2 +- .../steps/36/webapp/i18n/i18n.properties | 2 +- .../steps/36/webapp/index-cdn.html | 2 +- .../steps/36/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../36/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/36/webapp/manifest.json | 186 ++-- .../steps/36/webapp/model/formatter.ts | 26 +- .../steps/36/webapp/test/Test.cdn.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/36/webapp/test/mockServer-cdn.html | 2 +- .../36/webapp/test/testsuite.cdn.qunit.html | 2 +- .../36/webapp/test/unit/model/formatter.ts | 46 +- .../steps/36/webapp/view/App.view.xml | 20 +- .../36/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/36/webapp/view/HelloPanel.view.xml | 48 +- .../steps/36/webapp/view/InvoiceList.view.xml | 174 ++-- .../steps/36/webapp/view/Overview.view.xml | 22 +- packages/walkthrough/steps/37/README.md | 116 +-- packages/walkthrough/steps/37/package.json | 2 +- packages/walkthrough/steps/37/tsconfig.json | 33 +- packages/walkthrough/steps/37/ui5.yaml | 4 +- .../walkthrough/steps/37/webapp/Component.ts | 54 +- .../37/webapp/control/ProductRating.gen.d.ts | 54 +- .../37/webapp/controller/App.controller.ts | 4 +- .../37/webapp/controller/Detail.controller.ts | 74 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 50 +- .../walkthrough/steps/37/webapp/css/style.css | 2 +- .../steps/37/webapp/i18n/i18n.properties | 2 +- .../steps/37/webapp/index-cdn.html | 2 +- .../steps/37/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../37/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/37/webapp/manifest.json | 196 ++--- .../steps/37/webapp/model/formatter.ts | 26 +- .../steps/37/webapp/test/Test.cdn.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/37/webapp/test/mockServer-cdn.html | 2 +- .../37/webapp/test/testsuite.cdn.qunit.html | 2 +- .../37/webapp/test/unit/model/formatter.ts | 46 +- .../steps/37/webapp/view/App.view.xml | 20 +- .../37/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/37/webapp/view/HelloPanel.view.xml | 50 +- .../steps/37/webapp/view/InvoiceList.view.xml | 182 ++-- .../steps/37/webapp/view/Overview.view.xml | 40 +- packages/walkthrough/steps/38/package.json | 2 +- packages/walkthrough/steps/38/tsconfig.json | 33 +- packages/walkthrough/steps/38/ui5.yaml | 4 +- .../walkthrough/steps/38/webapp/Component.ts | 54 +- .../38/webapp/control/ProductRating.gen.d.ts | 54 +- .../38/webapp/controller/App.controller.ts | 4 +- .../38/webapp/controller/Detail.controller.ts | 74 +- .../controller/HelloPanel.controller.ts | 40 +- .../controller/InvoiceList.controller.ts | 50 +- .../walkthrough/steps/38/webapp/css/style.css | 2 +- .../steps/38/webapp/i18n/i18n.properties | 2 +- .../steps/38/webapp/index-cdn.html | 2 +- packages/walkthrough/steps/38/webapp/index.ts | 12 +- .../steps/38/webapp/localService/metadata.xml | 56 +- .../localService/mockdata/Invoices.json | 2 +- .../38/webapp/localService/mockserver.ts | 34 +- .../walkthrough/steps/38/webapp/manifest.json | 196 ++--- .../steps/38/webapp/model/formatter.ts | 26 +- .../steps/38/webapp/test/Test.cdn.qunit.html | 2 +- .../test/integration/NavigationJourney.ts | 2 +- .../test/integration/pages/HelloPanelPage.ts | 2 +- .../steps/38/webapp/test/mockServer-cdn.html | 2 +- .../38/webapp/test/testsuite.cdn.qunit.html | 2 +- .../38/webapp/test/unit/model/formatter.ts | 46 +- .../steps/38/webapp/view/App.view.xml | 20 +- .../38/webapp/view/HelloDialog.fragment.xml | 2 +- .../steps/38/webapp/view/HelloPanel.view.xml | 50 +- .../steps/38/webapp/view/InvoiceList.view.xml | 182 ++-- .../steps/38/webapp/view/Overview.view.xml | 40 +- 887 files changed, 28473 insertions(+), 27998 deletions(-) diff --git a/packages/navigation/steps/01/package.json b/packages/navigation/steps/01/package.json index 6f6810c80..16fcadaf7 100644 --- a/packages/navigation/steps/01/package.json +++ b/packages/navigation/steps/01/package.json @@ -9,7 +9,7 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "@types/openui5": "^1.147.0", + "@types/openui5": "^1.148.0", "@ui5/cli": "^4.0.53", "typescript": "^6.0.3", "ui5-middleware-livereload": "^3.3.1", diff --git a/packages/navigation/steps/01/ui5.yaml b/packages/navigation/steps/01/ui5.yaml index 5bf7607c1..2e95456f0 100644 --- a/packages/navigation/steps/01/ui5.yaml +++ b/packages/navigation/steps/01/ui5.yaml @@ -1,10 +1,10 @@ -specVersion: '3.0' +specVersion: "4.0" metadata: name: "ui5.tutorial.navigation" type: application framework: name: OpenUI5 - version: "1.147.1" + version: "1.148.1" libraries: - name: sap.m - name: sap.ui.core diff --git a/packages/navigation/steps/01/webapp/index-cdn.html b/packages/navigation/steps/01/webapp/index-cdn.html index 3f7d3e410..f012c70af 100644 --- a/packages/navigation/steps/01/webapp/index-cdn.html +++ b/packages/navigation/steps/01/webapp/index-cdn.html @@ -5,13 +5,14 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Navigation and Routing Tutorial diff --git a/packages/navigation/steps/01/webapp/index.html b/packages/navigation/steps/01/webapp/index.html index 85064c936..41251762e 100644 --- a/packages/navigation/steps/01/webapp/index.html +++ b/packages/navigation/steps/01/webapp/index.html @@ -11,7 +11,8 @@ }' data-sap-ui-on-init="module:ui5/tutorial/navigation/initMockServer" data-sap-ui-compat-version="edge" - data-sap-ui-async="true"> + data-sap-ui-async="true" + data-sap-ui-theme="sap_horizon"> diff --git a/packages/navigation/steps/01/webapp/localService/mockdata/Employees.json b/packages/navigation/steps/01/webapp/localService/mockdata/Employees.json index e37463b18..02595688f 100644 --- a/packages/navigation/steps/01/webapp/localService/mockdata/Employees.json +++ b/packages/navigation/steps/01/webapp/localService/mockdata/Employees.json @@ -1,155 +1,155 @@ -[ - { - "EmployeeID": 1, - "LastName": "Davolio", - "FirstName": "Nancy", - "Address": "507 - 20th Ave. E. Apt. 2A", - "City": "Seattle", - "Region": "WA", - "PostalCode": "98122", - "Country": "USA", - "HomePhone": "(206) 555-9857", - "ResumeID": 1, - "Resume" : { - "__deferred": { - "uri": "/here/goes/your/serviceUrl/Employees(1)/Resume" - } - } - }, - { - "EmployeeID": 2, - "LastName": "Fuller", - "FirstName": "Andrew", - "Address": "908 W. Capital Way", - "City": "Tacoma", - "Region": "WA", - "PostalCode": "98401", - "Country": "USA", - "HomePhone": "(206) 555-9482", - "ResumeID": 2, - "Resume" : { - "__deferred": { - "uri": "/here/goes/your/serviceUrl/Employees(2)/Resume" - } - } - }, - { - "EmployeeID": 3, - "LastName": "Leverling", - "FirstName": "Janet", - "Address": "722 Moss Bay Blvd.", - "City": "Kirkland", - "Region": "WA", - "PostalCode": "98033", - "Country": "USA", - "HomePhone": "(206) 555-3412", - "ResumeID": 3, - "Resume" : { - "__deferred": { - "uri": "/here/goes/your/serviceUrl/Employees(3)/Resume" - } - } - }, - { - "EmployeeID": 4, - "LastName": "Peacock", - "FirstName": "Margaret", - "Address": "4110 Old Redmond Rd.", - "City": "Redmond", - "Region": "WA", - "PostalCode": "98052", - "Country": "USA", - "HomePhone": "(206) 555-8122", - "ResumeID": 4, - "Resume" : { - "__deferred": { - "uri": "/here/goes/your/serviceUrl/Employees(4)/Resume" - } - } - }, - { - "EmployeeID": 5, - "LastName": "Buchanan", - "FirstName": "Steven", - "Address": "14 Garrett Hill", - "City": "London", - "Region": null, - "PostalCode": "SW1 8JR", - "Country": "UK", - "HomePhone": "(71) 555-4848", - "ResumeID": 5, - "Resume" : { - "__deferred": { - "uri": "/here/goes/your/serviceUrl/Employees(5)/Resume" - } - } - }, - { - "EmployeeID": 6, - "LastName": "Suyama", - "FirstName": "Michael", - "Address": "Coventry House Miner Rd.", - "City": "London", - "Region": null, - "PostalCode": "EC2 7JR", - "Country": "UK", - "HomePhone": "(71) 555-7773", - "ResumeID": 6, - "Resume" : { - "__deferred": { - "uri": "/here/goes/your/serviceUrl/Employees(6)/Resume" - } - } - }, - { - "EmployeeID": 7, - "LastName": "King", - "FirstName": "Robert", - "Address": "Edgeham Hollow Winchester Way", - "City": "London", - "Region": null, - "PostalCode": "RG1 9SP", - "Country": "UK", - "HomePhone": "(71) 555-5598", - "ResumeID": 7, - "Resume" : { - "__deferred": { - "uri": "/here/goes/your/serviceUrl/Employees(7)/Resume" - } - } - }, - { - "EmployeeID": 8, - "LastName": "Callahan", - "FirstName": "Laura", - "Address": "4726 - 11th Ave. N.E.", - "City": "Seattle", - "Region": "WA", - "PostalCode": "98105", - "Country": "USA", - "HomePhone": "(206) 555-1189", - "ResumeID": 8, - "Resume" : { - "__deferred": { - "uri": "/here/goes/your/serviceUrl/Employees(8)/Resume" - } - } - }, - { - "EmployeeID": 9, - "LastName": "Dodsworth", - "FirstName": "Anne", - "Address": "7 Houndstooth Rd.", - "City": "London", - "Region": null, - "PostalCode": "WG2 7LT", - "Country": "UK", - "HomePhone": "(71) 555-4444", - "ResumeID": 9, - "Resume" : { - "__deferred": { - "uri": "/here/goes/your/serviceUrl/Employees(9)/Resume" - } - } - } -] +[ + { + "EmployeeID": 1, + "LastName": "Davolio", + "FirstName": "Nancy", + "Address": "507 - 20th Ave. E. Apt. 2A", + "City": "Seattle", + "Region": "WA", + "PostalCode": "98122", + "Country": "USA", + "HomePhone": "(206) 555-9857", + "ResumeID": 1, + "Resume": { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(1)/Resume" + } + } + }, + { + "EmployeeID": 2, + "LastName": "Fuller", + "FirstName": "Andrew", + "Address": "908 W. Capital Way", + "City": "Tacoma", + "Region": "WA", + "PostalCode": "98401", + "Country": "USA", + "HomePhone": "(206) 555-9482", + "ResumeID": 2, + "Resume": { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(2)/Resume" + } + } + }, + { + "EmployeeID": 3, + "LastName": "Leverling", + "FirstName": "Janet", + "Address": "722 Moss Bay Blvd.", + "City": "Kirkland", + "Region": "WA", + "PostalCode": "98033", + "Country": "USA", + "HomePhone": "(206) 555-3412", + "ResumeID": 3, + "Resume": { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(3)/Resume" + } + } + }, + { + "EmployeeID": 4, + "LastName": "Peacock", + "FirstName": "Margaret", + "Address": "4110 Old Redmond Rd.", + "City": "Redmond", + "Region": "WA", + "PostalCode": "98052", + "Country": "USA", + "HomePhone": "(206) 555-8122", + "ResumeID": 4, + "Resume": { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(4)/Resume" + } + } + }, + { + "EmployeeID": 5, + "LastName": "Buchanan", + "FirstName": "Steven", + "Address": "14 Garrett Hill", + "City": "London", + "Region": null, + "PostalCode": "SW1 8JR", + "Country": "UK", + "HomePhone": "(71) 555-4848", + "ResumeID": 5, + "Resume": { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(5)/Resume" + } + } + }, + { + "EmployeeID": 6, + "LastName": "Suyama", + "FirstName": "Michael", + "Address": "Coventry House Miner Rd.", + "City": "London", + "Region": null, + "PostalCode": "EC2 7JR", + "Country": "UK", + "HomePhone": "(71) 555-7773", + "ResumeID": 6, + "Resume": { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(6)/Resume" + } + } + }, + { + "EmployeeID": 7, + "LastName": "King", + "FirstName": "Robert", + "Address": "Edgeham Hollow Winchester Way", + "City": "London", + "Region": null, + "PostalCode": "RG1 9SP", + "Country": "UK", + "HomePhone": "(71) 555-5598", + "ResumeID": 7, + "Resume": { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(7)/Resume" + } + } + }, + { + "EmployeeID": 8, + "LastName": "Callahan", + "FirstName": "Laura", + "Address": "4726 - 11th Ave. N.E.", + "City": "Seattle", + "Region": "WA", + "PostalCode": "98105", + "Country": "USA", + "HomePhone": "(206) 555-1189", + "ResumeID": 8, + "Resume": { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(8)/Resume" + } + } + }, + { + "EmployeeID": 9, + "LastName": "Dodsworth", + "FirstName": "Anne", + "Address": "7 Houndstooth Rd.", + "City": "London", + "Region": null, + "PostalCode": "WG2 7LT", + "Country": "UK", + "HomePhone": "(71) 555-4444", + "ResumeID": 9, + "Resume": { + "__deferred": { + "uri": "/here/goes/your/serviceUrl/Employees(9)/Resume" + } + } + } +] diff --git a/packages/navigation/steps/01/webapp/localService/mockdata/Resumes.json b/packages/navigation/steps/01/webapp/localService/mockdata/Resumes.json index 50c8f4fa6..24cb6a684 100644 --- a/packages/navigation/steps/01/webapp/localService/mockdata/Resumes.json +++ b/packages/navigation/steps/01/webapp/localService/mockdata/Resumes.json @@ -1,65 +1,65 @@ -[ - { - "ResumeID": 1, - "Information": "Information of Nancy Davolio", - "Projects": "Projects of Nancy Davolio", - "Hobbies": "Hobbies of Nancy Davolio", - "Notes": "Notes of Nancy Davolio" - }, - { - "ResumeID": 2, - "Information": "Information of Andrew Fuller", - "Projects": "Projects of Andrew Fuller", - "Hobbies": "Hobbies of Andrew Fuller", - "Notes": "Notes of Andrew Fuller" - }, - { - "ResumeID": 3, - "Information": "Information of Janet Leverling", - "Projects": "Projects of Janet Leverling", - "Hobbies": "Hobbies of Janet Leverling", - "Notes": "Notes of Janet Leverling" - }, - { - "ResumeID": 4, - "Information": "Information of Margaret Peacock", - "Projects": "Projects of Margaret Peacock", - "Hobbies": "Hobbies of Margaret Peacock", - "Notes": "Notes of Margaret Peacock" - }, - { - "ResumeID": 5, - "Information": "Information of Steven Buchanan", - "Projects": "Projects of Steven Buchanan", - "Hobbies": "Hobbies of Steven Buchanan", - "Notes": "Notes of Steven Buchanan" - }, - { - "ResumeID": 6, - "Information": "Information of Michael Suyama", - "Projects": "Projects of Michael Suyama", - "Hobbies": "Hobbies of Michael Suyama", - "Notes": "Notes of Michael Suyama" - }, - { - "ResumeID": 7, - "Information": "Information of Robert King", - "Projects": "Projects of Robert King", - "Hobbies": "Hobbies of Robert King", - "Notes": "Notes of Robert King" - }, - { - "ResumeID": 8, - "Information": "Information of Laura Callahan", - "Projects": "Projects of Laura Callahan", - "Hobbies": "Hobbies of Laura Callahan", - "Notes": "Notes of Laura Callahan" - }, - { - "ResumeID": 9, - "Information": "Information of Anne Dodsworth", - "Projects": "Projects of Anne Dodsworth", - "Hobbies": "Hobbies of Anne Dodsworth", - "Notes": "Notes of Anne Dodsworth" - } -] +[ + { + "ResumeID": 1, + "Information": "Information of Nancy Davolio", + "Projects": "Projects of Nancy Davolio", + "Hobbies": "Hobbies of Nancy Davolio", + "Notes": "Notes of Nancy Davolio" + }, + { + "ResumeID": 2, + "Information": "Information of Andrew Fuller", + "Projects": "Projects of Andrew Fuller", + "Hobbies": "Hobbies of Andrew Fuller", + "Notes": "Notes of Andrew Fuller" + }, + { + "ResumeID": 3, + "Information": "Information of Janet Leverling", + "Projects": "Projects of Janet Leverling", + "Hobbies": "Hobbies of Janet Leverling", + "Notes": "Notes of Janet Leverling" + }, + { + "ResumeID": 4, + "Information": "Information of Margaret Peacock", + "Projects": "Projects of Margaret Peacock", + "Hobbies": "Hobbies of Margaret Peacock", + "Notes": "Notes of Margaret Peacock" + }, + { + "ResumeID": 5, + "Information": "Information of Steven Buchanan", + "Projects": "Projects of Steven Buchanan", + "Hobbies": "Hobbies of Steven Buchanan", + "Notes": "Notes of Steven Buchanan" + }, + { + "ResumeID": 6, + "Information": "Information of Michael Suyama", + "Projects": "Projects of Michael Suyama", + "Hobbies": "Hobbies of Michael Suyama", + "Notes": "Notes of Michael Suyama" + }, + { + "ResumeID": 7, + "Information": "Information of Robert King", + "Projects": "Projects of Robert King", + "Hobbies": "Hobbies of Robert King", + "Notes": "Notes of Robert King" + }, + { + "ResumeID": 8, + "Information": "Information of Laura Callahan", + "Projects": "Projects of Laura Callahan", + "Hobbies": "Hobbies of Laura Callahan", + "Notes": "Notes of Laura Callahan" + }, + { + "ResumeID": 9, + "Information": "Information of Anne Dodsworth", + "Projects": "Projects of Anne Dodsworth", + "Hobbies": "Hobbies of Anne Dodsworth", + "Notes": "Notes of Anne Dodsworth" + } +] diff --git a/packages/navigation/steps/01/webapp/manifest.json b/packages/navigation/steps/01/webapp/manifest.json index e0a935085..38eefc1bb 100644 --- a/packages/navigation/steps/01/webapp/manifest.json +++ b/packages/navigation/steps/01/webapp/manifest.json @@ -1,74 +1,74 @@ -{ - "_version": "1.38.0", - "sap.app": { - "id": "ui5.tutorial.navigation", - "type": "application", - "i18n": { - "bundleUrl": "i18n/i18n.properties", - "supportedLocales": [ - "" - ], - "fallbackLocale": "" - }, - "title": "{{appTitle}}", - "description": "{{appDescription}}", - "applicationVersion": { - "version": "1.0.0" - }, - "dataSources": { - "employeeRemote": { - "uri": "/here/goes/your/serviceUrl/", - "type": "OData", - "settings": { - "odataVersion": "2.0", - "localUri" : "localService/metadata.xml" - } - } - } - }, - "sap.ui": { - "technology": "UI5", - "deviceTypes": { - "desktop": true, - "tablet": true, - "phone": true - } - }, - "sap.ui5": { - "contentDensities": { - "compact": true, - "cozy": true - }, - "rootView": { - "viewName": "ui5.tutorial.navigation.view.App", - "type": "XML", - "id": "app" - }, - "dependencies": { - "minUI5Version": "1.98.0", - "libs": { - "sap.m": {}, - "sap.ui.core": {} - } - }, - "models": { - "i18n": { - "type": "sap.ui.model.resource.ResourceModel", - "settings": { - "bundleName": "ui5.tutorial.navigation.i18n.i18n", - "supportedLocales": [ - "" - ], - "fallbackLocale": "", - "async": true - } - }, - "": { - "dataSource": "employeeRemote", - "settings": { - "defaultCountMode": "None" - } - } - } - } -} +{ + "_version": "2.8.0", + "sap.app": { + "id": "ui5.tutorial.navigation", + "type": "application", + "i18n": { + "bundleUrl": "i18n/i18n.properties", + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + }, + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "employeeRemote": { + "uri": "/here/goes/your/serviceUrl/", + "type": "OData", + "settings": { + "odataVersion": "2.0", + "localUri": "localService/metadata.xml" + } + } + } + }, + "sap.ui": { + "technology": "UI5", + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "contentDensities": { + "compact": true, + "cozy": true + }, + "rootView": { + "viewName": "ui5.tutorial.navigation.view.App", + "type": "XML", + "id": "app" + }, + "dependencies": { + "minUI5Version": "1.148", + "libs": { + "sap.m": {}, + "sap.ui.core": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "ui5.tutorial.navigation.i18n.i18n", + "supportedLocales": [ + "" + ], + "fallbackLocale": "", + "async": true + } + }, + "": { + "dataSource": "employeeRemote", + "settings": { + "defaultCountMode": "None" + } + } + } + } +} diff --git a/packages/navigation/steps/02/README.md b/packages/navigation/steps/02/README.md index 7f65f854e..ee58fcda8 100644 --- a/packages/navigation/steps/02/README.md +++ b/packages/navigation/steps/02/README.md @@ -42,50 +42,50 @@ webapp/ ```json { - "_version": "1.12.0", - "sap.app": { - ... + "_version": "1.12.0", + "sap.app": { + ... + }, + "sap.ui": { + ... + }, + "sap.ui5": { + + "rootView": { + "viewName": "ui5.tutorial.navigation.view.App", + "type": "XML", + "id": "app" }, - "sap.ui": { - ... + "dependencies": { + ... }, - "sap.ui5": { - - "rootView": { - "viewName": "ui5.tutorial.navigation.view.App", - "type": "XML", - "id": "app" - }, - "dependencies": { - ... - }, - "models": { - ... - }, - "routing": { - "config": { - "routerClass": "sap.m.routing.Router", - "type": "View", - "viewType": "XML", - "path": "ui5.tutorial.navigation.view", - "controlId": "app", - "controlAggregation": "pages", - "transition": "slide" - }, - "routes": [{ - "pattern": "", - "name": "appHome", - "target": "home" - }], - "targets": { - "home": { - "id": "home", - "name": "Home", - "level": 1 - } - } + "models": { + ... + }, + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "type": "View", + "viewType": "XML", + "path": "ui5.tutorial.navigation.view", + "controlId": "app", + "controlAggregation": "pages", + "transition": "slide" + }, + "routes": [{ + "pattern": "", + "name": "appHome", + "target": "home" + }], + "targets": { + "home": { + "id": "home", + "name": "Home", + "level": 1 } + } } + } } ``` @@ -122,36 +122,36 @@ import UIComponent from "sap/ui/core/UIComponent"; */ export default class Component extends UIComponent { - public static metadata = { - manifest: "json" - }; + public static metadata = { + manifest: "json" + }; - public init(): void { - super.init(); + public init(): void { + super.init(); - // create the views based on the url/hash - this.getRouter().initialize(); - } + // create the views based on the url/hash + this.getRouter().initialize(); + } } ``` ```js sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { - "use strict"; - - const Component = UIComponent.extend("ui5.tutorial.navigation.Component", { - metadata: { - interfaces: ["sap.ui.core.IAsyncContentCreation"], - manifest: "json" - }, - init: function _init() { - UIComponent.prototype.init.call(this); - - // create the views based on the url/hash - this.getRouter().initialize(); - } - }); - return Component; + "use strict"; + + const Component = UIComponent.extend("ui5.tutorial.navigation.Component", { + metadata: { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + manifest: "json" + }, + init: function _init() { + UIComponent.prototype.init.call(this); + + // create the views based on the url/hash + this.getRouter().initialize(); + } + }); + return Component; }); ``` @@ -161,13 +161,13 @@ We override the `init` function and call the parent’s `init` function first. W ```xml - - - + controllerName="ui5.tutorial.navigation.controller.App" + xmlns="sap.m" + xmlns:mvc="sap.ui.core.mvc" + displayBlock="true"> + + + ``` @@ -178,17 +178,17 @@ In the `App` view, we remove the content of `App` control. The pages will be add ```xml - - -