@openshift-assisted/ui-lib
Version:
React component library for the Assisted Installer UI
365 lines • 22.2 kB
JavaScript
;
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