debian-image-builder-frontend/src/store/wizardSlice.ts
2025-04-25 10:31:43 +02:00

1178 lines
33 KiB
TypeScript

import { PayloadAction, createSlice } from '@reduxjs/toolkit';
import { v4 as uuidv4 } from 'uuid';
import type { ApiRepositoryResponseRead } from './contentSourcesApi';
import type {
CustomRepository,
Distributions,
ImageRequest,
ImageTypes,
Locale,
Repository,
Timezone,
User,
} from './imageBuilderApi';
import type { ActivationKeys } from './rhsmApi';
import type { FileSystemConfigurationType } from '../Components/CreateImageWizard/steps/FileSystem';
import type {
Partition,
Units,
} from '../Components/CreateImageWizard/steps/FileSystem/FileSystemTable';
import type {
GroupWithRepositoryInfo,
IBPackageWithRepositoryInfo,
} from '../Components/CreateImageWizard/steps/Packages/Packages';
import type { AwsShareMethod } from '../Components/CreateImageWizard/steps/TargetEnvironment/Aws';
import type { AzureShareMethod } from '../Components/CreateImageWizard/steps/TargetEnvironment/Azure';
import type {
GcpAccountType,
GcpShareMethod,
} from '../Components/CreateImageWizard/steps/TargetEnvironment/Gcp';
import type { V1ListSourceResponseItem } from '../Components/CreateImageWizard/types';
import { generateDefaultName } from '../Components/CreateImageWizard/utilities/useGenerateDefaultName';
import { RHEL_9, X86_64 } from '../constants';
import { yyyyMMddFormat } from '../Utilities/time';
import type { RootState } from '.';
type WizardModeOptions = 'create' | 'edit';
export type RegistrationType =
| 'register-later'
| 'register-now'
| 'register-now-insights'
| 'register-now-rhc'
| 'register-satellite';
export type ComplianceType = 'openscap' | 'compliance';
export type UserWithAdditionalInfo = {
[K in keyof User]-?: NonNullable<User[K]>;
} & {
isAdministrator: boolean;
};
type UserPayload = {
index: number;
name: string;
};
type UserPasswordPayload = {
index: number;
password: string;
};
type UserSshKeyPayload = {
index: number;
sshKey: string;
};
type UserAdministratorPayload = {
index: number;
isAdministrator: boolean;
};
type UserGroupPayload = {
index: number;
group: string;
};
export type wizardState = {
env: {
serverUrl: string;
baseUrl: string;
};
blueprintId?: string;
wizardMode: WizardModeOptions;
architecture: ImageRequest['architecture'];
distribution: Distributions;
imageTypes: ImageTypes[];
aws: {
accountId: string;
shareMethod: AwsShareMethod;
source: V1ListSourceResponseItem | undefined;
sourceId?: string | undefined;
};
azure: {
shareMethod: AzureShareMethod;
tenantId: string;
subscriptionId: string;
source: string;
resourceGroup: string;
hyperVGeneration: 'V1' | 'V2';
};
gcp: {
shareMethod: GcpShareMethod;
accountType: GcpAccountType;
email: string;
};
registration: {
registrationType: RegistrationType;
activationKey: ActivationKeys['name'];
satelliteRegistration: {
command: string | undefined;
caCert: string | undefined;
};
};
compliance: {
complianceType: ComplianceType;
policyID: string | undefined;
profileID: string | undefined;
policyTitle: string | undefined;
};
fileSystem: {
mode: FileSystemConfigurationType;
partitions: Partition[];
};
snapshotting: {
useLatest: boolean;
snapshotDate: string;
template: string;
};
users: UserWithAdditionalInfo[];
firstBoot: {
script: string;
};
repositories: {
customRepositories: CustomRepository[];
payloadRepositories: Repository[];
recommendedRepositories: ApiRepositoryResponseRead[];
redHatRepositories: Repository[];
};
packages: IBPackageWithRepositoryInfo[];
groups: GroupWithRepositoryInfo[];
services: {
enabled: string[];
masked: string[];
disabled: string[];
};
kernel: {
name: string;
append: string[];
};
locale: Locale;
details: {
blueprintName: string;
isCustomName: boolean;
blueprintDescription: string;
};
timezone: Timezone;
hostname: string;
firewall: {
ports: string[];
services: {
enabled: string[];
disabled: string[];
};
};
metadata?: {
parent_id: string | null;
exported_at: string;
is_on_prem: boolean;
};
};
export const initialState: wizardState = {
env: {
serverUrl: '',
baseUrl: '',
},
wizardMode: 'create',
architecture: X86_64,
distribution: RHEL_9,
imageTypes: [],
aws: {
accountId: '',
shareMethod: 'sources',
source: undefined,
},
azure: {
shareMethod: 'sources',
tenantId: '',
subscriptionId: '',
source: '',
resourceGroup: '',
hyperVGeneration: 'V2',
},
gcp: {
shareMethod: 'withGoogle',
accountType: 'user',
email: '',
},
registration: {
registrationType: process.env.IS_ON_PREMISE
? 'register-later'
: 'register-now-rhc',
activationKey: undefined,
satelliteRegistration: {
command: undefined,
caCert: undefined,
},
},
compliance: {
complianceType: 'openscap',
policyID: undefined,
profileID: undefined,
policyTitle: undefined,
},
fileSystem: {
mode: 'automatic',
partitions: [],
},
snapshotting: {
useLatest: true,
snapshotDate: '',
template: '',
},
repositories: {
customRepositories: [],
payloadRepositories: [],
recommendedRepositories: [],
redHatRepositories: [],
},
packages: [],
groups: [],
services: {
enabled: [],
masked: [],
disabled: [],
},
kernel: {
name: '',
append: [],
},
locale: {
languages: [],
keyboard: '',
},
details: {
blueprintName: generateDefaultName(RHEL_9, X86_64),
isCustomName: false,
blueprintDescription: '',
},
timezone: {
timezone: '',
ntpservers: [],
},
hostname: '',
firewall: {
ports: [],
services: {
enabled: [],
disabled: [],
},
},
firstBoot: { script: '' },
users: [],
};
export const selectServerUrl = (state: RootState) => {
return state.wizard.env.serverUrl;
};
export const selectWizardMode = (state: RootState) => {
return state.wizard.wizardMode;
};
export const selectBlueprintId = (state: RootState) => {
return state.wizard.blueprintId;
};
export const selectBaseUrl = (state: RootState) => {
return state.wizard.env.baseUrl;
};
export const selectArchitecture = (state: RootState) => {
return state.wizard.architecture;
};
export const selectDistribution = (state: RootState) => {
return state.wizard.distribution;
};
export const selectImageTypes = (state: RootState) => {
return state.wizard.imageTypes;
};
export const selectAwsAccountId = (state: RootState): string => {
return state.wizard.aws.accountId;
};
export const selectAwsSourceId = (state: RootState): string | undefined => {
return state.wizard.aws.sourceId;
};
export const selectAwsShareMethod = (state: RootState) => {
return state.wizard.aws.shareMethod;
};
export const selectAzureTenantId = (state: RootState) => {
return state.wizard.azure.tenantId;
};
export const selectAzureShareMethod = (state: RootState) => {
return state.wizard.azure.shareMethod;
};
export const selectAzureSubscriptionId = (state: RootState) => {
return state.wizard.azure.subscriptionId;
};
export const selectAzureSource = (state: RootState) => {
return state.wizard.azure.source;
};
export const selectAzureResourceGroup = (state: RootState) => {
return state.wizard.azure.resourceGroup;
};
export const selectAzureHyperVGeneration = (state: RootState) => {
return state.wizard.azure.hyperVGeneration;
};
export const selectGcpShareMethod = (state: RootState) => {
return state.wizard.gcp.shareMethod;
};
export const selectGcpAccountType = (state: RootState) => {
return state.wizard.gcp.accountType;
};
export const selectGcpEmail = (state: RootState) => {
return state.wizard.gcp.email;
};
export const selectRegistrationType = (state: RootState) => {
return state.wizard.registration.registrationType;
};
export const selectActivationKey = (state: RootState) => {
return state.wizard.registration.activationKey;
};
export const selectSatelliteRegistrationCommand = (state: RootState) => {
return state.wizard.registration.satelliteRegistration?.command;
};
export const selectSatelliteCaCertificate = (state: RootState) => {
return state.wizard.registration.satelliteRegistration.caCert;
};
export const selectComplianceProfileID = (state: RootState) => {
return state.wizard.compliance.profileID;
};
export const selectCompliancePolicyID = (state: RootState) => {
return state.wizard.compliance.policyID;
};
export const selectCompliancePolicyTitle = (state: RootState) => {
return state.wizard.compliance.policyTitle;
};
export const selectComplianceType = (state: RootState) => {
return state.wizard.compliance.complianceType;
};
export const selectFileSystemConfigurationType = (state: RootState) => {
return state.wizard.fileSystem.mode;
};
export const selectPartitions = (state: RootState) => {
return state.wizard.fileSystem.partitions;
};
export const selectUseLatest = (state: RootState) => {
return state.wizard.snapshotting.useLatest;
};
export const selectSnapshotDate = (state: RootState) => {
return state.wizard.snapshotting.snapshotDate;
};
export const selectTemplate = (state: RootState) => {
return state.wizard.snapshotting.template;
};
export const selectCustomRepositories = (state: RootState) => {
return state.wizard.repositories.customRepositories;
};
export const selectPayloadRepositories = (state: RootState) => {
return state.wizard.repositories.payloadRepositories;
};
export const selectRecommendedRepositories = (state: RootState) => {
return state.wizard.repositories.recommendedRepositories;
};
export const selectRedHatRepositories = (state: RootState) => {
return state.wizard.repositories.redHatRepositories;
};
export const selectPackages = (state: RootState) => {
return state.wizard.packages;
};
export const selectGroups = (state: RootState) => {
return state.wizard.groups;
};
export const selectServices = (state: RootState) => {
return state.wizard.services;
};
export const selectUsers = (state: RootState) => {
return state.wizard.users;
};
export const selectKernel = (state: RootState) => {
return state.wizard.kernel;
};
export const selectLanguages = (state: RootState) => {
return state.wizard.locale.languages;
};
export const selectKeyboard = (state: RootState) => {
return state.wizard.locale.keyboard;
};
export const selectBlueprintName = (state: RootState) => {
return state.wizard.details.blueprintName;
};
export const selectIsCustomName = (state: RootState) => {
return state.wizard.details.isCustomName;
};
export const selectMetadata = (state: RootState) => {
return state.wizard.metadata;
};
export const selectBlueprintDescription = (state: RootState) => {
return state.wizard.details.blueprintDescription;
};
export const selectFirstBootScript = (state: RootState) => {
return state.wizard.firstBoot?.script;
};
export const selectTimezone = (state: RootState) => {
return state.wizard.timezone.timezone;
};
export const selectNtpServers = (state: RootState) => {
return state.wizard.timezone.ntpservers;
};
export const selectHostname = (state: RootState) => {
return state.wizard.hostname;
};
export const selectFirewall = (state: RootState) => {
return state.wizard.firewall;
};
export const wizardSlice = createSlice({
name: 'wizard',
initialState,
reducers: {
initializeWizard: () => initialState,
loadWizardState: (state, action: PayloadAction<wizardState>) =>
action.payload,
changeServerUrl: (state, action: PayloadAction<string>) => {
state.env.serverUrl = action.payload;
},
changeBaseUrl: (state, action: PayloadAction<string>) => {
state.env.baseUrl = action.payload;
},
changeArchitecture: (
state,
action: PayloadAction<ImageRequest['architecture']>
) => {
state.architecture = action.payload;
},
changeDistribution: (state, action: PayloadAction<Distributions>) => {
state.distribution = action.payload;
},
addImageType: (state, action: PayloadAction<ImageTypes>) => {
// Remove (if present) before adding to avoid duplicates
state.imageTypes = state.imageTypes.filter(
(imageType) => imageType !== action.payload
);
state.imageTypes.push(action.payload);
},
removeImageType: (state, action: PayloadAction<ImageTypes>) => {
state.imageTypes = state.imageTypes.filter(
(imageType) => imageType !== action.payload
);
},
changeImageTypes: (state, action: PayloadAction<ImageTypes[]>) => {
state.imageTypes = action.payload;
},
changeAwsAccountId: (state, action: PayloadAction<string>) => {
state.aws.accountId = action.payload;
},
changeAwsShareMethod: (state, action: PayloadAction<AwsShareMethod>) => {
state.aws.shareMethod = action.payload;
},
changeAwsSourceId: (state, action: PayloadAction<string | undefined>) => {
state.aws.sourceId = action.payload;
},
reinitializeAws: (state) => {
state.aws.accountId = '';
state.aws.shareMethod = 'sources';
state.aws.source = undefined;
},
changeAzureTenantId: (state, action: PayloadAction<string>) => {
state.azure.tenantId = action.payload;
},
changeAzureShareMethod: (
state,
action: PayloadAction<AzureShareMethod>
) => {
state.azure.shareMethod = action.payload;
},
changeAzureSubscriptionId: (state, action: PayloadAction<string>) => {
state.azure.subscriptionId = action.payload;
},
changeAzureSource: (state, action: PayloadAction<string>) => {
state.azure.source = action.payload;
},
changeAzureResourceGroup: (state, action: PayloadAction<string>) => {
state.azure.resourceGroup = action.payload;
},
changeAzureHyperVGeneration: (
state,
action: PayloadAction<'V1' | 'V2'>
) => {
state.azure.hyperVGeneration = action.payload;
},
reinitializeAzure: (state) => {
state.azure.shareMethod = 'sources';
state.azure.tenantId = '';
state.azure.subscriptionId = '';
state.azure.source = '';
state.azure.resourceGroup = '';
},
changeGcpShareMethod: (state, action: PayloadAction<GcpShareMethod>) => {
switch (action.payload) {
case 'withInsights':
state.gcp.accountType = undefined;
state.gcp.email = '';
break;
case 'withGoogle':
state.gcp.accountType = 'user';
}
state.gcp.shareMethod = action.payload;
},
changeGcpAccountType: (state, action: PayloadAction<GcpAccountType>) => {
state.gcp.accountType = action.payload;
},
changeGcpEmail: (state, action: PayloadAction<string>) => {
state.gcp.email = action.payload;
},
reinitializeGcp: (state) => {
state.gcp.shareMethod = 'withGoogle';
state.gcp.accountType = 'user';
state.gcp.email = '';
},
changeRegistrationType: (
state,
action: PayloadAction<RegistrationType>
) => {
state.registration.registrationType = action.payload;
},
changeSatelliteRegistrationCommand: (
state,
action: PayloadAction<string>
) => {
state.registration.satelliteRegistration.command = action.payload;
},
changeSatelliteCaCertificate: (state, action: PayloadAction<string>) => {
state.registration.satelliteRegistration.caCert = action.payload;
},
changeActivationKey: (
state,
action: PayloadAction<ActivationKeys['name']>
) => {
state.registration.activationKey = action.payload;
},
changeComplianceType: (state, action: PayloadAction<ComplianceType>) => {
state.compliance.complianceType = action.payload;
},
changeCompliance: (
state,
action: PayloadAction<{
policyID: string | undefined;
profileID: string | undefined;
policyTitle: string | undefined;
}>
) => {
state.compliance.policyID = action.payload.policyID;
state.compliance.profileID = action.payload.profileID;
state.compliance.policyTitle = action.payload.policyTitle;
},
changeFileSystemConfiguration: (
state,
action: PayloadAction<Partition[]>
) => {
state.fileSystem.partitions = action.payload;
},
changeFileSystemConfigurationType: (
state,
action: PayloadAction<FileSystemConfigurationType>
) => {
const currentMode = state.fileSystem.mode;
// Only trigger if mode is being *changed*
if (currentMode !== action.payload) {
state.fileSystem.mode = action.payload;
switch (action.payload) {
case 'automatic':
state.fileSystem.partitions = [];
break;
case 'manual':
state.fileSystem.partitions = [
{
id: uuidv4(),
mountpoint: '/',
min_size: '10',
unit: 'GiB',
},
];
}
}
},
clearPartitions: (state) => {
const currentMode = state.fileSystem.mode;
if (currentMode === 'manual') {
state.fileSystem.partitions = [
{
id: uuidv4(),
mountpoint: '/',
min_size: '10',
unit: 'GiB',
},
];
}
},
addPartition: (state, action: PayloadAction<Partition>) => {
// Duplicate partitions are allowed temporarily, the wizard is responsible for final validation
state.fileSystem.partitions.push(action.payload);
},
removePartition: (state, action: PayloadAction<Partition['id']>) => {
const index = state.fileSystem.partitions.findIndex(
(partition) => partition.id === action.payload
);
if (index !== -1) {
state.fileSystem.partitions.splice(index, 1);
}
},
removePartitionByMountpoint: (
state,
action: PayloadAction<Partition['mountpoint']>
) => {
const index = state.fileSystem.partitions.findIndex(
(partition) => partition.mountpoint === action.payload
);
if (index !== -1) {
state.fileSystem.partitions.splice(index, 1);
}
},
changePartitionOrder: (state, action: PayloadAction<string[]>) => {
state.fileSystem.partitions = state.fileSystem.partitions.sort(
(a, b) => action.payload.indexOf(a.id) - action.payload.indexOf(b.id)
);
},
changePartitionMountpoint: (
state,
action: PayloadAction<{ id: string; mountpoint: string }>
) => {
const { id, mountpoint } = action.payload;
const partitionIndex = state.fileSystem.partitions.findIndex(
(partition) => partition.id === id
);
if (partitionIndex !== -1) {
state.fileSystem.partitions[partitionIndex].mountpoint = mountpoint;
}
},
changePartitionUnit: (
state,
action: PayloadAction<{ id: string; unit: Units }>
) => {
const { id, unit } = action.payload;
const partitionIndex = state.fileSystem.partitions.findIndex(
(partition) => partition.id === id
);
if (partitionIndex !== -1) {
state.fileSystem.partitions[partitionIndex].unit = unit;
}
},
changePartitionMinSize: (
state,
action: PayloadAction<{ id: string; min_size: string }>
) => {
const { id, min_size } = action.payload;
const partitionIndex = state.fileSystem.partitions.findIndex(
(partition) => partition.id === id
);
if (partitionIndex !== -1) {
state.fileSystem.partitions[partitionIndex].min_size = min_size;
}
},
changeUseLatest: (state, action: PayloadAction<boolean>) => {
if (!action.payload && state.snapshotting.snapshotDate === '') {
state.snapshotting.snapshotDate = yyyyMMddFormat(new Date());
}
state.snapshotting.useLatest = action.payload;
},
changeSnapshotDate: (state, action: PayloadAction<string>) => {
const yyyyMMDDRegex = /^\d{4}-\d{2}-\d{2}$/;
const date = new Date(action.payload);
if (action.payload === '') {
state.snapshotting.snapshotDate = '';
} else if (yyyyMMDDRegex.test(action.payload) && !isNaN(date.getTime())) {
state.snapshotting.snapshotDate = date.toISOString();
}
},
changeTemplate: (state, action: PayloadAction<string>) => {
state.snapshotting.template = action.payload;
},
importCustomRepositories: (
state,
action: PayloadAction<CustomRepository[]>
) => {
state.repositories.customRepositories = [
...state.repositories.customRepositories,
...action.payload,
];
},
changeCustomRepositories: (
state,
action: PayloadAction<CustomRepository[]>
) => {
state.repositories.customRepositories = action.payload;
},
changePayloadRepositories: (state, action: PayloadAction<Repository[]>) => {
state.repositories.payloadRepositories = action.payload;
},
changeRedHatRepositories: (state, action: PayloadAction<Repository[]>) => {
state.repositories.redHatRepositories = action.payload;
},
addRecommendedRepository: (
state,
action: PayloadAction<ApiRepositoryResponseRead>
) => {
if (
!state.repositories.recommendedRepositories.some(
(repo) => repo.url === action.payload.url
)
) {
state.repositories.recommendedRepositories.push(action.payload);
}
},
removeRecommendedRepository: (
state,
action: PayloadAction<ApiRepositoryResponseRead>
) => {
state.repositories.recommendedRepositories =
state.repositories.recommendedRepositories.filter(
(repo) => repo.url !== action.payload.url
);
},
addPackage: (state, action: PayloadAction<IBPackageWithRepositoryInfo>) => {
const existingPackageIndex = state.packages.findIndex(
(pkg) => pkg.name === action.payload.name
);
if (existingPackageIndex !== -1) {
state.packages[existingPackageIndex] = action.payload;
} else {
state.packages.push(action.payload);
}
},
removePackage: (
state,
action: PayloadAction<IBPackageWithRepositoryInfo['name']>
) => {
const index = state.packages.findIndex(
(pkg) => pkg.name === action.payload
);
if (index !== -1) {
state.packages.splice(index, 1);
}
},
addGroup: (state, action: PayloadAction<GroupWithRepositoryInfo>) => {
const existingGrpIndex = state.groups.findIndex(
(grp) => grp.name === action.payload.name
);
if (existingGrpIndex !== -1) {
state.groups[existingGrpIndex] = action.payload;
} else {
state.groups.push(action.payload);
}
},
removeGroup: (
state,
action: PayloadAction<GroupWithRepositoryInfo['name']>
) => {
const index = state.groups.findIndex(
(grp) => grp.name === action.payload
);
if (index !== -1) {
state.groups.splice(index, 1);
}
},
addLanguage: (state, action: PayloadAction<string>) => {
if (
state.locale.languages &&
!state.locale.languages.some((lang) => lang === action.payload)
) {
state.locale.languages.push(action.payload);
}
},
removeLanguage: (state, action: PayloadAction<string>) => {
if (state.locale.languages) {
const index = state.locale.languages.findIndex(
(lang) => lang === action.payload
);
if (index !== -1) {
state.locale.languages.splice(index, 1);
}
}
},
clearLanguages: (state) => {
state.locale.languages = [];
},
changeKeyboard: (state, action: PayloadAction<string>) => {
state.locale.keyboard = action.payload;
},
changeBlueprintName: (state, action: PayloadAction<string>) => {
state.details.blueprintName = action.payload;
},
setIsCustomName: (state) => {
state.details.isCustomName = true;
},
changeBlueprintDescription: (state, action: PayloadAction<string>) => {
state.details.blueprintDescription = action.payload;
},
setFirstBootScript: (state, action: PayloadAction<string>) => {
state.firstBoot.script = action.payload;
},
changeEnabledServices: (state, action: PayloadAction<string[]>) => {
state.services.enabled = action.payload;
},
addEnabledService: (state, action: PayloadAction<string>) => {
if (
!state.services.enabled.some((service) => service === action.payload)
) {
state.services.enabled.push(action.payload);
}
},
removeEnabledService: (state, action: PayloadAction<string>) => {
const index = state.services.enabled.findIndex(
(service) => service === action.payload
);
if (index !== -1) {
state.services.enabled.splice(index, 1);
}
},
changeMaskedServices: (state, action: PayloadAction<string[]>) => {
state.services.masked = action.payload;
},
addMaskedService: (state, action: PayloadAction<string>) => {
if (
!state.services.masked.some((service) => service === action.payload)
) {
state.services.masked.push(action.payload);
}
},
removeMaskedService: (state, action: PayloadAction<string>) => {
const index = state.services.masked.findIndex(
(service) => service === action.payload
);
if (index !== -1) {
state.services.masked.splice(index, 1);
}
},
changeDisabledServices: (state, action: PayloadAction<string[]>) => {
state.services.disabled = action.payload;
},
addDisabledService: (state, action: PayloadAction<string>) => {
if (
!state.services.disabled.some((service) => service === action.payload)
) {
state.services.disabled.push(action.payload);
}
},
removeDisabledService: (state, action: PayloadAction<string>) => {
const index = state.services.disabled.findIndex(
(service) => service === action.payload
);
if (index !== -1) {
state.services.disabled.splice(index, 1);
}
},
changeKernelName: (state, action: PayloadAction<string>) => {
state.kernel.name = action.payload;
},
addKernelArg: (state, action: PayloadAction<string>) => {
const existingArgIndex = state.kernel.append.findIndex(
(arg) => arg === action.payload
);
if (existingArgIndex !== -1) {
state.kernel.append[existingArgIndex] = action.payload;
} else {
state.kernel.append.push(action.payload);
}
},
removeKernelArg: (state, action: PayloadAction<string>) => {
if (state.kernel.append.length > 0) {
const index = state.kernel.append.findIndex(
(arg) => arg === action.payload
);
if (index !== -1) {
state.kernel.append.splice(index, 1);
}
}
},
clearKernelAppend: (state) => {
state.kernel.append = [];
},
addEnabledFirewallService: (state, action: PayloadAction<string>) => {
if (
!state.firewall.services.enabled.some(
(service) => service === action.payload
)
) {
state.firewall.services.enabled.push(action.payload);
}
},
removeEnabledFirewallService: (state, action: PayloadAction<string>) => {
const index = state.firewall.services.enabled.findIndex(
(service) => service === action.payload
);
if (index !== -1) {
state.firewall.services.enabled.splice(index, 1);
}
},
addDisabledFirewallService: (state, action: PayloadAction<string>) => {
if (
!state.firewall.services.disabled.some(
(service) => service === action.payload
)
) {
state.firewall.services.disabled.push(action.payload);
}
},
removeDisabledFirewallService: (state, action: PayloadAction<string>) => {
const index = state.firewall.services.disabled.findIndex(
(service) => service === action.payload
);
if (index !== -1) {
state.firewall.services.disabled.splice(index, 1);
}
},
changeTimezone: (state, action: PayloadAction<string>) => {
state.timezone.timezone = action.payload;
},
addNtpServer: (state, action: PayloadAction<string>) => {
if (
!state.timezone.ntpservers?.some((server) => server === action.payload)
) {
state.timezone.ntpservers?.push(action.payload);
}
},
removeNtpServer: (state, action: PayloadAction<string>) => {
if (state.timezone.ntpservers) {
const index = state.timezone.ntpservers.findIndex(
(server) => server === action.payload
);
if (index !== -1) {
state.timezone.ntpservers.splice(index, 1);
}
}
},
changeHostname: (state, action: PayloadAction<string>) => {
state.hostname = action.payload;
},
addUser: (state) => {
const newUser = {
name: '',
password: '',
ssh_key: '',
groups: [],
isAdministrator: false,
hasPassword: false,
};
state.users.push(newUser);
},
removeUser: (state, action: PayloadAction<number>) => {
state.users = state.users.filter((_, index) => index !== action.payload);
},
setUserNameByIndex: (state, action: PayloadAction<UserPayload>) => {
state.users[action.payload.index].name = action.payload.name;
},
setUserPasswordByIndex: (
state,
action: PayloadAction<UserPasswordPayload>
) => {
state.users[action.payload.index].password = action.payload.password;
},
setUserSshKeyByIndex: (state, action: PayloadAction<UserSshKeyPayload>) => {
state.users[action.payload.index].ssh_key = action.payload.sshKey;
},
addPort: (state, action: PayloadAction<string>) => {
if (!state.firewall.ports.some((port) => port === action.payload)) {
state.firewall.ports.push(action.payload);
}
},
removePort: (state, action: PayloadAction<string>) => {
const index = state.firewall.ports.findIndex(
(port) => port === action.payload
);
if (index !== -1) {
state.firewall.ports.splice(index, 1);
}
},
setUserAdministratorByIndex: (
state,
action: PayloadAction<UserAdministratorPayload>
) => {
const { index, isAdministrator } = action.payload;
const user = state.users[index];
user.isAdministrator = isAdministrator;
if (isAdministrator) {
user.groups.push('wheel');
} else {
user.groups = user.groups.filter((group) => group !== 'wheel');
}
},
addUserGroupByIndex: (state, action: PayloadAction<UserGroupPayload>) => {
if (
!state.users[action.payload.index].groups.some(
(group) => group === action.payload.group
)
) {
state.users[action.payload.index].groups.push(action.payload.group);
}
},
removeUserGroupByIndex: (
state,
action: PayloadAction<UserGroupPayload>
) => {
const groupIndex = state.users[action.payload.index].groups.findIndex(
(group) => group === action.payload.group
);
if (groupIndex !== -1) {
state.users[action.payload.index].groups.splice(groupIndex, 1);
}
},
},
});
export const {
initializeWizard,
changeServerUrl,
changeBaseUrl,
changeArchitecture,
changeDistribution,
addImageType,
removeImageType,
changeImageTypes,
changeAwsAccountId,
changeAwsShareMethod,
changeAwsSourceId,
reinitializeAws,
changeAzureTenantId,
changeAzureShareMethod,
changeAzureSubscriptionId,
changeAzureSource,
changeAzureResourceGroup,
changeAzureHyperVGeneration,
reinitializeAzure,
changeGcpShareMethod,
changeGcpAccountType,
changeGcpEmail,
reinitializeGcp,
changeRegistrationType,
changeActivationKey,
changeCompliance,
changeComplianceType,
changeFileSystemConfiguration,
changeFileSystemConfigurationType,
clearPartitions,
addPartition,
removePartition,
removePartitionByMountpoint,
changePartitionMountpoint,
changePartitionUnit,
changePartitionMinSize,
changePartitionOrder,
changeUseLatest,
changeSnapshotDate,
changeTemplate,
changeCustomRepositories,
importCustomRepositories,
changePayloadRepositories,
addRecommendedRepository,
removeRecommendedRepository,
addPackage,
removePackage,
addGroup,
removeGroup,
addLanguage,
removeLanguage,
clearLanguages,
changeKeyboard,
changeBlueprintName,
setIsCustomName,
changeBlueprintDescription,
loadWizardState,
setFirstBootScript,
changeEnabledServices,
addEnabledService,
removeEnabledService,
changeMaskedServices,
addMaskedService,
removeMaskedService,
changeDisabledServices,
addDisabledService,
removeDisabledService,
changeKernelName,
addKernelArg,
removeKernelArg,
clearKernelAppend,
addDisabledFirewallService,
removeDisabledFirewallService,
addEnabledFirewallService,
removeEnabledFirewallService,
changeTimezone,
changeSatelliteRegistrationCommand,
changeSatelliteCaCertificate,
addNtpServer,
removeNtpServer,
changeHostname,
addPort,
removePort,
addUser,
removeUser,
setUserNameByIndex,
setUserPasswordByIndex,
setUserSshKeyByIndex,
setUserAdministratorByIndex,
addUserGroupByIndex,
removeUserGroupByIndex,
changeRedHatRepositories,
} = wizardSlice.actions;
export default wizardSlice.reducer;