From d6fe25756f82a7947492ed2d335f93438f13b7c0 Mon Sep 17 00:00:00 2001 From: Matthew Hagemann Date: Mon, 2 Dec 2024 11:00:39 +0200 Subject: [PATCH 1/4] docs: adding dev-docs for adding a new page to the installer --- .../adding-a-new-page-to-the-installer.md | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 dev-docs/adding-a-new-page-to-the-installer.md diff --git a/dev-docs/adding-a-new-page-to-the-installer.md b/dev-docs/adding-a-new-page-to-the-installer.md new file mode 100644 index 000000000..5f59083f0 --- /dev/null +++ b/dev-docs/adding-a-new-page-to-the-installer.md @@ -0,0 +1,55 @@ +# Adding a new page to the installer + +## Add your page +- Under `apps/ubuntu_bootstrap/lib/pages`, create a new directory for the page you would like to add +ie: `apps/ubuntu_bootstrap/lib/pages/` +- Create at minimum the following files: + - `_page.dart`: Defines the UI for the page you would like to add to the installer. + - `_model.dart`: Implements the provider and integrates with backend services to + support your page's functionality. +- Export your page for use in the installer by adding it to `apps/ubuntu_bootstrap/lib/pages.dart` +- Add your page to the installation steps by adding it as an enum to `InstallationStep` in +`apps/ubuntu_bootstrap/lib/app/installation_step.dart`. The order of the `InstallationStep` enums +determines the order they appear in the installation process. + +## Add your service +- Under `apps/ubuntu_bootstrap/lib/services`, create a new file `_service.dart` +- Within this file, define the backend service that supports your page, and will be called to by +your model. +- Export your service for use by your model by adding it to +`apps/ubuntu_bootstrap/lib/services.dart` +- Register your service for use in the installer by adding a statement +`tryRegisterService()` to `apps/ubuntu_bootstrap/lib/app.dart`. + +## Add UI text to the l10n file for translation +- Add any text that appear to the user on your page to the +`apps/ubuntu_bootstrap/lib/l10n/ubuntu_bootstrap_en.arb` file. +- In the `ubuntu_bootstrap` project root, run `flutter gen-l10n` to generate getters for use in your +page. +- Import `apps/ubuntu_bootstrap/lib/l10n/ubuntu_bootstrap_localizations.dart` and make use of the +variables you defined in `ubuntu_bootstrap_en.arb`. This allows for appropriate translated strings +to be chosen based on the end users selected locale. + +## Update tests +### `installer_wizard_test.dart` +- Under `test/`, add a directory for your new page and create at minimum a `buildModel` +helper function that returns a mocked model, making use of the `mokito` annotations for mock generation. +- Run `melos generate` to generate the mocks. +- For each failing test in `test/installer_wizard_test.dart` + - Initialize your mocked model + - Add the initialized model to the to the `ProviderScope` overrides. + - If needed, add statements to correctly navigate and identify your new page in the test flow, + using `tapNext()`, `pumpAndSettle()` and `expect()`. + +From here, appropriate unit tests for the new page should be added under the newly created +`test/` directory. + +### Integration tests +The integration tests are based on the absolute order in which pages appear in `InstallationStep` +in the `apps/ubuntu_bootstrap/lib/app/installation_step.dart` file. Adding a new page will thus +break all integration tests. + +To fix this, add a new `Future testPage()` function to +`UbuntuBootstrapPageTester` in the `/packages/ubuntu_provision_test/lib/src/bootstrap_tester.dart` +file. Adding this function in order to each integration test should fix the failing tests. + From 86d28b5680f487f704c6999f65ca2e4e61a26c3e Mon Sep 17 00:00:00 2001 From: Matthew Hagemann Date: Mon, 2 Dec 2024 11:13:25 +0200 Subject: [PATCH 2/4] docs: adding doc comments to relavent componets when adding a new page. --- apps/ubuntu_bootstrap/lib/app.dart | 15 ++++++++++++++- .../lib/app/installation_step.dart | 13 +++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/ubuntu_bootstrap/lib/app.dart b/apps/ubuntu_bootstrap/lib/app.dart index 5079938f7..5330966d6 100644 --- a/apps/ubuntu_bootstrap/lib/app.dart +++ b/apps/ubuntu_bootstrap/lib/app.dart @@ -26,6 +26,18 @@ import 'package:yaru/yaru.dart'; export 'app/installer_wizard.dart'; +/// Runs the installer. +/// +/// This function is the main entrypoint to the installer. It parses command-line arguments, +/// forwards arguments to subiquity, initializes the backend services used by the different +/// installation steps and starts the UI. +/// +/// Command-Line Options: +/// - `--dry-run`: Runs the Subiquity server in dry-run mode. +/// - `--dry-run-config`: Path to the configuration file for dry-run mode. +/// - `--machine-config`: Path to the machine configuration file for dry-run mode. +/// - `--source-catalog`: Path to the source catalog file for dry-run mode. +/// - `--try-or-install`: Displays the "Try or Install" page on startup. Future runInstallerApp( List args, { ThemeData? theme, @@ -79,7 +91,8 @@ Future runInstallerApp( .then((dir) => Directory(dir).existsSync() ? dir : null), ); - // conditional registration if not already registered by flavors or tests + // Conditional registration if not already registered by flavors or tests. All services must be + // registered here or their respective providers will fail to find them when building models. tryRegisterService(GnomeAccessibilityService.new); tryRegisterService( () => SubiquityActiveDirectoryService(getService()), diff --git a/apps/ubuntu_bootstrap/lib/app/installation_step.dart b/apps/ubuntu_bootstrap/lib/app/installation_step.dart index 971554877..0cd1663d2 100644 --- a/apps/ubuntu_bootstrap/lib/app/installation_step.dart +++ b/apps/ubuntu_bootstrap/lib/app/installation_step.dart @@ -6,6 +6,19 @@ import 'package:ubuntu_provision/ubuntu_provision.dart'; import 'package:ubuntu_utils/ubuntu_utils.dart'; import 'package:ubuntu_wizard/ubuntu_wizard.dart'; +/// Represents each step or page in the installer workflow. +/// +/// Each step corresponds to an enum value, which defines the page's behavior +/// and its role in the installer. The order of the enums determines the sequence +/// in which the steps appear in the installer. +/// +/// New pages must be added as additional enums to integrate into the workflow. +/// +/// Properties: +/// - `discreteStep`: Indicates whether the step is displayed as a discrete wizard step. +/// - `wizardStep`: Specifies if the step is part of the wizard flow. +/// - `required`: Marks the step as mandatory in the workflow. +/// - `allowedToHide`: Determines if the step can be conditionally hidden. enum InstallationStep with RouteName { loading( LoadingPage.new, From ac619750e35a2c57d2b7510c1d4c229611fbe149 Mon Sep 17 00:00:00 2001 From: Matthew Hagemann Date: Thu, 5 Dec 2024 09:21:40 +0200 Subject: [PATCH 3/4] docs: feedback from code review --- .../lib/app/installation_step.dart | 11 +++++++-- .../adding-a-new-page-to-the-installer.md | 24 ++++++++++++++----- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/apps/ubuntu_bootstrap/lib/app/installation_step.dart b/apps/ubuntu_bootstrap/lib/app/installation_step.dart index 0cd1663d2..95facfe26 100644 --- a/apps/ubuntu_bootstrap/lib/app/installation_step.dart +++ b/apps/ubuntu_bootstrap/lib/app/installation_step.dart @@ -15,10 +15,17 @@ import 'package:ubuntu_wizard/ubuntu_wizard.dart'; /// New pages must be added as additional enums to integrate into the workflow. /// /// Properties: -/// - `discreteStep`: Indicates whether the step is displayed as a discrete wizard step. -/// - `wizardStep`: Specifies if the step is part of the wizard flow. +/// - `discreteStep`: Indicates whether the step is displayed as a discrete wizard step. Discrete +/// steps get their own circle progress indicator at the bottom of the window. +/// - `wizardStep`: Specifies if the step is part of the wizard flow. Wizard steps appear with +/// circle progress indicators and the default step navigation at the bottom of the window. /// - `required`: Marks the step as mandatory in the workflow. /// - `allowedToHide`: Determines if the step can be conditionally hidden. +/// +/// References: +/// - [A discrete, wizard step](https://github.com/canonical/ubuntu-desktop-provision-screenshots/blob/main/bootstrap/light/accessibility.png) +/// - [A non-discrete, wizard step](https://github.com/canonical/ubuntu-desktop-provision-screenshots/blob/main/bootstrap/light/rst.png) +/// - [A non-discrete, non-wizard step](https://github.com/canonical/ubuntu-desktop-provision-screenshots/blob/main/bootstrap/light/install-0.png) enum InstallationStep with RouteName { loading( LoadingPage.new, diff --git a/dev-docs/adding-a-new-page-to-the-installer.md b/dev-docs/adding-a-new-page-to-the-installer.md index 5f59083f0..2697652ff 100644 --- a/dev-docs/adding-a-new-page-to-the-installer.md +++ b/dev-docs/adding-a-new-page-to-the-installer.md @@ -1,21 +1,34 @@ # Adding a new page to the installer +This project makes use of the [Model-view-viewmodel](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel) +architectural pattern. + ## Add your page +New pages can either be added to `apps/ubuntu_bootstrap/` for the main installer, `apps/ubuntu_init/` +for the first boot experience, or `packages/ubuntu_provision/` if they need to be shared between +the two flows. This document will assume you are adding a page to the main installer. + - Under `apps/ubuntu_bootstrap/lib/pages`, create a new directory for the page you would like to add -ie: `apps/ubuntu_bootstrap/lib/pages/` -- Create at minimum the following files: +ie: `apps/ubuntu_bootstrap/lib/pages/`. +- Create at minimum the following files (see existing pages for what these files should include): - `_page.dart`: Defines the UI for the page you would like to add to the installer. - - `_model.dart`: Implements the provider and integrates with backend services to - support your page's functionality. + This forms the `view` within the MVVM pattern. + - `_model.dart`: Implements the provider and integrates with backend services to + support your page's functionality. This forms the `view-model` within the MVVM pattern. - Export your page for use in the installer by adding it to `apps/ubuntu_bootstrap/lib/pages.dart` - Add your page to the installation steps by adding it as an enum to `InstallationStep` in `apps/ubuntu_bootstrap/lib/app/installation_step.dart`. The order of the `InstallationStep` enums determines the order they appear in the installation process. +Not all wizard pages are standalone. For more complicated flows, instead of adding a page, an +embedded wizard can be added to `InstallationStep`. These embedded wizards house their own wizard +steps, and may share state between multiple pages. See `StorageWizard` in +`apps/ubuntu_bootstrap/lib/pages/storage/storage_wizard.dart` + ## Add your service - Under `apps/ubuntu_bootstrap/lib/services`, create a new file `_service.dart` - Within this file, define the backend service that supports your page, and will be called to by -your model. +your model. This forms the `model` within the MVVM pattern. - Export your service for use by your model by adding it to `apps/ubuntu_bootstrap/lib/services.dart` - Register your service for use in the installer by adding a statement @@ -52,4 +65,3 @@ break all integration tests. To fix this, add a new `Future testPage()` function to `UbuntuBootstrapPageTester` in the `/packages/ubuntu_provision_test/lib/src/bootstrap_tester.dart` file. Adding this function in order to each integration test should fix the failing tests. - From ed5c4a0ab23b8e2de508c7790f8c97020ac4cf14 Mon Sep 17 00:00:00 2001 From: Matthew Hagemann Date: Thu, 5 Dec 2024 09:24:34 +0200 Subject: [PATCH 4/4] style: run the formatter --- apps/ubuntu_bootstrap/lib/app/installation_step.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/ubuntu_bootstrap/lib/app/installation_step.dart b/apps/ubuntu_bootstrap/lib/app/installation_step.dart index 95facfe26..370338853 100644 --- a/apps/ubuntu_bootstrap/lib/app/installation_step.dart +++ b/apps/ubuntu_bootstrap/lib/app/installation_step.dart @@ -15,9 +15,9 @@ import 'package:ubuntu_wizard/ubuntu_wizard.dart'; /// New pages must be added as additional enums to integrate into the workflow. /// /// Properties: -/// - `discreteStep`: Indicates whether the step is displayed as a discrete wizard step. Discrete +/// - `discreteStep`: Indicates whether the step is displayed as a discrete wizard step. Discrete /// steps get their own circle progress indicator at the bottom of the window. -/// - `wizardStep`: Specifies if the step is part of the wizard flow. Wizard steps appear with +/// - `wizardStep`: Specifies if the step is part of the wizard flow. Wizard steps appear with /// circle progress indicators and the default step navigation at the bottom of the window. /// - `required`: Marks the step as mandatory in the workflow. /// - `allowedToHide`: Determines if the step can be conditionally hidden.