Skip to content

Commit 7b7d0f8

Browse files
committed
remove Firehose
1 parent c4f8ee0 commit 7b7d0f8

File tree

20 files changed

+511
-366
lines changed

20 files changed

+511
-366
lines changed

frontend/packages/console-app/src/actions/hooks/useBindingActions.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ export const useBindingActions = (
4545
const navigate = useNavigate();
4646
const [commonActions] = useCommonActions(model, obj, [CommonActionCreator.Delete] as const);
4747

48-
const { subjectIndex, subjects = [] } = obj;
48+
const { subjectIndex, subjects } = obj ?? {};
4949
const subject = subjects?.[subjectIndex];
5050
const deleteBindingSubject = useWarningModal({
5151
title: t('public~Delete {{label}} subject?', {
52-
label: model.kind,
52+
label: model?.kind,
5353
}),
5454
children: t('public~Are you sure you want to delete subject {{name}} of type {{kind}}?', {
5555
name: subject?.name,
@@ -146,9 +146,9 @@ export const useBindingActions = (
146146
: []),
147147
factory.DuplicateBinding(),
148148
factory.EditBindingSubject(),
149-
...(subjects.length === 1 ? [commonActions.Delete] : [factory.DeleteBindingSubject()]),
149+
...(subjects?.length === 1 ? [commonActions.Delete] : [factory.DeleteBindingSubject()]),
150150
];
151-
}, [memoizedFilterActions, subject?.kind, factory, subjects.length, commonActions.Delete]);
151+
}, [memoizedFilterActions, subject?.kind, factory, subjects?.length, commonActions.Delete]);
152152

153153
return actions;
154154
};

frontend/packages/console-app/src/components/nodes/NodeTerminal.tsx

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import type { ReactNode, FC } from 'react';
2-
import { useState, useEffect } from 'react';
2+
import { useState, useEffect, useMemo } from 'react';
33
import { Alert } from '@patternfly/react-core';
44
import { useTranslation, Trans } from 'react-i18next';
5+
import { WatchK8sResource } from '@console/dynamic-plugin-sdk/src/extensions/console-types';
6+
import { useK8sWatchResource } from '@console/dynamic-plugin-sdk/src/utils/k8s/hooks/useK8sWatchResource';
57
import { PodConnectLoader } from '@console/internal/components/pod';
6-
import { Firehose } from '@console/internal/components/utils/firehose';
78
import { LoadingBox } from '@console/internal/components/utils/status-box';
8-
import type { FirehoseResource, FirehoseResult } from '@console/internal/components/utils/types';
99
import { ImageStreamTagModel, NamespaceModel, PodModel } from '@console/internal/models';
1010
import { NodeKind, PodKind, k8sCreate, k8sGet, k8sKillByName } from '@console/internal/module/k8s';
1111
import PaneBody from '@console/shared/src/components/layout/PaneBody';
@@ -15,7 +15,9 @@ type NodeTerminalErrorProps = {
1515
};
1616

1717
type NodeTerminalInnerProps = {
18-
obj?: FirehoseResult<PodKind>;
18+
pod: PodKind | undefined;
19+
loaded: boolean;
20+
loadError: any;
1921
};
2022

2123
type NodeTerminalProps = {
@@ -124,7 +126,7 @@ const NodeTerminalError: FC<NodeTerminalErrorProps> = ({ error }) => {
124126
);
125127
};
126128

