Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sap): add installation dashboard page #16363

Open
wants to merge 1 commit into
base: feat/sap-features-hub
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion packages/manager-react-components/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export * from './datagrid/useDatagrid';
export * from './datagrid/useDatagridSearchParams';
export * from './datagrid/clipboard-cell.component';

export * from './formatted-date/FormattedDate';

export * from './guides-header';

export * from './notifications/notifications.component';
Expand All @@ -25,7 +27,6 @@ export * from './filters';

export * from './ManagerButton/ManagerButton';
export * from './ManagerText/ManagerText';

export * from './pci-maintenance-banner';
export * from './region/region.component';
export * from './order';
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"dashboard_installation_title": "Assistant de pré-installation SAP",
"dashboard_installation_description": "Rapport d'installation",
"dashboard_installation_generals_informations": "Informations générales",
"dashboard_installation_item_start_date": "Date de lancement",
"dashboard_installation_item_end_date": "Date de fin",
"dashboard_installation_item_application_version": "Version d'application",
"dashboard_installation_item_application_type": "Type d'application",
"dashboard_installation_item_deploiement_type": "Type de déploiement",
"dashboard_installation_progress_step_initialisation": "Initialisation des ressources temporaires dans votre service VMware on OVHcloud",
"dashboard_installation_progress_step_create_virtuals_machines": "Création des machines virtuelles",
"dashboard_installation_progress_step_sap_hana_install": "Installation de SAP HANA et configuration des options demandées",
"dashboard_installation_progress_step_sap_install": "Installation du système SAP et configuration des options demandées",
"dashboard_installation_progress_step_clean_resources": "Suppression des ressources temporaires dans votre service VMware on OVHcloud",
"dashboard_installation_progress_step_success": "Étape terminée avec succès",
"dashboard_installation_progress_step_failure": "Étape échouée",
"dashboard_installation_progress_step_pending": "Étape en cours d'éxécution",
"dashboard_installation_progress_step_waiting": "Étape en attente",
"dashboard_installation_progress_status_label": "Statut de l'installation",
"dashboard_installation_error_message": "Erreur à l'étape \"{{stepName}}\". Plus de détails ci-dessous."
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,10 @@
"summary_title": "Validez la configuration de l'installation",
"summary_subtitle": "Vérifiez les informations saisies avant de lancer l'installation. Vous pouvez également télécharger le fichier de la configuration de votre installation <DownloadLink label=\"ici\">{{label}}</DownloadLink>. Vous pourrez le réutiliser ultérieurement pour initialiser une nouvelle installation.",
"summary_cta_submit": "Lancer l'installation",
"summary_api_error": "Le lancement de l'installation a échoué : {{ error }}"
"summary_api_error": "Le lancement de l'installation a échoué : {{ error }}",
"status_SUCCESS": "Succès",
"status_PENDING": "En attente",
"status_REVOKED": "Révoqué",
"status_FAILURE": "Erreur",
"status_STARTED": "En cours"
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@
"sap_hub_history_application_type": "Type d'application",
"sap_hub_history_deployment_type": "Type de déploiement",
"sap_hub_history_installation_status": "Statut",
"sap_hub_history_installation_SUCCESS": "Succès",
"sap_hub_history_installation_PENDING": "En attente",
"sap_hub_history_installation_REVOKED": "Révoqué",
"sap_hub_history_installation_FAILURE": "Erreur",
"sap_hub_history_installation_STARTED": "En cours",
"sap_hub_history_installation_RETRY": "Nouvelle tentative",
"sap_hub_history_installation_see_detail": "Voir le détail"
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import React from 'react';
import { OdsText } from '@ovhcloud/ods-components/react';
import { OdsText, OdsSkeleton } from '@ovhcloud/ods-components/react';
import { StepFieldData } from '@/types/formStep.type';
import { testIds } from '@/utils/testIds.constants';
import { FORM_LABELS } from '@/constants/form.constants';

