diff --git a/frontend/src/components/common/Resource/EditButton.tsx b/frontend/src/components/common/Resource/EditButton.tsx
index 0e9cfc15ba..a11b3a8f77 100644
--- a/frontend/src/components/common/Resource/EditButton.tsx
+++ b/frontend/src/components/common/Resource/EditButton.tsx
@@ -87,7 +87,7 @@ export default function EditButton(props: EditButtonProps) {
}
if (isReadOnly) {
- return ;
+ return ;
}
return (
diff --git a/frontend/src/components/common/Resource/MainInfoSection/MainInfoSectionHeader.tsx b/frontend/src/components/common/Resource/MainInfoSection/MainInfoSectionHeader.tsx
index 2a354093b8..6fe536aa47 100644
--- a/frontend/src/components/common/Resource/MainInfoSection/MainInfoSectionHeader.tsx
+++ b/frontend/src/components/common/Resource/MainInfoSection/MainInfoSectionHeader.tsx
@@ -1,19 +1,9 @@
-import { has } from 'lodash';
-import React, { isValidElement } from 'react';
+import React from 'react';
import { useLocation } from 'react-router-dom';
import { KubeObject } from '../../../../lib/k8s/KubeObject';
-import {
- DefaultHeaderAction,
- HeaderAction,
- HeaderActionType,
-} from '../../../../redux/actionButtonsSlice';
-import { useTypedSelector } from '../../../../redux/reducers/reducers';
-import ErrorBoundary from '../../ErrorBoundary';
+import { HeaderAction } from '../../../../redux/actionButtonsSlice';
import SectionHeader, { HeaderStyle } from '../../SectionHeader';
-import DeleteButton from '../DeleteButton';
-import EditButton from '../EditButton';
-import { RestartButton } from '../RestartButton';
-import ScaleButton from '../ScaleButton';
+import { generateActions } from '../generateHeaderActions';
export interface MainInfoHeaderProps {
resource: T | null;
@@ -32,90 +22,7 @@ export interface MainInfoHeaderProps {
export function MainInfoHeader(props: MainInfoHeaderProps) {
const { resource, title, actions = [], headerStyle = 'main', noDefaultActions = false } = props;
- const headerActions = useTypedSelector(state => state.actionButtons.headerActions);
- const headerActionsProcessors = useTypedSelector(
- state => state.actionButtons.headerActionsProcessors
- );
- function setupAction(headerAction: HeaderAction) {
- let Action = has(headerAction, 'action') ? (headerAction as any).action : headerAction;
-
- if (!noDefaultActions && has(headerAction, 'id')) {
- switch ((headerAction as HeaderAction).id) {
- case DefaultHeaderAction.RESTART:
- Action = RestartButton;
- break;
- case DefaultHeaderAction.SCALE:
- Action = ScaleButton;
- break;
- case DefaultHeaderAction.EDIT:
- Action = EditButton;
- break;
- case DefaultHeaderAction.DELETE:
- Action = DeleteButton;
- break;
- default:
- break;
- }
- }
-
- if (!Action || (headerAction as unknown as HeaderAction).action === null) {
- return null;
- }
-
- if (isValidElement(Action)) {
- return {Action};
- } else if (Action === null) {
- return null;
- } else if (typeof Action === 'function') {
- return (
-
-
-
- );
- }
- }
-
- const defaultActions = [
- {
- id: DefaultHeaderAction.RESTART,
- },
- {
- id: DefaultHeaderAction.SCALE,
- },
- {
- id: DefaultHeaderAction.EDIT,
- },
- {
- id: DefaultHeaderAction.DELETE,
- },
- ];
-
- let hAccs: HeaderAction[] = [];
- const accs = typeof actions === 'function' ? actions(resource) || [] : actions;
- if (accs !== null) {
- hAccs = [...accs].map((action, i): HeaderAction => {
- if ((action as HeaderAction)?.id !== undefined) {
- return action as HeaderAction;
- } else {
- return { id: `gen-${i}`, action: action as HeaderActionType };
- }
- });
- }
-
- let actionsProcessed = [...headerActions, ...hAccs, ...defaultActions];
- if (headerActionsProcessors.length > 0) {
- for (const headerProcessor of headerActionsProcessors) {
- actionsProcessed = headerProcessor.processor(resource, actionsProcessed);
- }
- }
-
- const allActions = React.Children.toArray(
- (function propsActions() {
- const pluginAddedActions = actionsProcessed.map(setupAction);
- return React.Children.toArray(pluginAddedActions);
- })()
- );
-
+ const allActions = generateActions(resource, 'action', actions, noDefaultActions);
return (
= {
/** Unique id for the column, not required but recommended */
@@ -87,7 +83,7 @@ export interface ResourceTableProps {
enableRowActions?: boolean;
/** Show or hide row selections and actions @default false*/
enableRowSelection?: boolean;
- actions?: null | RowAction[];
+ actions?: null | HeaderAction[];
/** Provide a list of columns that won't be shown and cannot be turned on */
hideColumns?: string[] | null;
/** ID for the table. Will be used by plugins to identify this table.
@@ -416,52 +412,12 @@ function ResourceTableContent(props: ResourceTablePr
tableSettings,
]);
- const defaultActions: RowAction[] = [
- {
- id: DefaultHeaderAction.RESTART,
- action: ({ item }) => ,
- },
- {
- id: DefaultHeaderAction.SCALE,
- action: ({ item }) => ,
- },
- {
- id: DefaultHeaderAction.EDIT,
- action: ({ item, closeMenu }) => (
-
- ),
- },
- {
- id: DefaultHeaderAction.VIEW,
- action: ({ item }) => ,
- },
- {
- id: DefaultHeaderAction.DELETE,
- action: ({ item, closeMenu }) => (
-
- ),
- },
- ];
- let hAccs: RowAction[] = [];
- if (actions !== undefined && actions !== null) {
- hAccs = actions;
- }
-
- const actionsProcessed: RowAction[] = [...hAccs, ...defaultActions];
-
const renderRowActionMenuItems = useMemo(() => {
- if (actionsProcessed.length === 0) {
+ if (!enableRowActions) {
return null;
}
- return ({ closeMenu, row }: { closeMenu: () => void; row: MRT_Row> }) => {
- return actionsProcessed.map(action => {
- if (action.action === undefined || action.action === null) {
- return ;
- }
- return action.action({ item: row.original, closeMenu });
- });
- };
- }, [actionsProcessed]);
+ return generateRowActionsMenu(actions);
+ }, [actions, enableRowActions]);
const wrappedEnableRowSelection = useMemo(() => {
if (import.meta.env.REACT_APP_HEADLAMP_ENABLE_ROW_SELECTION === 'false') {
diff --git a/frontend/src/components/common/Resource/generateHeaderActions.tsx b/frontend/src/components/common/Resource/generateHeaderActions.tsx
new file mode 100644
index 0000000000..37a30e3d4e
--- /dev/null
+++ b/frontend/src/components/common/Resource/generateHeaderActions.tsx
@@ -0,0 +1,130 @@
+import { has } from 'lodash';
+import { MRT_Row } from 'material-react-table';
+import { isValidElement } from 'react';
+import React from 'react';
+import { KubeObject } from '../../../lib/k8s/KubeObject';
+import {
+ DefaultHeaderAction,
+ HeaderAction,
+ HeaderActionType,
+} from '../../../redux/actionButtonsSlice';
+import { useTypedSelector } from '../../../redux/reducers/reducers';
+import { ButtonStyle } from '../ActionButton/ActionButton';
+import ErrorBoundary from '../ErrorBoundary';
+import DeleteButton from './DeleteButton';
+import EditButton from './EditButton';
+import { RestartButton } from './RestartButton';
+import ScaleButton from './ScaleButton';
+
+export function generateActions(
+ resource: T | null,
+ buttonStyle: ButtonStyle,
+ actions:
+ | ((resource: T | null) => React.ReactNode[] | HeaderAction[] | null)
+ | React.ReactNode[]
+ | null
+ | HeaderAction[],
+ noDefaultActions?: boolean,
+ closeMenu?: () => void
+): React.ReactNode[] {
+ const headerActions = useTypedSelector(state => state.actionButtons.headerActions);
+ const headerActionsProcessors = useTypedSelector(
+ state => state.actionButtons.headerActionsProcessors
+ );
+ function setupAction(headerAction: HeaderAction) {
+ let Action = has(headerAction, 'action') ? (headerAction as any).action : headerAction;
+
+ if (!noDefaultActions && has(headerAction, 'id')) {
+ switch ((headerAction as HeaderAction).id) {
+ case DefaultHeaderAction.RESTART:
+ Action = RestartButton;
+ break;
+ case DefaultHeaderAction.SCALE:
+ Action = ScaleButton;
+ break;
+ case DefaultHeaderAction.EDIT:
+ Action = EditButton;
+ break;
+ case DefaultHeaderAction.DELETE:
+ Action = DeleteButton;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!Action || (headerAction as unknown as HeaderAction).action === null) {
+ return null;
+ }
+
+ if (isValidElement(Action)) {
+ return {Action};
+ } else if (Action === null) {
+ return null;
+ } else if (typeof Action === 'function') {
+ return (
+
+
+
+ );
+ }
+ }
+
+ const defaultActions = [
+ {
+ id: DefaultHeaderAction.RESTART,
+ },
+ {
+ id: DefaultHeaderAction.SCALE,
+ },
+ {
+ id: DefaultHeaderAction.EDIT,
+ },
+ {
+ id: DefaultHeaderAction.DELETE,
+ },
+ ];
+
+ let hAccs: HeaderAction[] = [];
+ const accs = typeof actions === 'function' ? actions(resource) || [] : actions;
+ if (accs !== null) {
+ hAccs = [...accs].map((action, i): HeaderAction => {
+ if ((action as HeaderAction)?.id !== undefined) {
+ return action as HeaderAction;
+ } else {
+ return { id: `gen-${i}`, action: action as HeaderActionType };
+ }
+ });
+ }
+
+ let actionsProcessed = [...headerActions, ...hAccs, ...defaultActions];
+ if (headerActionsProcessors.length > 0) {
+ for (const headerProcessor of headerActionsProcessors) {
+ actionsProcessed = headerProcessor.processor(resource, actionsProcessed);
+ }
+ }
+
+ const allActions = React.Children.toArray(
+ (function propsActions() {
+ const pluginAddedActions = actionsProcessed.map(setupAction);
+ return React.Children.toArray(pluginAddedActions);
+ })()
+ );
+ return allActions;
+}
+
+export default function generateRowActionsMenu(actions: HeaderAction[] | null | undefined) {
+ return ({ closeMenu, row }: { closeMenu: () => void; row: MRT_Row> }) => {
+ const actionsProcessed = generateActions(
+ row.original as any,
+ 'menu',
+ actions || [],
+ false,
+ closeMenu
+ );
+ if (actionsProcessed.length === 0) {
+ return null;
+ }
+ return actionsProcessed;
+ };
+}
diff --git a/frontend/src/components/common/Resource/index.test.ts b/frontend/src/components/common/Resource/index.test.ts
index ae4c85ad8c..4ec6b80934 100644
--- a/frontend/src/components/common/Resource/index.test.ts
+++ b/frontend/src/components/common/Resource/index.test.ts
@@ -35,6 +35,7 @@ const checkExports = [
'SimpleEditor',
'ViewButton',
'AuthVisible',
+ 'generateHeaderActions',
];
function getFilesToVerify() {
diff --git a/frontend/src/redux/actionButtonsSlice.ts b/frontend/src/redux/actionButtonsSlice.ts
index cf96080970..dff637395d 100644
--- a/frontend/src/redux/actionButtonsSlice.ts
+++ b/frontend/src/redux/actionButtonsSlice.ts
@@ -7,17 +7,13 @@ export type HeaderActionType = ((...args: any[]) => ReactNode) | null | ReactEle
export type DetailsViewFunc = HeaderActionType;
export type AppBarActionType = ((...args: any[]) => ReactNode) | null | ReactElement | ReactNode;
-export type RowActionType = ((item: any) => JSX.Element | null | ReactNode) | null;
export type HeaderAction = {
id: string;
action?: HeaderActionType;
};
-export type RowAction = {
- id: string;
- action?: RowActionType;
-};
+export type RowAction = HeaderAction;
export type AppBarAction = {
id: string;