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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 8 additions & 23 deletions rust/agama-utils/src/api/software/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,57 +19,51 @@
// find current contact information at www.suse.com.
//! Representation of the software settings

use std::collections::HashMap;

use merge::Merge;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use std::collections::HashMap;
use url::Url;

/// User configuration for the localization of the target system.
///
/// This configuration is provided by the user, so all the values are optional.
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Merge, utoipa::ToSchema)]
#[schema(as = software::UserConfig)]
#[serde(rename_all = "camelCase")]
#[merge(strategy = merge::option::recurse)]
pub struct Config {
/// Product related configuration
#[serde(skip_serializing_if = "Option::is_none")]
pub product: Option<ProductConfig>,
/// Software related configuration
#[serde(skip_serializing_if = "Option::is_none")]
pub software: Option<SoftwareConfig>,
}

/// Addon settings for registration
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct AddonConfig {
pub id: String,
/// Optional version of the addon, if not specified the version is found
/// from the available addons
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
/// Free extensions do not require a registration code
#[serde(skip_serializing_if = "Option::is_none")]
pub registration_code: Option<String>,
}

/// Software settings for installation
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Merge, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
#[merge(strategy = merge::option::overwrite_none)]
pub struct ProductConfig {
/// ID of the product to install (e.g., "ALP", "Tumbleweed", etc.)
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub registration_code: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub registration_email: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub registration_url: Option<Url>,
#[serde(skip_serializing_if = "Option::is_none")]
pub addons: Option<Vec<AddonConfig>>,
}

Expand All @@ -84,21 +78,18 @@ impl ProductConfig {
}

/// Software settings for installation
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Merge, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
#[merge(strategy = merge::option::overwrite_none)]
pub struct SoftwareConfig {
/// List of user selected patterns to install.
#[serde(skip_serializing_if = "Option::is_none")]
pub patterns: Option<PatternsConfig>,
/// List of user selected packages to install.
#[serde(skip_serializing_if = "Option::is_none")]
pub packages: Option<Vec<String>>,
/// List of user specified repositories to use on top of default ones.
#[serde(skip_serializing_if = "Option::is_none")]
pub extra_repositories: Option<Vec<RepositoryConfig>>,
/// Flag indicating if only hard requirements should be used by solver.
#[serde(skip_serializing_if = "Option::is_none")]
pub only_required: Option<bool>,
}

Expand All @@ -118,11 +109,10 @@ impl Default for PatternsConfig {
}
}

#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
pub struct PatternsMap {
#[serde(skip_serializing_if = "Option::is_none")]
pub add: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub remove: Option<Vec<String>>,
}

Expand Down Expand Up @@ -165,32 +155,27 @@ impl SoftwareConfig {
}

/// Parameters for creating new a repository
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct RepositoryConfig {
/// repository alias. Has to be unique
pub alias: String,
/// repository name, if not specified the alias is used
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
/// Repository url (raw format without expanded variables)
pub url: String,
/// product directory (currently not used, valid only for multiproduct DVDs)
#[serde(skip_serializing_if = "Option::is_none")]
pub product_dir: Option<String>,
/// Whether the repository is enabled, if missing the repository is enabled
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
/// Repository priority, lower number means higher priority, the default priority is 99
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<i32>,
/// Whenever repository can be unsigned. Default is false
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_unsigned: Option<bool>,
/// List of fingerprints for GPG keys used for repository signing. If specified,
/// the new list of fingerprints overrides the existing ones instead of merging
/// with them. By default empty.
#[serde(skip_serializing_if = "Option::is_none")]
pub gpg_fingerprints: Option<Vec<String>>,
}

Expand Down
3 changes: 3 additions & 0 deletions rust/agama-utils/src/api/software/system_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
// find current contact information at www.suse.com.

use serde::Serialize;
use serde_with::skip_serializing_none;

