-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy pathutils.ts
More file actions
153 lines (134 loc) · 4.61 KB
/
utils.ts
File metadata and controls
153 lines (134 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import { defaultStorageMapping } from 'src/storageMaps/utils/constants';
import { OffloadPlugin, StorageMapFieldId, type StorageMapping } from 'src/storageMaps/utils/types';
import type { V1beta1StorageMap, V1beta1StorageMapSpecMap } from '@forklift-ui/types';
import { isEmpty } from '@utils/helpers';
import { t } from '@utils/i18n';
import type { CustomV1beta1StorageMapSpecMap, UpdateMappingsFormData } from './types';
/**
* Transforms form values into the format expected by the k8s StorageMap spec
*/
export const transformFormValuesToK8sSpec = (
formValues: UpdateMappingsFormData,
existingStorageMap: V1beta1StorageMap,
isOpenshift = false,
): V1beta1StorageMap | undefined => {
if (!existingStorageMap.spec) {
return undefined;
}
// Filter incomplete mappings and transform to k8s format
const transformedMappings = formValues.storageMap.reduce<CustomV1beta1StorageMapSpecMap[]>(
(acc, mapping) => {
// Skip incomplete mappings
if (!mapping.sourceStorage?.name || !mapping.targetStorage?.name) {
return acc;
}
const baseMapping: CustomV1beta1StorageMapSpecMap = {
destination: {
storageClass: mapping.targetStorage.name,
},
source: {
id: isOpenshift ? undefined : mapping.sourceStorage.id,
name: mapping.sourceStorage.name.startsWith('/')
? mapping.sourceStorage.name.slice(1)
: mapping.sourceStorage.name,
},
};
// Add offload plugin data if all required fields are present
if (mapping.offloadPlugin && mapping.storageProduct && mapping.storageSecret) {
acc.push({
...baseMapping,
offloadPlugin: {
vsphereXcopyConfig: {
secretRef: mapping.storageSecret,
storageVendorProduct: mapping.storageProduct,
},
},
});
} else {
acc.push(baseMapping);
}
return acc;
},
[],
);
return {
...existingStorageMap,
spec: {
...existingStorageMap.spec,
map: transformedMappings as V1beta1StorageMapSpecMap[],
},
};
};
/**
* Transforms storage map K8s spec to form-compatible structure
*/
export const transformStorageMapToFormValues = (
storageMap: V1beta1StorageMap,
): UpdateMappingsFormData => {
if (isEmpty(storageMap) || !storageMap?.spec?.map || isEmpty(storageMap.spec.map)) {
return {
storageMap: [defaultStorageMapping],
};
}
const transformedStorageMap = storageMap.spec.map.map(
(mapping: CustomV1beta1StorageMapSpecMap) => {
const sourceId = mapping.source?.id ?? '';
const sourceName = mapping.source?.name ?? '';
const displayName = sourceId
? (storageMap.status?.references?.find((ref) => ref.id === sourceId)?.name ?? sourceName)
: sourceName;
return {
offloadPlugin: mapping.offloadPlugin ? OffloadPlugin.VSphereXcopyConfig : '',
sourceStorage: {
id: sourceId,
name: displayName,
},
storageProduct: mapping.offloadPlugin?.vsphereXcopyConfig?.storageVendorProduct ?? '',
storageSecret: mapping.offloadPlugin?.vsphereXcopyConfig?.secretRef ?? '',
targetStorage: {
name: mapping.destination?.storageClass ?? '',
},
};
},
);
return {
storageMap: transformedStorageMap,
};
};
/**
* Validates storage mapping configurations to ensure complete and valid mappings
* @param values - Array of storage mappings to validate
* @returns Translation key string for validation error or undefined if valid
*/
export const validateUpdatedStorageMaps = (values: StorageMapping[]) => {
if (!Array.isArray(values)) return t('Invalid mappings');
let emptyCount = 0;
let validCount = 0;
let incompleteCount = 0;
// Count empty, valid, and incomplete rows
for (const value of values) {
const hasSource = Boolean(value[StorageMapFieldId.SourceStorage]?.name);
const hasTarget = Boolean(value[StorageMapFieldId.TargetStorage]?.name);
if (!hasSource && !hasTarget) {
emptyCount += 1;
} else if (hasSource && hasTarget) {
validCount += 1;
} else {
// Incomplete row: either source or target is missing
incompleteCount += 1;
}
}
// Any empty rows are invalid
if (emptyCount > 0) {
return t('Each row must have both source and target storage selected');
}
// Any incomplete rows are invalid
if (incompleteCount > 0) {
return t('Each row must have both source and target storage selected');
}
// No valid rows
if (validCount === 0) {
return t('At least one row must have both source and target storages');
}
return undefined;
};