127-
const NodeTerminalInner: FC<NodeTerminalInnerProps> = ({ obj }) => {
129+
const NodeTerminalInner: FC<NodeTerminalInnerProps> = ({ pod, loaded, loadError }) => {
128130
const { t } = useTranslation();
129131
const message = (
130132
<Trans t={t} ns="console-app">
@@ -133,32 +135,47 @@ const NodeTerminalInner: FC<NodeTerminalInnerProps> = ({ obj }) => {
133135
</p>
134136
</Trans>
135137
);
136-
switch (obj?.data?.status?.phase) {
138+
139+
if (loadError) {
140+
return <NodeTerminalError error={loadError.message || t('console-app~Failed to load pod')} />;
141+
}
142+
143+
if (!loaded || !pod) {
144+
return <LoadingBox />;
145+
}
146+
147+
switch (pod.status?.phase) {
137148
case 'Failed':
138149
return (
139150
<NodeTerminalError
140151
error={
141152
<>
142153
{t('console-app~The debug pod failed. ')}
143-
{obj?.data?.status?.containerStatuses?.[0]?.state?.terminated?.message ||
144-
obj?.data?.status?.message}
154+
{pod.status?.containerStatuses?.[0]?.state?.terminated?.message ||
155+
pod.status?.message}
145156
</>
146157
}
147158
/>
148159
);
149160
case 'Running':
150-
return <PodConnectLoader obj={obj.data} message={message} attach />;
161+
return <PodConnectLoader obj={pod} message={message} attach />;
151162
default:
152163
return <LoadingBox />;
153164
}
154165
};
155166

156167
const NodeTerminal: FC<NodeTerminalProps> = ({ obj: node }) => {
157-
const [resources, setResources] = useState<FirehoseResource[]>([]);
168+
const [podWatchResource, setPodWatchResource] = useState<WatchK8sResource | null>(null);
158169
const [errorMessage, setErrorMessage] = useState('');
159170
const nodeName = node.metadata.name;
160171
const isWindows = node.status?.nodeInfo?.operatingSystem === 'windows';
161172

173+
// Memoize the watch resource to prevent unnecessary re-renders
174+
const watchResource = useMemo(() => podWatchResource, [podWatchResource]);
175+
176+
// Watch the debug pod using the hook
177+
const [pod, loaded, loadError] = useK8sWatchResource<PodKind>(watchResource);
178+
162179
useEffect(() => {
163180
let namespace;
164181
const name = `${nodeName?.replace(/\./g, '-')}-debug`;
@@ -196,15 +213,12 @@ const NodeTerminal: FC<NodeTerminalProps> = ({ obj: node }) => {
196213
await new Promise((resolve) => setTimeout(resolve, 1000));
197214
const debugPod = await k8sCreate(PodModel, podToCreate);
198215
if (debugPod) {
199-
setResources([
200-
{
201-
isList: false,
202-
kind: 'Pod',
203-
name,
204-
namespace: namespace.metadata.name,
205-
prop: 'obj',
206-
},
207-
]);
216+
setPodWatchResource({
217+
kind: 'Pod',
218+
name,
219+
namespace: namespace.metadata.name,
220+
isList: false,
221+
});
208222
}
209223
} catch (e) {
210224
setErrorMessage(e.message);
@@ -221,13 +235,11 @@ const NodeTerminal: FC<NodeTerminalProps> = ({ obj: node }) => {
221235
};
222236
}, [nodeName, isWindows]);
223237

224-
return errorMessage ? (
225-
<NodeTerminalError error={errorMessage} />
226-
) : (
227-
<Firehose resources={resources}>
228-
<NodeTerminalInner />
229-
</Firehose>
230-
);
238+
if (errorMessage) {
239+
return <NodeTerminalError error={errorMessage} />;
240+
}
241+
242+
return <NodeTerminalInner pod={pod} loaded={loaded} loadError={loadError} />;
231243
};
232244

233245
export default NodeTerminal;

frontend/public/components/RBAC/bindings.tsx

Lines changed: 67 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ import { TableColumn } from '@console/internal/module/k8s';
4747
import { GetDataViewRows, ResourceFilters } from '@console/app/src/components/data-view/types';
4848
import { tableFilters } from '../factory/table-filters';
4949
import { ButtonBar } from '../utils/button-bar';
50-
import { Firehose } from '../utils/firehose';
5150
import { getQueryArgument } from '../utils/router';
5251
import { kindObj } from '../utils/inject';
5352
import type { ListDropdownProps } from '../utils/list-dropdown';
@@ -57,7 +56,7 @@ import { ResourceName } from '../utils/resource-icon';
5756
import { StatusBox, LoadingBox } from '../utils/status-box';
5857
import { useAccessReview } from '../utils/rbac';
5958
import { flagPending } from '../../reducers/features';
60-
import { useK8sWatchResources } from '../utils/k8s-watch-hook';
59+
import { useK8sWatchResource, useK8sWatchResources } from '../utils/k8s-watch-hook';
6160

6261
// Split each binding into one row per subject
6362
export const flatten = (resources): BindingKind[] =>
@@ -185,14 +184,16 @@ const bindingType = (binding: BindingKind) => {
185184
if (!binding) {
186185
return undefined;
187186
}
188-
if (binding.roleRef.name.startsWith('system:')) {
187+
if (binding.roleRef?.name?.startsWith('system:')) {
189188
return 'system';
190189
}
191-
return binding.metadata.namespace ? 'namespace' : 'cluster';
190+
return binding.metadata?.namespace ? 'namespace' : 'cluster';
192191
};
193192

194193
const getDataViewRows: GetDataViewRows<BindingKind> = (data, columns) => {
195-
return data.map(({ obj: binding }) => {
194+
return data.map((row) => {
195+
// Extract the actual binding from the row object
196+
const binding = (row as any).obj || row;
196197
const rowCells = {
197198
[tableColumnInfo[0].id]: {
198199
cell: <BindingName binding={binding} />,
@@ -784,52 +785,81 @@ const getSubjectIndex = () => {
784785
};
785786

786787
const BindingLoadingWrapper: FC<BindingLoadingWrapperProps> = (props) => {
788+
const { obj, loaded, loadError, fixedKeys } = props;
787789
const [, setActiveNamespace] = useActiveNamespace();
790+
791+
// Don't render the form until data is loaded and valid
792+
if (!loaded) {
793+
return <LoadingBox />;
794+
}
795+
796+
if (loadError) {
797+
return <StatusBox data={obj} loaded={loaded} loadError={loadError} />;
798+
}
799+
800+
// Guard against empty/invalid data
801+
if (!obj || _.isEmpty(obj)) {
802+
return <StatusBox data={obj} loaded={loaded} loadError={loadError} />;
803+
}
804+
788805
const fixed: { [key: string]: any } = {};
789-
_.each(props.fixedKeys, (k) => (fixed[k] = _.get(props.obj.data, k)));
806+
_.each(fixedKeys, (k) => (fixed[k] = _.get(obj, k)));
807+
790808
return (
791-
<StatusBox {...props.obj}>
792-
<BaseEditRoleBinding
793-
{...props}
794-
setActiveNamespace={setActiveNamespace}
795-
fixed={fixed}
796-
obj={props.obj.data}
797-
/>
798-
</StatusBox>
809+
<BaseEditRoleBinding
810+
{...props}
811+
setActiveNamespace={setActiveNamespace}
812+
fixed={fixed}
813+
obj={obj}
814+
/>
799815
);
800816
};
801817

802818
export const EditRoleBinding: FC<EditRoleBindingProps> = ({ kind }) => {
803819
const { t } = useTranslation();
804820
const params = useParams();
821+
822+
const [obj, loaded, loadError] = useK8sWatchResource<RoleBindingKind | ClusterRoleBindingKind>({
823+
kind,
824+
name: params.name,
825+
namespace: params.ns,
826+
isList: false,
827+
});
828+
805829
return (
806-
<Firehose
807-
resources={[{ kind, name: params.name, namespace: params.ns, isList: false, prop: 'obj' }]}
808-
>
809-
<BindingLoadingWrapper
810-
fixedKeys={['kind', 'metadata', 'roleRef']}
811-
subjectIndex={getSubjectIndex()}
812-
titleVerbAndKind={t('public~Edit RoleBinding')}
813-
saveButtonText={t('public~Save')}
814-
/>
815-
</Firehose>
830+
<BindingLoadingWrapper
831+
obj={obj}
832+
loaded={loaded}
833+
loadError={loadError}
834+
fixedKeys={['kind', 'metadata', 'roleRef']}
835+
subjectIndex={getSubjectIndex()}
836+
titleVerbAndKind={t('public~Edit RoleBinding')}
837+
saveButtonText={t('public~Save')}
838+
/>
816839
);
817840
};
818841

819842
export const CopyRoleBinding: FC<EditRoleBindingProps> = ({ kind }) => {
820843
const { t } = useTranslation();
821844
const params = useParams();
845+
846+
const [obj, loaded, loadError] = useK8sWatchResource<RoleBindingKind | ClusterRoleBindingKind>({
847+
kind,
848+
name: params.name,
849+
namespace: params.ns,
850+
isList: false,
851+
});
852+
822853
return (
823-
<Firehose
824-
resources={[{ kind, name: params.name, namespace: params.ns, isList: false, prop: 'obj' }]}
825-
>
826-
<BindingLoadingWrapper
827-
fixedKeys={['kind']}
828-
subjectIndex={getSubjectIndex()}
829-
isCreate={true}
830-
titleVerbAndKind={t('public~Duplicate RoleBinding')}
831-
/>
832-
</Firehose>
854+
<BindingLoadingWrapper
855+
obj={obj}
856+
loaded={loaded}
857+
loadError={loadError}
858+
fixedKeys={['kind']}
859+
subjectIndex={getSubjectIndex()}
860+
isCreate={true}
861+
titleVerbAndKind={t('public~Duplicate RoleBinding')}
862+
/>
833863
);
834864
};
835865

@@ -881,9 +911,9 @@ type BindingLoadingWrapperProps = {
881911
titleVerbAndKind: string;
882912
saveButtonText?: string;
883913
isCreate?: boolean;
884-
obj?: {
885-
data: RoleBindingKind | ClusterRoleBindingKind;
886-
};
914+
obj?: RoleBindingKind | ClusterRoleBindingKind;
915+
loaded: boolean;
916+
loadError: any;
887917
};
888918

889919
type EditRoleBindingProps = {

frontend/public/components/cluster-settings/cluster-settings.tsx

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ import { ExternalLink } from '@console/shared/src/components/links/ExternalLink'
8888
import { documentationURLs, getDocumentationURL, isManaged } from '../utils/documentation';
8989
import { EmptyBox } from '../utils/status-box';
9090
import { FieldLevelHelp } from '../utils/field-level-help';
91-
import { Firehose } from '../utils/firehose';
92-
import type { FirehoseResource } from '../utils/types';
9391
import { HorizontalNav } from '../utils/horizontal-nav';
9492
import { ReleaseNotesLink } from '../utils/release-notes-link';
9593
import { ResourceLink, resourcePathFromModel } from '../utils/resource-link';
@@ -1170,23 +1168,24 @@ export const ClusterSettingsPage: FC = () => {
11701168
const { t } = useTranslation();
11711169
const hasClusterAutoscaler = useFlag(FLAGS.CLUSTER_AUTOSCALER);
11721170
const title = t('public~Cluster Settings');
1173-
const resources: FirehoseResource[] = [
1174-
{
1175-
kind: clusterVersionReference,
1176-
name: 'version',
1177-
isList: false,
1178-
prop: 'obj',
1179-
},
1180-
];
1181-
if (hasClusterAutoscaler) {
1182-
resources.push({
1183-
kind: clusterAutoscalerReference,
1184-
isList: true,
1185-
prop: 'autoscalers',
1186-
optional: true,
1187-
});
1188-
}
1189-
const resourceKeys = _.map(resources, 'prop');
1171+
1172+
const [objData, objLoaded, objLoadError] = useK8sWatchResource<ClusterVersionKind>({
1173+
kind: clusterVersionReference,
1174+
name: 'version',
1175+
});
1176+
1177+
const [autoscalersData, autoscalersLoaded, autoscalersLoadError] = useK8sWatchResource<
1178+
K8sResourceKind[]
1179+
>(
1180+
hasClusterAutoscaler
1181+
? {
1182+
kind: clusterAutoscalerReference,
1183+
isList: true,
1184+
}
1185+
: null,
1186+
);
1187+
1188+
const resourceKeys = hasClusterAutoscaler ? ['obj', 'autoscalers'] : ['obj'];
11901189
const pages = [
11911190
{
11921191
href: '',
@@ -1211,12 +1210,25 @@ export const ClusterSettingsPage: FC = () => {
12111210
telemetryPrefix: 'Cluster Settings',
12121211
titlePrefix: title,
12131212
};
1213+
1214+
const loaded = hasClusterAutoscaler ? objLoaded && autoscalersLoaded : objLoaded;
1215+
const loadError = objLoadError || autoscalersLoadError;
1216+
1217+
const horizontalNavProps = {
1218+
pages,
1219+
resourceKeys,
1220+
obj: { data: objData, loaded: objLoaded },
1221+
...(hasClusterAutoscaler && {
1222+
autoscalers: { data: autoscalersData, loaded: autoscalersLoaded },
1223+
}),
1224+
loaded,
1225+
loadError,
1226+
};
1227+
12141228
return (
12151229
<PageTitleContext.Provider value={titleProviderValues}>
12161230
<PageHeading title={<div data-test-id="cluster-settings-page-heading">{title}</div>} />
1217-
<Firehose resources={resources}>
1218-
<HorizontalNav pages={pages} resourceKeys={resourceKeys} />
1219-
</Firehose>
1231+
<HorizontalNav {...(horizontalNavProps as any)} />
12201232
</PageTitleContext.Provider>
12211233
);
12221234
};

0 commit comments

Comments
 (0)