diff --git a/locales/en/plugin__forklift-console-plugin.json b/locales/en/plugin__forklift-console-plugin.json index 12bbf0334..13458e036 100644 --- a/locales/en/plugin__forklift-console-plugin.json +++ b/locales/en/plugin__forklift-console-plugin.json @@ -1,52 +1,49 @@ { - "AddProvider": "Add Provider", - "Any": "Any", + "{{type}} provider {{name}} will no longer be selectable as a migration source.": "{{type}} provider {{name}} will no longer be selectable as a migration source.", + "{{type}} provider {{name}} will no longer be selectable as a migration target.": "{{type}} provider {{name}} will no longer be selectable as a migration target.", + "Add Provider": "Add Provider", "Cancel": "Cancel", - "CannotDeleteProvider": "Cannot remove provider", - "ClearAllFilters": "Clear all filters", + "Cannot remove provider": "Cannot remove provider", + "Clear all filters": "Clear all filters", "Clusters": "Clusters", "Delete": "Delete", - "DeleteProvider": "Delete Provider", - "EditProvider": "Edit Provider", + "Delete Provider": "Delete Provider", + "Edit Provider": "Edit Provider", + "Endpoint": "Endpoint", "False": "False", - "FilterByName": "Filter by name", - "FilterByNamespace": "Filter by namespace", - "FilterByStatus": "Filter by status", - "FilterByType": "Filter by type", - "FilterByUrl": "Filter by endpoint", + "Filter by endpoint": "Filter by endpoint", + "Filter by name": "Filter by name", + "Filter by namespace": "Filter by namespace", "Hosts": "Hosts", - "Loading": "Loading...", - "ManageColumns": "Manage columns", + "KubeVirt": "KubeVirt", + "Loading": "Loading", + "Manage Columns": "Manage Columns", "Mappings for VM Import": "Mappings for VM Import", "Name": "Name", "Namespace": "Namespace", "Networks": "Networks", - "NoResultsFound": "No results found", - "NoResultsMatchFilter": "No results match the filter criteria. Clear all filters and try again.", - "Openshift": "Openshift", - "Ovirt": "oVirt", - "PermanentlyDeleteProvider": "Permanently delete provider?", + "No information": "No information", + "No results found": "No results found", + "No results match the filter criteria. Clear all filters and try again.": "No results match the filter criteria. Clear all filters and try again.", + "oVirt": "oVirt", + "Permanently delete provider?": "Permanently delete provider?", "Plans for VM Import": "Plans for VM Import", - "ProviderNoLongerSelectableAsSource": "{{type}} provider {{name}} will no longer be selectable as a migration source.", - "ProviderNoLongerSelectableAsTarget": "{{type}} provider {{name}} will no longer be selectable as a migration target.", "Providers": "Providers", "Providers for VM Import": "Providers for VM Import", "Ready": "Ready", "Reorder": "Reorder", - "RestoreDefaultColums": "Restore default colums", + "Restore default colums": "Restore default colums", "Save": "Save", - "SelectFilter": "Select Filter", - "SelectMigrationNetwork": "Select migration network", - "Status": "Status", + "Select Filter": "Select Filter", + "Select migration network": "Select migration network", + "Selected columns will be displayed in the table.": "Selected columns will be displayed in the table.", "Storage": "Storage", - "Success": "Success", - "TableColumnManagement": "Table column management", - "Type": "Type", + "Table column management": "Table column management", "True": "True", - "UnableToRetrieve": "Unable to retrieve data", + "Type": "Type", + "Unable to retrieve data": "Unable to retrieve data", "Unknown": "Unknown", - "Url": "Endpoint", "Virtualization": "Virtualization", - "Vsphere": "vSphere", - "VMs": "VMs" -} \ No newline at end of file + "VMs": "VMs", + "VMware": "VMware" +} diff --git a/src/Providers/ProviderRow.tsx b/src/Providers/ProviderRow.tsx index d316fab2b..c54d3338c 100644 --- a/src/Providers/ProviderRow.tsx +++ b/src/Providers/ProviderRow.tsx @@ -28,6 +28,12 @@ const StatusCell = ({ value, entity: { conditions } }: CellProps) => { const existingConditions = Object.values(conditions).filter(Boolean); const toState = (value) => value === 'True' ? 'Ok' : value === 'False' ? 'Error' : 'Unknown'; + const label = + value === 'True' + ? t('True') + : value === 'False' + ? t('False') + : t('Unknown'); return ( { /> ); }) - : 'No information'} + : t('No information')} } > - ); @@ -74,7 +80,7 @@ const ProviderRow = ({ columns, entity }: RowProps) => { const { t } = useTranslation(); const [isActionMenuOpen, setIsActionMenuOpen] = useState(false); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); - console.warn('Modal open?', isDeleteModalOpen, entity); + const toggleDeleteModal = () => setIsDeleteModalOpen(!isDeleteModalOpen); const deleteProviderMutation = useDeleteProviderMutation( entity.type as ProviderType, @@ -102,13 +108,13 @@ const ProviderRow = ({ columns, entity }: RowProps) => { isPlain dropdownItems={[ - {t('EditProvider')} + {t('Edit Provider')} , - {t('DeleteProvider')} + {t('Delete Provider')} , - {t('SelectMigrationNetwork')} + {t('Select migration network')} , ]} /> @@ -130,15 +136,26 @@ const ProviderRow = ({ columns, entity }: RowProps) => { }) } mutateResult={deleteProviderMutation} - title={t('PermanentlyDeleteProvider')} - body={t( + title={t('Permanently delete provider?')} + body={ isTarget(entity.type as ProviderType) - ? 'ProviderNoLongerSelectableAsTarget' - : 'ProviderNoLongerSelectableAsSource', - { type: entity.type, name: entity.name }, - )} + ? t( + '{{type}} provider {{name}} will no longer be selectable as a migration target.', + { + type: entity.type, + name: entity.name, + }, + ) + : t( + '{{type}} provider {{name}} will no longer be selectable as a migration source.', + { + type: entity.type, + name: entity.name, + }, + ) + } confirmButtonText={t('Delete')} - errorText={t('CannotDeleteProvider')} + errorText={t('Cannot remove provider')} cancelButtonText={t('Cancel')} /> diff --git a/src/Providers/ProvidersPage.tsx b/src/Providers/ProvidersPage.tsx index 603ebb3da..814af4e24 100644 --- a/src/Providers/ProvidersPage.tsx +++ b/src/Providers/ProvidersPage.tsx @@ -47,95 +47,98 @@ import ProviderRow from './ProviderRow'; const fieldsMetadata: Field[] = [ { id: NAME, - tKey: 'Name', + toLabel: (t) => t('Name'), isVisible: true, isIdentity: true, filter: { type: 'freetext', - placeholderKey: 'FilterByName', + toPlaceholderLabel: (t) => t('Filter by name'), }, sortable: true, }, { id: NAMESPACE, - tKey: 'Namespace', + toLabel: (t) => t('Namespace'), isVisible: true, isIdentity: true, filter: { type: 'freetext', - placeholderKey: 'FilterByNamespace', + toPlaceholderLabel: (t) => t('Filter by namespace'), }, sortable: true, }, { id: READY, - tKey: 'Ready', + toLabel: (t) => t('Ready'), isVisible: true, filter: { type: 'enum', primary: true, - placeholderKey: 'Ready', + toPlaceholderLabel: (t) => t('Ready'), values: [ - { id: 'True', tKey: 'True' }, - { id: 'False', tKey: 'False' }, - { id: 'Unknown', tKey: 'Unknown' }, + { id: 'True', toLabel: (t) => t('True') }, + { id: 'False', toLabel: (t) => t('False') }, + { id: 'Unknown', toLabel: (t) => t('Unknown') }, ], }, sortable: true, }, { id: URL, - tKey: 'Url', + toLabel: (t) => t('Endpoint'), isVisible: true, filter: { type: 'freetext', - placeholderKey: 'FilterByUrl', + toPlaceholderLabel: (t) => t('Filter by endpoint'), }, sortable: true, }, { id: TYPE, - tKey: 'Type', + toLabel: (t) => t('Type'), isVisible: true, filter: { type: 'enum', primary: true, - placeholderKey: 'Type', + toPlaceholderLabel: (t) => t('Type'), values: [ - { id: 'vsphere', tKey: 'Vsphere' }, - { id: 'ovirt', tKey: 'Ovirt' }, - { id: 'openshift', tKey: 'Openshift' }, + // t('VMware') + { id: 'vsphere', toLabel: (t) => t('VMware') }, + // t('oVirt') + { id: 'ovirt', toLabel: (t) => t('oVirt') }, + // t('KubeVirt') + { id: 'openshift', toLabel: (t) => t('KubeVirt') }, ], }, sortable: true, }, { id: VM_COUNT, - tKey: 'VMs', + toLabel: (t) => t('VMs'), isVisible: true, sortable: true, }, { id: NETWORK_COUNT, - tKey: 'Networks', + toLabel: (t) => t('Networks'), isVisible: true, sortable: true, }, { id: CLUSTER_COUNT, - tKey: 'Clusters', + toLabel: (t) => t('Clusters'), isVisible: true, sortable: true, }, { id: HOST_COUNT, - tKey: 'Hosts', + toLabel: (t) => t('Hosts'), isVisible: false, sortable: true, }, { id: STORAGE_COUNT, - tKey: 'Storage', + toLabel: (t) => t('Storage'), isVisible: false, sortable: true, }, @@ -180,7 +183,7 @@ export const ProvidersPage = ({ namespace, kind }: ProvidersPageProps) => { @@ -188,7 +191,7 @@ export const ProvidersPage = ({ namespace, kind }: ProvidersPageProps) => { } breakpoint="xl"> @@ -245,7 +248,7 @@ const ErrorState = () => { - {t('UnableToRetrieve')} + {t('Unable to retrieve data')} ); @@ -269,7 +272,7 @@ const NoResultsFound = () => { - {t('NoResultsFound')} + {t('No results found')} ); @@ -285,12 +288,16 @@ const NoResultsMatchFilter = ({ - {t('NoResultsFound')} + {t('No results found')} - {t('NoResultsMatchFilter')} + + {t( + 'No results match the filter criteria. Clear all filters and try again.', + )} + diff --git a/src/components/Filter/AttributeValueFilter.tsx b/src/components/Filter/AttributeValueFilter.tsx index ab4860e96..69d3323d9 100644 --- a/src/components/Filter/AttributeValueFilter.tsx +++ b/src/components/Filter/AttributeValueFilter.tsx @@ -50,19 +50,19 @@ export const AttributeValueFilter = ({ onToggle={setExpanded} isOpen={expanded} variant={SelectVariant.single} - aria-label={t('SelectFilter')} + aria-label={t('Select Filter')} selections={toSelectOption( currentFilterType.id, - t(currentFilterType.tKey), + currentFilterType.toLabel(t), )} > - {filterTypes.map(({ id, tKey }) => ( - + {filterTypes.map(({ id, toLabel }) => ( + ))} - {filterTypes.map(({ id, tKey: fieldKey, filter }) => { + {filterTypes.map(({ id, toLabel: toFieldLabel, filter }) => { const FieldFilter = supportedFilters[filter.type]; return ( FieldFilter && ( @@ -74,10 +74,10 @@ export const AttributeValueFilter = ({ [id]: values, }) } - placeholderLabel={t(filter.placeholderKey)} + placeholderLabel={filter.toPlaceholderLabel(t)} selectedFilters={selectedFilters[id] ?? []} showFilter={currentFilterType?.id === id} - title={t(filter.tKey ?? fieldKey)} + title={filter?.toLabel?.(t) ?? toFieldLabel(t)} supportedValues={filter.values} /> ) diff --git a/src/components/Filter/EnumFilter.tsx b/src/components/Filter/EnumFilter.tsx index 321adfb36..ba7532254 100644 --- a/src/components/Filter/EnumFilter.tsx +++ b/src/components/Filter/EnumFilter.tsx @@ -17,15 +17,22 @@ export const useUnique = ({ supportedEnumValues, onSelectedEnumIdsChange, selectedEnumIds, +}: { + supportedEnumValues: { + id: string; + toLabel(t: (key: string) => string): string; + }[]; + onSelectedEnumIdsChange: (values: string[]) => void; + selectedEnumIds: string[]; }) => { const { t, i18n } = useTranslation(); const translated = useMemo( () => - supportedEnumValues.map(({ id, tKey }) => ({ + supportedEnumValues.map((it) => ({ // fallback to ID - label: tKey ? t(tKey) : id, - id, + label: it.toLabel?.(t) ?? it.id, + id: it.id, })), [supportedEnumValues], diff --git a/src/components/Filter/PrimaryFilters.tsx b/src/components/Filter/PrimaryFilters.tsx index 80ff0bd19..a8f1e4d8d 100644 --- a/src/components/Filter/PrimaryFilters.tsx +++ b/src/components/Filter/PrimaryFilters.tsx @@ -15,7 +15,7 @@ export const PrimaryFilters = ({ return ( - {filterTypes.map(({ id, tKey: fieldKey, filter }) => { + {filterTypes.map(({ id, toLabel: toFieldLabel, filter }) => { const FieldFilter = supportedFilters[filter.type]; return ( FieldFilter && ( @@ -27,9 +27,9 @@ export const PrimaryFilters = ({ [id]: values, }) } - placeholderLabel={t(filter.placeholderKey)} + placeholderLabel={filter.toPlaceholderLabel(t)} selectedFilters={selectedFilters[id] ?? []} - title={t(filter.tKey ?? fieldKey)} + title={filter?.toLabel?.(t) ?? toFieldLabel(t)} showFilter={true} supportedValues={filter.values} /> diff --git a/src/components/Filter/types.ts b/src/components/Filter/types.ts index db11b37e1..e8b0784a2 100644 --- a/src/components/Filter/types.ts +++ b/src/components/Filter/types.ts @@ -1,8 +1,8 @@ export interface FilterDef { type: string; - placeholderKey: string; - values?: { id: string; tKey: string }[]; - tKey?: string; + toPlaceholderLabel(t: (key: string) => string): string; + values?: { id: string; toLabel(t: (key: string) => string): string }[]; + toLabel?(t: (key: string) => string): string; primary?: boolean; } @@ -13,14 +13,17 @@ export interface FieldFilterProps { selectedFilters: string[]; showFilter: boolean; title: string; - supportedValues?: { id: string; tKey?: string }[]; + supportedValues?: { + id: string; + toLabel(t: (key: string) => string): string; + }[]; } export interface MetaFilterProps { selectedFilters: { [id: string]: string[] }; filterTypes: { id: string; - tKey: string; + toLabel(t: (key: string) => string): string; filter: FilterDef; }[]; onFilterUpdate(filters: { [id: string]: string[] }): void; diff --git a/src/components/TableView/ManageColumnsToolbar.tsx b/src/components/TableView/ManageColumnsToolbar.tsx index c454647dd..64f389ff1 100644 --- a/src/components/TableView/ManageColumnsToolbar.tsx +++ b/src/components/TableView/ManageColumnsToolbar.tsx @@ -38,11 +38,11 @@ export const ManageColumnsToolbar = ({ const [manageColumns, setManageColumns] = useState(false); return ( - + @@ -50,7 +50,7 @@ export const ManageColumnsToolbar = ({ setManageColumns(false)} - description="Selected columns will be displayed in the table." + description={t('Selected columns will be displayed in the table.')} columns={columns} onChange={setColumns} defaultColumns={defaultColumns} @@ -105,7 +105,7 @@ const ManageColumns = ({ return ( - {t('plugin__forklift-console-plugin~Save')} + {t('Save')} , , , ]} > - {editedColumns.map(({ id, isVisible, isIdentity, tKey }) => ( + {editedColumns.map(({ id, isVisible, isIdentity, toLabel }) => ( - {t(tKey)} + {toLabel(t)} , ]} /> diff --git a/src/components/TableView/TableView.tsx b/src/components/TableView/TableView.tsx index f694b9445..07097b6d1 100644 --- a/src/components/TableView/TableView.tsx +++ b/src/components/TableView/TableView.tsx @@ -36,7 +36,7 @@ export function TableView({ - {visibleColumns.map(({ id, tKey, sortable }, columnIndex) => ( + {visibleColumns.map(({ id, toLabel, sortable }, columnIndex) => ( ({ }) } > - {t(tKey)} + {toLabel(t)} ))} diff --git a/src/components/TableView/sort.ts b/src/components/TableView/sort.ts index a4f12bffc..0be1ea39f 100644 --- a/src/components/TableView/sort.ts +++ b/src/components/TableView/sort.ts @@ -37,7 +37,7 @@ export const useSort = ( const [activeSort, setActiveSort] = useState({ isAsc: false, id: firstField?.id, - tKey: firstField?.tKey, + toLabel: firstField?.toLabel, }); const comparator = compareWith( diff --git a/src/components/TableView/types.ts b/src/components/TableView/types.ts index 224344228..da520ee99 100644 --- a/src/components/TableView/types.ts +++ b/src/components/TableView/types.ts @@ -2,7 +2,7 @@ import { Field } from '../types'; export interface Column { id: string; - tKey: string; + toLabel(t: (key: string) => string): string; sortable?: boolean; } diff --git a/src/components/types.ts b/src/components/types.ts index c1723d49f..4c3581fbb 100644 --- a/src/components/types.ts +++ b/src/components/types.ts @@ -3,15 +3,21 @@ import { FilterDef } from './Filter/types'; export interface SortType { isAsc: boolean; id: string; - tKey: string; + toLabel(t: (key: string) => string): string; } export interface Field { id: string; - tKey: string; + toLabel(t: (key: string) => string): string; isVisible?: boolean; isIdentity?: boolean; sortable?: boolean; filter?: FilterDef; comparator?: (a: any, b: any, locale: string) => number; } + +// t('True') +// t('False') +// t('Unknown') +export const K8sConditionStatusValues = ['True', 'False', 'Unknown'] as const; +export type K8sConditionStatus = typeof K8sConditionStatusValues[number];