UNPKG

@openshift-assisted/ui-lib

Version:

React component library for the Assisted Installer UI

365 lines 22.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HostsTableModals = exports.useHostsTable = void 0; const tslib_1 = require("tslib"); const React = tslib_1.__importStar(require("react")); const react_redux_1 = require("react-redux"); const common_1 = require("../../../common"); const AdditionalNTPSourcesDialog_1 = require("../../../common/components/hosts/AdditionalNTPSourcesDialog"); const api_1 = require("../../../common/api"); const slice_1 = require("../../store/slices/current-cluster/slice"); const ModalDialogsContext_1 = require("./ModalDialogsContext"); const utils_1 = require("./utils"); const hosts_1 = require("../../../common/components/hosts"); const HostsTable_1 = tslib_1.__importDefault(require("../../../common/components/hosts/HostsTable")); const tableUtils_1 = require("../../../common/components/hosts/tableUtils"); const ResetHostModal_1 = tslib_1.__importDefault(require("./ResetHostModal")); const DeleteHostModal_1 = tslib_1.__importDefault(require("./DeleteHostModal")); const fetchEvents_1 = require("../fetching/fetchEvents"); const services_1 = require("../../services"); const UpdateDay2ApiVipModal_1 = tslib_1.__importDefault(require("./UpdateDay2ApiVipModal")); const usePagination_1 = require("../../../common/components/hosts/usePagination"); const use_translation_wrapper_1 = require("../../../common/hooks/use-translation-wrapper"); const HardwareStatus_1 = require("./HardwareStatus"); const ClusterWizardContext_1 = require("../clusterWizard/ClusterWizardContext"); const selectors_1 = require("../../store/slices/current-cluster/selectors"); const use_feature_1 = require("../../hooks/use-feature"); const useHostsTable = (cluster) => { const isSingleClusterFeatureEnabled = (0, use_feature_1.useFeature)('ASSISTED_INSTALLER_SINGLE_CLUSTER_FEATURE'); const { addAlert } = (0, common_1.useAlerts)(); const { eventsDialog, editHostDialog, deleteHostDialog, resetHostDialog, massUpdateHostnameDialog, massDeleteHostDialog, } = (0, ModalDialogsContext_1.useModalDialogsContext)(); const { resetCluster } = React.useContext(common_1.AddHostsContext); const { isViewerMode } = (0, react_redux_1.useSelector)(selectors_1.selectCurrentClusterPermissionsState); const { t } = (0, use_translation_wrapper_1.useTranslation)(); const dispatch = (0, react_redux_1.useDispatch)(); const hostActions = React.useMemo(() => ({ onDeleteHost: (host) => { const inventory = (0, common_1.getInventory)(host); deleteHostDialog.open({ hostId: host.id, hostname: ((host === null || host === void 0 ? void 0 : host.requestedHostname) || (inventory === null || inventory === void 0 ? void 0 : inventory.hostname)), }); }, onInstallHost: (host) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { const hostId = host.id; try { const { data } = yield services_1.HostsService.install(host); resetCluster ? void resetCluster() : dispatch((0, slice_1.updateHost)(data)); } catch (e) { (0, api_1.handleApiError)(e, () => addAlert({ title: `Failed to enable host ${hostId}`, message: (0, api_1.getApiErrorMessage)(e) })); } }), }), [dispatch, resetCluster, addAlert, deleteHostDialog]); const onViewHostEvents = React.useCallback((host) => { const { id, requestedHostname } = host; const inventory = (0, common_1.getInventory)(host); const hostname = requestedHostname || (inventory === null || inventory === void 0 ? void 0 : inventory.hostname) || id; eventsDialog.open({ hostId: id, hostname }); }, [eventsDialog]); const onEditHost = React.useCallback((host) => { const inventory = (0, common_1.getInventory)(host); editHostDialog.open({ host, inventory }); }, [editHostDialog]); const onHostReset = React.useCallback((host) => { const inventory = (0, common_1.getInventory)(host); const hostname = (host === null || host === void 0 ? void 0 : host.requestedHostname) || (inventory === null || inventory === void 0 ? void 0 : inventory.hostname) || ''; resetHostDialog.open({ hostId: host.id, hostname }); }, [resetHostDialog]); const onDownloadHostLogs = React.useCallback((host) => { void (0, utils_1.downloadHostInstallationLogs)(addAlert, host); }, [addAlert]); const onDiskRole = React.useCallback((hostId, diskId, role) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { try { if (!diskId) { // noinspection ExceptionCaughtLocallyJS throw new Error(`Cannot update disk role in host ${hostId}\nMissing diskId`); } const host = services_1.ClustersService.findHost(cluster.hosts, hostId); if (!host) { throw new Error(`No host found with id:${hostId}`); } const { data } = yield services_1.HostsService.updateDiskRole(host, diskId, role); resetCluster ? void resetCluster() : dispatch((0, slice_1.updateHost)(data)); } catch (e) { (0, api_1.handleApiError)(e, () => addAlert({ title: 'Failed to set disk role', message: (0, api_1.getApiErrorMessage)(e) })); if ((0, api_1.isUnknownServerError)(e)) { dispatch((0, slice_1.setServerUpdateError)()); } } }), [dispatch, resetCluster, addAlert, cluster.hosts]); const onExcludedODF = React.useCallback((hostId, nodeLabels) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { try { const host = services_1.ClustersService.findHost(cluster.hosts, hostId); if (!host) { throw new Error(`No host found with id:${hostId}`); } const { data } = yield services_1.HostsService.updateHostODF(host, nodeLabels); resetCluster ? yield resetCluster() : dispatch((0, slice_1.updateHost)(data)); } catch (e) { (0, api_1.handleApiError)(e, () => addAlert({ title: 'Failed to update ODF status', message: (0, api_1.getApiErrorMessage)(e) })); if ((0, api_1.isUnknownServerError)(e)) { dispatch((0, slice_1.setServerUpdateError)()); } } }), [cluster.hosts, resetCluster, dispatch, addAlert]); const onUpdateDay2ApiVip = React.useCallback((apiVip, onError) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { try { const { data } = yield services_1.ClustersService.update(cluster.id, cluster.tags, { apiVipDnsName: apiVip, }); dispatch((0, slice_1.updateCluster)(data)); } catch (e) { (0, api_1.handleApiError)(e, () => onError((0, api_1.getApiErrorMessage)(e))); if ((0, api_1.isUnknownServerError)(e)) { dispatch((0, slice_1.setServerUpdateError)()); } } }), [cluster.id, cluster.tags, dispatch]); const onAdditionalNtpSource = React.useMemo(() => (...args) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { return yield (0, utils_1.onAdditionalNtpSourceAction)(dispatch, cluster, ...args); }), [cluster, dispatch]); const updateDiskSkipFormatting = React.useCallback((shouldFormatDisk, hostId, diskId) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { try { if (!cluster.id) { throw new Error(`Failed to update disks skip formatting state in host ${hostId}\nMissing cluster id`); } if (!diskId) { throw new Error(`Failed to update disks skip formatting state in host ${hostId}\nMissing disk id`); } const host = services_1.ClustersService.findHost(cluster.hosts, hostId); if (!host) { throw new Error(`No host found with id:${hostId}`); } const { data } = yield services_1.HostsService.updateFormattingDisks(host, diskId, !shouldFormatDisk); resetCluster ? void resetCluster() : dispatch((0, slice_1.updateHost)(data)); } catch (e) { (0, api_1.handleApiError)(e, () => addAlert({ title: 'Failed to set disks skip formatting', message: (0, api_1.getApiErrorMessage)(e), })); if ((0, api_1.isUnknownServerError)(e)) { dispatch((0, slice_1.setServerUpdateError)()); } } }), [dispatch, addAlert, cluster, resetCluster]); const actionChecks = React.useMemo(() => ({ canEditRole: (host) => { if (isSingleClusterFeatureEnabled && host.bootstrap) { return false; } return !isViewerMode && (0, hosts_1.canEditRole)(cluster.status, host.status, (0, common_1.isSNO)(cluster)); }, canInstallHost: (host) => !isViewerMode && (0, hosts_1.canInstallHost)(cluster, host.status), canEditDisks: (host) => !isViewerMode && (0, hosts_1.canEditDisks)(cluster.status, host.status), canEnable: (host) => !isViewerMode && (0, hosts_1.canEnable)(cluster.status, host.status), canDisable: (host) => !isViewerMode && (0, hosts_1.canDisable)(cluster.status, host.status), canDelete: (host) => !isViewerMode && (0, hosts_1.canDelete)(cluster.status, host.status), canEditHost: (host) => !isViewerMode && (0, hosts_1.canEditHost)(cluster.status, host.status), canReset: (host) => !isViewerMode && (0, hosts_1.canReset)(cluster.status, host.status), canEditHostname: (host) => !isViewerMode && (0, hosts_1.canEditHostname)(cluster.status, host), }), [cluster, isViewerMode, isSingleClusterFeatureEnabled]); const onReset = React.useCallback(() => { var _a; const reset = (hostId) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { if (hostId) { try { const host = services_1.ClustersService.findHost(cluster.hosts, hostId); if (!host) { throw new Error(`No host found with id:${hostId}`); } const { data } = yield services_1.HostsService.reset(host); resetCluster ? void resetCluster() : dispatch((0, slice_1.updateHost)(data)); } catch (e) { (0, api_1.handleApiError)(e, () => addAlert({ title: `Failed to reset host ${hostId}`, message: (0, api_1.getApiErrorMessage)(e), })); } } }); void reset((_a = resetHostDialog.data) === null || _a === void 0 ? void 0 : _a.hostId); resetHostDialog.close(); }, [addAlert, cluster.hosts, dispatch, resetCluster, resetHostDialog]); const onDelete = React.useCallback(() => { var _a; const deleteHost = (hostId) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { if (hostId) { try { const host = services_1.ClustersService.findHost(cluster.hosts, hostId); if (!host) { throw new Error(`No host found with id:${hostId}`); } yield services_1.HostsService.delete(host); resetCluster ? void resetCluster() : dispatch((0, slice_1.forceReload)()); } catch (e) { (0, api_1.handleApiError)(e, () => addAlert({ title: `Failed to delete host ${hostId}`, message: (0, api_1.getApiErrorMessage)(e), })); } } }); void deleteHost((_a = deleteHostDialog.data) === null || _a === void 0 ? void 0 : _a.hostId); deleteHostDialog.close(); }, [deleteHostDialog, cluster.hosts, resetCluster, dispatch, addAlert]); const onEditRole = React.useCallback((host, role) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { try { if (!host.clusterId) { // noinspection ExceptionCaughtLocallyJS throw new Error(`Failed to edit role in host: ${host.id}.\nMissing cluster_id`); } const { data } = yield services_1.HostsService.updateRole(host, role); if (resetCluster) { void resetCluster(); } else { dispatch((0, slice_1.updateHost)(data)); // Reload to obtain cluster-level validations that may be affected by role change dispatch((0, slice_1.forceReload)()); } } catch (e) { (0, api_1.handleApiError)(e, () => addAlert({ title: 'Failed to set role', message: (0, api_1.getApiErrorMessage)(e) })); if ((0, api_1.isUnknownServerError)(e)) { dispatch((0, slice_1.setServerUpdateError)()); } } }), [addAlert, dispatch, resetCluster]); const actionResolver = React.useMemo(() => (0, tableUtils_1.hostActionResolver)(Object.assign(Object.assign(Object.assign({ t }, actionChecks), { onEditRole, onDiskRole, onExcludedODF, onEditHost, onHostReset, onDownloadHostLogs, onViewHostEvents, canDownloadHostLogs: hosts_1.canDownloadHostLogs }), hostActions)), [ t, actionChecks, hostActions, onEditRole, onDiskRole, onEditHost, onHostReset, onDownloadHostLogs, onExcludedODF, onViewHostEvents, ]); const [selectedHostIDs, setSelectedHostIDs] = React.useState([]); const onSelect = React.useCallback((obj, isSelected) => { if (isSelected) { setSelectedHostIDs([...selectedHostIDs, obj.id]); } else { setSelectedHostIDs(selectedHostIDs.filter((sh) => sh !== obj.id)); } }, [selectedHostIDs]); const onMassChangeHostname = React.useCallback(() => { var _a; if (selectedHostIDs.length === 1) { const host = (_a = cluster.hosts) === null || _a === void 0 ? void 0 : _a.find((host) => host.id === selectedHostIDs[0]); return host && onEditHost(host); } return massUpdateHostnameDialog.open({ hostIDs: selectedHostIDs, cluster, reloadCluster: () => (resetCluster ? void resetCluster() : dispatch((0, slice_1.forceReload)())), }); }, [selectedHostIDs, massUpdateHostnameDialog, cluster, onEditHost, resetCluster, dispatch]); const onMassDeleteHost = React.useCallback(() => { var _a; if (selectedHostIDs.length === 1) { const host = (_a = cluster.hosts) === null || _a === void 0 ? void 0 : _a.find((host) => host.id === selectedHostIDs[0]); return (host && deleteHostDialog.open({ hostId: host.id, hostname: host === null || host === void 0 ? void 0 : host.requestedHostname, })); } else { return massDeleteHostDialog.open({ hosts: (cluster.hosts || []).filter((h) => selectedHostIDs.includes(h.id)), onDelete: (host) => services_1.HostsService.delete(host), reloadCluster: () => (resetCluster ? void resetCluster() : dispatch((0, slice_1.forceReload)())), }); } }, [ selectedHostIDs, cluster.hosts, deleteHostDialog, massDeleteHostDialog, resetCluster, dispatch, ]); return { onDiskRole, onEditHost, actionChecks, onEditRole, actionResolver, onReset, onDelete, onAdditionalNtpSource, onUpdateDay2ApiVip, onSelect: isViewerMode ? undefined : onSelect, selectedHostIDs, setSelectedHostIDs, onMassChangeHostname, onMassDeleteHost, updateDiskSkipFormatting, }; }; exports.useHostsTable = useHostsTable; const HostsTableModals = ({ cluster, onDelete, onReset, onAdditionalNtpSource, onUpdateDay2ApiVip, }) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s; const { wizardPerPage, setWizardPerPage } = React.useContext(ClusterWizardContext_1.ClusterWizardContext) || {}; const dispatch = (0, react_redux_1.useDispatch)(); const { resetCluster } = React.useContext(common_1.AddHostsContext); const { uiState } = (0, react_redux_1.useSelector)(selectors_1.selectCurrentClusterState); const { t } = (0, use_translation_wrapper_1.useTranslation)(); const { eventsDialog, editHostDialog, deleteHostDialog, resetHostDialog, additionalNTPSourcesDialog, UpdateDay2ApiVipDialog, massUpdateHostnameDialog, massDeleteHostDialog, } = (0, ModalDialogsContext_1.useModalDialogsContext)(); const content = React.useMemo(() => [(0, tableUtils_1.hostnameColumn)(t), (0, HardwareStatus_1.hardwareStatusColumn)({ isWithinModal: true })], [t]); const paginationProps = (0, usePagination_1.usePagination)(((_b = (_a = massDeleteHostDialog.data) === null || _a === void 0 ? void 0 : _a.hosts) === null || _b === void 0 ? void 0 : _b.length) || 0, wizardPerPage, setWizardPerPage); if (uiState === common_1.ResourceUIState.UPDATE_ERROR) { // Do not show a modal beneath the ServerUpdateError return null; } return (React.createElement(React.Fragment, null, eventsDialog.isOpen && (React.createElement(common_1.EventsModal, { isOpen: true, title: `Host Events${eventsDialog.isOpen ? `: ${(_c = eventsDialog.data) === null || _c === void 0 ? void 0 : _c.hostname}` : ''}`, entityKind: "host", cluster: cluster, hostId: (_d = eventsDialog.data) === null || _d === void 0 ? void 0 : _d.hostId, onClose: eventsDialog.close, onFetchEvents: fetchEvents_1.onFetchEvents })), resetHostDialog.isOpen && (React.createElement(ResetHostModal_1.default, { isOpen: true, hostname: (_e = resetHostDialog.data) === null || _e === void 0 ? void 0 : _e.hostname, onClose: resetHostDialog.close, onReset: onReset })), deleteHostDialog.isOpen && (React.createElement(DeleteHostModal_1.default, { isOpen: true, hostname: (_f = deleteHostDialog.data) === null || _f === void 0 ? void 0 : _f.hostname, onClose: deleteHostDialog.close, onDelete: onDelete })), editHostDialog.isOpen && (React.createElement(hosts_1.EditHostModal, { isOpen: true, host: (_g = editHostDialog.data) === null || _g === void 0 ? void 0 : _g.host, inventory: (_h = editHostDialog.data) === null || _h === void 0 ? void 0 : _h.inventory, usedHostnames: (_j = cluster === null || cluster === void 0 ? void 0 : cluster.hosts) === null || _j === void 0 ? void 0 : _j.map((h) => h.requestedHostname).filter((h) => h), onClose: editHostDialog.close, onSave: (values) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { const host = services_1.ClustersService.findHost(cluster.hosts, values.hostId); if (!host) { throw new Error(`No host found with id:${values.hostId}`); } const { data } = yield services_1.HostsService.updateHostName(host, values.hostname); resetCluster ? void resetCluster() : dispatch((0, slice_1.updateHost)(data)); editHostDialog.close(); }), onHostSaveError: (e) => { if ((0, api_1.isUnknownServerError)(e)) { dispatch((0, slice_1.setServerUpdateError)()); editHostDialog.close(); } }, getEditErrorMessage: (e) => { (0, api_1.handleApiError)(e); return (0, api_1.getApiErrorMessage)(e); } })), additionalNTPSourcesDialog.isOpen && (React.createElement(AdditionalNTPSourcesDialog_1.AdditionalNTPSourcesDialog, { isOpen: true, additionalNtpSource: cluster.additionalNtpSource, onClose: additionalNTPSourcesDialog.close, onAdditionalNtpSource: onAdditionalNtpSource })), UpdateDay2ApiVipDialog.isOpen && (React.createElement(UpdateDay2ApiVipModal_1.default, { isOpen: true, onClose: UpdateDay2ApiVipDialog.close, onUpdateDay2ApiVip: onUpdateDay2ApiVip, currentApiVip: cluster.apiVipDnsName })), massUpdateHostnameDialog.isOpen && (React.createElement(common_1.MassChangeHostnameModal, { isOpen: true, onClose: massUpdateHostnameDialog.close, hosts: ((_l = (_k = massUpdateHostnameDialog.data) === null || _k === void 0 ? void 0 : _k.cluster) === null || _l === void 0 ? void 0 : _l.hosts) || [], selectedHostIDs: ((_m = massUpdateHostnameDialog.data) === null || _m === void 0 ? void 0 : _m.hostIDs) || [], onChangeHostname: (host, hostname) => services_1.HostsService.updateHostName(host, hostname), onHostSaveError: (e) => { if ((0, api_1.isUnknownServerError)(e)) { dispatch((0, slice_1.setServerUpdateError)()); editHostDialog.close(); } }, canChangeHostname: () => [true, undefined], reloadCluster: (_o = massUpdateHostnameDialog.data) === null || _o === void 0 ? void 0 : _o.reloadCluster })), massDeleteHostDialog.isOpen && (React.createElement(common_1.MassDeleteHostModal, { isOpen: true, onClose: massDeleteHostDialog.close, hosts: ((_p = massDeleteHostDialog.data) === null || _p === void 0 ? void 0 : _p.hosts) || [], onDelete: (_q = massDeleteHostDialog.data) === null || _q === void 0 ? void 0 : _q.onDelete, reloadCluster: (_r = massDeleteHostDialog.data) === null || _r === void 0 ? void 0 : _r.reloadCluster }, React.createElement(HostsTable_1.default, Object.assign({ hosts: ((_s = massDeleteHostDialog.data) === null || _s === void 0 ? void 0 : _s.hosts) || [], content: content }, paginationProps), React.createElement("div", null, "No hosts selected")))))); }; exports.HostsTableModals = HostsTableModals; //# sourceMappingURL=use-hosts-table.js.map