type FormFieldSummaryProps = React.HTMLAttributes<HTMLDivElement> & {
field: StepFieldData;
isLoading?: boolean;
};

export const FormFieldSummary = ({
field,
isLoading,
...props
}: FormFieldSummaryProps) => {
const valueText = field.isSecretValue ? FORM_LABELS.secretText : field.value;
Expand All @@ -20,9 +22,12 @@ export const FormFieldSummary = ({
{...props}
>
<OdsText className="max-w-60">{field.label}</OdsText>
<OdsText className="max-w-60" data-testid={testIds.summaryFieldValue}>
{field.value ? valueText : FORM_LABELS.unknownText}
</OdsText>
{isLoading && <OdsSkeleton className="w-20" />}
{!isLoading && (
<OdsText className="max-w-60" data-testid={testIds.summaryFieldValue}>
{field.value ? valueText : FORM_LABELS.unknownText}
</OdsText>
)}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,7 @@ describe('SAPInstallationStatus component tests suite', () => {

const badge = container.querySelector('ods-badge');
expect(badge).toHaveAttribute('color', color);
expect(badge).toHaveAttribute(
'label',
`sap_hub_history_installation_${status}`,
);
expect(badge).toHaveAttribute('label', `status_${status}`);
},
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ export const InstallationStatus = ({
size = ODS_BADGE_SIZE.md,
...rest
}: InstallationStatusProps) => {
const { t } = useTranslation('listing');
const { t } = useTranslation('installation');
return (
<React.Suspense>
<OdsBadge
label={t(`sap_hub_history_installation_${status}`)}
label={t(`status_${status}`)}
size={size}
color={BADGE_COLOR_STATUS[status] ?? ODS_BADGE_COLOR.neutral}
{...rest}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ApiResponse, v6 } from '@ovh-ux/manager-core-api';
import { InstallationDetails } from '@/types/installation.type';

const getApplicationVersionRoute = (serviceName: string) =>
`/dedicatedCloud/${serviceName}/sap/capabilities`;
Expand All @@ -7,3 +8,21 @@ export const getApplicationVersions = async (
serviceName: string,
): Promise<ApiResponse<unknown>> =>
v6.get(getApplicationVersionRoute(serviceName));

export type GetInstallationTaskDetailsRouteParams = {
serviceName: string;
taskId: string;
};

const getInstallationTaskDetailsRoute = ({
serviceName,
taskId,
}: GetInstallationTaskDetailsRouteParams) =>
`/dedicatedCloud/${serviceName}/sap/${taskId}`;

export const getInstallationTaskDetails = async ({
serviceName,
taskId,
}: GetInstallationTaskDetailsRouteParams): Promise<ApiResponse<
InstallationDetails
>> => v6.get(getInstallationTaskDetailsRoute({ serviceName, taskId }));
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { useQuery } from '@tanstack/react-query';
import { getApplicationVersions } from '@/data/api/installationDeployment';
import {
getApplicationVersions,
getInstallationTaskDetails,
GetInstallationTaskDetailsRouteParams,
} from '@/data/api/installationDeployment';
import {
InstallationDetails,
SAPInstallationStatus,
} from '@/types/installation.type';

// TODO: implement API calls when developed
export const useApplicationVersions = (serviceName: string) =>
Expand All @@ -9,3 +17,85 @@ export const useApplicationVersions = (serviceName: string) =>
select: (res) => res.data,
enabled: !!serviceName,
});

export const installationTaskDetailsQueryKey = ({
serviceName,
taskId,
}: GetInstallationTaskDetailsRouteParams) => [
'sap',
serviceName,
'tasks',
taskId,
];

// TODO: implement API calls when developed
export const useInstallationTaskDetails = ({
serviceName,
taskId,
}: GetInstallationTaskDetailsRouteParams) =>
useQuery({
queryKey: installationTaskDetailsQueryKey({ serviceName, taskId }),
queryFn: () => getInstallationTaskDetails({ serviceName, taskId }),
select: (res) => res.data,
enabled: !!serviceName && !!taskId,
});

export const useMockInstallationTaskDetails = ({
serviceName,
taskId,
}: GetInstallationTaskDetailsRouteParams) => {
return useQuery({
queryKey: installationTaskDetailsQueryKey({ serviceName, taskId }),
queryFn: () => {
return new Promise((resolve) => {
// Generate fake data for InstallationDetails
const mockData: InstallationDetails = {
ansibleSapHanaStatus: SAPInstallationStatus.failure,
ansibleSapSystemStatus: SAPInstallationStatus.failure,
applicationType: 'ABAP',
applicationVersion: '1.0.0',
cleanStatus: SAPInstallationStatus.pending,
deploymentType: 'Standard',
endTime: '2022-01-01T12:00:00',
errorMessage: `1. [ERROR] DependencyError: Failed to install package "libwebsocket-3.2.1"
2. [WARN] VersionMismatch: Requested Node >=16.x, found Node v14.15.0
3. [CRITICAL] SegmentationFault: Installation aborted at step "configure_network_adapter"
4. [ERROR] ChecksumFailed: File integrity compromised on "module-crypto-4.0.2.tar.gz"
5. [FATAL] PermissionDenied: Unable to access "/usr/local/bin/" directory
6. [ERROR] CompilationError: Rust crate "tokio-async-1.6.3" failed to build
7. [WARN] TimeoutWarning: Network timeout while downloading dependency "[email protected]"
8. [ERROR] SyntaxError: Unexpected token 'import' during parsing config.js
9. [CRITICAL] KernelIncompatibility: Module "fs-extended" incompatible with Linux Kernel 5.8.0
10. [ERROR] PortUnavailable: Default port 5432 already in use by another service
11. [WARN] EnvironmentVariableMissing: Variable DATABASE_URL not found
12. [ERROR] ConflictDetected: Conflicting installations detected for package "express-router"
13. [FATAL] DiskSpaceInsufficient: Less than 200MB remaining on partition "/var"
14. [ERROR] AuthenticationFailed: Access denied to private repository "[email protected]:user/private-lib.git"
15. [CRITICAL] DockerDaemonOffline: Docker service unavailable or stopped
16. [ERROR] SSLHandshakeFailed: Unable to verify certificate for domain "api.example.com"
17. [WARN] DeprecationNotice: Package "[email protected]" deprecated, installation skipped
18. [ERROR] DatabaseMigrationFailed: PostgreSQL migration error at script "20240401_init.sql"
19. [CRITICAL] MissingSystemLibrary: Required system library "libssl-dev" not found
20. [ERROR] InvalidConfiguration: Unrecognized parameter "max_memory_allocation" in config.yml`,
gatewayStatus: SAPInstallationStatus.success,
iam: {
displayName: 'John Doe',
id: '123456',
urn: 'urn:iam:123456',
},
sapHanaSid: 'HANA01',
sapSid: 'SAP01',
startTime: '2022-01-01T10:00:00',
status: SAPInstallationStatus.pending,
taskId: '789012',
terraformStatus: SAPInstallationStatus.success,
};
setTimeout(() => {
resolve({ data: mockData });
}, 500);
});
},
select: (res) => (res as any).data,
enabled: () => !!serviceName && !!taskId,
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useQueryClient } from '@tanstack/react-query';
import { useEffect } from 'react';

type AutoRefetchProps = {
queryKey: string[];
enabled: boolean;
interval?: number;
};

export const useAutoRefetch = ({
queryKey,
enabled,
interval = 10_000,
}: AutoRefetchProps) => {
const queryClient = useQueryClient();

useEffect(() => {
if (!enabled) return;

const refetchQueries = () => {
queryClient.invalidateQueries({ queryKey });
};

const refetchInterval = setInterval(() => refetchQueries(), interval);

// eslint-disable-next-line consistent-return
return () => clearInterval(refetchInterval);
}, [enabled, interval, queryKey, queryClient]);
};
Loading
Loading