/// Software-related information of the system where the installer
/// is running.
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, utoipa::ToSchema)]
pub struct SystemInfo {
/// List of known patterns.
Expand Down Expand Up @@ -66,6 +68,7 @@ pub struct Pattern {
pub preselected: bool,
}

#[skip_serializing_none]
#[derive(Clone, Default, Debug, Serialize, utoipa::ToSchema)]
pub struct RegistrationInfo {
/// Registration code.
Expand Down
4 changes: 2 additions & 2 deletions web/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ import { useSystem } from "~/hooks/model/system";
import { Product } from "~/types/software";
import { PATHS } from "~/router";
import { PRODUCT } from "~/routes/paths";
import type { Config } from "~/api";
import type { Progress, Stage } from "~/model/status";
import App from "./App";
import { System } from "~/model/system/network";
import type { Config } from "~/model/config";
import type { Progress, Stage } from "~/model/status";

jest.mock("~/client");

Expand Down
4 changes: 2 additions & 2 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { useStatusChanges, useStatus } from "~/hooks/model/status";
import { useSystemChanges } from "~/hooks/model/system";
import { useProposalChanges } from "~/hooks/model/proposal";
import { useIssuesChanges } from "~/hooks/model/issue";
import { useProduct } from "~/hooks/model/config";
import { useProductInfo } from "~/hooks/model/config/product";
import { ROOT } from "~/routes/paths";
import { useQueryClient } from "@tanstack/react-query";

Expand All @@ -38,7 +38,7 @@ import { useQueryClient } from "@tanstack/react-query";
*/
const Content = () => {
const location = useLocation();
const product = useProduct();
const product = useProductInfo();
const { progresses, stage } = useStatus();

console.log("App Content component", {
Expand Down
6 changes: 1 addition & 5 deletions web/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,4 @@ export {
getStorageJobs,
};

export type { Response, System, Config, Proposal };
export type * as system from "~/model/system";
export type * as config from "~/model/config";
export type * as proposal from "~/model/proposal";
export type * as issue from "~/model/issue";
export type { Response };
4 changes: 2 additions & 2 deletions web/src/components/core/ConfirmPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ import NetworkDetailsItem from "~/components/network/NetworkDetailsItem";
import SoftwareDetailsItem from "~/components/software/SoftwareDetailsItem";
import PotentialDataLossAlert from "~/components/storage/PotentialDataLossAlert";
import { startInstallation } from "~/model/manager";
import { useProduct } from "~/hooks/model/config";
import { useProductInfo } from "~/hooks/model/config/product";
import { PRODUCT } from "~/routes/paths";
import { useDestructiveActions } from "~/hooks/use-destructive-actions";
import { _ } from "~/i18n";

export default function ConfirmPage() {
const product = useProduct();
const product = useProductInfo();
const { actions } = useDestructiveActions();
const hasDestructiveActions = actions.length > 0;

Expand Down
7 changes: 3 additions & 4 deletions web/src/components/core/InstallationFinished.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@
*/

import React from "react";

import { screen } from "@testing-library/react";
import { plainRender } from "~/test-utils";
import InstallationFinished from "./InstallationFinished";
import { Encryption } from "~/model/config/storage";
import type { Storage } from "~/model/config";

jest.mock("~/queries/status", () => ({
...jest.requireActual("~/queries/status"),
Expand All @@ -39,12 +38,12 @@ type guidedEncryption = {
pbkdFunction?: string;
};

let mockEncryption: undefined | Encryption | guidedEncryption;
let mockEncryption: undefined | Storage.Encryption | guidedEncryption;
let mockType: storageConfigType;

const mockStorageConfig = (
type: storageConfigType,
encryption: undefined | Encryption | guidedEncryption,
encryption: undefined | Storage.Encryption | guidedEncryption,
) => {
const encryptionHash = {};
if (encryption !== undefined) encryptionHash["encryption"] = encryption;
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/core/InstallerOptions.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import React from "react";
import { screen, within } from "@testing-library/react";
import { installerRender, mockRoutes } from "~/test-utils";
import { useSystem } from "~/hooks/model/system";
import { useProduct } from "~/hooks/model/config";
import { useProductInfo } from "~/hooks/model/config/product";
import { Product } from "~/types/software";
import { Keymap, Locale } from "~/model/system/l10n";
import { Progress, Stage } from "~/model/status";
Expand Down Expand Up @@ -88,7 +88,7 @@ jest.mock("~/hooks/api", () => ({
stage: mockStateFn(),
progresses: mockProgressesFn(),
}),
useProduct: (): ReturnType<typeof useProduct> => mockSelectedProductFn(),
useProductInfo: (): ReturnType<typeof useProductInfo> => mockSelectedProductFn(),
}));

jest.mock("~/context/installerL10n", () => ({
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/core/InstallerOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import { localConnection } from "~/utils";
import { _ } from "~/i18n";
import supportedLanguages from "~/languages.json";
import { PRODUCT, ROOT, L10N } from "~/routes/paths";
import { useProduct } from "~/hooks/model/config";
import { useProductInfo } from "~/hooks/model/config/product";
import { useSystem } from "~/hooks/model/system";
import { useStatus } from "~/hooks/model/status";
import { patchConfig } from "~/api";
Expand Down Expand Up @@ -556,7 +556,7 @@ export default function InstallerOptions({
} = useSystem();
const { language, keymap, changeLanguage, changeKeymap } = useInstallerL10n();
const { stage } = useStatus();
const selectedProduct = useProduct();
const selectedProduct = useProductInfo();
const initialFormState = {
language,
keymap,
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/layout/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import { ChangeProductOption, InstallButton, InstallerOptions, SkipTo } from "~/
import ProgressStatusMonitor from "../core/ProgressStatusMonitor";
import { ROOT } from "~/routes/paths";
import { _ } from "~/i18n";
import { useProduct } from "~/hooks/model/config";
import { useProductInfo } from "~/hooks/model/config/product";

export type HeaderProps = {
/** Whether the application sidebar should be mounted or not */
Expand Down Expand Up @@ -112,7 +112,7 @@ export default function Header({
isSidebarOpen,
toggleSidebar,
}: HeaderProps): React.ReactNode {
const product = useProduct();
const product = useProductInfo();
const routeMatches = useMatches() as Route[];
const currentRoute = routeMatches.at(-1);
// TODO: translate title
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/layout/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ import {
import { Icon } from "~/components/layout";
import { rootRoutes } from "~/router";
import { _ } from "~/i18n";
import { useProduct } from "~/hooks/model/config";
import { useProductInfo } from "~/hooks/model/config/product";

const MainNavigation = (): React.ReactNode => {
const product = useProduct();
const product = useProductInfo();
const location = useLocation();

if (!product) {
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/overview/OverviewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ import React from "react";
import { Navigate } from "react-router";
import { Content, Grid, GridItem } from "@patternfly/react-core";
import { Page } from "~/components/core";
import { useProduct } from "~/hooks/model/config";
import { useProductInfo } from "~/hooks/model/config/product";
import { PRODUCT } from "~/routes/paths";
import { _ } from "~/i18n";
import SystemInformationSection from "./SystemInformationSection";
import InstallationSummarySection from "./InstallationSummarySection";

export default function OverviewPage() {
const product = useProduct();
const product = useProductInfo();

if (!product) {
return <Navigate to={PRODUCT.root} />;
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/product/ProductRegistrationAlert.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import React from "react";
import { screen } from "@testing-library/react";
import { installerRender, mockRoutes } from "~/test-utils";
import { useSystem } from "~/hooks/model/system";
import { useProduct } from "~/hooks/model/config";
import { useProductInfo } from "~/hooks/model/config/product";
import { useIssues } from "~/hooks/model/issue";
import { Issue } from "~/model/issue";
import { PRODUCT, REGISTRATION, ROOT } from "~/routes/paths";
Expand Down Expand Up @@ -65,7 +65,7 @@ jest.mock("~/hooks/api", () => ({
products: [tw, sle],
network,
}),
useProduct: (): ReturnType<typeof useProduct> => mockSelectedProduct(),
useProductInfo: (): ReturnType<typeof useProductInfo> => mockSelectedProduct(),
useIssues: (): ReturnType<typeof useIssues> => mockIssues(),
}));

Expand Down
4 changes: 2 additions & 2 deletions web/src/components/product/ProductRegistrationAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { REGISTRATION, SIDE_PATHS } from "~/routes/paths";
import { _ } from "~/i18n";
import { sprintf } from "sprintf-js";
import { useIssues } from "~/hooks/model/issue";
import { useProduct } from "~/hooks/model/config";
import { useProductInfo } from "~/hooks/model/config/product";

const LinkToRegistration = ({ text }: { text: string }) => {
const location = useLocation();
Expand All @@ -44,7 +44,7 @@ const LinkToRegistration = ({ text }: { text: string }) => {

export default function ProductRegistrationAlert() {
const location = useLocation();
const product = useProduct();
const product = useProductInfo();
// FIXME: what scope reports these issues with the new API?
const issues = useIssues("product");
const registrationRequired = issues?.find((i) => i.class === "missing_registration");
Expand Down
Loading
Loading